VC下将位图存为BMP文件(Save CBitmap to file)
从The Code Project上找到的代码,也不容易的
代码声明:
/************************************************** * CBitmap To File Function * 参数: * pWnd - 窗体指针 * cb - 所要存储的CBitmap对象 * name - 所要存储的文件名 **************************************************/ BOOL WriteBMPtoFile( CWnd* pWnd, CBitmap& cb,CString name ); //另外两个函数(不需要自己调用) HANDLE DDBToDIB( CBitmap& bitmap, DWORD dwCompression, CPalette* pPal ); BOOL WriteDIB( LPTSTR szFile, HANDLE hDIB );
具体代码:
/************************************************************************/ // CBitmap转换为.bmp图片函数 /************************************************************************/ BOOL CMyFun::WriteBMPtoFile(CWnd* pWnd, CBitmap& cb,CString name) { // Create logical palette if device support a palette CWindowDC* mpScreenDC = new CWindowDC(pWnd); CDC dc; dc.CreateCompatibleDC(mpScreenDC); CPalette pal; if( dc.GetDeviceCaps(RASTERCAPS) & RC_PALETTE ) { UINT nSize = sizeof(LOGPALETTE) + (sizeof(PALETTEENTRY) * 256); LOGPALETTE *pLP = (LOGPALETTE *) new BYTE[nSize]; pLP->palVersion = 0x300; pLP->palNumEntries = GetSystemPaletteEntries(dc , 0, 255, pLP->palPalEntry ); // Create the palette pal.CreatePalette( pLP ); delete[] pLP; } // Convert the bitmap to a DIB HANDLE hDIB = DDBToDIB(cb, BI_RGB, &pal ); if( hDIB == NULL ) return FALSE; // Write it to file WriteDIB(name.GetBuffer(1), hDIB ); //(LPCTSTR)CString // Free the memory allocated by DDBToDIB for the DIB GlobalFree( hDIB ); dc.DeleteDC(); return TRUE; } HANDLE CMyFun::DDBToDIB( CBitmap& bitmap, DWORD dwCompression, CPalette* pPal ) { BITMAP bm; BITMAPINFOHEADER bi; LPBITMAPINFOHEADER lpbi; DWORD dwLen; HANDLE hDIB; HANDLE handle; HDC hDC; HPALETTE hPal; ASSERT( bitmap.GetSafeHandle() ); // The function has no arg for bitfields if( dwCompression == BI_BITFIELDS ) return NULL; // If a palette has not been supplied use defaul palette hPal = (HPALETTE) pPal->GetSafeHandle(); if (hPal==NULL) hPal = (HPALETTE) GetStockObject(DEFAULT_PALETTE); // Get bitmap information bitmap.GetObject(sizeof(bm),(LPSTR)&bm); // Initialize the bitmapinfoheader bi.biSize = sizeof(BITMAPINFOHEADER); bi.biWidth = bm.bmWidth; bi.biHeight = bm.bmHeight; bi.biPlanes = 1; bi.biBitCount = bm.bmPlanes * bm.bmBitsPixel; bi.biCompression = dwCompression; bi.biSizeImage = 0; bi.biXPelsPerMeter = 0; bi.biYPelsPerMeter = 0; bi.biClrUsed = 0; bi.biClrImportant = 0; // Compute the size of the infoheader and the color table int nColors = (1 << bi.biBitCount); if( nColors > 256 ) nColors = 0; dwLen = bi.biSize + nColors * sizeof(RGBQUAD); // We need a device context to get the DIB from hDC = ::GetDC(NULL); hPal = SelectPalette(hDC,hPal,FALSE); RealizePalette(hDC); // Allocate enough memory to hold bitmapinfoheader and color table hDIB = GlobalAlloc(GMEM_FIXED,dwLen); if (!hDIB){ SelectPalette(hDC,hPal,FALSE); ::ReleaseDC(NULL,hDC); return NULL; } lpbi = (LPBITMAPINFOHEADER)hDIB; *lpbi = bi; // Call GetDIBits with a NULL lpBits param, so the device driver // will calculate the biSizeImage field GetDIBits(hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, (DWORD)bi.biHeight, (LPBYTE)NULL, (LPBITMAPINFO)lpbi, (DWORD)DIB_RGB_COLORS); bi = *lpbi; // If the driver did not fill in the biSizeImage field, then compute it // Each scan line of the image is aligned on a DWORD (32bit) boundary if (bi.biSizeImage == 0){ bi.biSizeImage = ((((bi.biWidth * bi.biBitCount) + 31) & ~31) / 8) * bi.biHeight; // If a compression scheme is used the result may infact be larger // Increase the size to account for this. if (dwCompression != BI_RGB) bi.biSizeImage = (bi.biSizeImage * 3) / 2; } // Realloc the buffer so that it can hold all the bits dwLen += bi.biSizeImage; if (handle = GlobalReAlloc(hDIB, dwLen, GMEM_MOVEABLE)) hDIB = handle; else{ GlobalFree(hDIB); // Reselect the original palette SelectPalette(hDC,hPal,FALSE); ::ReleaseDC(NULL,hDC); return NULL; } // Get the bitmap bits lpbi = (LPBITMAPINFOHEADER)hDIB; // FINALLY get the DIB BOOL bGotBits = GetDIBits( hDC, (HBITMAP)bitmap.GetSafeHandle(), 0L, // Start scan line (DWORD)bi.biHeight, // # of scan lines (LPBYTE)lpbi // address for bitmap bits + (bi.biSize + nColors * sizeof(RGBQUAD)), (LPBITMAPINFO)lpbi, // address of bitmapinfo (DWORD)DIB_RGB_COLORS); // Use RGB for color table if( !bGotBits ) { GlobalFree(hDIB); SelectPalette(hDC,hPal,FALSE); ::ReleaseDC(NULL,hDC); return NULL; } SelectPalette(hDC,hPal,FALSE); ::ReleaseDC(NULL,hDC); return hDIB; } BOOL CMyFun::WriteDIB( LPTSTR szFile, HANDLE hDIB) { BITMAPFILEHEADER hdr; LPBITMAPINFOHEADER lpbi; if (!hDIB) return FALSE; CFile file; if( !file.Open( szFile, CFile::modeWrite|CFile::modeCreate) ) return FALSE; lpbi = (LPBITMAPINFOHEADER)hDIB; int nColors = 1 << lpbi->biBitCount; // Fill in the fields of the file header hdr.bfType = ((WORD) ('M' << 8) | 'B'); // is always "BM" hdr.bfSize = GlobalSize (hDIB) + sizeof( hdr ); hdr.bfReserved1 = 0; hdr.bfReserved2 = 0; hdr.bfOffBits = (DWORD) (sizeof( hdr ) + lpbi->biSize + nColors * sizeof(RGBQUAD)); // Write the file header file.Write( &hdr, sizeof(hdr) ); // Write the DIB header and the bits file.Write( lpbi, GlobalSize(hDIB) ); return TRUE; }
调用演示:
CFileDialog fileDialog( FALSE,".bmp","MyCatchBmp",OFN_HIDEREADONLY|OFN_OVERWRITEPROMPT, "图片文件 (*.bmp)|*.bmp||",this ); if(fileDialog.DoModal() == IDOK) { if(m_pBitmap != NULL) { //存文件 m_MyFun.WriteBMPtoFile(this,*m_pBitmap, fileDialog.GetPathName()); } }
其他问题:
在同样的显示效果下,用这种生成的BMP文件比普通生成的BMP文件要大…..(不知为何…文件头比较大?)
如想生成较小的文件,可以使用CxImage开源的类库,还可以转换为其他格式的图形文件
Trackback from your site.