MFC BitBlt and SetDIBits vs. SetBitmapBits

MFC BitBlt and SetDIBits vs. SetBitmapBits

本文关键字:vs SetBitmapBits SetDIBits and BitBlt MFC      更新时间:2023-10-16

我有一个存储为BGRA字节数组的位图。这是我用来绘制位图的代码:

CDC *dispDC = new CDC();
dispDC->CreateCompatibleDC(pDC);
CBitmap *dispBMP = new CBitmap();
dispBMP->CreateCompatibleBitmap(pDC, sourceImage->GetWidth(), sourceImage->GetHeight());
dispDC->SelectObject(this->dispBMP);

translatedImage数组中像素的实际复制是这样进行的:

dispBMP->SetBitmapBits(sourceImage->GetArea() * 4, translatedImage);

然后经过一些更多的处理,我调用pDC->StretchBltdispDC作为源CDC。这在本地登录时可以正常工作,因为显示也设置为32bpp。

一旦我登录远程桌面,显示到16bpp,图像是混乱的。罪魁祸首是SetBitmapBits;也就是说,为了让它工作,我必须正确地填充translatedImage与我想要显示的16bpp版本。而不是自己这样做,我搜索了文档,发现SetDIBits听起来像我想要的:

SetDIBits函数使用在指定的DIB中找到的颜色数据在兼容位图(DDB)中设置像素。

在我的例子中,DIB是32bpp RGBA数组,DDB是我用CreateCompatibleBitmap创建的dispBMP

所以我没有调用SetBitmapBits,而是这样做:

BITMAPINFO info;
ZeroMemory(&info, sizeof(BITMAPINFO));
info.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
info.bmiHeader.biBitCount = 32;
info.bmiHeader.biPlanes = 1;
info.bmiHeader.biCompression = BI_RGB;
info.bmiHeader.biSizeImage = sourceImage->GetArea()*4;
info.bmiHeader.biWidth = sourceImage->GetWidth();
info.bmiHeader.biHeight = sourceImage->GetHeight();
info.bmiHeader.biClrUsed = 0;
int r = SetDIBits(pDC->GetSafeHdc(), (HBITMAP)dispBMP,
                  0, sourceImage->GetHeight(), translatedImage, 
                  &info, DIB_PAL_COLORS);

然而,r总是零,自然地,我得到的只是黑色的窗口。代码有什么问题?

根据SetDIBits的文档:

不能选择hbmp参数标识的位图应用程序调用此函数时的设备上下文。

在您的示例代码中,您在创建它后将其选择到设备上下文中,因此可能这就是SetDIBits失败的原因。

Ross Ridge指出的代码顺序错误是正确的。然而,这并没有解决问题。

问题出在我传递的参数上。我是c++和MFC的新手,经常忘记所有可以作用于类型以自动转换它们的"操作符"。

之前我有这个:

int r = SetDIBits(pDC->GetSafeHdc(), (HBITMAP)dispBMP,
              0, sourceImage->GetHeight(), translatedImage, 
              &info, DIB_PAL_COLORS);

正确的调用是:

int r = SetDIBits(*pDC, *dispBMP,
              0, sourceImage->GetHeight(), translatedImage, 
              &info, DIB_PAL_COLORS);

(注意,我在前两个形参中传递了未引用指针。)其他一切都是正确的,包括反直觉的DIB_PAL_COLORS标志位图没有调色板。

在明显错过了文档中的一些关键点之后,我重新阅读了它,然后发现了这个示例代码,显示我只是错误地传递了参数。