이 작업을 수행하는 코드를 작성했습니다.
AntialiasedText
기능은 오프 스크린 비트 맵에 앤티 앨리어스 텍스트를 그립니다. AlphaBlend
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;
앤티 앨리어싱 된 텍스트처럼 보이는 것은 아닙니다. 일반적인 결과는 검은 얼룩 (black blob)입니다. 배경이 검은 색으로 알파가 0 인 결과입니다. 검은 색에서 검은 색으로 앤티 앨리어싱을 수행합니다. 핵심 문제는 당연히 윈도우 나 비트 맵 뒤에있는 실제 배경을 추측 할 수 없다는 것입니다. 타임머신이 필요합니다. Windows가 유리를 위해 그것을 어떻게 풀어 냈는지에 주목하십시오. 창의 제목은 텍스트와 거의 같은 형태 인 유백색 배경에 표현됩니다. DrawThemeTextEx()는 DTT_GLOWSIZE를 사용합니다. –
저는 ** 수학 **를 사용하여 알려진 단색 배경색에 대해 앤티 앨리어스 처리 된 텍스트를 포함하는 비트 맵을 알파 채널이있는 텍스트로 변환 할 수 있는지 궁금했습니다. 당신이 그것을 할 수있는 방법을 생각해 내면 알려주십시오 :) –
안티 앨리어싱 픽셀을 감지하는 것은 쉬운 일입니다. (입력 된 색상이 아닌 색상 만 검색하면됩니다.) 문제의 색상이 가까울 때 문제가 발생합니다. 흰색 정도로. @Hans 필자가 수동으로'ppvBits'를'memset()'으로 채울 것이기 때문에 블롭 색상이 완전 흰색이라는 것을 알지만 그 이외에는 정확히 내 문제입니다! – andlabs