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

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

导读:获取图标的位图数据.分两次使用GetDIBits(),以便于正确设置缓存的大小.正确设置BITMAPINFO的大小,否则就会报堆栈溢出错误.ICONINFO info = { 0 };.GetIconInfo(hIcon, &info).HDC bmp, maskbmp;.bmp

获取图标的位图数据

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

内容
  • Qt-FFmpeg开发-打开本地摄像头录制视频(7)
    Qt-FFmpeg开发-打开本地
    2023-12-05
    音视频/FFmpeg #Qt.Qt-FFmpeg开发-打开本地摄像头录制视频【软解码+ OpenGL显示YUV】.目录.
  • 一种新的告警收敛方式“先知预警”,为您的系统健康护航
    一种新的告警收敛方式“先知预警”
    2023-12-08
    前言.简介.买基金,上京东.基金交易系统是用户使用京东金融APP进行基金交易的核心支撑系统,每天有数十亿元的交易额。.在
  • 4.10 x64dbg 反汇编功能的封装
    4.10 x64dbg 反汇编功
    2023-12-06
    LyScript.插件提供的反汇编系列函数虽然能够实现基本的反汇编功能,但在实际使用中,可能会遇到一些更为复杂的需求,此
  • 如何在unity中手写一个四叉树地形lod系统(二)
    如何在unity中手写一个四叉树
    2023-12-07
    在根据四叉树节点创建了1365个地形分块网格并保存到本地后,我们接下来要在游戏运行的过程中动态地显示所需的网格,这是最关
  • windows 网络模拟工具分享
    windows 网络模拟工具分享
    2023-12-02
    【下载地址】.Releases · jagt/clumsy · GitHub.【介绍】.无需安装.无需篡改和代理.系统级
  • 常用的 http 状态码有哪些?
    常用的 http 状态码有哪些?
    2023-12-08
    在我们进行网页,网址的访问过程中,http,https.都是我们主要使用到的协议,在使用这协议的时候,对于他的协助状态,