[转]CreateDIBitmap与CreateDIBSection
HBITMAP CreateDIBitmap(HDC hdc,
CONST BITMAPINFOHEADER *lpbmih,
DWORD fdwlnit,
CONST VOID *lpblnit,
CONST BITMAPINFO *lpbmi,
UINT fuUsage);
HBITMAP LoadBitmapEx(LPCTSTR lpszFile)
{
if(lpszFile == NULL) return NULL; HBITMAP hBitmap;
HANDLE hf;
BITMAPFILEHEADER* pbmfh;
DWORD dwBytesRead, dwFileSize, dwFileSizeHigh;
BOOL bSuccess;
// 打开一个bmp文件
hf = CreateFile(lpszFile, GENERIC_READ, FILE_SHARE_READ,
NULL, OPEN_EXISTING, FILE_FLAG_SEQUENTIAL_SCAN, NULL);
if( hf == INVALID_HANDLE_VALUE)
{
TRACE("Open file filed with error %d ", GetLastError());
return NULL;
}
// 得到这个文件大小
dwFileSize = GetFileSize(hf, &dwFileSizeHigh);
if( dwFileSizeHigh )
{
CloseHandle(hf);
return NULL;
}
// 分配内存,大小为该文件的大小
pbmfh = (BITMAPFILEHEADER*)malloc(dwFileSize);
if( !pbmfh )
{
CloseHandle(hf);
return NULL;
}
// 读取数据
bSuccess = ReadFile(hf, pbmfh, dwFileSize, &dwBytesRead, NULL);
CloseHandle(hf);
// 效验文件大小和文件格式
if( !bSuccess || dwFileSize != dwBytesRead || pbmfh->bfType != 0x4D42 || pbmfh->bfSize != dwFileSize)
{
free((void*)pbmfh);
return NULL;
}
// 进行DIB转换
hBitmap = CreateDIBitmap(GetWindowDC(NULL),
(BITMAPINFOHEADER*)(pbmfh + 1),
CBM_INIT,
(BYTE*)pbmfh + pbmfh->bfOffBits,
(BITMAPINFO*)(pbmfh + 1),
DIB_RGB_COLORS);
free((void*)pbmfh);
return hBitmap;
}
HBITMAP MakeBitmap(HDC hDc, LPBYTE lpBits, long lWidth, long lHeight, WORD wBitCount)
{
BITMAPINFO bitinfo;
memset(&bitinfo, 0, sizeof(BITMAPINFO)); bitinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bitinfo.bmiHeader.biWidth = lWidth;
bitinfo.bmiHeader.biHeight = lHeight;
bitinfo.bmiHeader.biPlanes = 1;
bitinfo.bmiHeader.biBitCount = wBitCount;
bitinfo.bmiHeader.biCompression = BI_RGB;
bitinfo.bmiHeader.biSizeImage = lWidth*lHeight*(wBitCount/8);
bitinfo.bmiHeader.biXPelsPerMeter = 96;
bitinfo.bmiHeader.biYPelsPerMeter = 96;
bitinfo.bmiHeader.biClrUsed = 0;
bitinfo.bmiHeader.biClrImportant = 0; return CreateDIBitmap(hDc, &bitinfo.bmiHeader, CBM_INIT, lpBits, &bitinfo, DIB_RGB_COLORS);
}
函数原型:
HBITMAP CreateDIBSection(HDC hdc,
CONST BITMAPINFO * pbmi,
UINT iUsage,
VOID * ppvBits,
HANDLE hSection,
DWORD dwOffset );
参数:
hdc:设备环境句柄。如果iUsage的值是DIB_PAL_COLORS,那么函数使用该设备环境的逻辑调色板对与设备无关位图的颜色进行初始化。
pbmi:指向BITMAPINFO结构的指针,该结构指定了设备无关位图的各种属性,其中包括位图的尺寸和颜色。
iUsage:指定由pbmi参数指定的BITMAPINFO结构中的成员bmiColors数组包含的数据类型(要么是逻辑调色板索引值,要么是原文的RGB值)。下列值是系统定义的,其含义为:
|
值 |
描述 |
|
DIB_RGB_COLORS |
根据BITMAPINFOHEADER 的biCompression 成员决定BITMAPINFO 结构包含位掩码还是调色板数组,在呈现位图时使用该数组值。DIB_RGB_COLORS 可以在任何位数的位图上使用。 |
|
DIB_PAL_COLORS |
BITMAPINFO.bmiColors 数组被取消,在呈现位图时使用目标调色板。DIB_PAL_COLORS只能在8bpp位图中指定。 |
ppvBits:指向一个变量的指针,该变量接收一个指向DIB位数据值的指针。
hSection:该参数设置为NULL。
dwOffset:参数取消。
返回值:
成功,返回值是一个指向刚刚创建的设备无关位图的句柄,并且*ppvBits指向该位图的位数据值;失败,那么返回值为NULL,并且*ppvBit也为NULL,若想获得更多错误信息,请调用GetLastError函数。
备注:
系统为设备独立位图分配内存。如果在之后调用DeleteObject来删除设备独立位图,系统自动关闭内句柄。
在Windows CE 2.0及其以后版本,如果图像是调色板模式(通常是1,2,4和8格式)的,BITMAPINFO 结构中必须包含一个颜色表。对于16bpp或32bpp非调色板图像,颜色表必须是3个入口的长度,这3个入口必须指定红、绿、蓝色掩码。 而且,BITMAPINFOHEADER 结构的biCompression 成员应该被设置为BI_BITFIELDS。 这些位深不支持BI_RGB。 GDI取消24bpp图像的颜色表,他们的像素必须被存储为 蓝-绿-红 (BGR)格式。
Windows CE 不支持332位阈设备。
在Windows CE 1.0 和 1.01版本,pbmi指向的BITMAPINFO结构必须指定每个像素点为1或2位。
实例:下面这段代码实现由已存在的图像裸数据得到CBitmap位图:
CBitmap bitmap ;
BITMAPINFO bmpInfo; //创建位图
bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmpInfo.bmiHeader.biWidth = 480;//宽度
bmpInfo.bmiHeader.biHeight = 480;//高度
bmpInfo.bmiHeader.biPlanes = 1;
bmpInfo.bmiHeader.biBitCount = 24;
bmpInfo.bmiHeader.biCompression = BI_RGB; UINT uiTotalBytes = 480 * 480 * 3;
void *pArray = new BYTE(uiTotalBytes );
HBITMAP hbmp = CreateDIBSection(NULL, &bmpInfo, DIB_RGB_COLORS, &pArray, NULL, 0);//创建DIB
ASSERT(hbmp != NULL);
//! 将裸数据复制到bitmap关联的像素区域
memcpy(pArray, pImageData, uiTotalBytes); bitmap.Attach(hbmp);
其中pImageData即是已知的图像裸数据。
注意:
这里想说声sorry,之前没太深入理解CreateDIBSection函数的工作机理,在上面的例子中使用new为pArray开辟了一块空间,然后将pArray传入CreateDIBSection函数,其实这种方式是错误的,在Debug下面调试之后发现,你使用new开辟的pArray,
在使用之后并不能正常delete[]掉。CreateDIBSection参数ppvBits正常的使用应该只要传入一个指针即可(就像上面实例中那样
,只要定义一个BYTE *pArray,不需要自己分配空间,直接传给CreateDIBSection即可)。
其实通过ppvBits参数类型(二级指针)也就明白了CreateDIBSection函数的基本使用原理 - CreateDIBSection函数使用hDC及
BITMAPINFO结构信息创建一个指定大小等信息的位图,系统自动为其开辟所需的像素空间,开辟的像素空间地址就是用ppvBits参数
返回的。而且此位图空间系统会自动释放。
之所以需要返回此地址,是因为CreateDIBSection调用时只是根据我们提供的一些信息创建合适大小、格式的位图并开辟控件
,而并不会填充实际像素值(这也是为什么我们直接将指向真实像素值的指针传入此函数中无效的原因),返回这个指针只是为了
之后使用真实像素值填充此段空间(就像上面示例中的memcpy那样)!
1、关于CreateDIBSection函数的使用需要注意一点就是参数ppvBits的使用:传给CreateDIBSection函数的不是一个new
出来一块的空间,也不是直接传入真实像素指针pImageData,而只是传入一个指针变量(如本例中的pArray)用以接收CreateDIBSection自动开辟的像素区域指针!如果你传入了自己手动new出来的一块区域,在Debug调试运行时会发现一个delete []错误,此错误指明你之前new出来的空间无法释放,原因是堆损坏,这部分需要了解下new、delete(或内存检测)原理,详见《new/delete内存分配及释放检测》。
2、像素数据的复制必须在调用了CreateDIBSection函数之后进行,如本例所示,memcpy(pArray, pImageData, uiTotalBytes);是在HBITMAP hbmp = CreateDIBSection(NULL, &bmpInfo, DIB_RGB_COLORS, &pArray, NULL, 0);之后进行的。可能是由于CreateDIBSection函数会对传入的像素空间进行“清除”工作,所以在调用此函数前就先进行像素复制的话,你会发现最终绘制的图像时一片漆黑!
说明:CreateDIBSection函数具有内存映射文件功能,但是一般我们不会使用!所以此处忽略讨论!
此外还需说明的是,有时候在使用CreateDIBSection函数时会发生内存泄露的问题。当初本人开发一个项目时曾经碰到过此问题,在一个窗口进入特定模式后会频繁的调用此函数生成特定的图像,并用此图像去重绘窗口背景。最后调试正是此函数发生了内存泄露,但是代码中确是对产生的HBITMAP及DC进行了释放。当时是使用了另一种方式解决了此问题,但是对于CreateDIBSection函数发生的泄露问题却一直没有深入研究。
虽然如此,对于使用此函数之后善后处理这里仅提几点:
1、最后一次使用完CreateDIBSection函数创建位图之后将其从DC中换出memdc.SelectObject(pOldBmp);
2、在最后一次使用完CreateDIBSection函数创建的位图之后才可delete[] pArray释放掉像素空间。
3、注意释放位图资源bitmap.DeleteObject();
4、释放内存memdc.ReleaseDC();
更多关于CreateDIBSection函数内存使用问题详见:http://blog.sina.com.cn/s/blog_8ec096580101gmmb.html
[转]CreateDIBitmap与CreateDIBSection的更多相关文章
- (转载博文)VC++API速查
窗口处理 2.1 窗口简介 2.2.1 创建普通窗口(CreateWindow.CreateWindowEx) 2.2.2 关闭窗口(CloseWindow) 2.2.3 销毁窗口(DestroyWi ...
- CreateDIBSection函数
HBITMAP CreateDIBSection( HDC hdc, // handle to DC CONSTBITMAPINFO*pbmi, // bitmap dataUINT iUsage, ...
- CreateDIBSection和位图结构
2019独角兽企业重金招聘Python工程师标准>>> 理解分辨率 我们常说的屏幕分辨率为640×480,刷新频率为70Hz,意思是说每行要扫描640个象素,一共有480行,每秒重复 ...
- Windows API 函数列表 附帮助手册
所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...
- 第16章 调色板管理器_16.4 一个DIB位图库的实现(1)
16.4.1自定义的 DIBSTRUCT结构体 字段 含义 PBYTE *ppRow ①指向位图视觉上最上面的一行像素.(不管是自下而上,还是自上而下) ②放在第一个字段,为的是后面定义宏时可方便访问 ...
- 第15章 设备无关位图_15.3 DIB和DDB的结合
第15章 设备相关位图_15.3 DIB和DDB的结合 15.3.1 从DIB创建DDB (1)hBitmap =CreateDIBitmap(…)——注意这名称会误导,实际上创建的是DDB 参数 说 ...
- 英文不好也能快速"记忆" API
英文不好不要紧,把API函数导入打字练习类软件,即是练习打字速度,提高编程效率:也能短时间记忆API. 坚持每天打一遍,约2小时,连续打两周,会对API有很好的记忆,此方法是结合英文学习方法!以下是W ...
- Windows 位图
目录 第1章简介 1 1.1 DFB 1 1.2 DDB 1 1.3 DIB 2 第2章相关API 3 2.1 创建 3 2.1.1 CreateCompatibl ...
- DELPHI下API简述(1800个API)
DELPHI下API简述 http://zero.cnbct.org/show.asp?id=144 auxGetDevCaps API 获取附属设备容量 auxGetNumDevs API 返回附属 ...
随机推荐
- js中迭代元素特性与DOM中的DocumentFragment类型 笔记
JS中迭代元素特性 在需要将DOM结构序列化为XML或者HTML字符串时,多数都会涉及遍历元素的特性,这个时候attributes属性就可以派上用场. 以下代码展示了如何迭代元素的每一个特性,然后将他 ...
- Friends and Enemies(思维)
Friends and Enemies Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Othe ...
- JavaScript中常用转义字符
\b 退格 \f 换页 \r 回车 \n 换行 \" 双引号 \' 单引号 \t Tab字符 \\ 反斜杠 \xnn 十六进制代码nn表示的字符 \unnnn 十 ...
- 2017博普杯 东北大学邀请赛(B. Drink too much water)(贪心+树链剖分)
题目地址:https://oj.neu.edu.cn/problem/1204 题目大意: 其实就是树上的线段覆盖, 给出一棵n个结点的树,然后给出树上的一些路径进行覆盖,然后要求选取最少的点,能够把 ...
- [洛谷P3690]【模板】Link Cut Tree (动态树)
题目大意:给定$n$个点以及每个点的权值,要你处理接下来的$m$个操作.操作有$4$种.操作从$0到3编号.点从1到n编号. $0,x,y$:代表询问从$x$到$y$的路径上的点的权值的$xor$和. ...
- [洛谷P4208][JSOI2008]最小生成树计数
题目大意:有$n$个点和$m$条边(最多有$10$条边边权相同),求最小生成树个数 题解:对于所有最小生成树,每种边权的边数是一样的.于是就可以求出每种边权在最小生成树中的个数,枚举这种边的边集,求出 ...
- 【MySQL】数据库 --MySQL的安装
本篇教程主要讲解在CentOS 6.5下编译安装MySQL 5.6.14! 1.卸载旧版本: 使用下面的命令检测是否安装有MySQL server <span style="font- ...
- cookie 是存储于访问者的计算机中的变量
今天把javascript如何用来创建及存储cookie复习了一下,其中的一点体会拿出来和大家讨论,首先看一下基础知识: 什么是cookie cookie 是存储于访问者的计算机中的变量.每当同一台计 ...
- JAVA List 一边遍历一边删除元素
JAVA List 一边遍历一边删除元素,报java.util.ConcurrentModificationException异常 2015年02月10日 14:42:49 zhanzkw 阅读数:3 ...
- hadoop更换硬盘
hadoop服务器更换硬盘操作步骤(datanode hadoop目录${HADOOP_HOME}/bin 日志位置:/var/log/hadoop)1.登陆服务器,切换到mapred用户,执行 ...