Frage

Ich brauche eine benutzerdefinierte Steuerelement erstellen BMP-Bilder mit Alpha-Kanal angezeigt werden soll. Der Hintergrund kann in verschiedenen Farben lackiert werden und die Bilder haben Schatten so dass ich wirklich brauchen, um den Alphakanal „malen“.

Hat jemand wissen, wie es zu tun?

Ich mag auch, wenn möglich, eine Maske mit den Alpha-Kanal Informationen kennen zu erstellen, ob der Mausklick auf dem Bild oder auf dem transparenten Bereich gewesen ist.

wird jede Art von Hilfe dankbar!

Danke.

Edited (JDePedro): Wie einige von euch haben vorgeschlagen, ich habe die Bitmap mit Alpha-Kanal zu malen versucht, Alpha-Blending zu verwenden. Dies ist nur ein Test, den ich implementiert habe, wo ich einen 32-Bit-Bitmap aus Ressourcen geladen werden, und ich versuche, es zu malen Alphablend-Funktion:

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

Dies ist nur ein Test, damit ich den Code in der OnPaint des Dialogs setzen (ich habe auch versucht die Alphablend Funktion des CDC-Objekt).

Die undurchsichtigen Bereiche korrekt gezeichnet werden, aber ich weiß, wo sollte die Bitmap transparent sein.

Jede Hilfe ???

Dies ist ein screenshot..it ist nicht leicht zu sehen, aber es ist ein weißes Rechteck um den blauen Kreis: alt text http://img385.imageshack.us/img385/7965/alphamh8.png

Ok. Ich hab es geschafft! Ich muss jedes Pixel für den Alpha-Wert im Voraus multiplizieren. Jemand kann die optimierte Art und Weise lassen vermuten, dass zu tun?

War es hilfreich?

Lösung

So wie ich in der Regel dies tun, ist über eine DIBSection - eine geräteunabhängige Bitmap, die Sie die Pixel direkt ändern können. Leider gibt es keine MFC-Unterstützung für DIBSections. Sie die Win32-Funktion CreateDIBSection verwenden (), es zu benutzen

Start durch die Bitmap als 32-Bit RGBA geladen (das heißt, vier Bytes pro Pixel: eine rote, eine grüne, eine blaue und eine für den alpha-Kanal). Bei der Steuerung schaffen eine ausreichend große, DIBSection. Dann wird in der Farbe Routine

  • Kopieren der Bitmap-Daten in den Bitmap-Daten des DIBSection, den Alphakanal-Byte mit dem Bitmap-Bild mit der Hintergrundfarbe zu mischen.
  • Erstellen Sie einen Gerätekontext und wählen Sie das DIBSection hinein.
  • Verwenden Sie BitBlt () von dem neuen Gerätekontext an den Farbe Gerätekontext zu kopieren.

Sie können eine Maske erstellen, um die rohen Bitmap-Daten einfach durch einen Blick auf den Alphakanalwerte gegeben - ich bin nicht sicher, was Sie fragen hier

.

Andere Tipps

Für zukünftige Google-Nutzer, ist hier eine Arbeits Pre-Multiplikationsfunktion. Beachten Sie, dass diese von 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);
}

So dann OnPaint wird:

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

Und das Laden des Bildes (im Konstruktor Ihrer Kontrolle):

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

Sie benötigen eine Alpha-Blending- mit Ihrer Hintergrundfarbe zu tun, nehmen Sie dann die alpha Kanal an die Steuerung zu malen.

Der Alphakanal sollte nur jedes vierte Byte des Bildes sein. Sie können die für Ihre Maske direkt verwenden, oder Sie können nur jedes vierte Byte auf ein neues Maskenbild kopieren.

Malerei ist es sehr einfach, mit der Alphablend Funktion .

Wie Sie maskieren, müssen Sie erhalten die Bits der Bitmap und untersuchen den alpha-Kanal-Byte für jedes Pixel in Sie interessiert sind.

Eine optimierte Art und Weise, um die RGB-Kanäle mit dem Alphakanal vorge zu multiplizieren ist, einen [256] [256] Array mit den berechneten Multiplikationsergebnissen einzustellen. Die erste Dimension ist der Alpha-Wert, die zweite ist die R / G / B-Wert ist, werden die Werte in dem Array sind die pre-multiplizierten Werten Sie benötigen.

Mit diesem Array richtig eingerichtet ist, können Sie den Wert, den Sie wie folgt benötigen berechnen:

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

Sie sind auf dem richtigen Weg, müssen aber zwei Dinge beheben.

Erster Einsatz :: Loadimage (.. LR_CREATEDIBSECTION ..) statt CBitmap :: Loadbitmap. Zwei, müssen Sie RGB-Werte jeden Pixel in einem Bitmap zu ihrem jeweiligen A-Wert „pre-multiplizieren“. Dies ist eine Anforderung von Alphablend-Funktion finden Sie AlphaFormat Beschreibung auf diese MSDN-Seite . T

Die lpng hat einen Arbeitscode, der die Vormultiplikation der DIB-Daten der Fall ist.

Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top