VC/MFC怎样将位图CBitmap对象保存成为bmp格式文件?
虽然说现在写程序主要依靠 Internet ,特别是 Google 搜索(不过有时候 被墙,只能凑合着用百度)。编程技术人员的普遍经验都是:Google 在搜索技术资料的时候确实比 百度 要强。
废话少说,今晚找了些资料,终于搞定了 将CBitmap表示的位图对象保存成为正宗的 bmp 格式文件。不过其中有些小的曲折,总结一下,网上大体提供了以下几种方式:
1. 用 CImage 来解决,就几行,但需要 .net 支持;
- // http://blog.csdn.net/benpluslib/article/details/3975774
- // 使用下面的代码,可以把CBitmap类中的图像保存到图像文件中。支持格式:BMP、JPG、GIF和PNG。
- // 但CImage只在.net下有
- // CImage imgTemp; // CImage是MFC中的类。
- // imgTemp.Attach(Bitmap.operator HBITMAP());
- // imgTemp.Save(strFilePath);
2. 很多网站提供的 void WriteBmp(CBitmap *PBitmap, char m_FileName[]) 原代码,要放在 某个 Windows 类中作为成员函数才行。但很不幸,不怎么灵。
- // http://blog.csdn.net/xs813/article/details/6321924
- // 保存CBitmap到文件
- // 经过测试,这个方法是不灵的:
- // 有时候能正确保存,
- // 有时候保存之后打开报“绘图失败”,
- // 有时候程序执行非法操作
- void CTestClipboardDlg::WriteBmp(CBitmap *PBitmap, char m_FileName[])
- // 代码省略,网上有(既然不灵,也就没必要贴出来了)
- // 调用方式
- //WriteBmp(cbm, "clipboard1.bmp"); // 这个方法不行
3. 也还有 bool SaveBitmapToFile(CBitmap* bitmap, LPSTR lpFileName) 此方法甚好,就用它了。下面贴出完整的经本人辛苦格式化的代码,再此向作者致敬(虽然原作者已无从考证)。
- // http://blog.sina.com.cn/s/blog_6ee382440100moeu.html
- // http://apps.hi.baidu.com/share/detail/32878068
- // bitmap 位图CBitmap对象指针
- // lpFileName 为位图文件名
- bool SaveBitmapToFile(CBitmap* bitmap, LPSTR lpFileName)
- {
- HBITMAP hBitmap; // 为刚才的屏幕位图句柄
- HDC hDC; //设备描述表
- int iBits; //当前显示分辨率下每个像素所占字节数
- WORD wBitCount; //位图中每个像素所占字节数
- DWORD dwPaletteSize = 0, //定义调色板大小
- dwBmBitsSize, //位图中像素字节大小
- dwDIBSize, //位图文件大小
- dwWritten; //写入文件字节数
- BITMAP Bitmap; //位图属性结构
- BITMAPFILEHEADER bmfHdr; //位图文件头结构
- BITMAPINFOHEADER bi; //位图信息头结构
- LPBITMAPINFOHEADER lpbi; //指向位图信息头结构
- HANDLE fh, //定义文件
- hDib, //分配内存句柄
- hPal, //调色板句柄
- hOldPal = NULL;
- //计算位图文件每个像素所占字节数
- hBitmap = (HBITMAP)*bitmap;
- hDC = CreateDC("DISPLAY",NULL,NULL,NULL);
- iBits = GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES);
- DeleteDC(hDC);
- if (iBits <= 1)
- wBitCount = 1;
- else if (iBits <= 4)
- wBitCount = 4;
- else if (iBits <= 8)
- wBitCount = 8;
- else if (iBits <= 24)
- wBitCount = 24;
- else if (iBits <= 32)
- wBitCount = 32;
- //计算调色板大小
- if (wBitCount <= 8)
- dwPaletteSize = (1 << wBitCount) * sizeof (RGBQUAD);
- //设置位图信息头结构
- GetObject(hBitmap, sizeof (BITMAP), (LPSTR)&Bitmap);
- bi.biSize = sizeof (BITMAPINFOHEADER);
- bi.biWidth = Bitmap.bmWidth;
- bi.biHeight = Bitmap.bmHeight;
- bi.biPlanes = 1;
- bi.biBitCount = wBitCount;
- bi.biCompression = BI_RGB;
- bi.biSizeImage = 0;
- bi.biXPelsPerMeter = 0;
- bi.biYPelsPerMeter = 0;
- bi.biClrUsed = 0;
- bi.biClrImportant = 0;
- dwBmBitsSize = ((Bitmap.bmWidth * wBitCount+31) / 32) * 4 * Bitmap.bmHeight;
- //为位图内容分配内存
- hDib = GlobalAlloc(GHND, dwBmBitsSize + dwPaletteSize + sizeof (BITMAPINFOHEADER));
- lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDib);
- *lpbi = bi;
- // 处理调色板
- hPal = GetStockObject(DEFAULT_PALETTE);
- if (hPal)
- {
- hDC = ::GetDC(NULL);
- hOldPal = ::SelectPalette(hDC, (HPALETTE)hPal, FALSE);
- RealizePalette(hDC);
- }
- // 获取该调色板下新的像素值
- GetDIBits(hDC, hBitmap, 0, (UINT) Bitmap.bmHeight,
- (LPSTR)lpbi + sizeof (BITMAPINFOHEADER) + dwPaletteSize,
- (LPBITMAPINFO)lpbi, DIB_RGB_COLORS);
- //恢复调色板
- if (hOldPal)
- {
- SelectPalette(hDC, (HPALETTE)hOldPal, TRUE);
- RealizePalette(hDC);
- ::ReleaseDC(NULL, hDC);
- }
- //创建位图文件
- fh = CreateFile(lpFileName, GENERIC_WRITE,
- 0, NULL, CREATE_ALWAYS,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
- if (fh == INVALID_HANDLE_VALUE)
- return FALSE;
- // 设置位图文件头
- bmfHdr.bfType = 0x4D42; // "BM"
- dwDIBSize = sizeof (BITMAPFILEHEADER)
- + sizeof (BITMAPINFOHEADER)
- + dwPaletteSize + dwBmBitsSize;
- bmfHdr.bfSize = dwDIBSize;
- bmfHdr.bfReserved1 = 0;
- bmfHdr.bfReserved2 = 0;
- bmfHdr.bfOffBits = (DWORD)sizeof (BITMAPFILEHEADER)
- + (DWORD)sizeof (BITMAPINFOHEADER)
- + dwPaletteSize;
- // 写入位图文件头
- WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL);
- // 写入位图文件其余内容
- WriteFile(fh, (LPSTR)lpbi, dwDIBSize,
- &dwWritten, NULL);
- //清除
- GlobalUnlock(hDib);
- GlobalFree(hDib);
- CloseHandle(fh);
- return TRUE;
- }
使用的方式也相当的简单。
- SaveBitmapToFile(cbm, "clipboard.bmp");
4. 其他第三方库:比如 CxImage ,现在还没有来得及研究。
下一步准备将 CBitmap 保存为 jpg 格式,或将已保存的 bmp 格式文件 转为 jpg 格式文件。