我寫了一些代碼來做到這一點。
AntialiasedText
函數將消除鋸齒的文本繪製到屏幕外的位圖上。它會計算透明度,以便可以使用API函數將文本與任何背景混合。
該函數後面跟着一個WM_PAINT
處理函數來說明它的用法。
// Yeah, I'm lazy...
const int BitmapWidth = 500;
const int BitmapHeight = 128;
// Draw "text" using the specified font and colour and return an anti-aliased bitmap
HBITMAP AntialiasedText(LOGFONT* plf, COLORREF colour, LPCWSTR text)
{
BITMAPINFO bmi = {0};
bmi.bmiHeader.biSize = sizeof(bmi.bmiHeader);
bmi.bmiHeader.biWidth = BitmapWidth;
bmi.bmiHeader.biHeight = BitmapHeight;
bmi.bmiHeader.biPlanes = 1;
bmi.bmiHeader.biBitCount = 32;
LPBYTE pBits;
HBITMAP hDIB = CreateDIBSection(0, &bmi, DIB_RGB_COLORS, (LPVOID*)&pBits, 0, 0);
// Don't want ClearType
LOGFONT lf = *plf;
lf.lfQuality = ANTIALIASED_QUALITY;
HFONT hFont = CreateFontIndirect(&lf);
HDC hScreenDC = GetDC(0);
HDC hDC = CreateCompatibleDC(hScreenDC);
ReleaseDC(0, hScreenDC);
HBITMAP hOldBMP = (HBITMAP)SelectObject(hDC, hDIB);
HFONT hOldFont = (HFONT)SelectObject(hDC, hFont);
RECT rect = {0, 0, BitmapWidth, BitmapHeight};
FillRect(hDC, &rect, WHITE_BRUSH);
TextOut(hDC, 2, 2, text, wcslen(text));
// Flush drawing
GdiFlush();
// Calculate alpha
LPBYTE pixel = pBits;
int pixelCount = BitmapWidth * BitmapHeight;
BYTE r = GetRValue(colour);
BYTE g = GetGValue(colour);
BYTE b = GetBValue(colour);
for (int c = 0; c != pixelCount; ++c)
{
// Set alpha
BYTE alpha = 255 - pixel[0];
pixel[3] = alpha;
// Set colour
pixel[0] = b * alpha/255;
pixel[1] = g * alpha/255;
pixel[2] = r * alpha/255;
pixel += 4;
}
SelectObject(hDC, hOldFont);
SelectObject(hDC, hOldBMP);
DeleteDC(hDC);
DeleteObject(hFont);
return hDIB;
}
這是一個WM_PAINT
處理函數來執行此函數。它將兩次繪製相同的文本,首先使用TextOut
,然後使用消除鋸齒的位圖。它們看起來差不多,但不如ClearType。
case WM_PAINT:
{
LPCWSTR someText = L"Some text";
hdc = BeginPaint(hWnd, &ps);
LOGFONT font = {0};
font.lfHeight = 40;
font.lfWeight = FW_NORMAL;
wcscpy_s(font.lfFaceName, L"Comic Sans MS");
// Draw the text directly to compare to the bitmap
font.lfQuality = ANTIALIASED_QUALITY;
HFONT hFont = CreateFontIndirect(&font);
font.lfQuality = 0;
HFONT hOldFont = (HFONT)SelectObject(hdc, hFont);
TextOut(hdc, 2, 10, someText, wcslen(someText));
SelectObject(hdc, hOldFont);
DeleteObject(hFont);
// Get an antialiased bitmap and draw it to the screen
HBITMAP hBmp = AntialiasedText(&font, RGB(0, 0, 0), someText);
HDC hScreenDC = GetDC(0);
HDC hBmpDC = CreateCompatibleDC(hScreenDC);
ReleaseDC(0, hScreenDC);
HBITMAP hOldBMP = (HBITMAP)SelectObject(hBmpDC, hBmp);
BLENDFUNCTION bf;
bf.BlendOp = AC_SRC_OVER;
bf.BlendFlags = 0;
bf.SourceConstantAlpha = 255;
bf.AlphaFormat = AC_SRC_ALPHA;
int x = 0;
int y = 40;
AlphaBlend(hdc, x, y, BitmapWidth, BitmapHeight, hBmpDC, 0, 0, BitmapWidth, BitmapHeight, bf);
SelectObject(hBmpDC, hOldBMP);
DeleteDC(hBmpDC);
DeleteObject(hBmp);
EndPaint(hWnd, &ps);
}
break;
這是可能的,只是不指望它看起來像反鋸齒文本。典型的結果是一個黑色的背景,背景是黑色的,alpha值爲0.從黑色到黑色的反鋸齒。核心問題當然是,你永遠無法猜測窗口或位圖背後的實際背景,這需要時間機器。注意Windows如何解決它的玻璃問題,窗口的標題是在與文本大致相同的乳白色背景上呈現的。 DrawThemeTextEx()通過DTT_GLOWSIZE來完成。 – 2014-09-24 18:59:24
我一直在想,如果使用** maths **的力量,可以將包含已知固體背景顏色反鋸齒文本的位圖轉換爲帶alpha通道的文本。如果您想出了一種方法,請告訴我們:) – 2014-09-24 19:47:28
檢測抗鋸齒像素應該很容易(只搜索任何不是輸入顏色的顏色),但是當問題顏色接近時會產生問題足夠白色。 @Hans我知道我的blob顏色是全白的,因爲我用'memset()'手工填充'ppvBits',但除此之外,是的,這正是我的問題! – andlabs 2014-09-24 19:59:06