UpdateLayeredWindow后,使用Gdi DrawText文字透明的解决办法

来源:http://stackoverflow.com/questions/5309914/updatelayeredwindow-and-drawtext

要点就是在先在memDc DrawText,然后手动设置DIB的Alpha值,最后通过AlphaBlend贴到DC。

 

Question:

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+.

 

Answer:

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:

 

 1 HBITMAP CreateAlphaTextBitmap(LPCSTR inText, HFONT inFont, COLORREF inColour)
 2 { 
 3     int TextLength = (int)strlen(inText); 
 4     if (TextLength <= 0) return NULL; 
 5 
 6     // Create DC and select font into it 
 7     HDC hTextDC = CreateCompatibleDC(NULL); 
 8     HFONT hOldFont = (HFONT)SelectObject(hTextDC, inFont); 
 9     HBITMAP hMyDIB = NULL; 
10 
11     // Get text area 
12     RECT TextArea = {0, 0, 0, 0}; 
13     DrawText(hTextDC, inText, TextLength, &TextArea, DT_CALCRECT); 
14     if ((TextArea.right > TextArea.left) && (TextArea.bottom > TextArea.top))
15     { 
16         BITMAPINFOHEADER BMIH; 
17         memset(&BMIH, 0x0, sizeof(BITMAPINFOHEADER)); 
18         void *pvBits = NULL; 
19 
20         // Specify DIB setup 
21         BMIH.biSize = sizeof(BMIH); 
22         BMIH.biWidth = TextArea.right - TextArea.left; 
23         BMIH.biHeight = TextArea.bottom - TextArea.top; 
24         BMIH.biPlanes = 1; 
25         BMIH.biBitCount = 32; 
26         BMIH.biCompression = BI_RGB; 
27 
28         // Create and select DIB into DC 
29         hMyDIB = CreateDIBSection(hTextDC, (LPBITMAPINFO)&BMIH, 0, (LPVOID*)&pvBits, NULL, 0); 
30         HBITMAP hOldBMP = (HBITMAP)SelectObject(hTextDC, hMyDIB); 
31         if (hOldBMP != NULL)
32         { 
33             // Set up DC properties 
34             SetTextColor(hTextDC, 0x00FFFFFF); 
35             SetBkColor(hTextDC, 0x00000000); 
36             SetBkMode(hTextDC, OPAQUE); 
37 
38             // Draw text to buffer 
39             DrawText(hTextDC, inText, TextLength, &TextArea, DT_NOCLIP); 
40             BYTE* DataPtr = (BYTE*)pvBits; 
41             BYTE FillR = GetRValue(inColour); 
42             BYTE FillG = GetGValue(inColour); 
43             BYTE FillB = GetBValue(inColour); 
44             BYTE ThisA; 
45             for (int LoopY = 0; LoopY < BMIH.biHeight; LoopY++) { 
46                 for (int LoopX = 0; LoopX < BMIH.biWidth; LoopX++) { 
47                     ThisA = *DataPtr; // Move alpha and pre-multiply with RGB 
48                     *DataPtr++ = (FillB * ThisA) >> 8; 
49                     *DataPtr++ = (FillG * ThisA) >> 8; 
50                     *DataPtr++ = (FillR * ThisA) >> 8; 
51                     *DataPtr++ = ThisA; // Set Alpha 
52                 } 
53             } 
54 
55             // De-select bitmap 
56             SelectObject(hTextDC, hOldBMP); 
57         } 
58     } 
59 
60     // De-select font and destroy temp DC 
61     SelectObject(hTextDC, hOldFont); 
62     DeleteDC(hTextDC); 
63 
64     // Return DIBSection 
65     return hMyDIB; 
66 }

 

Here is the code that drives the CreateAlphaTextBitmap method:

 1 { 
 2     const char *DemoText = "Hello World!\0"; 
 3     RECT TextArea = {0, 0, 0, 0}; 
 4     HFONT TempFont = CreateFont(50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial\0"); 
 5     HBITMAP MyBMP = CreateAlphaTextBitmap(DemoText, TempFont, 0xFF); 
 6     DeleteObject(TempFont); 
 7     if (MyBMP)
 8     {
 9         // Create temporary DC and select new Bitmap into it 
10         HDC hTempDC = CreateCompatibleDC(inDC); 
11         HBITMAP hOldBMP = (HBITMAP)SelectObject(hTempDC, MyBMP); 
12         if (hOldBMP)
13         {
14             // Get Bitmap image size
15             BITMAP BMInf;
16             GetObject(MyBMP, sizeof(BITMAP), &BMInf); 
17 
18             // Fill blend function and blend new text to window 
19             BLENDFUNCTION bf; 
20             bf.BlendOp = AC_SRC_OVER; 
21             bf.BlendFlags = 0; 
22             bf.SourceConstantAlpha = 0x80; 
23             bf.AlphaFormat = AC_SRC_ALPHA; 
24             AlphaBlend(inDC, inX, inY, BMInf.bmWidth, BMInf.bmHeight, hTempDC, 0, 0, BMInf.bmWidth, BMInf.bmHeight, bf); 
25 
26             // Clean up 
27             SelectObject(hTempDC, hOldBMP); 
28             DeleteObject(MyBMP); 
29             DeleteDC(hTempDC); 
30         } 
31     } 
32 } 

 

还未测试~先放这儿

posted on 2014-03-25 11:59  紫夜,风凌  阅读(2038)  评论(0编辑  收藏  举报

导航