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