2008-12-02 19 views
7

Cuando creo un nuevo Gdiplus :: Bitmap utilizando la función Bitmap :: FromHBITMAP, , el mapa de bits resultante es opaco, no se conserva ninguna de las transparencias parciales del HBITMAP original.Cómo crear un Gdiplus :: Bitmap desde un HBITMAP, conservando la información del canal alfa?

¿Hay alguna manera de crear un Gdiplus :: Bitmap desde un HBITMAP que atraviese los datos del canal alfa?

+0

¿Sabe usted para asegurarse de que el HBITMAP tiene un canal alfa para empezar? Por ejemplo, ¿lo creó como un DIB con BI_RGB y 32bpp o de alguna otra manera? –

+0

Sí, tiene transparencia. Dibuja muy bien usando la función :: AlphaBlend(). – mackenir

+0

(Lo creé en C# usando un nuevo mapa de bits (cadena de nombre de archivo) y llamando a GetHBitmap() en el objeto de mapa de bits .NET) – mackenir

Respuesta

4

Resulta que GDI + nunca trae el canal alfa cuando se crea un mapa de bits a partir de un HBITMAP.

La respuesta es:

  • Uso GetObject que pasa en un mapa de bits y la HBITMAP, para obtener el ancho y la altura (y si el mapa de bits de entrada es un DIB, los datos de píxeles) de la HBITMAP de entrada.
  • Cree un mapa de bits del tamaño correcto con el formato de 32 bits PARGB de píxeles.
  • Utilice LockBits para obtener la memoria pixelData de su nuevo mapa de bits.
  • Si obtuvo los píxeles de GetObject, copie los valores ARGB a través del uso de memcpy.
  • Llamar UnlockBits en el nuevo mapa de bits.

En mi caso, el formato de la entrada HBITMAP es correcto para hacer una memcpy directamente de datos de píxeles de mapa de bits de entrada a los nuevos datos de píxeles de mapa de bits.

Si no obtuvo los datos de entrada de píxeles de GetObject, use GetDIBits para obtener una copia en el formato correcto. código

9

Creo que trabajar es más útil que las instrucciones, así que:

#include <GdiPlus.h> 
#include <memory> 

Gdiplus::Status HBitmapToBitmap(HBITMAP source, Gdiplus::PixelFormat pixel_format, Gdiplus::Bitmap** result_out) 
{ 
    BITMAP source_info = { 0 }; 
    if(!::GetObject(source, sizeof(source_info), &source_info)) 
    return Gdiplus::GenericError; 

    Gdiplus::Status s; 

    std::auto_ptr<Gdiplus::Bitmap> target(new Gdiplus::Bitmap(source_info.bmWidth, source_info.bmHeight, pixel_format)); 
    if(!target.get()) 
    return Gdiplus::OutOfMemory; 
    if((s = target->GetLastStatus()) != Gdiplus::Ok) 
    return s; 

    Gdiplus::BitmapData target_info; 
    Gdiplus::Rect rect(0, 0, source_info.bmWidth, source_info.bmHeight); 

    s = target->LockBits(&rect, Gdiplus::ImageLockModeWrite, pixel_format, &target_info); 
    if(s != Gdiplus::Ok) 
    return s; 

    if(target_info.Stride != source_info.bmWidthBytes) 
    return Gdiplus::InvalidParameter; // pixel_format is wrong! 

    CopyMemory(target_info.Scan0, source_info.bmBits, source_info.bmWidthBytes * source_info.bmHeight); 

    s = target->UnlockBits(&target_info); 
    if(s != Gdiplus::Ok) 
    return s; 

    *result_out = target.release(); 

    return Gdiplus::Ok; 
} 
+0

Tuve un problema similar con un 'CBitmap', del cual recuperé el' HBITMAP'. En ese caso ':: GetObject()' left 'source_info.bmBits' establecido en NULL. Podría resolver esto llamando 'myCBitmapPtr-> GetBitmapBits (source_info.bmWidthBytes * source_info.bmHeight, target_info.Scan0)' – foraidt

+0

BTW, los valores de retorno están bien marcados en su ejemplo, pero si 'source_info.bmBits' es NULL, hay un acceso violación en la llamada a 'CopyMemory()'. – foraidt

Cuestiones relacionadas