GDI +字体渲染,尤其是在分层窗口中

时间:2011-04-13 09:53:17

标签: c++ fonts gdi+ rendering

这对我的朋友来说,是一个很长的...

当我尝试在分层窗口中渲染文本时,我得到了一些非常奇怪的行为。

奇怪的是,对于某些字体/字体样式/字体大小的组合,GDI +会更改渲染方法。对于Tahoma-Bold字体 8.49和16.49(像素单位)之间的,包括“失败”。对于其他字体和样式,我会以不同的尺寸“失败”。

output from code below

为了清楚起见,我已经提供了一个完整的可执行示例。要使用的两个关键参数在第23行:

Color g_oTextColor( 255, 240, 0, 0 ); // Simply change Color to ( 254, 240, 0, 0 ) [to add slight transparency] and everything will work!
#define USE_LAYERED_WINDOW // or just comment this line out [to use a regular window], and everything will work!

当使用分层窗口和完全不透明度时,字体在背景中绘制一个透明的“洞”。但是,如果我为文本颜色添加轻微的透明度(alpha-channel = 254),则字体会变得不透明。或者,如果我使用常规(非分层)窗口,则字体呈现不透明。 这里发生了什么?

但即使没有分层/透明问题,很明显这里发生了一些奇怪的事情。字体大小为8.49 - 16.48,渲染像素完美,其他字体质量模糊,特别是小字体。因此,系统似乎采用不同的方法来渲染这些中等大小。 有人可以对此有所了解,我怎么可能渲染字体大小为8.0像素而没有上面的模糊?我已经尝试了SetTextRenderingHint()SetTextContrast()的各种设置但是对于8号字体来说,没有一个看起来很清脆。我试过了Tahoma&只有Arial ......


问题1: 我想使用纯GDI +进行离屏绘图,但我无法通过简单地创建Bitmap& Graphics个对象。我仍然不得不使用旧的GDI东西来创建DC并选择HBitmap。我怎样才能在GDI +中完成所有工作?

问题2(仅限极客): 我也尝试在古老的GDI中绘制字体,但是我得到了一些更奇怪的效果:(1)在分层窗口中,文本变得透明,但是在添加剂中方式。 (所以如果背后的窗户是黑暗的,那么红色的文字看起来会很好但是如果背后的窗户是白色的,那么文字完全消失了!)此外,如果我用半透明的方形填充我自己的窗户,那么表现就像预期的那样。 (如果背后的窗口是黑色的话,红色正方形会变成深红色,并且正方形会在白色窗口上变成浅红色)。我可以在一个分层窗口中同时观察这两种行为。并且(2)作为一个非常不受欢迎的奖励,所绘制的文字失去了它的命中测试并变得无法点击? 有任何解释吗?

如果您已经阅读了这篇文章,感谢您的持久,感谢您的回答!

// Create as a console application project
// + Unicode charset
// + Precompiled headers off
// + make sure to add linker input: gdiplus.lib

#ifndef _WIN32_WINNT        // Allow use of features specific to Windows XP or later.                   
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif                      

// Standard and GDI+ stuffstuff 
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <iostream>
#include <cassert>
#include <Gdiplus.h>
using namespace Gdiplus;
GdiplusStartupInput g_oGdiPlusStartupInput;
ULONG_PTR g_pGdiPlusToken = NULL;


// #*#*#*#*#*#*#*#*# LINES TO CHANGE ---------->---------->---------->
Color g_oTextColor( 255, 240, 0, 0 ); // Simply change Color to ( 254, 240, 0, 0 ) [to add slight transparency] and everything will work!
#define USE_LAYERED_WINDOW // or just comment this line out [to use a regular window], and everything will work!


// Forward declarations
void RegWndClass();
LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam );
void CreateWindows();
void Draw();
void MsgLoop();

// Other Globals
ATOM g_iWndClass = 0;
HWND g_hWndGdiPlus = NULL;
HWND g_hWndGdi = NULL;
const wchar_t* g_pWndClass = L"TST";
int g_iWidth = 200;
int g_iHeight = 200;

// Main entry-point
int _tmain( int argc, _TCHAR* argv[] )
{
    GdiplusStartup( &g_pGdiPlusToken, &g_oGdiPlusStartupInput, NULL );

    RegWndClass();
    CreateWindows();
    Draw();

    MsgLoop();

    ::UnregisterClass( g_pWndClass, NULL );
    ::Sleep( 500 );


    GdiplusShutdown( g_pGdiPlusToken );

    return 0;
} // _tmain

void CreateWindows()
{
#ifdef USE_LAYERED_WINDOW
        // The key trick is to create a window with style WS_EX_LAYERED, but WITHOUT any subsequent calls to SetLayeredWindowAttributes()
        // This gives us a magic window that must be updated with UpdateLayeredWindow() ( and it does NOT recieve any WM_PAINT messages )
        // as brilliantly described in: http://alexkr.com/source-code/50/layered-windows-and-updatelayeredwindow/
        g_hWndGdiPlus = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL ); 
#else
        g_hWndGdiPlus = ::CreateWindowEx( 0, g_pWndClass, L"", WS_OVERLAPPEDWINDOW | WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL ); 
#endif

    //g_hWndGdi = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 720, 500, 200, 200, NULL, NULL, NULL, NULL ); 

} // CreateWindows

void Draw()
{
    // Init GDI+ surface
    HDC hOff = ::CreateCompatibleDC( NULL );
    Bitmap oDaBigOne( g_iWidth, g_iHeight, PixelFormat32bppARGB );
    HBITMAP hBMit =  NULL;
    Color oCol( 0, 0, 0, 0 );
    oDaBigOne.GetHBITMAP( oCol, &hBMit );
    HGDIOBJ hSave = ::SelectObject( hOff, hBMit );

#ifdef USE_LAYERED_WINDOW
        Graphics oGraph( hOff );
#else
        Graphics oGraph( g_hWndGdiPlus );
#endif

    oGraph.Clear( Color( 255, 55, 155, 255 ) );

    // Draw text
    oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );
    oGraph.SetTextContrast( 0xffffffff );
    oGraph.SetCompositingMode( CompositingModeSourceOver );
    oGraph.SetCompositingQuality( CompositingQualityHighQuality );
    oGraph.SetPixelOffsetMode( PixelOffsetModeHighQuality );

    const FontFamily oFamily( L"Tahoma", NULL );

#if 1 // Use bold
    Font oF600( &oFamily, 6.00, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF800( &oFamily, 8.00, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF848( &oFamily, 8.48, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF849( &oFamily, 8.49, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1200( &oFamily, 12.00, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1500( &oFamily, 15.00, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1648( &oFamily, 16.48, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1649( &oFamily, 16.49, FontStyle::FontStyleBold, Unit::UnitPixel );
#else // Use regular
    Font oF600( &oFamily, 6.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF800( &oFamily, 8.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF848( &oFamily, 8.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF849( &oFamily, 8.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1200( &oFamily, 12.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1500( &oFamily, 15.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1648( &oFamily, 16.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1649( &oFamily, 16.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
#endif

    assert( oF600.GetLastStatus() == Ok ); // Make sure font is OK

    SolidBrush oBrush( g_oTextColor ); 

    double dy = 1.0;
    oGraph.DrawString( L"Size 6.00", -1, &oF600, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 8.00", -1, &oF800, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 8.48", -1, &oF848, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 8.49", -1, &oF849, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 12.00", -1, &oF1200, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 15.00", -1, &oF1500, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 16.48", -1, &oF1648, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 16.49", -1, &oF1649, PointF( 30.0, dy += 18.0 ), &oBrush );

#ifndef USE_LAYERED_WINDOW
    return;
#endif

    // Do da layered window magic stuff
    BLENDFUNCTION oBF = { 0 };
    oBF.BlendOp = AC_SRC_OVER;
    oBF.BlendFlags = 0;
    oBF.SourceConstantAlpha = 255;
    oBF.AlphaFormat = AC_SRC_ALPHA;

    SIZE oSize = { 0 };
    oSize.cx = g_iWidth;
    oSize.cy = g_iHeight;

    POINT oPTZero = { 0 };

    RECT oRect = { 0 };
    ::GetWindowRect( g_hWndGdiPlus, &oRect );

    POINT oPTWnd = { 0 };

    oPTWnd.x = oRect.left;
    oPTWnd.y = oRect.top;

    //HDC hDC = oGraph.GetHDC();
    BOOL bOK = ::UpdateLayeredWindow( g_hWndGdiPlus,
        NULL, //HDC hdcDst,
        &oPTWnd, // POINT &oPtNull,
        &oSize, // SIZE *psize,
        hOff, // HDC hdcSrc,
        &oPTZero, // POINT *pptSrc,
        RGB(255,255,255), // COLORREF crKey,
        &oBF, // BLENDFUNCTION *pblend,
        ULW_ALPHA // DWORD dwFlags
    );
} // Draw

void MsgLoop()
{
    ::SetTimer( g_hWndGdiPlus, 0, 19999, NULL ); // Self-destruct timer

    MSG msg = { 0 };
    while ( ::GetMessage( &msg, NULL, 0, 0 ) )
    {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
    }
} // MsgLoop

void RegWndClass()
{

        WNDCLASSEX wcex = { 0 };

        wcex.cbSize          = sizeof(WNDCLASSEX);
        wcex.style           = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
        wcex.lpfnWndProc     = WndProc;
        wcex.cbClsExtra      = 0;
        wcex.cbWndExtra      = 8; // 8 bytes, to allow for 64-bit architecture
        wcex.hInstance       = NULL; // CHECK
        wcex.hIcon           = NULL;
        wcex.hCursor         = ::LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground   = (HBRUSH)NULL_BRUSH; // CHECK
        wcex.lpszMenuName    = NULL;
        wcex.lpszClassName   = g_pWndClass;
        wcex.hIconSm         = NULL;

        g_iWndClass = ::RegisterClassEx(&wcex);
} // RegWndClass

LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
{
    switch( uiMsg )
    {
        case WM_TIMER:
        {
            std::wstring s;
            std::wcout <<  L"Let´s quit" ;
            ::PostQuitMessage( 0 );
            return 0;
        }
        case WM_PAINT:
            Draw();
            break;

        default:
        {
            return DefWindowProc( hWnd, uiMsg, wParam, lParam );
        }
    }
    return DefWindowProc( hWnd, uiMsg, wParam, lParam );
} // WndProc

[编辑]问题解决了! 根据{{​​3}}出色的建议,下面的代码。 感谢他和他的巨大感谢。我真的很感激。

所有修改都标有//#MOD

// Create as a console application project
// + Unicode charset
// + Precompiled headers off
// + make sure to add linker input: gdiplus.lib

#ifndef _WIN32_WINNT        // Allow use of features specific to Windows XP or later.                   
#define _WIN32_WINNT 0x0501 // Change this to the appropriate value to target other versions of Windows.
#endif                      

// Standard stuff
#include <stdio.h>
#include <tchar.h>
#include <windows.h>
#include <iostream>
#include <cassert>

// GDI+ stuff
#include <Gdiplus.h>
using namespace Gdiplus;
GdiplusStartupInput g_oGdiPlusStartupInput;
ULONG_PTR g_pGdiPlusToken = NULL;




// #*#*#*#*#*#*#*#*# LINES TO CHANGE ---------->---------->---------->
Color g_oTextColor( 255, 240, 0, 0 ); // Simply change Color to ( 254, 240, 0, 0 ) [to add slight transparency] and everything will work!
#define USE_LAYERED_WINDOW // or just omment this line [to use a regular window], and everything will work!






// Forward declarations
void RegWndClass();
LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam );
void CreateWindows();
void Draw();
void MsgLoop();

// Other Globals
ATOM g_iWndClass = 0;
HWND g_hWndGdiPlus = NULL;
HWND g_hWndGdi = NULL;
const wchar_t* g_pWndClass = L"TST";
int g_iWidth = 200;
int g_iHeight = 200;

// Main entry-point
int _tmain( int argc, _TCHAR* argv[] )
{
    GdiplusStartup( &g_pGdiPlusToken, &g_oGdiPlusStartupInput, NULL );

    RegWndClass();
    CreateWindows();
    Draw();

    MsgLoop();

    ::UnregisterClass( g_pWndClass, NULL );
    ::Sleep( 500 );


    GdiplusShutdown( g_pGdiPlusToken );

    return 0;
} // _tmain

void CreateWindows()
{
#ifdef USE_LAYERED_WINDOW
        // The key trick is to create a window with style WS_EX_LAYERED, but WITHOUT any subsequent calls to SetLayeredWindowAttributes()
        // This gives us a magic window that must be updated with UpdateLayeredWindow() ( and it does NOT recieve any WM_PAINT messages )
        // as brilliantly described in: http://alexkr.com/source-code/50/layered-windows-and-updatelayeredwindow/
        g_hWndGdiPlus = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL ); 
#else
        g_hWndGdiPlus = ::CreateWindowEx( 0, g_pWndClass, L"", WS_OVERLAPPEDWINDOW | WS_POPUP | WS_VISIBLE, 1000, 200, g_iWidth, g_iHeight, NULL, NULL, NULL, NULL ); 
#endif

    //g_hWndGdi = ::CreateWindowEx( WS_EX_LAYERED, g_pWndClass, L"", WS_POPUP | WS_VISIBLE, 720, 500, 200, 200, NULL, NULL, NULL, NULL ); 

} // CreateWindows

void Draw()
{
    // Init GDI+ surface
    HDC hOff = ::CreateCompatibleDC( NULL );
    Bitmap oDaBigOne( g_iWidth, g_iHeight, PixelFormat32bppARGB );
    HBITMAP hBMit =  NULL;
    Color oCol( 0, 0, 0, 0 );
    // oDaBigOne.GetHBITMAP( oCol, &hBMit ); //#MOD
    // HGDIOBJ hSave = ::SelectObject( hOff, hBMit ); //#MOD


    { // Limit oGraph scope //#MOD
#ifdef USE_LAYERED_WINDOW
        //Graphics oGraph( hOff ); //#MOD
        Graphics oGraph( &oDaBigOne ); //#MOD
#else
        Graphics oGraph( g_hWndGdiPlus );
#endif

    oGraph.Clear( Color( 255, 55, 155, 255 ) );

    // Draw text
    oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );
    oGraph.SetCompositingMode( CompositingModeSourceOver );
    oGraph.SetCompositingQuality( CompositingQualityHighQuality );
    oGraph.SetPixelOffsetMode( PixelOffsetModeHighQuality );

    const FontFamily oFamily( L"Tahoma", NULL );

#if 1 // Use bold
    Font oF600( &oFamily, 6.00, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF848( &oFamily, 8.48, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF849( &oFamily, 8.49, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1200( &oFamily, 12.00, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1500( &oFamily, 15.00, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1648( &oFamily, 16.48, FontStyle::FontStyleBold, Unit::UnitPixel );
    Font oF1649( &oFamily, 16.49, FontStyle::FontStyleBold, Unit::UnitPixel );
#else // Use regular
    Font oF600( &oFamily, 6.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF848( &oFamily, 8.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF849( &oFamily, 8.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1200( &oFamily, 12.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1500( &oFamily, 15.00, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1648( &oFamily, 16.48, FontStyle::FontStyleRegular, Unit::UnitPixel );
    Font oF1649( &oFamily, 16.49, FontStyle::FontStyleRegular, Unit::UnitPixel );
#endif

    assert( oF600.GetLastStatus() == Ok ); // Make sure font is OK

    SolidBrush oBrush( g_oTextColor ); 

    double dy = 10.0;
    oGraph.DrawString( L"Size 6.00", -1, &oF600, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 8.48", -1, &oF848, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 8.49", -1, &oF849, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 12.00", -1, &oF1200, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 15.00", -1, &oF1500, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 16.48", -1, &oF1648, PointF( 30.0, dy += 18.0 ), &oBrush );
    oGraph.DrawString( L"Size 16.49", -1, &oF1649, PointF( 30.0, dy += 18.0 ), &oBrush );

#ifndef USE_LAYERED_WINDOW
    return;
#endif
    } // Limit oGraph scope //#MOD

    // Do da layered window magic stuff
    BLENDFUNCTION oBF = { 0 };
    oBF.BlendOp = AC_SRC_OVER;
    oBF.BlendFlags = 0;
    oBF.SourceConstantAlpha = 255;
    oBF.AlphaFormat = AC_SRC_ALPHA;

    SIZE oSize = { 0 };
    oSize.cx = g_iWidth;
    oSize.cy = g_iHeight;

    POINT oPTZero = { 0 };

    RECT oRect = { 0 };
    ::GetWindowRect( g_hWndGdiPlus, &oRect );

    POINT oPTWnd = { 0 };

    oPTWnd.x = oRect.left;
    oPTWnd.y = oRect.top;

    oDaBigOne.GetHBITMAP( oCol, &hBMit ); //#MOD
    HGDIOBJ hSave = ::SelectObject( hOff, hBMit ); //#MOD

    //HDC hDC = oGraph.GetHDC();
    BOOL bOK = ::UpdateLayeredWindow( g_hWndGdiPlus,
        NULL, //HDC hdcDst,
        &oPTWnd, // POINT &oPtNull,
        &oSize, // SIZE *psize,
        hOff, // HDC hdcSrc,
        &oPTZero, // POINT *pptSrc,
        RGB(255,255,255), // COLORREF crKey,
        &oBF, // BLENDFUNCTION *pblend,
        ULW_ALPHA // DWORD dwFlags
    );
} // Draw

void MsgLoop()
{
    ::SetTimer( g_hWndGdiPlus, 0, 19999, NULL ); // Self-destruct timer

    MSG msg = { 0 };
    while ( ::GetMessage( &msg, NULL, 0, 0 ) )
    {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
    }
} // MsgLoop

void RegWndClass()
{

        WNDCLASSEX wcex = { 0 };

        wcex.cbSize          = sizeof(WNDCLASSEX);
        wcex.style           = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
        wcex.lpfnWndProc     = WndProc;
        wcex.cbClsExtra      = 0;
        wcex.cbWndExtra      = 8; // 8 bytes, to allow for 64-bit architecture
        wcex.hInstance       = NULL; // CHECK
        wcex.hIcon           = NULL;
        wcex.hCursor         = ::LoadCursor(NULL, IDC_ARROW);
        wcex.hbrBackground   = (HBRUSH)NULL_BRUSH; // CHECK
        wcex.lpszMenuName    = NULL;
        wcex.lpszClassName   = g_pWndClass;
        wcex.hIconSm         = NULL;

        g_iWndClass = ::RegisterClassEx(&wcex);
} // RegWndClass

LRESULT CALLBACK WndProc( HWND hWnd, UINT uiMsg, WPARAM wParam, LPARAM lParam )
{
    switch( uiMsg )
    {
        case WM_TIMER:
        {
            std::wstring s;
            std::wcout <<  L"Let´s quit" ;
            ::PostQuitMessage( 0 );
            return 0;
        }
        case WM_PAINT:
            Draw();
            break;

        default:
        {
            return DefWindowProc( hWnd, uiMsg, wParam, lParam );
        }
    }
    return DefWindowProc( hWnd, uiMsg, wParam, lParam );
} // WndProc

4 个答案:

答案 0 :(得分:6)

我认为问题在于GDI(没有+)不能很好地支持alpha透明度。充其量,它保持alpha通道不受影响。

当您使用具有Alpha通道的选定位图的HDC构建Graphics对象时......事情变得非常糟糕。我的猜测是GDI +字体栅格化决定了基于大量参数使用哪种方法进行渲染;然后,如果GDI支持这种方法,它将被使用(并忽略alpha通道);如果GDI不支持渲染方法,它将回退到逐像素渲染或类似渲染,并且alpha通道将被正确使用。

因此,要获得正确的结果,您不应使用HDC修改Alpha通道。请尝试以下更改:

  • 使用位图创建Graphics对象,而不是HDC:

    Graphics oGraph( &oDaBigOne );
    
  • 仅在完成渲染后才将位图选择到HDC hOff中。为了确保Graphics对象被销毁更好,用{...}限制其范围。

<强> [编辑]

在新代码之后,解决方案很简单:不仅应该在绘图之后将调用移动到SelectObject(),还要调用GetBitmap()。也就是说,这两个函数应该在调用之前:UpdateLayeredWindow():

oDaBigOne.GetHBITMAP( oCol, &hBMit );
HGDIOBJ hSave = ::SelectObject( hOff, hBMit );

答案 1 :(得分:2)

我认为,昨天我找到了一个(部分)解决方案,这可能比rodrigo建议的更容易实现:你可以简单地在{{StringFormatFlags::StringFormatFlagsBypassGDI中指定StringFormat作为格式标志1}} - 你传递给DrawString的实例,瞧:一切都是使用支持alpha的字体渲染器绘制的。这解决了alpha通道问题,至少......

答案 2 :(得分:1)

我暂时无法找到对这种奇怪行为的解释。但是,我确实发现使用默认渲染值可以使用某些字体获得更好的结果,请尝试使用以下设置进行Arial:

oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );
oGraph.SetPixelOffsetMode( PixelOffsetModeDefault );
oGraph.SetCompositingMode( CompositingModeSourceOver );
oGraph.SetCompositingQuality( CompositingQualityDefault );

答案 3 :(得分:0)

尝试将PixelFormat32bppARGB替换为PixelFormat32bppPARGBBLENDFUNCTION结构的文档声明它需要在源中预乘alpha。