C++保存HBITMAP为位图文件
本文为转载内容微加工,原文地址:C++将HBITMAP保存为bmp图片。
本文使用C++将位图句柄HBITMAP保存为位图文件,配合C++抓图代码可以实现抓图保存文件(.bmp)。
其步骤如下:
1、创建位图文件;
2、计算位图中每个像素所占字节数;
3. 获取位图结构BITMAP;
4、构造位图信息头BITMAPINFOHEADER;
5、构造位图文件头BITMAPFILEHEADER;
6、为位图内容分配内存;
7、处理调色板;
8、写入文件;
9、清除资源。
下面是C++源代码:
ImageHelper.h
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #pragma once #include <windows.h> #include <string> using namespace std; class ImageHelper { public : static bool SaveBitmapToFile( HBITMAP bitmap, const string& filename); //保存位图到文件 private : static WORD GetBitmapBitCount(); //计算位图文件每个像素所占字节数 static void ProcessPalette( HBITMAP hBitmap, const BITMAP& bitmap, DWORD paletteSize, LPBITMAPINFOHEADER lpBmpInfoHeader); //处理调色板 }; |
ImageHelper.cpp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 | #include "ImageHelper.h" #include <shlwapi.h> bool ImageHelper::SaveBitmapToFile( HBITMAP hBitmap, const string& filename) { //1. 创建位图文件 const auto file = CreateFileA(filename.c_str(), GENERIC_WRITE, 0, nullptr , CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, nullptr ); if (file == INVALID_HANDLE_VALUE) { return false ; } //2. 计算位图文件每个像素所占字节数 const auto bitCount = GetBitmapBitCount(); //3. 获取位图结构 BITMAP bitmap; ::GetObject(hBitmap, sizeof (bitmap), reinterpret_cast < LPSTR >(&bitmap)); //位图中像素字节大小(32字节对齐) const DWORD bmBitsSize = ((bitmap.bmWidth * bitCount + 31) / 32) * 4 * bitmap.bmHeight; //调色板大小 const DWORD paletteSize = 0; //4. 构造位图信息头 BITMAPINFOHEADER bmpInfoHeader; //位图信息头结构 bmpInfoHeader.biSize = sizeof (BITMAPINFOHEADER); bmpInfoHeader.biWidth = bitmap.bmWidth; bmpInfoHeader.biHeight = bitmap.bmHeight; bmpInfoHeader.biPlanes = 1; bmpInfoHeader.biBitCount = bitCount; bmpInfoHeader.biCompression = BI_RGB; bmpInfoHeader.biSizeImage = 0; bmpInfoHeader.biXPelsPerMeter = 0; bmpInfoHeader.biYPelsPerMeter = 0; bmpInfoHeader.biClrImportant = 0; bmpInfoHeader.biClrUsed = 0; //5. 构造位图文件头 BITMAPFILEHEADER bmpFileHeader; bmpFileHeader.bfType = 0x4D42; //"BM" //位图文件大小 const DWORD dibSize = sizeof (BITMAPFILEHEADER) + sizeof (BITMAPINFOHEADER) + paletteSize + bmBitsSize; bmpFileHeader.bfSize = dibSize; bmpFileHeader.bfReserved1 = 0; bmpFileHeader.bfReserved2 = 0; bmpFileHeader.bfOffBits = static_cast < DWORD >( sizeof (BITMAPFILEHEADER)) + static_cast < DWORD >( sizeof (BITMAPINFOHEADER)) + paletteSize; //6. 为位图内容分配内存 const auto dib = GlobalAlloc(GHND, bmBitsSize + paletteSize + sizeof (BITMAPINFOHEADER)); //内存句柄 const auto lpBmpInfoHeader = static_cast <LPBITMAPINFOHEADER>(GlobalLock(dib)); //指向位图信息头结构 *lpBmpInfoHeader = bmpInfoHeader; //7. 处理调色板 ProcessPalette(hBitmap, bitmap, paletteSize, lpBmpInfoHeader); //8. 写入文件 DWORD written = 0; //写入文件字节数 WriteFile(file, reinterpret_cast < LPSTR >(&bmpFileHeader), sizeof (BITMAPFILEHEADER), &written, nullptr ); //写入位图文件头 WriteFile(file, reinterpret_cast < LPSTR >(lpBmpInfoHeader), dibSize, &written, nullptr ); //写入位图文件其余内容 //9. 清理资源 GlobalUnlock(dib); GlobalFree(dib); CloseHandle(file); return true ; } //计算位图文件每个像素所占字节数 WORD ImageHelper::GetBitmapBitCount() { const auto dc = ::CreateDCA( "DISPLAY" , nullptr , nullptr , nullptr ); //当前分辨率下每像素所占字节数 const auto bits = ::GetDeviceCaps(dc, BITSPIXEL) * GetDeviceCaps(dc, PLANES); ::DeleteDC(dc); //位图中每像素所占字节数 WORD bitCount; if (bits <= 1) bitCount = 1; else if (bits <= 4) bitCount = 4; else if (bits <= 8) bitCount = 8; else bitCount = 24; return bitCount; } //处理调色板 void ImageHelper::ProcessPalette( HBITMAP hBitmap, const BITMAP& bitmap, DWORD paletteSize, LPBITMAPINFOHEADER lpBmpInfoHeader) { HANDLE oldPalette = nullptr ; HDC dc = nullptr ; const auto palette = GetStockObject(DEFAULT_PALETTE); if (palette != nullptr ) { dc = ::GetDC( nullptr ); oldPalette = ::SelectPalette(dc, static_cast < HPALETTE >(palette), FALSE); ::RealizePalette(dc); //实现设备调色板 } //获取该调色板下新的像素值 GetDIBits(dc, hBitmap, 0, static_cast < UINT >(bitmap.bmHeight), reinterpret_cast < LPSTR >(lpBmpInfoHeader) + sizeof (BITMAPINFOHEADER) + paletteSize, reinterpret_cast <BITMAPINFO*>(lpBmpInfoHeader), DIB_RGB_COLORS); //恢复调色板 if (oldPalette != nullptr ) { ::SelectPalette(dc, static_cast < HPALETTE >(oldPalette), TRUE); ::RealizePalette(dc); ::ReleaseDC( nullptr , dc); } } |
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 没有源码,如何修改代码逻辑?
· 一个奇形怪状的面试题:Bean中的CHM要不要加volatile?
· [.NET]调用本地 Deepseek 模型
· 一个费力不讨好的项目,让我损失了近一半的绩效!
· .NET Core 托管堆内存泄露/CPU异常的常见思路
· DeepSeek “源神”启动!「GitHub 热点速览」
· 微软正式发布.NET 10 Preview 1:开启下一代开发框架新篇章
· C# 集成 DeepSeek 模型实现 AI 私有化(本地部署与 API 调用教程)
· DeepSeek R1 简明指南:架构、训练、本地部署及硬件要求
· NetPad:一个.NET开源、跨平台的C#编辑器