2011-04-13 24 views
8

Esto mis amigos, es una va a ser larga ...GDI + de representación de fuentes, especialmente en ventanas superpuestas

estoy recibiendo un comportamiento bastante extraño cuando trato de representar el texto en una ventana de capas.

Lo extraño es que para algunas combinaciones de fuente/fuente-estilo/tamaño de fuente, GDI + cambia el método de representación. Para tamaños de fuente Tahoma-Bold entre 8.49 y 16.49 (Unidades de píxeles) inclusive "falla". Para otras fuentes y estilos me sale "falla" en diferentes tamaños.

output from code below

Para mayor claridad que he proporcionado un ejemplo ejecutable completa más abajo. Los dos parámetros clave para jugar están en la línea 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! 

Al utilizar ventanas superpuestas y opacidad completa las fuentes dibujar una transparente "agujero" en el fondo. Sin embargo, si agrego una ligera transparencia al color del texto (canal alfa = 254) las fuentes se vuelven opacas. O si uso ventanas regulares (sin capas) las fuentes se vuelven opacas. ¿Qué está pasando aquí?

Pero incluso sin los problemas de capas/transparencia, está claro que algo extraño está sucediendo aquí. Las fuentes tamaño 8.49 - 16.48 se convierten en píxeles perfectos, las otras fuentes tienen una ligera calidad borrosa, especialmente las pequeñas. Por lo tanto, parece que el sistema adopta un enfoque diferente para representar estos tamaños medios. ¿Alguien puede arrojar algo de luz sobre esto, cómo puedo renderizar, por ejemplo, fuentes de tamaño 8.0 píxeles sin la imagen borrosa arriba? que han intentado todo tipo de ajustes para SetTextRenderingHint() y SetTextContrast() pero ninguno parecía nítido para las fuentes de tamaño 8. He intentado Tahoma & Arial única ...


pregunta Lado 1: que quería utilizar GDI puro para el dibujo fuera de la pantalla pero no pude hacer que funcione simplemente creando Bitmap & Graphics objetos. Todavía tenía que usar material antiguo de GDI para crear un DC y seleccionar HBitmap en él. ¿Cómo puedo hacer todo en GDI +?

pregunta Lado 2 (sólo Geeks): También trataron de sacar las fuentes de buena de edad GDI pero no me dieron algunos efectos aún más extrañas: (1) En una ventana por capas el texto se volvió transparente pero en un aditivo manera. (Así que un texto rojo se vería bien si la ventana detrás estuviera oscura, pero si la ventana detrás de ella estaba con el texto desaparecido por completo!) Además, si llené mi propia ventana con un cuadrado semitransparente, entonces eso se comportaría como se esperaba. (Un cuadrado rojo se volvería rojo oscuro si la ventana detrás de él fuera negra, y el cuadrado se volvería de color rojo claro sobre una ventana blanca). Y puedo observar estos dos comportamientos simultáneamente en una ventana en capas. Y (2) como una bonificación altamente indeseable, el texto dibujado perdió su prueba de aciertos y se hizo inactivo? ¿Alguna explicación por ahí?

Y si ha leído hasta aquí, gracias por perdurar, y gracias por cualquier respuesta!

// 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 

[EDIT] Problema resuelto! Código de acuerdo a Rodrogo´s excelentes sugerencias. Felicitaciones y una inmensa cantidad de gracias a él. Estoy realmente agradecido

Todas las ediciones están marcados con // # 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 

Respuesta

6

creo que el problema es que GDI (sin el +) no admite la transparencia alfa muy bien. En el mejor de los casos, mantiene intacto el canal alfa.

Cuando construyes un objeto Graphics usando un HDC con un mapa de bits seleccionado que tiene un canal alfa ... bueno, las cosas se mezclan mal. Supongo que la fuente GDI + rasterizada decide qué método utilizar para representar en función de muchos parámetros; luego, si este método es compatible con GDI, se usará (y se ignorará el canal alfa); si el método de renderizado no es compatible con GDI, retrocederá a un procesamiento de píxel por píxel, o similar, y el canal alfa se usará correctamente.

Por lo tanto, para obtener los resultados correctos, no debe usar el HDC para modificar el canal alfa. Pruebe los siguientes cambios:

  • Utilice el mapa de bits para crear los gráficos de objeto, no el HDC:

    Graphics oGraph(&oDaBigOne); 
    
  • Seleccione el mapa de bits en el HDC Hoff sólo después de que el render se ha hecho. Para estar seguro, es mejor que el objeto Graphics se destruya, limitando su alcance con {...}.

[EDIT]

Después de que el nuevo código, la solución es fácil: no sólo hay que mover la llamada a SelectObject() después del sorteo, también la GetBitmap(). Es decir, estas dos funciones shoul ser justo antes de la llamada a: UpdateLayeredWindow():

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

THX! Suena interesante. Me temo que no puedo probar esto esta semana, pero lo haré más tarde. Y publicar comentarios. Aclamaciones. – Adam

+0

Rodrigo, en realidad encontré un poco de tiempo para probar esto. Lo siento, no hay cigarro ...Si no tengo DC seleccionado, las operaciones de GDI + mostrarán: nada. (De hecho, me di cuenta, había intentado esto, hace mucho tiempo, como está implícito en la "pregunta lateral n. ° 1" anterior). Así que todavía tengo el problema de que la representación de GDI + va mal para algunos tamaños de fuente de Tahoma. Lo que queda por probar es un enfoque puro de GDI como se describe en algunas respuestas en: http://www.gamedev.net/topic/333453-32-bit-alpha-bitmaps-and-gdi-fun-alert/ – Adam

+0

Curious, pero lo intenté y funcionó para mí. ¿Podría publicar el código con este método? O si lo prefieres, podría publicar el mío ;-) – rodrigo

0

Trate de reemplazar con PixelFormat32bppARGBPixelFormat32bppPARGB. La documentación para la estructura BLENDFUNCTION indica que requiere alfa premultiplicada en la fuente.

+0

Bueno, gracias, pero ya lo intenté. Sin suerte allí, por desgracia. – Adam

1

No he podido encontrar explicaciones para este extraño comportamiento desde hace un tiempo. Sin embargo, he encontrado que el uso de valores de representación por omisión da resultados mucho mejores con algunas fuentes, tratan Arial con los siguientes valores:

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

creo, he encontrado una solución (parcial) a esto ayer, que podría ser más fácil de implementar, a la que sugerido por rodrigo: Simplemente puede especificar StringFormatFlags::StringFormatFlagsBypassGDI como indicador de formato dentro de StringFormat -instancia que pasa al DrawString, y listo: todo se dibuja usando el renderizador de fuentes compatible con alfa. Esto soluciona el problema del canal alfa, al menos ...

Cuestiones relacionadas