1

我试图将内存 DC 保存到位图文件中。但我无法获得关于以下大小的正确值:

infoHeader.biSizeImage

fileHeader.bfSize


fileHeader.bfOffBits

WriteFile(hFile, &fileHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);

WriteFile(hFile, &infoHeader, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);

WriteFile(hFile, pPixels, info.bmiHeader.biSizeImage, &dwBytesWritten, NULL);

我可以得到一个文件,但我无法打开它,因为它抱怨它已损坏或不再受支持。

有很多关于保存到 bmp 的来源,但其中许多对大小有不同的价值。有些还包括调色板信息。我完全糊涂了。

有人可以指出如何填写正确的信息吗?

static void SaveAsBmp(TCHAR *fileName)
{
HDC hdcView = GetDC(hwndView);
HDC memDC = CreateCompatibleDC(hdcView);

RECT rcView;
GetClientRect(hwndView, &rcView);

int rcView_dx = rcView.right - rcView.left;
int rcView_dy = rcView.bottom - rcView.top;

HBITMAP hMemBmp = CreateCompatibleBitmap(hdcView, rcView_dx, rcView_dy);
HBITMAP hOldBmp = (HBITMAP)SelectObject(memDC, hMemBmp);

BitBlt(memDC, 0, 0, rcView_dx, rcView_dy, hdcView, 0, 0, SRCCOPY);

//----------

BITMAP bmp;
GetObject(hMemBmp, sizeof(BITMAP), &bmp);

//----------

WORD wBits = (WORD)(bmp.bmBitsPixel * bmp.bmPlanes);

if(wBits <=  1)                                                   
    wBits = 1;             
else  if(wBits <=  4)                               
    wBits  = 4;             
else if(wBits <=  8)                               
    wBits  = 8;             
else if (wBits <= 16)
    wBits = 16;
else if (wBits <= 24)
    wBits = 24;
else wBits = 32; 

//----------

BITMAPINFOHEADER infoHeader;
BITMAPINFO info;
info.bmiHeader = infoHeader;

infoHeader.biSize = sizeof(BITMAPINFOHEADER);    
infoHeader.biWidth = bmp.bmWidth; 
infoHeader.biHeight = bmp.bmHeight;    
infoHeader.biPlanes = bmp.bmPlanes;    
infoHeader.biBitCount = bmp.bmBitsPixel;     
infoHeader.biCompression = BI_RGB;   

infoHeader.biSizeImage = 2 * ((bmp.bmWidth * bmp.bmBitsPixel + 15) / 16)  * bmp.bmPlanes * bmp.bmHeight;
infoHeader.biXPelsPerMeter = 0;  
infoHeader.biYPelsPerMeter = 0;
infoHeader.biClrUsed = 0;
infoHeader.biClrImportant = 0;

RGBQUAD *pPixels = new RGBQUAD[bmp.bmWidth * bmp.bmWidth]; 
GetDIBits(memDC, hMemBmp, 0, bmp.bmWidth, pPixels, &info, DIB_RGB_COLORS);

BITMAPFILEHEADER fileHeader;
fileHeader.bfType = 0x4d42;
fileHeader.bfSize = (DWORD)(sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + info.bmiHeader.biSizeImage);
fileHeader.bfReserved1 = 0;
fileHeader.bfReserved2 = 0;
fileHeader.bfOffBits = (DWORD)(sizeof(BITMAPFILEHEADER) + info.bmiHeader.biSize);

HANDLE hFile = CreateFile(fileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL);

DWORD dwBytesWritten;

WriteFile(hFile, &fileHeader, sizeof(BITMAPFILEHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, &infoHeader, sizeof(BITMAPINFOHEADER), &dwBytesWritten, NULL);
WriteFile(hFile, pPixels, info.bmiHeader.biSizeImage, &dwBytesWritten, NULL);

CloseHandle(hFile);

delete pPixels;

SelectObject(memDC, hOldBmp);
DeleteObject(hMemBmp);
DeleteDC(memDC);
4

1 回答 1

0

infoHeader.biSizeImage = 2 * ((bmp.bmWidth * bmp.bmBitsPixel + 15) / 16) * bmp.bmPlanes * bmp.bmHeight;

在这里看起来不正确,它应该是bmp.bmBitsPixel >> 3,假设它是 24 或 32。也就是说,它是每像素的位数,而您正在使用它,就好像它是每像素的字节数。

总体而言,代码看起来不错,您应该使用调试器检查变量以查找不匹配项(或将它们粘贴到此处,尤其是BITMAPINFOHEADER)。

另请注意,您可能以不同的方式完成了它:CreateCompatibleBitmap您可以使用CreateDIBSection您感兴趣的格式,例如 24 bpp RGB,而不是使用,您将立即收到指向位的原始指针。然后将数据传送到此位图中,您不再需要GetObject调用,因为您已经拥有了所需的一切。并且,GetObject可能会返回您DIBSECTION已经准备好使用的格式BITMAPINFOHEADER。都是一样的,只是更简单。

于 2012-09-08T18:28:10.260 回答