transparente transparentar transparencia seleccion imagen guardar fondo color canal alfa mfc alphablending bmp

mfc - transparentar - guardar imagen sin fondo en gimp



Cómo dibujar bitmaps de canal alfa de 32 bits? (6)

La forma en que generalmente hago esto es a través de una DIBSection, un mapa de bits independiente del dispositivo que puede modificar directamente los píxeles. Lamentablemente, no hay compatibilidad con MFC para DIBSections: debe usar la función CreateDIBSection () de Win32 para usarla.

Comience por cargar el mapa de bits como RGBA de 32 bits (es decir, cuatro bytes por píxel: uno rojo, uno verde, uno azul y uno para el canal alfa). En el control, crea una DIBSección de tamaño adecuado. Luego, en la rutina de pintura

  • Copie los datos de mapa de bits en los datos de mapa de bits de DIBSection, utilizando el byte de canal alfa para combinar la imagen de mapa de bits con el color de fondo.
  • Cree un contexto de dispositivo y seleccione la DIBSection en él.
  • Use BitBlt () para copiar desde el nuevo contexto del dispositivo al contexto del dispositivo de pintura.

Puede crear una máscara con los datos brutos del mapa de bits simplemente mirando los valores del canal alfa. No estoy seguro de lo que está preguntando aquí.

Necesito crear un control personalizado para mostrar imágenes bmp con canal alfa. El fondo se puede pintar en diferentes colores y las imágenes tienen sombras, así que necesito "pintar" realmente el canal alfa.

¿Alguien sabe cómo hacerlo?

También quiero, si es posible, crear una máscara utilizando la información del canal alfa para saber si el mouse ha hecho clic en la imagen o en el área transparente.

¡Cualquier tipo de ayuda será apreciada!

Gracias.

Editado (JDePedro): Como algunos de ustedes han sugerido, he tratado de usar la mezcla alfa para pintar el mapa de bits con el canal alfa. Esta es solo una prueba que he implementado donde cargo un mapa de bits de 32 bits de recursos y trato de pintarlo usando la función AlphaBlend:

void CAlphaDlg::OnPaint() { CClientDC dc(this); CDC dcMem; dcMem.CreateCompatibleDC(&dc); CBitmap bitmap; bitmap.LoadBitmap(IDB_BITMAP); BITMAP BitMap; bitmap.GetBitmap(&BitMap); int nWidth = BitMap.bmWidth; int nHeight = BitMap.bmHeight; CBitmap *pOldBitmap = dcMem.SelectObject(&bitmap); BLENDFUNCTION m_bf; m_bf.BlendOp = AC_SRC_OVER; m_bf.BlendFlags = 0; m_bf.SourceConstantAlpha = 255; m_bf.AlphaFormat = AC_SRC_ALPHA; AlphaBlend(dc.GetSafeHdc(), 100, 100, nWidth, nHeight, dcMem.GetSafeHdc(), 0, 0,nWidth, nHeight,m_bf); dcMem.SelectObject(pOldBitmap); CDialog::OnPaint(); }

Esto es solo una prueba, así que puse el código en OnPaint del diálogo (también probé la función AlphaBlend del objeto CDC).

Las áreas no transparentes se están pintando correctamente, pero me pongo blanco donde el mapa de bits debe ser transparente.

¿¿¿Alguna ayuda???

Esta es una captura de pantalla ... no es fácil de ver, pero hay un rectángulo blanco alrededor del círculo azul: texto alternativo http://img385.imageshack.us/img385/7965/alphamh8.png

De acuerdo. ¡Entiendo! Tengo que multiplicar previamente cada píxel por el valor alfa. Alguien puede sugerir la forma optimizada para hacer eso?


Necesitas hacer una mezcla alfa con tu color de fondo, luego sacar el canal alfa para pintarlo al control.

El canal alfa debería ser solo cada cuarto byte de su imagen. Puede usarlo directamente para su máscara, o simplemente puede copiar cada 4to byte a una nueva imagen de máscara.


Una forma optimizada de pre-multiplicar los canales RGB con el canal alfa es configurar una matriz [256] [256] que contenga los resultados de la multiplicación calculados. La primera dimensión es el valor alfa, la segunda es el valor R / G / B, los valores en la matriz son los valores pre-multiplicados que necesita.

Con esta matriz configurada correctamente, puede calcular el valor que necesita de esta manera:

R = multiplicationLookup[alpha][R]; G = multiplicationLookup[alpha][G]; B = multiplicationLookup[alpha][B];


Estás en el camino correcto, pero necesitas arreglar dos cosas.

Primer uso :: LoadImage (.. LR_CREATEDIBSECTION ..) en lugar de CBitmap :: LoadBitmap. Dos, debe "pre-multiplicar" los valores RGB de cada píxel en un mapa de bits a su valor A respectivo. Este es un requisito de la función AlphaBlend, consulte la descripción de AlphaFormat en esta página de MSDN . T

El lpng tiene un código de trabajo que realiza la premultiplicación de los datos DIB.


Para futuros usuarios de Google, aquí hay una función de pre-multiplicación en funcionamiento. Tenga en cuenta que esto fue tomado de http://www.viksoe.dk/code/alphatut1.htm .

inline void PremultiplyBitmapAlpha(HDC hDC, HBITMAP hBmp) { BITMAP bm = { 0 }; GetObject(hBmp, sizeof(bm), &bm); BITMAPINFO* bmi = (BITMAPINFO*) _alloca(sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD))); ::ZeroMemory(bmi, sizeof(BITMAPINFOHEADER) + (256 * sizeof(RGBQUAD))); bmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER); BOOL bRes = ::GetDIBits(hDC, hBmp, 0, bm.bmHeight, NULL, bmi, DIB_RGB_COLORS); if( !bRes || bmi->bmiHeader.biBitCount != 32 ) return; LPBYTE pBitData = (LPBYTE) ::LocalAlloc(LPTR, bm.bmWidth * bm.bmHeight * sizeof(DWORD)); if( pBitData == NULL ) return; LPBYTE pData = pBitData; ::GetDIBits(hDC, hBmp, 0, bm.bmHeight, pData, bmi, DIB_RGB_COLORS); for( int y = 0; y < bm.bmHeight; y++ ) { for( int x = 0; x < bm.bmWidth; x++ ) { pData[0] = (BYTE)((DWORD)pData[0] * pData[3] / 255); pData[1] = (BYTE)((DWORD)pData[1] * pData[3] / 255); pData[2] = (BYTE)((DWORD)pData[2] * pData[3] / 255); pData += 4; } } ::SetDIBits(hDC, hBmp, 0, bm.bmHeight, pBitData, bmi, DIB_RGB_COLORS); ::LocalFree(pBitData); }

Entonces, su OnPaint se convierte en:

void MyButton::OnPaint() { CPaintDC dc(this); CRect rect(0, 0, 16, 16); static bool pmdone = false; if (!pmdone) { PremultiplyBitmapAlpha(dc, m_Image); pmdone = true; } BLENDFUNCTION bf; bf.BlendOp = AC_SRC_OVER; bf.BlendFlags = 0; bf.SourceConstantAlpha = 255; bf.AlphaFormat = AC_SRC_ALPHA; HDC src_dc = m_Image.GetDC(); ::AlphaBlend(dc, rect.left, rect.top, 16, 16, src_dc, 0, 0, 16, 16, bf); m_Image.ReleaseDC(); }

Y la carga de la imagen (en el constructor de su control):

if ((HBITMAP)m_Image == NULL) { m_Image.LoadFromResource(::AfxGetResourceHandle(), IDB_RESOURCE_OF_32_BPP_BITMAP); }


Pintar es muy fácil con la función AlphaBlend .

En cuanto a su máscara, necesitará obtener los bits del mapa de bits y examinar el byte del canal alfa para cada píxel que le interese.