我的目标是在运行时将任意文本动态地放入HICON图像中。我正在使用以下代码:
//Error checks are omitted for brevity
//First create font
LOGFONT lf = {0};
lf.lfHeight = -58;
lf.lfWeight = FW_NORMAL;
lf.lfOutPrecision = OUT_TT_PRECIS; //Use TrueType fonts for anti-alliasing
lf.lfQuality = CLEARTYPE_QUALITY;
lstrcpy(lf.lfFaceName, L"Segoe UI");
HFONT hFont = ::CreateFontIndirect(&lf);
//HICON hIcon = original icon to use as a source
//I'm using a large 256x256 pixel icon
hIcon = (HICON)::LoadImage(theApp.m_hInstance, MAKEINTRESOURCE(IDI_ICON_GREEN_DIAMOND), IMAGE_ICON, 256, 256, LR_DEFAULTCOLOR);
ICONINFO ii = {0};
::GetIconInfo(hIcon, &ii);
BITMAP bm = {0};
::GetObject(ii.hbmColor, sizeof(bm), &bm);
SIZE szBmp = {bm.bmWidth, bm.bmHeight};
HDC hDc = ::GetDC(hWnd);
HDC hMemDC = ::CreateCompatibleDC(hDc);
HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor);
HGDIOBJ hOldFont = ::SelectObject(hMemDC, hFont);
::SetBkMode(hMemDC, TRANSPARENT);
::SetTextColor(hMemDC, RGB(255, 0, 0)); //Red text
//Draw text
//NOTE that DrawText API behaves in a similar way
::TextOut(hMemDC, 0, 0, L"Hello", 5);
::SelectObject(hMemDC, hOldFont);
::SelectObject(hMemDC, hOldBmp);
//We need a simple mask bitmap for the icon
HBITMAP hBmpMsk = ::CreateBitmap(szBmp.cx, szBmp.cy, 1, 1, NULL);
ICONINFO ii2 = {0};
ii2.fIcon = TRUE;
ii2.hbmColor = ii.hbmColor;
ii2.hbmMask = hBmpMsk;
//Create updated icon
HICON hIcon2 = ::CreateIconIndirect(&ii2);
//Cleanup
::DeleteObject(hBmpMsk);
::DeleteDC(hMemDC);
::ReleaseDC(hWnd, hDc);
::DeleteObject(ii.hbmColor);
::DeleteObject(ii.hbmMask);
::DeleteObject(hFont);
然后我可以在OnPaint()
处理程序中显示图标(以便我可以看到它的效果):
::DrawIconEx(dc.GetSafeHdc(), 0, 0,
hIcon2,
256, 256, NULL,
::GetSysColorBrush(COLOR_BTNFACE),
DI_NORMAL);
所以这是我得到的: 为了查看我的
hIcon2
中每个像素的情况,我从上面的代码中调用了GetDIBits
函数,并传入了它的ii.hbmColor
参数。最终得到的像素数组,应该显示我的单词“Hello”,但实际上是这样的:
这个内存转储中像素的编码格式是 BGRA
,因此每个 DWORD 中的第四个字节表示透明度:0=透明,FF=不透明。但在这种情况下,TextOut
没有填充透明度,或者将其保留为 0,这被解释为“完全透明”。相反,它似乎将其预先乘以 RGB
颜色本身。请注意,如果我继续查看同一位图向下滚动到绿色菱形开始的位置,图像像素似乎正确设置了透明度字节:
你有没有想过如何绘制文本,使API可以设置透明度字节?
编辑:如下方所建议,我尝试了以下GDI+方法:
HGDIOBJ hOldBmp = ::SelectObject(hMemDC, ii.hbmColor);
Graphics grpx(hMemDC);
RectF rcfTxt(0.0f, 0.0f, (REAL)szBmp.cx, (REAL)szBmp.cy);
Font gdiFont(L"Segoe UI", 58.0f, FontStyleRegular, UnitPixel);
SolidBrush gdiBrush(Color(255, 0, 0));
StringFormat gdiSF;
gdiSF.SetAlignment(StringAlignmentNear);
gdiSF.SetFormatFlags(StringFormatFlagsNoWrap);
gdiSF.SetHotkeyPrefix(HotkeyPrefixNone);
//The reason I was using GDI was because I was setting
//spacing between letters using SetTextCharacterExtra()
//Unfortunately with GDI+ this does not work!
HDC hTmpDC = grpx.GetHDC();
::SetTextCharacterExtra(hTmpDC, -4); //This doesn't do anything!
grpx.ReleaseHDC(hTmpDC);
grpx.DrawString(L"Hello", 5, &gdiFont, rcfTxt, &gdiSF, &gdiBrush);
::SelectObject(hMemDC, hOldBmp);
除了不能像使用GDI时使用SetTextCharacterExtra
设置字符间距之外,这是我得到的东西(稍微放大以便查看):
显然透明度仍然存在问题。
SetTextCharacterExtra
函数来改变字符间距。你知道我是否仍然可以在GDI+中使用它吗? - c00000fd