Domanda

Devo creare un controllo personalizzato per visualizzare immagini bmp con canale alfa. Lo sfondo può essere dipinto in diversi colori e le immagini hanno ombre, quindi devo veramente "dipingere". il canale alfa.

Qualcuno sa come farlo?

Voglio anche se possibile creare una maschera usando le informazioni del canale alfa per sapere se il mouse è stato cliccato sull'immagine o sull'area trasparente.

Sarà apprezzato qualsiasi tipo di aiuto!

Grazie.

Modificato (JDePedro): come alcuni di voi hanno suggerito, ho cercato di usare la fusione alfa per dipingere la bitmap con il canale alfa. Questo è solo un test che ho implementato dove carico una bitmap a 32 bit dalle risorse e provo a dipingerla usando la funzione 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();
}

Questo è solo un test, quindi ho inserito il codice nell'OnPaint della finestra di dialogo (ho anche provato la funzione AlphaBlend dell'oggetto CDC).

Le aree non trasparenti vengono dipinte correttamente ma divento bianco dove la bitmap dovrebbe essere trasparente.

Qualsiasi aiuto ???

Questo è uno screenshot ... non è facile da vedere ma c'è un rettangolo bianco attorno al cerchio blu: alt text http://img385.imageshack.us/img385/7965/alphamh8.png

Ok. Capito! Devo pre-moltiplicare ogni pixel per il valore alfa. Qualcuno può suggerire il modo ottimizzato per farlo?

È stato utile?

Soluzione

Il modo in cui lo faccio di solito è tramite una DIBSection, una bitmap indipendente dal dispositivo di cui è possibile modificare direttamente i pixel. Sfortunatamente non esiste alcun supporto MFC per DIBSections: devi usare la funzione Win32 CreateDIBSection () per usarlo.

Inizia caricando la bitmap come RGBA a 32 bit (ovvero quattro byte per pixel: uno rosso, uno verde, uno blu e uno per il canale alfa). Nel controllo, creare una DIBSection di dimensioni adeguate. Quindi, nella routine di pittura

  • Copia i dati bitmap nei dati bitmap di DIBSection, usando il byte del canale alfa per fondere l'immagine bitmap con il colore di sfondo.
  • Crea un contesto di dispositivo e seleziona la DIBSection in esso.
  • Usa BitBlt () per copiare dal nuovo contesto del dispositivo nel contesto del dispositivo di disegno.

Puoi creare una maschera dati i dati bitmap grezzi semplicemente osservando i valori del canale alfa - non sono sicuro di ciò che stai chiedendo qui.

Altri suggerimenti

Per i futuri utenti di Google, ecco una funzione di pre-moltiplicazione attiva. Si noti che questo è stato preso da 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);
}

Quindi il tuo OnPaint diventa:

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();
}

E il caricamento dell'immagine (nel costruttore del tuo controllo):

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

Devi fare una alpha blend con il colore di sfondo, quindi eliminare l'alfa canale per dipingerlo al controllo.

Il canale alfa dovrebbe essere solo ogni 4 byte della tua immagine. Puoi usarlo direttamente per la tua maschera, oppure puoi semplicemente copiare ogni 4 byte in una nuova immagine maschera.

Dipingere è molto semplice con la Funzione AlphaBlend .

Per quanto riguarda la tua maschera, dovrai ottieni i bit della bitmap ed esamina il byte del canale alfa per ogni pixel che ti interessa.

Un modo ottimizzato per pre-moltiplicare i canali RGB con il canale alfa è quello di impostare un array [256] [256] contenente i risultati di moltiplicazione calcolati. La prima dimensione è il valore alfa, la seconda è il valore R / G / B, i valori nell'array sono i valori pre-moltiplicati necessari.

Con questo array impostato correttamente, è possibile calcolare il valore necessario in questo modo:

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

Sei sulla strada giusta, ma devi risolvere due cose.

Primo utilizzo :: LoadImage (.. LR_CREATEDIBSECTION ..) invece di CBitmap :: LoadBitmap. Due, devi "pre-moltiplicare" Valori RGB di ogni pixel in una bitmap al rispettivo valore A. Questo è un requisito della funzione AlphaBlend, vedere la descrizione di AlphaFormat su questa pagina MSDN . T

La lpng ha un codice funzionante che esegue la premoltiplicazione dei dati DIB.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top