You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

GetDiBits技术疑问:未选入DC的位图能否使用及DI含义解析

关于GetDiBits的几个常见疑问解答

咱们先把Windows GDI里的两种位图类型搞清楚,这是理解所有问题的基础:

  • DDB(Device-Dependent Bitmap,设备兼容位图):和特定DC的设备格式绑定,像素数据存储在GDI资源里,用户无法直接访问,只能通过GDI函数操作(比如BitBlt)。
  • DIB(Device-Independent Bitmap,设备独立位图):像素数据以标准格式(比如RGB)存储,不依赖具体设备,用户可以直接读写其像素缓冲区。

1. GetDiBits为什么不需要将位图选入DC?

BitBlt需要把位图选入DC,是因为它是在DC之间执行绘制操作——DC是GDI的绘图上下文,必须把位图设为DC的当前绘图对象,才能让BitBlt知道要绘制哪张图。

而GetDiBits的本质是从DDB中提取像素数据,并转换为DIB格式输出到你提供的缓冲区。它直接操作的是位图对象本身的GDI资源,不需要通过DC的上下文来定位或访问位图数据。简单说,它是“读取位图对象的原始数据并转格式”,而不是“用位图来绘图”,所以不需要选入DC。

2. 能否直接将未选入DC的新建位图作为GetDiBits的参数?

完全可以!只要你拿到的是有效的DDB句柄(比如用CreateCompatibleBitmapLoadBitmap创建的),不管它有没有被选入过DC,都能传给GetDiBits。

不过要注意:如果是刚用CreateCompatibleBitmap创建的空白DDB,它的像素数据是未初始化的(可能是随机值或全黑),GetDiBits会读取这些原始数据;如果是已经绘制过内容的DDB,不管是通过选入DC绘制还是其他方式,GetDiBits都能正确提取其像素。

举个简单的代码片段示例:

// 创建一个兼容DC(只是用来创建DDB,之后不需要选入)
HDC hdcScreen = GetDC(NULL);
HDC hdcMem = CreateCompatibleDC(hdcScreen);
// 创建空白DDB
HBITMAP hBitmap = CreateCompatibleBitmap(hdcScreen, 100, 100);
// 直接调用GetDiBits,不需要将hBitmap选入hdcMem
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
bmi.bmiHeader.biWidth = 100;
bmi.bmiHeader.biHeight = -100; // 顶部为原点
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 24;
bmi.bmiHeader.biCompression = BI_RGB;
BYTE* pBuffer = new BYTE[100*100*3];
GetDiBits(hdcScreen, hBitmap, 0, 100, pBuffer, &bmi, DIB_RGB_COLORS);
// 后续清理资源...

3. 为什么叫GetDiBits,但MSDN说它获取的是“兼容位图的位数据”?

这里的DI(Device-Independent)指的是输出的数据格式,而不是操作的对象

虽然GetDiBits的输入是DDB(设备兼容位图),但它输出的是设备独立格式的像素数据——你可以通过BITMAPINFO指定输出的像素格式(比如24位RGB、32位ARGB等),不管原DDB是16位、24位还是其他和设备绑定的格式,GetDiBits都会自动转换为你指定的DIB格式。

CreateDibSection是直接创建一个DIB对象,并且返回指向其像素缓冲区的指针,让你可以直接读写设备独立的像素数据。两者的区别在于:

  • GetDiBits是从DDB转DIB的工具,输出DIB格式的数据;
  • CreateDibSection是直接创建DIB,并提供直接访问像素的途径。

内容的提问来源于stack exchange,提问作者sergiu reznicencu

火山引擎 最新活动