使用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时,颜色表占用的内存空间剧增,机器内存很可能无法满足,因此不再建议使用此函数。
使用GetDIBits()获取Windows位图数据的标准用法,解决内存、堆栈报错问题的更多相关文章
- 关于jsp web项目,jsp页面与servlet数据不同步的解决办法(报错404、405等)即访问.jsp和访问web.xml中注册的/servlet/的区别
报错信息: Type Status Report Message HTTP method GET is not supported by this URL Description The method ...
- windows下配置redis集群,启动节点报错:createing server TCP listening socket *:7000:listen:Unknown error
windows下配置redis集群,启动节点报错:createing server TCP listening socket *:7000:listen:Unknown error 学习了:https ...
- Windows Server 2012 R2 安装.NET Framework 3.5报错
简单记录一下,Windows Server 2012 R2 安装.NET Framework 3.5报错,下面是解决方法 载入ISO文件Windows Server 2012 R2,而且在安装的过程中 ...
- 【问题记录】使用FreeMarker生成数据,模板明明没错却一直报错“The following has evaluated to null or missing:”
今天使用FreeMarker生成数据时一直报错,错误信息是“The following has evaluated to null or missing:”,告知我找不到值. 但是我再三确认,这些属性 ...
- Servlet(三):获取表单数据、解决乱码和报错问题
在了解了servlet的生命周期以及运行过程后,再来动手写一个小例子,加深对servlet的理解. 一.需求说明 在用户注册信息页面,输入用户名.密码.性别.邮箱等一些信息后,页面返回刚刚填写的信息. ...
- 解决asp.net 报错 无法获取所需的权限错误
asp.net 报错 无法获取所需的权限 无法获取所需的权限.说明: 执行当前 Web 请求期间,出现未处理的异常.请检查堆栈跟踪信息,以了解有关该错误以及代码中导致错误的出处的详细信息. 无法获取所 ...
- Python2.7在Windows下CMD编码为65001/utf-8时print报错[Errno 0]/[Errno 2]
使用python2.7处理unicode的字符串,环境变量已设置PYTHONIOENCODING为utf-8,cmd编码为utf-8时print unicode字符串会报错[Errno 0]或[Err ...
- 解决kettle在两个mysql之间迁移数据时乱码的问题 和 相关报错 及参数调整, 速度优化
1. 乱码问题 编辑目标数据库的链接: 配置编码参数即可. 2. 报错 No operations allowed after statement closed. 需要调整wait_timeout: ...
- Windows安装Redis并添加本地自启动服务并解决客户端dll报错
参考文章:https://blog.csdn.net/realjh/article/details/82026160 Redis下载: https://github.com/MicrosoftArch ...
- [vue]子组件通过props获取父组件数据以及使用watch解决动态数据不生效问题
父子组件的传值,在Vue官方也写得很清楚,父组件中使用v-bind绑定传送,子组件使用props接收. 父组件通过v-bind绑定数据: <template> <router-vie ...
随机推荐
- 2022春每日一题:Day 11
题目:高斯消元法 高斯消元法是一个模板,下面简单介绍其内容以及实现方法. 高斯消元是求一个求多元一次方程组的解的算法. 就是形式如下的关于x1,x2...xn的方程组的解. a11x1 + a12x2 ...
- 有关二级指针char **p 的问题
int main() { char *str[] = {"welcome", "to", "Fortemdia", "Nanjin ...
- 在链表上实现 Partition 以及荷兰国旗问题
在链表上实现 Partition 以及荷兰国旗问题 作者:Grey 原文地址: 博客园:在链表上实现 Partition 以及荷兰国旗问题 CSDN:在链表上实现 Partition 以及荷兰国旗问题 ...
- 关于sublime-build的配置详解
前言 sublime-build 可以做很多自定义的构建命令,然后用其执行代码,十分方便! 开始 这里我就简单的用python 的配置来详细说明各个配置项目的作用 { "shell_cmd& ...
- 1、创建Django项目并配置settings文件
一.先安装Django第三方库 二.创建项目 新建好项目的目录是这样的 迁移数据库,注意:没有安装pymysql的需要通过pip install pymysql安装. 三.创建模块 四.设置setti ...
- 使用mysqldump备份与还原的mysql数据库
使用mysqldump备份与还原的mysql数据库 一.mysqldump命令介绍 1.mysqldump -help 查看命令介绍: mysqldump --help 2.mysqldump登录选项 ...
- selenium常用配置
def init_chrome_options(self,): chrome_options = webdriver.ChromeOptions() # 设置浏览器初始 位置x,y & 宽高x ...
- java中的字符串数组
本文主要讲述java中的字符串数组 字符串数组的声明有如下几种形式: // 第一种方式:new // 注意在String的后面[]中不需要添加字符串数组的长度.否则报错. String[] arr_1 ...
- AcWing342. 道路与航线
原题链接 解题思路 这题用\(SPFA\)会被卡,所以我们不能用\(SPFA\) 但是观察数据我们可以发现对于道路,\(0≤C_i≤10^{5}\) 所以对于每个连通块(内部不存在航线),我们可以用\ ...
- Python实验报告(第5章)
实验5:字符串及正则表达式 一.实验目的和要求 学会使用字符串的常用操作方法和正确应用正则表达式 二.实验环境 软件版本:Python 3.10 64_bit 三.实验过程 1.实例01:使用字符串拼 ...