GDI + Рендеринг шрифтов, особенно в многослойных окнах - PullRequest
8 голосов
/ 13 апреля 2011

Это мои друзья, это будет долго ...

Я получаю довольно странное поведение, когда пытаюсь сделать текст в многослойном окне.

Странная вещьзаключается в том, что для некоторых комбинаций font / font-style / font-size 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!

При использовании многослойных окон и полной непрозрачности шрифты рисуют прозрачную «дыру» на фоне.Однако, если я добавлю небольшую прозрачность к цвету текста (альфа-канал = 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

[ПРАВИТЬ]Задача решена!Код ниже в соответствии с Родрого отличные предложения.Слава и огромное количество спасибо ему.Я очень благодарен.

Все изменения помечены как // # 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 ]

6 голосов
/ 08 августа 2011

Я думаю, что проблема в том, что GDI (без +) не очень хорошо поддерживает альфа-прозрачность. В лучшем случае альфа-канал остается без изменений.

Когда вы создаете графический объект с использованием HDC с выбранным растровым изображением, имеющим альфа-канал ... ну, все плохо смешивается. Я предполагаю, что растеризованный шрифт GDI + решает, какой метод использовать для рендеринга, основываясь на большом количестве параметров; затем, если этот метод поддерживается в GDI, он будет использоваться (и альфа-канал игнорируется); если метод рендеринга не поддерживается в GDI, он откатится к попиксельному рендерингу или подобному, и альфа-канал будет использоваться правильно.

Таким образом, для получения правильных результатов не следует использовать HDC для изменения альфа-канала. Попробуйте следующие изменения:

  • Используйте растровое изображение для создания графического объекта, а не HDC:

    Graphics oGraph( &oDaBigOne );
    
  • Выберите растровое изображение в HDC hOff только после завершения рендеринга. Конечно, лучше, чтобы объект Graphics был уничтожен, ограничивая его область действия {...}.

[EDIT]

После нового кода решение легко: не только вы должны переместить вызов SelectObject () после рисования, но и GetBitmap (). То есть эти две функции должны быть непосредственно перед вызовом: UpdateLayeredWindow ():

oDaBigOne.GetHBITMAP( oCol, &hBMit );
HGDIOBJ hSave = ::SelectObject( hOff, hBMit );
2 голосов
/ 26 октября 2011

Я думаю, я нашел (частичное) решение этого вчера, которое может быть более простым для реализации, чем предложенное Rodrigo: Вы можете просто указать StringFormatFlags::StringFormatFlagsBypassGDI как флаг формата в пределах StringFormat -Например, вы передаете DrawString и вуаля: все рисуется с помощью альфа-способного рендерера шрифтов.Это решает проблему альфа-канала, по крайней мере ...

1 голос
/ 02 августа 2011

Я некоторое время не мог найти объяснения этому странному поведению.Однако я обнаружил, что использование значений рендеринга по умолчанию дает гораздо лучшие результаты с некоторыми шрифтами, попробуйте Arial со следующими настройками:

oGraph.SetTextRenderingHint( TextRenderingHintAntiAliasGridFit );
oGraph.SetPixelOffsetMode( PixelOffsetModeDefault );
oGraph.SetCompositingMode( CompositingModeSourceOver );
oGraph.SetCompositingQuality( CompositingQualityDefault );
0 голосов
/ 30 июля 2011

Попробуйте заменить PixelFormat32bppARGB на PixelFormat32bppPARGB.Документация для структуры BLENDFUNCTION гласит, что для нее требуется предварительно умноженная альфа в источнике.

...