2014-09-24 11 views
1

저는 Go에 대한 플랫폼에 무관심한 벡터 그래픽 시스템을 쓰고 싶었 기 때문에 텍스트 앨리어싱과 라인 앨리어싱 및 투명도에 대해 많은 질문을했습니다. Windows 코드는 C로 작성되었습니다. 미리 곱셈의 헛소리 때문에 텍스트를 렌더링하는 데 집중할 수있게되었습니다 (시스템 글꼴에 액세스 할 수있게되었습니다).순수 GDI를 사용하여 투명 배경에 앤티 엘리 어싱 된 텍스트를 렌더링 할 수 있습니까?

지금은 화면 밖 비트 맵에 텍스트를 그립니다. 이 기능은 앤티 엘리 어싱 된 비트를 제외하고는 작동합니다. 내 코드에서 알파 버퍼 (GDI는 그려지는 픽셀에 대해 0x00으로 설정 함)를 뒤집기 위해 메모리 버퍼를 0xFF로 채울 때 앤티 앨리어싱은 흰색입니다. Other people have seen antialiasing to black.ANTIALIASED_QUALITYCLEARTYPE_QUALITY 모두 발생합니다.

이 경우 DIB에 TextOut()으로 그립니다. DIB는 DC (GetDC(NULL)) 화면의 사본을받습니다.

텍스트를 투명하게 만들 수있는 방법이 있습니까? 어떻게 든 흰 픽셀을 감지하고, 블렌드를 풀고, 알파로 변환 할 수 있습니까? 나는 흰색과 비슷한 색을 위해 그것을 어떻게 할 것인가?

감사합니다.

+1

앤티 앨리어싱 된 텍스트처럼 보이는 것은 아닙니다. 일반적인 결과는 검은 얼룩 (black blob)입니다. 배경이 검은 색으로 알파가 0 인 결과입니다. 검은 색에서 검은 색으로 앤티 앨리어싱을 수행합니다. 핵심 문제는 당연히 윈도우 나 비트 맵 뒤에있는 실제 배경을 추측 할 수 없다는 것입니다. 타임머신이 필요합니다. Windows가 유리를 위해 그것을 어떻게 풀어 냈는지에 주목하십시오. 창의 제목은 텍스트와 거의 같은 형태 인 유백색 배경에 표현됩니다. DrawThemeTextEx()는 DTT_GLOWSIZE를 사용합니다. –

+0

저는 ** 수학 **를 사용하여 알려진 단색 배경색에 대해 앤티 앨리어스 처리 된 텍스트를 포함하는 비트 맵을 알파 채널이있는 텍스트로 변환 할 수 있는지 궁금했습니다. 당신이 그것을 할 수있는 방법을 생각해 내면 알려주십시오 :) –

+0

안티 앨리어싱 픽셀을 감지하는 것은 쉬운 일입니다. (입력 된 색상이 아닌 색상 만 검색하면됩니다.) 문제의 색상이 가까울 때 문제가 발생합니다. 흰색 정도로. @Hans 필자가 수동으로'ppvBits'를'memset()'으로 채울 것이기 때문에 블롭 색상이 완전 흰색이라는 것을 알지만 그 이외에는 정확히 내 문제입니다! – andlabs

답변

3

이 작업을 수행하는 코드를 작성했습니다.

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; 
+0

@andlabs 저는 제 코드가 투명도를 계산한다고 언급하지 않았습니다. 너에게 효과가 있니? – arx

+0

아직 테스트를 해보지는 않았지만 말씀을드립니다. +1 –

+0

(지연에 대해 유감스럽게 생각합니다.) 나를 위해 일하는 것처럼 보이지만 나만이 쉼표가 너무 투명합니까? Helvetica, 12 포인트, 안티 앨리어스 또는 ClearType 품질 (쉼표와 동일하게 나타남) http : // imgur.co.kr/A7GYmmO (와인 중) 다시 한번 감사드립니다! 저것은 영리한 접근이고 나는 그것이 = P – andlabs