GetBitmapBits和GetDIBits的区别(Windows GDI)

Windows GDI中有两个用来得到位图图像数据的API,分别是GetBitmapBits和GetDIBits;
按照MSDN的解释,前者是用来得到设备独立位图的BITS,
后者是得到兼容位图的BITS,

所以在调用该函数的时候,
第一个主要的区别是:GetDIBits需要提供一个设备内容,同时需要将位图的HANDLE选进这个设备内容(DC)才能能够得到位图的信息。
我想上面的区别大家可能都知道,
其实它还隐藏着另一个区别:就是对于同一个位图,得到的BITS内容的BUFFER不一样!

大家都知道BMP文件存储数据是倒叙的,也就是从图像的右下角开始存储,文件的最后是图像的左上角(这个来历可以看:WINDOWS编程中介绍);
使用GetBitmapBits取得的BUFFER,位图的右下角的内容为第一个字节,实际上和真正的图像字节应该是一样的,

而GetDIBits刚好相反,其BUFFER的顺序符合BMP文件中的顺序,如果按照正常的坐标,其存储顺序应该是倒叙。
所以在程序中要合理的使用这两个API来得到你想要的位图数据。

以上是摘自网上的,下面是具体例子展示说明:
---------------------------------------------------------------------------------------------------
一,如果我们的CBitmap是得到设备兼容的位图:即:CreateCompatibleBitmap来创建的位图,则最好使用
GetDIBits得到位图数据; ::GetDIBits(memdc.m_hDC, btp, 0, bp.bmHeight, pData, pBpInfo, DIB_RGB_COLORS);
之后就可以根据位图数据显示该位图了
// 在客户区显示位图
 CClientDC dc(this);
 StretchDIBits(dc.m_hDC, 0, 0, bp.bmWidth, bp.bmHeight, 0, 0, bp.bmWidth, bp.bmHeight, pData, pBpInfo, DIB_RGB_COLORS, SRCCOPY);

 也可以利用GetBitmapBits得到位图信息但是得到的位图数据需要转化才与本来位图实际数据对应。

// 对于与设备兼容的位图,用GetBitmapBits得到的位图数据需要转换才可以正确显示位图
 // 用GetBitmapBits,然后交换每行数据,最后再交行整个缓冲数据
 // 位图本来存储格式如下:
 // [g....k]
 // [j....t]
 // [......]
 // [y....b]
 // [x....a]
 // 但是利用GetBitmapBits得到位图数据格式为 [x...a][y...b][....][j...t][g...k]
 // 我们需要将其转化为[g...k][j...t][...][y...b][x...a]
 // 步骤为:第一步将每行数据逆置,得到[a...x][b...y][...][t...j][k...g]
 // 第二步:将第一步得到的格式,当做一个整体,进行逆置则得到[g...k][j...t][...][y...b][x...a]
 dwRet = btp.GetBitmapBits(bp.bmWidthBytes * bp.bmHeight, pData); // 该方式获取位图信息,位图对象应该是LoadBitmap形式获取的

 int nRow = bp.bmHeight; // 行数
 // 先交换每行的位图数据
 char *pS = NULL, *pE= NULL;
 for (int j = 1; j <= nRow; j++)
 {
  pS = pData+(j-1)*bp.bmWidthBytes;
  pE = pData+j*bp.bmWidthBytes -1 ;

  SwapArray(pS, pE, bp.bmWidthBytes);
 }

 // 再交换整个数组数据
 SwapArray(pData, pData+dwRet-1, dwRet);
  
 // 在客户区显示位图
 CClientDC dc(this);
 StretchDIBits(dc.m_hDC, 0, 0, bp.bmWidth, bp.bmHeight, 0, 0, bp.bmWidth, bp.bmHeight, pData, pBpInfo, DIB_RGB_COLORS, SRCCOPY);
 LocalFree(pData);


void SwapArray(char *pS, char *pE, int nCount)
{
 int nMidIndex = nCount / 2;

 char tmp;
 for (int i = 0; i < nMidIndex; i ++)
 {
  tmp = *pS;
  *pS = *pE;
  *pE = tmp;
  pS++;
  pE--;
 }
 
}

 

二,如果位图是与设备无关,例如:利用LoadBitmap加载了位图资源,则利用GetBitmapBits得到问题数据,也需要转化的,才可以显示位图了,例如:
 

// 创建独立于设备的位图
 CClientDC dc1(this);
 CBitmap btp1;
 btp1.LoadBitmap(IDB_BITMAP1);
 btp1.GetBitmap(&bp);
 pData = (char*)LocalAlloc(LPTR, bp.bmWidthBytes * bp.bmHeight);
 btp1.GetBitmapBits(bp.bmWidthBytes * bp.bmHeight, pData);

 pBtInfo->bmiHeader.biBitCount = bp.bmBitsPixel;
 pBtInfo->bmiHeader.biClrImportant = 0;
 pBtInfo->bmiHeader.biCompression = 0;
 pBtInfo->bmiHeader.biHeight = bp.bmHeight;
 pBtInfo->bmiHeader.biWidth = bp.bmWidth;
 pBtInfo->bmiHeader.biPlanes = bp.bmPlanes;
 pBtInfo->bmiHeader.biSizeImage = bp.bmWidthBytes * bp.bmHeight;
 pBtInfo->bmiHeader.biSize = sizeof(BITMAPINFO);
 pBtInfo->bmiHeader.biXPelsPerMeter = 0;
 pBtInfo->bmiHeader.biYPelsPerMeter = 0;

 int nRows = bp.bmHeight; // 位图行数
 char *pS = NULL, *pE = NULL;
 for (int i = 0; i < nRows; i++)
 {
  pS = pData + i * bp.bmWidthBytes;
  SwapArray(pS, bp.bmWidthBytes);
 }
 
 SwapArray(pData, bp.bmWidthBytes * bp.bmHeight);
 StretchDIBits(dc1.m_hDC, 0, 0, bp.bmWidth, bp.bmHeight, 0, 0, bp.bmWidth, bp.bmHeight, pData, pBtInfo, DIB_RGB_COLORS, SRCCOPY);

// 参数pS:要交换的数组的起始地址
// 参数dwCount:要交换的数据的总长度
void CTddDlg::SwapArray(char *pS, UINT dwCount)
{
 char temp;
 for (UINT i = 0; i < dwCount / 2; i++)
 {
  temp = pS[i];
  pS[i] = pS[dwCount - i -1];
  pS[dwCount - i - 1] = temp;
 }
}

你可能感兴趣的:(windows,api,null,存储,buffer,colors)