c++ - 如何从 GDI 设备上下文中获取 32bpp 位图/图像?

标签 c++ mfc gdi+ gdi alphablending

我正在使用这个项目的代码 http://www.codeproject.com/Articles/9064/Yet-Another-Transparent-Static-Control为了将我的子类 Button 控件中的透明按钮图像绘制到我的 CDialogEx 上。

此代码适用于遗留的 24bpp GDI 函数:

BOOL CTransparentStatic2::OnEraseBkgnd(CDC* pDC)
{
   if (m_Bmp.GetSafeHandle() == NULL)
   {
      CRect Rect;
      GetWindowRect(&Rect);
      CWnd *pParent = GetParent();
      ASSERT(pParent);
      pParent->ScreenToClient(&Rect); //convert our corrdinates to our parents

      //copy what's on the parents at this point
      CDC *pDC = pParent->GetDC();
      CDC MemDC;
      MemDC.CreateCompatibleDC(pDC);
      m_Bmp.CreateCompatibleBitmap(pDC,Rect.Width(),Rect.Height());
      CBitmap *pOldBmp = MemDC.SelectObject(&m_Bmp);

      MemDC.BitBlt(0,0,Rect.Width(),Rect.Height(),pDC,Rect.left,Rect.top,SRCCOPY);

      MemDC.SelectObject(pOldBmp);

      pParent->ReleaseDC(pDC);
   }
   else //copy what we copied off the parent the first time back onto the parent
   {
      CRect Rect;
      GetClientRect(Rect);
      CDC MemDC;
      MemDC.CreateCompatibleDC(pDC);
      CBitmap *pOldBmp = MemDC.SelectObject(&m_Bmp);
      pDC->BitBlt(0,0,Rect.Width(),Rect.Height(),&MemDC,0,0,SRCCOPY);
      MemDC.SelectObject(pOldBmp);
   }

   return TRUE;
}

然而,我的 CDialogEx 背景是用 GDI+ 32bpp 渲染绘制的,如下所示:

BOOL CParentDialogEx::OnEraseBkgnd(CDC* pDC)
{
   // Get GDI+ Graphics for the current Device Context
   Graphics gr(*pDC);

   // Get the client area
   CRect clientRect;
   GetClientRect(&clientRect);

   // Draw the dialog background
   // PLEASE NOTE: m_imgDlgBkgnd is a Gdiplus::Image with PNG format ==> 32bpp Image
   gr.DrawImage(m_imgDlgBkgnd, 0, 0, clientRect.Width(), clientRect.Height());
}

这会导致第一个代码片段备份一个黑色矩形而不是 32bpp 绘制的内容。这再次导致我的按钮控件始终具有黑色背景。

为了让我的问题更清楚,请看下面的图片:

  1. 正在将按钮图像绘制到 CDialogEx 背景上(通常):

Normal Button Background

  1. 正在使用第一个代码片段绘制按钮图像

Faulty Button Background

如您所见,GDI 24bpp 看不到对话框背景。它只是假定纯黑色背景。只有 GDI+ 可以看到它。但是,我无法找到从 Gdiplus::Graphics 对象获取位图的方法。

如何获得 32bpp 背景备份以便正确绘制我的透明图像?

完全不使用备份图像会导致 GDI+ 的 alpha 混合在每次绘制时越来越模糊背景。

最佳答案

经过 3 天的思考,我通过测试找到了一些东西。这实际上可以通过 32bpp 渲染更容易地完成!

// Get the client area on the parent
CRect Rect;
GetWindowRect(&Rect);
CWnd *pParent = GetParent();
ASSERT(pParent);
pParent->ScreenToClient(&Rect);

// Get the Parent's DC
CDC *parentDC = pParent->GetDC();

// GDI Code (only 24bpp support)
//CDC MemDC;
//CBitmap bmp;
//MemDC.CreateCompatibleDC(parentDC);
//bmp.CreateCompatibleBitmap(parentDC,Rect.Width(),Rect.Height());
//CBitmap *pOldBmp = MemDC.SelectObject(&bmp);
//MemDC.BitBlt(0,0,Rect.Width(),Rect.Height(),parentDC,Rect.left,Rect.top,SRCCOPY);
//MemDC.SelectObject(pOldBmp);

// GDI+ Code with 32 bpp support (here comes the important change)
Bitmap* bmp = new Bitmap(Rect.Width(), Rect.Height());
Graphics bmpGraphics(bmp);
HDC hBmpDC = bmpGraphics.GetHDC();
BitBlt(hBmpDC, 0, 0, Rect.Width(), Rect.Height(), parentDC->GetSafeHdc(), Rect.left, Rect.top, SRCCOPY); // BitBlt is actually capable of doing 32bpp blts

// Release DCs
bmpGraphics.ReleaseDC(hBmpDC);
pParent->ReleaseDC(parentDC);

给你! 4 行代码,你得到一个 32bpp 的 Gdiplus::Bitmap!您稍后可以在 OnEraseBkgnd 中绘制:

// Get client Area
CRect rect;
GetClientRect(&rect);

// Draw copied background back onto the parent
Graphics gr(*pDC);
gr.DrawImage(bmp, 0, 0, rect.Width(), rect.Height());

请注意,为了提高性能,Bitmap 应该是一个成员变量。它还必须在控件销毁时被释放。

关于c++ - 如何从 GDI 设备上下文中获取 32bpp 位图/图像?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33058788/

相关文章:

c++ - 如何在 emacs lisp 中获取 c/c++ 头系统包含目录?

c++ - mfc sdi 应用程序 cdocument dosave 错误 0xFEEEFEEE

c++ - 如何更改菜单文本

c# - 如何通过 GDI 绘制椭圆 C#?

c++ - 哪个有更好的内存访问? (C++)

c++ - 如何测量每秒的增量数

c++ - 从相机获取每个像素的深度

winapi - 如何监控当前哪个窗口具有键盘焦点

c++ - 将 24 位位图转换为带抖动的 16 位位图的优化 C/C++ 算法是什么?

gdi+ - 应用程序验证程序停止 0202 : Freeing heap block containing an active critical section during GdiPlusShutdown