【问题标题】:UpdateLayeredWindow and DrawTextUpdateLayeredWindow 和 DrawText
【发布时间】:2011-07-15 15:49:29
【问题描述】:

我正在使用 UpdateLayeredWindow 来显示应用程序窗口。我创建了自己的自定义按钮,并且想创建自己的静态文本。问题是当我尝试在 hdc 上绘制文本时,DrawText 或 TextOut 函数会覆盖我图片的 alpha 通道,并且文本将变得透明。我试图找到解决方案,但我找不到任何解决方案。我的自定义控件的设计方式是它们将在名为 Draw(HDC hDc) 的成员函数中完成所有绘图,因此它们只能访问 hdc。我想保留这个设计。谁能帮我?我正在使用 MFC,我希望在不使用 GDI+ 的情况下达到预期的效果。

【问题讨论】:

    标签: winapi mfc


    【解决方案1】:

    我知道这是一篇旧帖子……但我也遇到了同样的问题……这让我发疯了。

    最终,我偶然发现了 Mike Sutton 在 microsoft.public.win32.programmer.gdi 新闻组中发布的 post ......来自大约 7 年前!

    基本上,DrawText(和 TextOut)不能很好地与 Alpha 通道和 UpdateLayeredWindow 配合使用......并且您需要将 R、G 和 B 通道与 Alpha 通道预乘

    在 Mike 的帖子中,他展示了如何创建另一个 DIB(与设备无关的位图),在该位图上绘制文本……然后 alpha 将其混合到另一个位图中。

    完成此操作后,我的文字看起来很完美!

    以防万一,新闻组帖子的链接失效了……我将在此处包含代码。所有功劳归功于 Mike Sutton (@mikedsutton)。

    这是创建带有文本的 alpha 混合位图的代码:

    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; 
    }
    

    下面是驱动 CreateAlphaTextBitmap 方法的代码:

    void TestAlphaText(HDC inDC, int inX, int inY)
    { 
        const char *DemoText = "Hello World!\0"; 
        RECT TextArea = {0, 0, 0, 0}; 
        HFONT TempFont = CreateFont(50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, "Arial\0"); 
        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); 
            } 
        } 
    } 
    

    【讨论】:

    • +1 很高兴知道这个解决方案。我认为之前在分层窗口中使用 gdi drawtext 是不可能的。
    • 让它使用 COLORREF white = 0x00FFFFFF; COLORREF 黑色 = 0x00000000;自动 x = ::SetTextColor(hTextDC, 白色);自动 y = ::SetBkColor(hTextDC, 黑色);还使用了 CString intext {inText} (GetLength) 而不是 LPCSTR,非常感谢
    猜你喜欢
    • 1970-01-01
    • 2013-11-03
    • 1970-01-01
    • 2011-12-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多