CreateDIBSection 与 CreateDIBitmap 的区别——详细探讨

wonaixiaogang 2009-05-09 06:59:28
很多人说,IDB和DDB之间的相互转换比较慢,所以我们使用CreateDIBSection()来创建一个DIB区块。这样作图速度快。
CreateDIBSection()返回的是一个HBITMAP,CreateDIBitmap()返回的也是HBITMAP。
两者的区别是,CreateDIBSection创建的是一个DIBSECTION结构,而CreateDIBitmap创建的是BITMAP结构。
----------------------------------------------------
DIB区块(DIBSECTION)是什么?看看它的结构:
typedef struct tagDIBSECTION {
BITMAP dsBm;
BITMAPINFOHEADER dsBmih;
DWORD dsBitfields[3];
HANDLE dshSection;
DWORD dsOffset;
} DIBSECTION, *PDIBSECTION;
可以看到,它包含了一个 位图结构BITMAP,一个DIB信息头BITMAPINFOHEADER,一个掩码表dsBitfields[3].
还有一个内存映射文件句柄和偏移量。我们不去理睬最后两个字段。
因此,使用GDI函数对CreateDIBSection()返回的HBITMAP作图是没有什么问题的。
-------------------------------------------------------------------------
我不明白的是,既然我们可以使用CreateDIBitmap()来从DIB得到DDB,干嘛微软还要多此一举弄一个CreateDIBSection()(除开内存映射文件功能)?
这连个函数的作图效率有差别么?如果有,是什么原因。在我看来,DIB和DDB的区别无非就是信息头不同。一个是BITMAPINFOHEADER,一个是BITMAP,还有,一个带有颜色表,而另一个没有颜色表。而DIB和DDB的位图数据是完全一样的。

求牛人指教。
...全文
1958 20 打赏 收藏 转发到动态 举报
写回复
用AI写文章
20 条回复
切换为时间正序
请发表友善的回复…
发表回复
WWSWWSWWS 2012-04-27
  • 打赏
  • 举报
回复
这么复杂啊!学习了。原来只是使用,没有考虑这些问题,真是见识了。
wangbao2011_12 2012-04-06
  • 打赏
  • 举报
回复
我也月到了这样的问题
wangbao2011_12 2012-04-06
  • 打赏
  • 举报
回复
我来晚了,现在都2012年了,你这还是09年的帖子,我想借助你的帖子也解决下我的项目
我在16位颜色下,建立32位的内存DC,要先建立32位的内存位图,然后选进内存DC里,这个内存DC也是32位的吧。也许我这方法根本不可行。希望指教
wonaixiaogang 2009-05-14
  • 打赏
  • 举报
回复
虽然,感谢LS耐心的回答。看来我们还是要继续研究这个函数,NND。
wonaixiaogang 2009-05-12
  • 打赏
  • 举报
回复
晕菜了。
DDB 究竟是什么样的结构?除了一个BITMAP信息头之外,是不是就只有数据区了?
数据区是什么格式的?是4字节一像素的RGB格式,还是每个像素指向DC的颜色表的索引值?
如果DDB的数据是32位1像素的RGB格式的,而DC是8位的256色的颜色盘。把DDB选入DC时,会进行数据区域的转换么?
如果不转换,用DC来作图岂不是会造成颜色错误?
wonaixiaogang 2009-05-12
  • 打赏
  • 举报
回复
实验代码:

void *ppV;
void *ppV2;
BITMAP B;
HBITMAP hBitmap = CreateDIBSection(NULL,(BITMAPINFO *)pBuf,DIB_RGB_COLORS,&ppV,NULL,NULL);
GetObject( hBitmap, sizeof(BITMAP),&B);
ppV2 = B.bmBits ;
if(ppV==ppV2)
{
TRACE("相同\n");
}
else
{
TRACE("不同\n");
}
wonaixiaogang 2009-05-12
  • 打赏
  • 举报
回复
[Quote=引用 11 楼 lambochan 的回复:]
同一台机器,DC绝对一样的.
[/Quote]
你总是说一些片面的句子。
同一台机器,我自己创建的DC和屏幕DC就可能不一样。
[Quote=引用 11 楼 lambochan 的回复:]
当然不是啦,create 8位的BMP的话,取它的DIB数据指针处理,每个像素还是一个字节的,24位就3个字节.
除非你是在32位色深系统下用GetObject()来取它HIBMTAP那个BITMAP结构里的DDB数据指针,那才会是4个字节的RGBX数据.
[/Quote]
你是说:CreateDIBSection()创建的DIB数据返回的指针 和GetObject()来取它HIBMTAP那个BITMAP结构里的DDB数据指针指向的不是同一个位置?
我去试验了下,证明这两个指针指向的是同一个位置。
lambochan 2009-05-12
  • 打赏
  • 举报
回复
晕..DC当然有8位,那是因为是设备是8位..
同样,DDB当然也有32位的.

很简单,use CreateCompaibleBitmap() Create个Bitmap出来,然后GetObject(),就知道设备是多少位的,因为Create出来的DDB是设备相关的.

同一台机器,DC绝对一样的.

"CreateDIBSection()创建的DIB是直接由4字节一像素的RGB值构成,不使用HDC的色深,是和HDC不兼容的。"
当然不是啦,create 8位的BMP的话,取它的DIB数据指针处理,每个像素还是一个字节的,24位就3个字节.
除非你是在32位色深系统下用GetObject()来取它HIBMTAP那个BITMAP结构里的DDB数据指针,那才会是4个字节的RGBX数据.

建议lz去看看周长发的<<精通Visual C++.net图象处理编程>>.或者去google search DDB & DIB和DC的概念
wonaixiaogang 2009-05-12
  • 打赏
  • 举报
回复
当然,我可能说错了,也有可能,CreateDIBSection()的第3个参数使用DIB_RGB_COLORS时,
CreateDIBSection()创建的DIB是直接和屏幕的DC兼容,也就是使用系统的色深,
不过就算这样,依然是不使用传入的HDC的色深,是可能和HDC不兼容的。
wonaixiaogang 2009-05-12
  • 打赏
  • 举报
回复
[Quote=引用 8 楼 lambochan 的回复:]
根本就不会存在有32位DDB而DC是8位的.
[/Quote]
你这样说,那我们使用DC还有什么用?
屏幕和打印机的DC是不一样的,创建兼容位图就是说创建和DC兼容的位图,是要传入DC参数的。
DC绝对是有8位的,DDB也绝对是有32位的,就看你传入的DC是什么位。
为什么GDI的很多函数都要用到HDC传进参数?就是因为DC可能不一样。
在网上看了一下,CreateDIBSection()的第3个参数使用DIB_RGB_COLORS时,
CreateDIBSection()创建的DIB是直接由4字节一像素的RGB值构成,不使用HDC的色深,是和HDC不兼容的。
lambochan 2009-05-12
  • 打赏
  • 举报
回复
[Quote=引用 7 楼 wonaixiaogang 的回复:]
晕菜了。
DDB 究竟是什么样的结构?除了一个BITMAP信息头之外,是不是就只有数据区了?
数据区是什么格式的?是4字节一像素的RGB格式,还是每个像素指向DC的颜色表的索引值?
如果DDB的数据是32位1像素的RGB格式的,而DC是8位的256色的颜色盘。把DDB选入DC时,会进行数据区域的转换么?
如果不转换,用DC来作图岂不是会造成颜色错误?
[/Quote]

DDB很简单,你的系统是什么色深的,它就是什么色深.
你的系统设置是24Bit true color,DDB就是24Bit true color,如果设置的是16 or 32bit,那么DDB就是16 or 32Bit.
根本就不会存在有32位DDB而DC是8位的.
DC就好比你的屏幕,而DDB就象是屏幕上显示的图,屏幕上能显示的图是多少位(色深),DDB就是多少位的.
DDB是设备相关的.
lambochan 2009-05-12
  • 打赏
  • 举报
回复
传统所说的DC,就是屏幕的设备上下文.
偶之说以说它是一样的,那是因为通常都是用GetDC()来获取DC来显示,获得的色深在一台机器上肯定是相同的..


lambochan 2009-05-12
  • 打赏
  • 举报
回复
那正好说明CreateDIBSection()创建出来的DIB由里到外都是设备无关...虽然偶还以为它那个HBITMAP的BITMAP结构已经转换为DDB.
但那又怎样呢?并不如你所说:它的像素是由四个字节RGBX组成的.
依然是8位就1个字节(color table索引),16位就两个字节,是绝对设备无关的.
在上面怎么作图,都不会因为系统色深不同而改变,依然是8bit还是8bit,24bit还是24bit.

说说你的DC..既然你都是说你创建的DC了,和屏幕的不一样又怎样..
估计你说的是CreateDC(),偶也不知道你Create出什么DC来.
不过,最终显示到屏幕上的DDB的色深肯定和显示设备设置的色深一样.
wonaixiaogang 2009-05-12
  • 打赏
  • 举报
回复
现在我貌似有点点明白了:

CreateDIBSection()的第一个参数HDC和第二个参数BITMAPINFO的色深必须一样,使用DIB_PAL_COLORS时,函数才会成功。这是因为:

使用DIB_PAL_COLORS时,只是把HDC的颜色表拷贝到DIB的DIBSECTION里的颜色表。而使用DIB_RGB_COLOR时,
DIB的颜色表保持默认的颜色表。

也不知道我说对了没有。我靠,这函数网上的资料和MSDN都没说清楚。而使用它的人也都似懂非懂,将就使用。
lambochan 2009-05-09
  • 打赏
  • 举报
回复
永远指定为DIB_RGB_COLORS,无论任何情况都不会作图失败的.
因为任何对该HBITMAP( DDB )的改动,都会反映在它的数据块内(那个const void ** 指针).

例如你用这个CreateDIBSection()函数建了个HBITAMP,就可以直接选入内存DC画图,然后就直接可以保存,因为所有改动都记录在数据指针内 :
HDC hDC = GetDC( NULL );
HBITMAP hBitmap = CreateDIBSection( hDC, ( CONST BITMAPINFO * )lpBminfo, DIB_RGB_COLORS,
( CONST VOID ** )&pBits, NULL, 0 );

HDC hMemDC = CreateCompatibleDC( hDC );

HBITMAP hOldBmp = ( HBITMAP )SelectObject( hMemDC, hBitmap );
DrawCodeHere().....
DrawAgain().....
// release
SelectObject( hMemDC, hOldBmp );
DeleteDC( hMemDC );
ReleaseDC( NULL, hDC );
// 然后就可以保存或者其它..
BITMAPFILEHEADER bmfh;
bmfh.bfType = 0x4d42;
.........
.....
..
==========================================================================
那是绝对和设备无关的, 绝对不会因为和设备不同而失败, 所以几乎都用它来构造什么CDib之类的.

当然,如果处理的是8bit或以下的bmp的话,还要有设置调色板( PALETTE )和彩色表( colors table )的代码
wonaixiaogang 2009-05-09
  • 打赏
  • 举报
回复
4楼,按你说法,我这样理解你看对不对:
当第四个参数是 DIB_RGB_COLORS时,CreateDIBSection()创建的DIB不使用HDC的色深,是和HDC不兼容的。那么我们直接使用CreateDIBSection()返回的HBITMAP 作图的时候,就有可能失败或者错误。
而当第四个参数是 DIB_PAL_COLORS 时,位图色深与HDC兼容,这时,我们用lpBminfo指定的色深就无效了。此时就不能把DIB直接保存到文件中了。
如果我理解错误,请你解释一下,但DC和lpBminfo的色深不一样时,CreateDIBSection()是如何工作的。谢谢
lambochan 2009-05-09
  • 打赏
  • 举报
回复
其实一句话,使用CreateDIBSection()容易控制,因为你构造的BITMAPINFO是多少bit就按多少bit来操作它的位数据.
而CreateDIBitmap(), create出来的是DDB,是和屏幕色深相同的,在这台机它可能是16Bit的,而在那台机器它可能是24bit或者是32bit,明显不利于代码操控/维护..

CreateDIBSection()使用时传入一个LPBITMAPINFO和一个空的CONST VOID **的指针,一旦create了,就可以直接对那个位数据指针(CONST VOID **)操纵,而不需要理会它是怎样转换为DDB的.

不过要说的是,DIB肯定比DDB慢,因为它还要转成DDB显示.
=====================================================
hBitmap = CreateDIBSection( hDC, ( CONST BITMAPINFO * )lpBminfo, DIB_RGB_COLORS,
( VOID ** )&pBits, NULL, 0 );

// 一旦create了,就可以直接操控pBits这个指针,例如:

memset( pBits, 0x0, ImageSize ); // 全部变黑或者象下面的
*( pBits + xxxx ) = 255; // 对某个像素赋值.

========================================================
比较方便,所以很多人都会用这个方法,而且保存为文件时也是相当容易的,有BITMAPINFO和位数据指针,填个BITMAPFILEHEADER就可以全部写入为一个BMP了.
菜牛 2009-05-09
  • 打赏
  • 举报
回复
你首先要搞明白DIB和DDB的区别,对于DDB到DIB的转换,只要加上一个位图信息头就是了;但是从DIB到DDB的转换,要根据当前DC的位图格式(多少位色彩),可能要扩展也可能要减少色彩位数,如果你考虑这个因素,可以认为是由速度的损失。因此GDI下DDB作图肯定是最快的,直接拷贝位图数据到显存即可。
贪玩的老鼠 2009-05-09
  • 打赏
  • 举报
回复
CreateDIBitmap The DDB that is created will be whatever bit depth your reference DC is.
CreateDIBSection To create a bitmap that is of different bit depth

19,468

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 图形处理/算法
社区管理员
  • 图形处理/算法社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧