将位数组转换为 HBITMAP 后 bmBits 的 NULL 指针

Posted

技术标签:

【中文标题】将位数组转换为 HBITMAP 后 bmBits 的 NULL 指针【英文标题】:NULL pointer for bmBits after converting a bit array to HBITMAP 【发布时间】:2017-08-29 00:11:17 【问题描述】:

我正在尝试按照以下帖子中的说明将像素数组转换为 HBITMAP:How to convert an Array of pixels to HBITMAP。

基本上,数组被转换为HBITMAP,然后通过复制到剪贴板进行验证。但是,当通过其bmBits 成员访问BITMAP 构造中的位值时,它返回NULL

我可能在这里缺少一些东西。如果HBITMAP创建成功,为什么我们仍然会得到一个指向其位值的NULL指针?

uint8 width = 160;
uint8 height = 120;

uint8* pixels = new uint8[160 * 120 * 4];
for (int i = 0; i < 160 * 120 * 4; i++)
    pixels[i] = (i % 4 == 1) * 255; // testing pixels


BITMAPINFOHEADER bmih;
bmih.biSize = sizeof(BITMAPINFOHEADER);
bmih.biWidth = width;
bmih.biHeight = -1 * height;
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 10;
bmih.biYPelsPerMeter = 10;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;

BITMAPINFO dbmi;
ZeroMemory(&dbmi, sizeof(dbmi));
dbmi.bmiHeader = bmih;
dbmi.bmiColors->rgbBlue = 0;
dbmi.bmiColors->rgbGreen = 0;
dbmi.bmiColors->rgbRed = 0;
dbmi.bmiColors->rgbReserved = 0;

HDC hdc = ::GetDC(NULL);

HBITMAP hbmp = CreateDIBitmap(hdc, &bmih, CBM_INIT, pixels, &dbmi, DIB_RGB_COLORS);
if (hbmp == NULL) 
    ::MessageBox(NULL, L"Could not load the desired image", L"Error", MB_OK);
    return NULL;


::ReleaseDC(NULL, hdc);

// a little test if everything is OK
OpenClipboard(NULL);
EmptyClipboard();
SetClipboardData(CF_BITMAP, hbmp); // I can verify the image by pasting
CloseClipboard();

// verify the bitmap
BITMAP bitmap;
::GetObject(hbmp, sizeof(BITMAP), &bitmap);
uint8* lpbits = (uint8*)bitmap.bmBits;

assert(lpbits != NULL); // Why this assertion failed??

// cleanup
// DeleteObject(hbmp);

【问题讨论】:

调用 GetLastError 来查看调用失败的原因——至少你会得到一个线索 @pm100:大多数 GDI 函数不使用 GetLastError() 进行错误报告,本示例中使用的 GDI 函数肯定是这种情况(只有剪贴板函数使用)。 @RemyLebeau 够公平的。因此,除了“那行不通”之外,别无他法。但是,如果某些底层事情失败(文件错误),那么 GetLastError 将返回一些东西(尽管它可能是一个红鲱鱼) 尽管有它的名字,CreateDIBitmap() 实际上创建了一个 DDB 而不是 DIB。该引用告诉它曾经有一个标志 CBM_CREATDIB 不再受支持。 【参考方案1】:

答案在GetObject() documentation:

如果hgdiobj 是通过调用CreateDIBSection 创建的位图的句柄,并且指定的缓冲区足够大,则GetObject 函数返回DIBSECTION 结构。此外,DIBSECTION 中包含的BITMAP 结构的bmBits 成员将包含指向位图位值的指针。

如果 hgdiobj 是通过任何其他方式创建的位图的句柄,GetObject 仅返回位图的宽度、高度和颜色格式信息。可以通过调用GetDIBits()GetBitmapBits()函数获取位图的位值。

这意味着 bmBits 仅在查询 DIB 位图以获取 DIBSECTION 结构时填充,其中包含 BITMAP 等。

您正在为 BITMAP 结构查询 DDB 位图,因此不会填充 bmBits,您必须单独检索像素位。

【讨论】:

以上是关于将位数组转换为 HBITMAP 后 bmBits 的 NULL 指针的主要内容,如果未能解决你的问题,请参考以下文章

MFC如何将具有透明属性的PNG转换为HBITMAP

如何通过 Bitmap::GetHBITMAP 将位图转换为带有 alpha 的 HBITMAP?

如何从 HBITMAP 转换为 .NET 的 Bitmap 类?

将位数组转换为短数组

Javascript - 将整数转换为位数组

将字节数组转换为位数组问题