使用GetDIBits()获取Windows位图数据的标准用法,解决内存、堆栈报错问题
获取图标的位图数据
- 分两次使用GetDIBits(),以便于正确设置缓存的大小
- 正确设置BITMAPINFO的大小,否则就会报堆栈溢出错误
ICONINFO info = { 0 }; GetIconInfo(hIcon, &info) HDC bmp, maskbmp; bmp = CreateCompatibleDC(NULL); SelectObject(bmp, info.hbmColor); maskbmp = CreateCompatibleDC(NULL); SelectObject(maskbmp, info.hbmMask); BYTE* lpvBits = NULL; int nRet = 2; // 正确设置 BITMAPINFO 的大小,否则读取位图后头信息将无法存储 BITMAPINFO bmpInfo = { 0 }; bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader); BITMAP bm; GetObject(info.hbmMask, sizeof(bm), &bm); int ncolors = 1 << bm.bmBitsPixel; int bmpinfo_size = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * ncolors; std::vector<BYTE> buf(bmpinfo_size); BITMAPINFO* bmpinfo = (BITMAPINFO*)buf.data(); bmpinfo->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); // 第一次调用,获取位图数据需要的多大的缓冲区存储 nRet = ::GetDIBits(maskbmp, info.hbmMask, 0, 0, NULL, bmpinfo, DIB_RGB_COLORS); // 设置正确的缓冲区存储位图数据 lpvBits = new BYTE[bmpinfo->bmiHeader.biSizeImage]; // 第二次调用,将位图数据存入缓冲区中 nRet = ::GetDIBits(maskbmp, info.hbmMask, 0, nHeight, lpvBits, bmpinfo, DIB_RGB_COLORS); // 按照每行有32列的形式打印,注意bmp位图数据是倒向的,打印出来的图像是实际图像的逆向 for (int i = 0; i < bmpinfo->bmiHeader.biSizeImage; i++) { if (i % 4 == 0) { printf_s("\n"); } BYTE tmp = lpvBits[i]; for (int j = 0; j < 8; j++) { bool res = tmp & 0x80; tmp = tmp << 1; printf_s("%d", res); } } printf_s("\n");
使用注意
BITMAPINFOHEADER 结构后跟调色板条目或颜色掩码数组。 规则取决于 biCompression 的值。Link
- 如果 biCompression 等于 BI_RGB并且 位图使用 8 bpp 或更少,则位图在 BITMAPINFOHEADER 结构之后立即具有颜色表。 颜色表由 RGBQUAD 值数组组成。 数组的大小由 biClrUsed 成员提供。 如果 biClrUsed 为零,则数组包含给定 bitdepth 的最大颜色数;即 2^biBitCount 颜色。
- 如果 biCompression 是视频 FOURCC,则视频格式隐含颜色表的存在。 不应假定位深度为 8 bpp 或更少时存在颜色表。 但是,某些旧组件可能假定存在颜色表。 因此,如果要分配 BITMAPINFOHEADER 结构,建议在位深度为 8 bpp 或更少时为颜色表分配空间,即使不使用颜色表也是如此。
- 请注意,如果位图使用颜色表或颜色掩码,则整个格式结构的大小 (BITMAPINFOHEADER 加上颜色信息) 不等于 sizeof(BITMAPINFOHEADER) 或 sizeof(BITMAPINFO)。 必须计算每个实例的实际大小。
根据Windows API官方介绍文档可以看出,使用GetDIBits()必须为BITMAPINFO计算实际的大小,否则从内存读取了较多内容,但是没有足够的空间去存放,在释放内存时就会出错,如堆栈错误或堆错误;当大于8bpp时,颜色表占用的内存空间剧增,机器内存很可能无法满足,因此不再建议使用此函数。
本文作者:GreyWang
本文链接:https://www.cnblogs.com/GreyWang/p/17123873.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步