如何在 CBitmap 上使用具有透明背景的 CDC 绘制文本?

Posted

技术标签:

【中文标题】如何在 CBitmap 上使用具有透明背景的 CDC 绘制文本?【英文标题】:How to draw text using CDC with transparent background on CBitmap? 【发布时间】:2011-10-04 22:54:56 【问题描述】:

我有以下代码,如果你屏蔽掉粉红色像素,我真正想要的是像 PNG 文件这样的透明位,这样我就可以避免 alpha 混合问题,并且需要在位图的任何地方屏蔽特定颜色将被使用。

CClientDC dc(pWnd);
CDC memDC;

if(!memDC.CreateCompatibleDC(&dc))
   return NULL;

CRect bitmapRect;
bitmapRect.SetRectEmpty();

CFont* pOldFont = memDC.SelectObject(pWnd->GetFont());
CSize fontSize = memDC.GetTextExtent(imageText);

bitmapRect.right = fontSize.cx;
bitmapRect.bottom = fontSize.cy;

CBitmap bitmap;
if(!bitmap.CreateCompatibleBitmap(&dc, bitmapRect.Width(), bitmapRect.Height()))
   return NULL;

CBitmap* pOldMemDCBitmap = memDC.SelectObject(&bitmap);

memDC.FillSolidRect(&bitmapRect, RGB(255,0,255));
//memDC.SetBkMode(TRANSPARENT); // doesn't work
//memDC.SetBkColor(TRANSPARENT); // doesn't work
memDC.SetTextColor(GetSysColor(COLOR_WINDOWTEXT));

//memDC.DrawText(imageText, bitmapRect, DT_TOP|DT_LEFT|DT_NOCLIP); // same difference
memDC.TextOut(0, 0, imageText);

memDC.SelectObject(pOldMemDCBitmap);
memDC.SelectObject(pOldFont);
memDC.DeleteDC();

CImageList bmImage;
bmImage.Create(bitmapRect.Width(), bitmapRect.Height(), ILC_COLOR32|ILC_MASK, 0, 1);
// this masks out the pink but for some windows blends edges of text causing pink text instead of black!
bmImage.Add(&bitmap, RGB(255,0,255));

是否只是 MFC 行为不端的充满错误的野兽,还是我遗漏了什么?

【问题讨论】:

IIRC SetBkMode(TRANSPARENT) 应该可以解决问题。您没有任何机会只尝试将该行与随后对 SetBkColor(TRANSPARENT) 的调用结合起来(它可能会将常量 TRANSPARENT 解释为某个颜色值,并可能覆盖透明度模式)...? 不,这些是相互排斥的,只是我尝试过的事情的残余......我想我刚刚发现了我的问题,但在更新或发布答案之前进行了测试。 【参考方案1】:

简单的DrawText(),没有MFC的透明背景:

// in my case a user drawn button:
_windowHandle = CreateWindowEx(...);
SendMessage(_windowHandle, WM_SETFONT, (WPARAM)font, (LPARAM)NULL);

...

// WM_DRAWITEM
SetTextColor(hDC, RGB(216, 27, 27));
SetBkMode(hDC, TRANSPARENT);
RECT rect =  0, 0, backgroundBitmap.bmWidth, backgroundBitmap.bmHeight ;
DrawText(hDC, _text.c_str(), -1, &rect, DT_CENTER | DT_WORDBREAK);

--hfrmobile

【讨论】:

【参考方案2】:

问这个问题大约 10 分钟后,我阅读了自己的评论并意识到“某些窗口”意味着它与传入的窗口有关。特别是从所述窗口使用的字体。具有默认属性的字体呈现出奇怪的混合。

在一天结束时,我决定我需要修改字体以关闭那些弄乱我的绘图代码的东西。我最终将其缩小到导致问题的罪魁祸首:

CClientDC dc(pWnd);
CDC memDC;

if(!memDC.CreateCompatibleDC(&dc))
   return NULL;

LOGFONT tempFont;
CFont* winFont = pWnd->GetFont();
if (winFont)
   winFont->GetLogFont(&tempFont);
else

   // generate a likely font
   SecureZeroMemory(&tempFont, sizeof(LOGFONT));
   //TEXTMETRIC txt;
   //GetTextMetrics(memDC, &txt);
   //tempFont.lfHeight = txt.tmHeight * -1; // 16 is too big looking
   tempFont.lfHeight = -12;
   tempFont.lfWeight = FW_NORMAL;
   tempFont.lfCharSet = DEFAULT_CHARSET;
   wcscpy_s(tempFont.lfFaceName, L"Segoe UI"); // Win7 control default


tempFont.lfQuality = NONANTIALIASED_QUALITY; // this is the fix!!!

CFont newFont;
newFont.CreateFontIndirect(&tempFont);

CFont* pOldFont = memDC.SelectObject(&newFont);
// ... other stuff same as before ...

所以我仍然FillSolidRect 粉红色,然后绘制我的图标、文本、我想要的任何内容等。然后掩盖粉红色像素。通过字体质量调整,它不再将粉红色混合到字体文本中,并且看起来不错。上面的 else 情况会创建一个默认字体,以防传入的 CWnd* 没有指定有效字体。

【讨论】:

以上是关于如何在 CBitmap 上使用具有透明背景的 CDC 绘制文本?的主要内容,如果未能解决你的问题,请参考以下文章

如何将背景转换为透明? [关闭]

如何将一个 Div 放在另一个具有透明背景的 Div 上? [复制]

具有透明背景的 MPMoviePlayerViewController 视频

如何使用 ggplot2 在 R 中制作具有透明背景的图形?

如何在 react-native 中实现具有透明背景的视频

如何从具有透明背景的 matplotlib 导出绘图?