// 从将内存位图句柄(HBITMAP)写入到BMP文件中
// 返回 非零表示成功写入
// 参数 LPCTSTR 文件名
// 参数 HBITMAP 内存位图句柄
BOOL CreateBMPFileFromBitmapObject(LPCTSTR szFileName, HBITMAP hBitmap)
{
BITMAPFILEHEADER hdr; // bitmap file-header
BITMAP bmp;
PBITMAPINFOHEADER pbih = NULL; // bitmap info-header
PBITMAPINFO pbmi = NULL;
LPBYTE lpBits = NULL; // memory pointer
DWORD dwTotal; // total count of bytes
DWORD dwTmp;
HANDLE hFile = NULL;
HDC hdc = NULL;
WORD cClrBits;
BOOL bSuccess = FALSE;
if(hBitmap == NULL || szFileName == NULL)
return FALSE;
// Retrieve the bitmap color format, width, and height.
if (!::GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bmp))
return FALSE;
// Convert the color format to a count of bits.
cClrBits = (WORD)(bmp.bmPlanes * bmp.bmBitsPixel);
if (cClrBits == 1) cClrBits = 1;
else if (cClrBits <= 4) cClrBits = 4;
else if (cClrBits <= 8) cClrBits = 8;
else if (cClrBits <= 16) cClrBits = 16;
else if (cClrBits <= 24) cClrBits = 24;
else cClrBits = 32;
// Allocate memory for the BITMAPINFO structure. (This structure
// contains a BITMAPINFOHEADER structure and an array of RGBQUAD
// data structures.)
//if (cClrBits != 24)
if (cClrBits < 24) // 防止在64位机下的出错
{
pbmi = (PBITMAPINFO) LocalAlloc(LPTR,
sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * (1<< cClrBits));
}
else
{
// There is no RGBQUAD array for the 24-bit-per-pixel format.
pbmi = (PBITMAPINFO) LocalAlloc(LPTR, sizeof(BITMAPINFOHEADER));
}
if(pbmi == NULL)
goto end;
// Initialize the fields in the BITMAPINFO structure.
pbmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pbmi->bmiHeader.biWidth = bmp.bmWidth;
pbmi->bmiHeader.biHeight = bmp.bmHeight;
pbmi->bmiHeader.biPlanes = bmp.bmPlanes;
pbmi->bmiHeader.biBitCount = bmp.bmBitsPixel;
if (cClrBits < 24)
pbmi->bmiHeader.biClrUsed = (1<<cClrBits);
// If the bitmap is not compressed, set the BI_RGB flag.
pbmi->bmiHeader.biCompression = BI_RGB;
// Compute the number of bytes in the array of color
// indices and store the result in biSizeImage.
// For Windows NT, the width must be DWORD aligned unless
// the bitmap is RLE compressed. This example shows this.
// For Windows 95/98/Me, the width must be WORD aligned unless the
// bitmap is RLE compressed.
pbmi->bmiHeader.biSizeImage = ((pbmi->bmiHeader.biWidth * cClrBits +31) & ~31) /8
* pbmi->bmiHeader.biHeight;
// Set biClrImportant to 0, indicating that all of the
// device colors are important.
pbmi->bmiHeader.biClrImportant = 0;
hdc = GetDC(NULL);
pbih = (PBITMAPINFOHEADER) pbmi;
lpBits = (LPBYTE) ::GlobalAlloc(GMEM_FIXED, pbih->biSizeImage);
if(lpBits == NULL)
goto end;
// Retrieve the color table (RGBQUAD array) and the bits
// (array of palette indices) from the DIB.
if (!GetDIBits(hdc, hBitmap, 0, (WORD) pbih->biHeight, lpBits, pbmi, DIB_RGB_COLORS))
goto end;
// Create the .BMP file.
hFile = CreateFile(szFileName,
GENERIC_READ | GENERIC_WRITE,
(DWORD) 0,
NULL,
CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL,
(HANDLE) NULL);
if (hFile == INVALID_HANDLE_VALUE)
goto end;
hdr.bfType = 0x4d42; // 0x42 = "B" 0x4d = "M"
// Compute the size of the entire file.
hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + pbih->biSize +
pbih->biClrUsed * sizeof(RGBQUAD) + pbih->biSizeImage);
hdr.bfReserved1 = 0;
hdr.bfReserved2 = 0;
// Compute the offset to the array of color indices.
hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + pbih->biSize +
pbih->biClrUsed * sizeof (RGBQUAD);
// Copy the BITMAPFILEHEADER into the .BMP file.
if (!WriteFile(hFile, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), (LPDWORD) &dwTmp, NULL))
goto end;
// Copy the BITMAPINFOHEADER and RGBQUAD array into the file.
if (!WriteFile(hFile, (LPVOID) pbih,
sizeof(BITMAPINFOHEADER) + pbih->biClrUsed * sizeof (RGBQUAD),
(LPDWORD) &dwTmp, ( NULL))
)
goto end;
// Copy the array of color indices into the .BMP file.
dwTotal = pbih->biSizeImage;
if (!WriteFile(hFile, (LPVOID) lpBits, (int) dwTotal, (LPDWORD) &dwTmp,NULL))
goto end;
bSuccess = TRUE;
end:;
// Close the .BMP file.
if(hFile != NULL)
CloseHandle(hFile);
if(pbmi != NULL)
LocalFree((HLOCAL)pbmi);
// Free memory.
if(lpBits != NULL)
GlobalFree((HGLOBAL)lpBits);
if(hdc != NULL)
ReleaseDC(NULL, hdc);
return bSuccess;
}