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

最佳答案

我知道这是一个老帖子...但是我也遇到了同样的问题...这让我发疯了。

最终,我偶然发现了Mike Sutton的post到将近7年前的microsoft.public.win32.programmer.gdi新闻组!

基本上,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);
        }
    }
}

07-24 09:37
查看更多