2014-09-24 44 views
1

最近我一直在問關於文本別名和線條別名以及透明度的許多問題,因爲我想爲Go編寫一個平臺不可知的矢量圖形系統; Windows代碼是用C語言編寫的。預先複製惡意代碼讓我將注意力轉移到了渲染文本上(所以我可以訪問系統字體)。是否可以使用純粹的GDI將抗鋸齒文本渲染到透明背景上?

現在我有東西將文本繪製到離屏位圖。這工作,除了antialiased位。在我的代碼中,當我用0xFF填充內存緩衝區來翻轉alpha字節(GDI爲所繪製的像素設置爲0x00)時,抗鋸齒就是白色。 Other people have seen antialiasing to black.這發生在ANTIALIASED_QUALITYCLEARTYPE_QUALITY

在這種情況下,我正在使用TextOut()繪製DIB。 DIB由屏幕DC副本支持(GetDC(NULL))。

有什麼我可以做的只是讓文本透明?我可以以某種方式檢測白色像素,將它們取消混合並將其轉換爲alpha?我會如何做到顏色與白色相似?

謝謝。

+1

這是可能的,只是不指望它看起來像反鋸齒文本。典型的結果是一個黑色的背景,背景是黑色的,alpha值爲0.從黑色到黑色的反鋸齒。核心問題當然是,你永遠無法猜測窗口或位圖背後的實際背景,這需要時間機器。注意Windows如何解決它的玻璃問題,窗口的標題是在與文本大致相同的乳白色背景上呈現的。 DrawThemeTextEx()通過DTT_GLOWSIZE來完成。 – 2014-09-24 18:59:24

+0

我一直在想,如果使用** maths **的力量,可以將包含已知固體背景顏色反鋸齒文本的位圖轉換爲帶alpha通道的文本。如果您想出了一種方法,請告訴我們:) – 2014-09-24 19:47:28

+0

檢測抗鋸齒像素應該很容易(只搜索任何不是輸入顏色的顏色),但是當問題顏色接近時會產生問題足夠白色。 @Hans我知道我的blob顏色是全白的,因爲我用'memset()'手工填充'ppvBits',但除此之外,是的,這正是我的問題! – andlabs 2014-09-24 19:59:06

回答

3

我寫了一些代碼來做到這一點。

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

@andlabs我忽略提及我的代碼計算透明度。對你起作用嗎? – arx 2014-09-25 09:16:17

+0

我還沒有測試過,但我對此表示贊同。 +1 – 2014-09-25 19:43:19

+0

(對不起,我推遲了。)似乎爲我工作,但它只是我還是這個逗號太透明? Helvetica,12點,無論是antialiased或ClearType質量(他們看起來相同的逗號)。 HTTP:// imgur。com/A7GYmmO(在葡萄酒中)再次感謝!這是一個聰明的做法,我希望我已經想到了這一點= P – andlabs 2014-09-30 13:34:40