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);