【问题标题】:MFC BitBlt and SetDIBits vs. SetBitmapBitsMFC BitBlt 和 SetDIBits 与 SetBitmapBits
【发布时间】:2014-07-03 08:21:18
【问题描述】:

我有一个存储为 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->StretchBlt 并以dispDC 作为源CDC。这在本地登录时可以正常工作,因为显示也设置为 32bpp。

我使用远程桌面登录后,显示速度变为 16bpp,并且图像被破坏。罪魁祸首是SetBitmapBits;即为了让它工作,我必须用我想要显示的 16bpp 版本正确填充translatedImage。我没有自己做,而是搜索了文档并找到了SetDIBits,这听起来像是我想要的:

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

在我的例子中,DIB 是 32bpp RGBA 阵列,而 DDB 是 dispBMP,我使用 CreateCompatibleBitmap 创建。

所以我没有打电话给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 的输入?例如,在这种情况下,dispBMP!=NULL 是真的吗?

标签: c++ bitmap mfc bitblt dib


【解决方案1】:

根据documentation for SetDIBits

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

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

【讨论】:

  • 这显然不是原因。我现在在StretchBLT 调用之前有SelectObject 调用,在两者之间有SetDIBits 并且仍然变黑。 SetDIBits 返回零并且显然什么都不做,因为如果我同时保留它和 SetBitmapBits 调用,我会得到正确的图像(直到我进入远程桌面)。
【解决方案2】:

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 标志,用于没有调色板的位图。

在明显遗漏了文档中的一些关键点之后,我重新阅读它,然后找到了this,它的示例代码表明我只是错误地传递了参数。

【讨论】:

  • 您使用的 GetSafeHdc 没有任何问题,问题在于将指针转换为 CBitmap dispBMP 而不是对象本身 *dispBMP。我很好奇你为什么一开始就把它变成一个指针而不是一个本地对象?
  • @MarkRansom: dispBMP 是一个类成员变量,因为根据我使用 C 的经验,我发现在我处理的应用程序类型(数据处理)中分配内存通常非常昂贵.因此,由于这是一个从头开始的新项目,我非常小心地重用位图和位图字节数组等大型内存对象。
  • 在这种情况下,这种策略不会给你带来太多好处。做一个sizeof(dispBMP) 看看我的意思 - 它不包含位图,它拥有一个位图的句柄,它是单独分配的。
  • @MarkRansom:对。所以如果我失去了那个句柄,我每次都需要创建一个新的位图。分配内存的不是CreateCompatibleBitmap吗?我没有在我的 sn-p 中显示它,但在实际代码中,我只在我知道图像大小改变或 dispBMPNULL 时才调用它。
猜你喜欢
  • 1970-01-01
  • 2023-03-09
  • 1970-01-01
  • 1970-01-01
  • 2019-05-11
  • 1970-01-01
  • 2020-06-16
  • 1970-01-01
  • 2011-09-03
相关资源
最近更新 更多