Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
489 views
in Technique[技术] by (71.8m points)

winapi - UpdateLayeredWindow and DrawText

I'm using UpdateLayeredWindow to display an application window. I have created my own custom buttons and i would like to create my own static text. The problem is that when i try to draw the text on the hdc, the DrawText or TextOut functions overwrite the alpha channel of my picture and the text will become transparent. I tried to find a solution to this but i could not find any. My custom controls are designed in such way that they will do all the drawing in a member function called Draw(HDC hDc), so they can only access the hdc. I would like to keep this design. Can anyone help me? I am using MFC and i would want to achieve the desired result without the use of GDI+.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I know this is an old post ... but I just had this very same problem ... and it was driving me CRAZY.

Eventually, I stumbled upon this post by Mike Sutton to the microsoft.public.win32.programmer.gdi newsgroup ... from almost 7 years ago!

Basically, the DrawText (and TextOut) do not play nicely with the alpha channel and UpdateLayeredWindow ... and you need to premultiply the R, G, and B channels with the alpha channel.

In Mike's post, he shows how he creates another DIB (device independent bitmap) upon which he draws the text ... and alpha blends that into the other bitmap.

After doing this, my text looked perfect!

Just in case, the link to the newsgroup post dies ... I am going to include the code here. All credit goes to Mike Sutton (@mikedsutton).

Here is the code that creates the alpha blended bitmap with the text on it:

HBITMAP CreateAlphaTextBitmap(LPCSTR inText, HFONT inFont, COLORREF inColour)
{ 
    int TextLength = (int)strlen(inText); 
    if (TextLength <= 0) return NULL; 

    // Create DC and select font into it 
    HDC hTextDC = CreateCompatibleDC(NULL); 
    HFONT hOldFont = (HFONT)SelectObject(hTextDC, inFont); 
    HBITMAP hMyDIB = NULL; 

    // Get text area 
    RECT TextArea = {0, 0, 0, 0}; 
    DrawText(hTextDC, inText, TextLength, &TextArea, DT_CALCRECT); 
    if ((TextArea.right > TextArea.left) && (TextArea.bottom > TextArea.top))
    { 
        BITMAPINFOHEADER BMIH; 
        memset(&BMIH, 0x0, sizeof(BITMAPINFOHEADER)); 
        void *pvBits = NULL; 

        // Specify DIB setup 
        BMIH.biSize = sizeof(BMIH); 
        BMIH.biWidth = TextArea.right - TextArea.left; 
        BMIH.biHeight = TextArea.bottom - TextArea.top; 
        BMIH.biPlanes = 1; 
        BMIH.biBitCount = 32; 
        BMIH.biCompression = BI_RGB; 

        // Create and select DIB into DC 
        hMyDIB = CreateDIBSection(hTextDC, (LPBITMAPINFO)&BMIH, 0, (LPVOID*)&pvBits, NULL, 0); 
        HBITMAP hOldBMP = (HBITMAP)SelectObject(hTextDC, hMyDIB); 
        if (hOldBMP != NULL)
        { 
            // Set up DC properties 
            SetTextColor(hTextDC, 0x00FFFFFF); 
            SetBkColor(hTextDC, 0x00000000); 
            SetBkMode(hTextDC, OPAQUE); 

            // Draw text to buffer 
            DrawText(hTextDC, inText, TextLength, &TextArea, DT_NOCLIP); 
            BYTE* DataPtr = (BYTE*)pvBits; 
            BYTE FillR = GetRValue(inColour); 
            BYTE FillG = GetGValue(inColour); 
            BYTE FillB = GetBValue(inColour); 
            BYTE ThisA; 
            for (int LoopY = 0; LoopY < BMIH.biHeight; LoopY++) { 
                for (int LoopX = 0; LoopX < BMIH.biWidth; LoopX++) { 
                    ThisA = *DataPtr; // Move alpha and pre-multiply with RGB 
                    *DataPtr++ = (FillB * ThisA) >> 8; 
                    *DataPtr++ = (FillG * ThisA) >> 8; 
                    *DataPtr++ = (FillR * ThisA) >> 8; 
                    *DataPtr++ = ThisA; // Set Alpha 
                } 
            } 

            // De-select bitmap 
            SelectObject(hTextDC, hOldBMP); 
        } 
    } 

    // De-select font and destroy temp DC 
    SelectObject(hTextDC, hOldFont); 
    DeleteDC(hTextDC); 

    // Return DIBSection 
    return hMyDIB; 
}

Here is the code that drives the CreateAlphaTextBitmap method:

void TestAlphaText(HDC inDC, int inX, int inY)
{ 
    const char *DemoText = "Hello World!"; 
    RECT TextArea = {0, 0, 0, 0}; 
    HFONT TempFont = CreateFont(50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial"); 
    HBITMAP MyBMP = CreateAlphaTextBitmap(DemoText, TempFont, 0xFF); 
    DeleteObject(TempFont); 
    if (MyBMP)
    {
        // Create temporary DC and select new Bitmap into it 
        HDC hTempDC = CreateCompatibleDC(inDC); 
        HBITMAP hOldBMP = (HBITMAP)SelectObject(hTempDC, MyBMP); 
        if (hOldBMP)
        {
            // Get Bitmap image size
            BITMAP BMInf;
            GetObject(MyBMP, sizeof(BITMAP), &BMInf); 

            // Fill blend function and blend new text to window 
            BLENDFUNCTION bf; 
            bf.BlendOp = AC_SRC_OVER; 
            bf.BlendFlags = 0; 
            bf.SourceConstantAlpha = 0x80; 
            bf.AlphaFormat = AC_SRC_ALPHA; 
            AlphaBlend(inDC, inX, inY, BMInf.bmWidth, BMInf.bmHeight, hTempDC, 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf); 

            // Clean up 
            SelectObject(hTempDC, hOldBMP); 
            DeleteObject(MyBMP); 
            DeleteDC(hTempDC); 
        } 
    } 
} 

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...