GetDiBits技术疑问:未选入DC的位图能否使用及DI含义解析
咱们先把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句柄(比如用CreateCompatibleBitmap或LoadBitmap创建的),不管它有没有被选入过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




