首先明确最主要区别CreateDIBitmap创建的是设备相关位图句柄 - HBITMAP.

                              CreateDIBSection创建的是设备无关位图句柄 - HBITMAP.

DIBDDB之间的相互转换比较慢(关于DIB与DDB区别详见《设备相关(DDB)与设备无关(DIB)》),所以我们使用CreateDIBSection()来创建一个DIB区块。这样作图速度快。 
CreateDIBSection()返回的是一个HBITMAP,CreateDIBitmap()返回的也是HBIT MAP。 
两者的区别在于:CreateDIBSection创建的是一个DIBSECTION结构,
                            CreateDIBitmap创建的是BITMAP结构。 
---------------------------------------------------- 
关于DIB区块(DIBSECTION)详见:http://technet.microsoft.com/zh-cn/library/aa930771
可以看到,它包含了一个 位图结构BITMAP,一个DIB信息头BITMAPINFOHEADER,一个掩码表dsBIT fields[3]. 
还有一个内存映射文件句柄和偏移量。我们不去理睬最后两个字段。 
因此,使用GDI函数对CreateDIBSection()返回的HBITMAP作图是没有什么问题的。 
 
关于CreateDIBSection与CreateDIBitmap函数的对比可参见:http://blog.csdn.net/strikebone/article/details/5832631
 
一、CreateDIBitmap
 
函数功能:该函数由与设备无关的位图(DIB)创建与设备有关的位图(DDB),并且有选择地为位图置位。
所以此函数最终创建的是与设备有关的位图
原型

HBITMAP CreateDIBitmap(HDC hdc,

CONST BITMAPINFOHEADER *lpbmih,

DWORD fdwlnit,

CONST VOID *lpblnit,

CONST BITMAPINFO *lpbmi,

UINT fuUsage);

参数
hdc:设备环境句柄。由于是设备相关的,所以需要指明DC。
lpbmih:指向位图信息头结构的指针,它可以是下列操作系统位图信息头之一:
BITMAPINFOHEADER  Windows NT 3.51和早期使用。
BITMAPV4HEADER      Windows NT 4.0和Windows 95使用。
BITMAPV5HEADER      Windows NT 5.0和Windows 98使用。
如果fdwlnit是CBM_INIT,那么此函数使用此信息息头结构来获取位图所需的宽度、高度以及其他信息。注意高度若是正数,那么表示是自底向上DIB,而负数表示为自顶向下DIB,这种情况与CreateDIBitmap函数兼容。
Fdwlnit:位标识集。它指定系统如何对位图的位进行初始化。
CBM_INIT:如果设置了该标志,那么系统将使用lpblnit和lpbmi两个参数指向的数据来对位图中的位进行初始化。如果没有该标志,那么表示上述两个参数指向的数据无效。如果fdwlnit为0,那么系统不会对位图的位进行初始化。
lpblnit:该指针指向包含初始的位图数据的字节类型数组。数据格式与参数lpbmi指向的BITMAPINFO结构中的成员biBitCount有关。
lpbmi:指向BITMAPINFO结构的旨针。该结构描述了参数lpbmi指向的数组的维数和颜色格式。
fuUsage:表示BITMAPINFO结构的成员bmiColors是否初始化过,并且如果是,那么bmiColors是否包含明确的红、绿、蓝(RGB)值或调色板索引。参数fuUsage必须取下列值中的一个,这些值的含义为:
DIB_PAL_COLORS :表示提供一个颜色表,并且该表由该位图要选入的设备环境的逻辑调色板的16位索引值数组组成。
DIB_RGB_COLORS:表示提供一个颜色表,并且表中包含了原义的RGB值。
 
返回值
如果函数执行成功,返回值则是创建的位图的句柄;如果函数执行失败,那么返回值为NULL,若想获取更多错误信息,请调用GetLastError函数。
 
实例:以下代码完成从位图文件中读取DIB位图,并转换成DDB位图:
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;
}

  

其中使用到了位图信息头结构BITMAPFILEHEADER)及位图信息结构BITMAPINFO)。
两者的关系详见《BITMAPFILEHEADER 与 BITMAPINFO》。
 
再看一个使用CreateDIBitmap函数如何由裸像素数据得到位图句柄 - 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);
}
 
一、CreateDIBSection
函数功能:该函数创建应用程序可以直接写入的、与设备无关的位图(DIB)。该函数返回一个位图句柄。

 

函数原型:

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的更多相关文章

  1. (转载博文)VC++API速查

    窗口处理 2.1 窗口简介 2.2.1 创建普通窗口(CreateWindow.CreateWindowEx) 2.2.2 关闭窗口(CloseWindow) 2.2.3 销毁窗口(DestroyWi ...

  2. CreateDIBSection函数

    HBITMAP CreateDIBSection( HDC hdc, // handle to DC CONSTBITMAPINFO*pbmi, // bitmap dataUINT iUsage, ...

  3. CreateDIBSection和位图结构

    2019独角兽企业重金招聘Python工程师标准>>> 理解分辨率 我们常说的屏幕分辨率为640×480,刷新频率为70Hz,意思是说每行要扫描640个象素,一共有480行,每秒重复 ...

  4. Windows API 函数列表 附帮助手册

    所有Windows API函数列表,为了方便查询,也为了大家查找,所以整理一下贡献出来了. 帮助手册:700多个Windows API的函数手册 免费下载 API之网络函数 API之消息函数 API之 ...

  5. 第16章 调色板管理器_16.4 一个DIB位图库的实现(1)

    16.4.1自定义的 DIBSTRUCT结构体 字段 含义 PBYTE *ppRow ①指向位图视觉上最上面的一行像素.(不管是自下而上,还是自上而下) ②放在第一个字段,为的是后面定义宏时可方便访问 ...

  6. 第15章 设备无关位图_15.3 DIB和DDB的结合

    第15章 设备相关位图_15.3 DIB和DDB的结合 15.3.1 从DIB创建DDB (1)hBitmap =CreateDIBitmap(…)——注意这名称会误导,实际上创建的是DDB 参数 说 ...

  7. 英文不好也能快速"记忆" API

    英文不好不要紧,把API函数导入打字练习类软件,即是练习打字速度,提高编程效率:也能短时间记忆API. 坚持每天打一遍,约2小时,连续打两周,会对API有很好的记忆,此方法是结合英文学习方法!以下是W ...

  8. 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 ...

  9. DELPHI下API简述(1800个API)

    DELPHI下API简述 http://zero.cnbct.org/show.asp?id=144 auxGetDevCaps API 获取附属设备容量 auxGetNumDevs API 返回附属 ...

随机推荐

  1. A - 移动的骑士

    A - 移动的骑士 Time Limit: 1000/1000MS (C++/Others) Memory Limit: 65536/65536KB (C++/Others) Problem Desc ...

  2. 【EasyNetQ】- 发送接收

    发布/订阅和请求/响应模式是位置透明的,因为您不需要指定消息的使用者所在的位置,而发送/接收模式专门用于通过命名队列进行通信.它也不会假设可以通过队列发送的消息类型.这意味着您可以通过同一队列发送不同 ...

  3. 基于网络的 Red Hat 无人值守安装

    基于网络的 Red Hat 无人值守安装 本文介绍了 PC 平台上的一种快速 Red Hat Linux 安装方案.它具有很高的自动化程度--用户只需手工启动机器并选择从网络启动,就可以完成整个安装过 ...

  4. 【bzoj4517】[Sdoi2016]排列计数 组合数+dp

    题目描述 求有多少种长度为 n 的序列 A,满足以下条件: 1 ~ n 这 n 个数在序列中各出现了一次 若第 i 个数 A[i] 的值为 i,则称 i 是稳定的.序列恰好有 m 个数是稳定的 满足条 ...

  5. C#中构造函数和析构函数的用法

    构造函数与析构函数是一个类中看似较为简单的两类函数,但在实际运用过程中总会出现一些意想不到的运行错误.本文将较系统的介绍构造函数与析构函数的原理及在C#中的运用,以及在使用过程中需要注意的若干事项.一 ...

  6. 关于HTML中的object元素

    <object>元素:它主要用于定义网页中的多媒体,比如音频,视频,Java applets,PDF,Active和Flash.object标签内除了param标签外,其他的内容将在浏览器 ...

  7. SCOI2005 互不侵犯 [状压dp]

    题目传送门 题目大意:有n*n个格子,你需要放置k个国王使得它们无法互相攻击,每个国王的攻击范围为上下左走,左上右上左下右下,共8个格子,求最多的方法数 看到题目,是不是一下子就想到了玉米田那道题,如 ...

  8. bzoj 3513 [MUTC2013]idiots FFT 生成函数

    [MUTC2013]idiots Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 806  Solved: 265[Submit][Status][Di ...

  9. CentOS 64位上编译 Hadoop2.6.0

    由于hadoop-2.6.0.tar.gz安装包是在32位机器上编译的,64位的机器加载本地库.so文件时会出错,比如: java.lang.UnsatisfiedLinkError: org.apa ...

  10. Windows下查看某个端口被哪个服务占用

    1.查看某个端口是否被占用 打开命令行,输入:netstat -ano | findstr "3306" 2.查看端口被哪个服务占用 tasklist | findstr “PID ...