欢迎访问104网

当前位置: 首页 >  网络安全盾 >  使用GetDIBits()获取Windows位图数据的标准用法,解决内存、堆栈报错问题

使用GetDIBits()获取Windows位图数据的标准用法,解决内存、堆栈报错问题

时间:2023-12-06 12:30| 作者:admin

获取图标的位图数据

  • 分两次使用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 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时,颜色表占用的内存空间剧增,机器内存很可能无法满足,因此不再建议使用此函数。

热门

Copyright © 2018-2024 104网 版权所有 | 备案号:京ICP备104