2010-10-15 21 views
7

Bajo Win32, es una técnica común para generar una máscara de bits en blanco y negro de un mapa de bits para su uso transparencia de la siguiente manera:Cómo genrate una máscara de bits en blanco y negro de un mapa de bits de 32 bits

SetBkColor(hdcSource, clrTransparency); 
VERIFY(BitBlt(hdcMask, 0, 0, bm.bmWidth, bm.bmHeight, hdcSource, 0, 0, SRCCOPY)); 

Esto supone que hdcSource es una memoria DC que contiene la imagen fuente, y hdcMask es una memoria DC que contiene un mapa de bits monocromático del mismo tamaño (por lo tanto, ambos son 32x32, pero la fuente es de 4 bits de color, mientras que el objetivo es monocromo de 1 bit).

Sin embargo, esto parece fallarme cuando la fuente es 32 bit color + alpha. En lugar de obtener un mapa de bits monocromo en hdcMask, obtengo una máscara que es completamente negra. Ningún bit se establece en blanco (1). Mientras que esto funciona para la fuente de color de 4 bits.

Mi búsqueda está fallando, ya que no puedo encontrar ninguna referencia a este problema en particular.

He aislado que este es realmente el problema en mi código: es decir, si uso un mapa de bits de origen de 16 colores (4 bits), funciona; si utilizo una imagen de 32 bits, produce la máscara completamente negra.

¿Existe algún método alternativo que deba usarse en el caso de las imágenes en color de 32 bits? ¿Hay algún problema con el canal alfa que anule el comportamiento normal de la técnica anterior?

¡Gracias por cualquier ayuda que pueda tener que ofrecer!

ADDENDUM: Todavía no puedo encontrar una técnica que cree un mapa de bits monocromático válido para mi mapa de bits de origen producido por GDI +.

He aliviado un poco mi problema en particular simplemente no generando una máscara de bits monocromática en absoluto, y en su lugar estoy usando TransparentBlt(), que parece hacerlo bien (pero no sé lo que están haciendo internamente) eso es diferente que les permite enmascarar correctamente la imagen).

Podría ser útil tener una muy buena función, trabajando:

HBITMAP CreateTransparencyMask(HDC hdc, HBITMAP hSource, COLORREF crTransparency); 

donde siempre crea una máscara de transparencia válida, independientemente de la profundidad de color de Hsource.

Ideas?

+3

GDI está atascado en 24 bpp. TransparentBlt() es un poco inusual, está documentado para admitir 32bpp. Es hora de pasar a GDI + tal vez. –

Respuesta

3

No puede hacerlo si hay un canal alfa. COLORREF utiliza los 8 bits superiores para diversos propósitos, incluida la especificación de si los 3 bytes inferiores son un índice de tabla de colores en la paleta actual, o un triplete RGB. Como tal, no puede especificar nada excepto 0x00 en el byte superior de clrTransparency.

Si tiene un mapa de bits alfa entonces, para GDI que sigue siendo "inconsciente" del canal alfa, no hay una manera sensata de comparar realmente un BkColor de 24 bits con píxeles de 32 bits en el mapa de bits.

Esperaría que GDI trate el canal alfa en mapas de bits de 32 bits como "Reservado", y solo compare píxeles con éxito donde el canal reservado sea cero. es decir, el color de la máscara debe ser totalmente transparente para tener posibilidades de éxito. (y, si ha creado un mapa de bits premultiplicado legítimo, eso implica que los valores RGV también serían cero, restringiendo la elección de colores de máscara: P)

+0

En este caso particular, el problema es que estoy empezando con un mapa de bits de color de 4 bits. Luego, para mostrarlo de una manera agradable cuando está deshabilitado, me gustaría hacer una representación en escala de grises, y luego usar eso como la cara del botón (usando la técnica de transparencia enmascarada como antes). Pero el código que estoy usando para producir la escala de grises está basado en GDI +, que sospecho que crea una imagen en color de 32 bits en lugar de una imagen en color de 24 bits. – Mordachai

+1

@Mordachai: Dado lo que acaba de describir, ¿puede hacer la máscara de la imagen original de 4 bits y usarla con la creada por GDI? –

+0

Me gusta la idea para mis propósitos. Pero todavía estaría interesado en un genérico "cómo crear una máscara de bits monocromática para * ANY * fuente HBITMAP". – Mordachai

0

Un método alternativo sería escanear los píxeles usted mismo y generar monocromáticos mapa de bits basado en el color de origen (o fuente alfa frente a un umbral).

Tenga en cuenta que si usa GDI +, dependiendo de la operación, los píxeles pueden tener un antialias, por lo que ninguno de ellos es exactamente coinciden con su color "transparente".

+0

Guardé la imagen de escala de grises generada por GDI + como PNG de 32 bits de profundidad, y luego tomé muestras de los píxeles en Paint. Están bien. Sin embargo, compruebo dos veces el HBITMAP resultante que produce GDI + (a través de Bitmap :: GetHBitmap()) y, de hecho, siempre tiene una profundidad de 32 bits, a pesar de que la instancia de Bitmap subyacente es PixelFormat24bppRGB. – Mordachai

3

Can do :)
Según lo señalado por 'Chris Becke' anterior, GDI solo se puede comparar si el canal Alpha reservado es cero.
El HBITMAP obtenido de BITMAP :: GetHBITMAP() devuelve un HBITMAP con Alpha Channel, todo configurado en 0xFF.
Esto debe ser 0x00 para que la Comparación de SetBkColor() funcione.
Por lo tanto, la Soln: Pasa por cada píxel y establece el Componente Alfa en Cero.

Bitmap img(L"X.bmp"); 
HBITMAP hBM; 
img.GetHBITMAP(Color::White, &hBM); 
BITMAP bm; 
GetObject(g_hbmBall, sizeof(BITMAP), &bm); 
for(UINT i = 0, n = -1; i < bm.bmHeight; i++) 
    for(UINT j = 0; j < bm.bmWidth; j++) 
    { 
     n += 4; // Once per Pixel of 4 Bytes 
     ((LPBYTE)bm.bmBits)[n] = 0; 
    }
// Now SetBkColor and BitBlt will work as expected
+0

Gracias por la idea. Terminé decidiendo no utilizar esta técnica en absoluto, por lo que esta rama de codificación actualmente está extinta. Puedo volver a hacerlo en el futuro y probaré esta idea nuevamente. ;) – Mordachai

0

El método que trabajó para mí era convertir el mapa de bits de 32 bits a 24 bits en primer lugar.

1. CreateCompatibleDC 
2. CreateDIBSection with 24 as the biBitCount. 
3. SelectObject 
4. BitBlt from 32bit DC to 24 bit. This removes alpha. 
5. BitBlt from 24 bit DC to the monochrome DC works as expected. 

En mi máquina, esto se ejecuta más rápido que el doble de la respuesta de Ujjwal.

+0

Gracias. Bueno saber. – Mordachai

+0

Simplemente para aclarar este método, a. 3) SelectObject está seleccionando el mapa de bits creado con CreateDIBSection en un nuevo DC creado en 1) b. Para crear la máscara, debe asegurarse de llamar a SetBkColor en el nuevo DC de 24 bits creado en 1), de forma accidental solicité que SetBkColor llamara al DC de 32 bits y me tomó un tiempo solucionarlo. – frank

Cuestiones relacionadas