c++ - vectorial - Cómo generar una máscara de bits monocromática para un mapa de bits de 32 bits
procesamiento de mapas de bits graficacion (4)
En Win32, es una técnica común generar una máscara de bits monocromática a partir de un mapa de bits para uso de transparencia haciendo lo siguiente:
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 (ambos son 32x32, pero la fuente es de 4 bits, 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.
¿Hay algún método alternativo que debería usar 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!
ADENDO: 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 particular simplemente no generando una máscara de bits monocromática, y en su lugar estoy usando TransparentBlt (), que parece hacerlo bien (pero no sé qué están haciendo internamente eso es diferente que les permite enmascarar correctamente la imagen).
Puede ser útil tener una función realmente buena y funcional:
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?
No puedes hacerlo si hay un canal alfa. El uso de COLORREF de los 8 bits superiores tiene varias finalidades, 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 permanece "desconocedor" 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, lo que limitaría la elección de los colores de la máscara: P)
Un método alternativo sería escanear los píxeles usted mismo y generar un mapa de bits monocromático basado en el color de origen (o fuente alfa frente a un umbral).
Tenga en cuenta que si está usando GDI +, entonces, dependiendo de la operación, los píxeles pueden haber sido antialias, lo que hace que ninguno de ellos sea una coincidencia exacta para su color "transparente".
Puede hacer :)
Como señaló ''Chris Becke'' arriba, GDI puede comparar solo 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
El método que funcionó para mí fue convertir el mapa de bits de 32 bits a 24 bits primero.
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.