11

アルファ チャネルを使用して bmp 画像を表示するには、カスタム コントロールを作成する必要があります。背景はさまざまな色でペイントでき、画像には影があるため、アルファ チャネルを真に「ペイント」する必要があります。

誰もそれを行う方法を知っていますか?

また、可能であれば、アルファ チャネル情報を使用してマスクを作成し、マウスが画像をクリックしたのか、透明な領域をクリックしたのかを知りたいと思っています。

どんな種類の助けも大歓迎です!

ありがとう。

Edited(JDePedro): 何人かが示唆しているように、アルファ ブレンドを使用してビットマップをアルファ チャネルでペイントしようとしています。これは、リソースから 32 ビット ビットマップをロードし、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();
}

これは単なるテストなので、ダイアログの OnPaint にコードを入れました (CDC オブジェクトの AlphaBlend 関数も試しました)。

不透明な領域は正しくペイントされていますが、ビットマップを透明にする必要がある場所が白くなります。

助けて?

これはスクリーンショットです。見にくいですが、青い円の周りに白い四角形があります: 代替テキスト http://img385.imageshack.us/img385/7965/alphamh8.png

Ok。わかった!アルファ値のすべてのピクセルを事前に乗算する必要があります。誰かがそれを行うための最適化された方法を提案できますか?

4

6 に答える 6

12

将来のGoogleユーザーのために、これは機能する事前乗算機能です。これは 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);
}

したがって、OnPaint は次のようになります。

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

画像の読み込み (コントロールのコンストラクター内):

if ((HBITMAP)m_Image == NULL) {
    m_Image.LoadFromResource(::AfxGetResourceHandle(), IDB_RESOURCE_OF_32_BPP_BITMAP);
}
于 2013-06-19T08:55:25.073 に答える
6

私が通常これを行う方法は、ピクセルを直接変更できるデバイスに依存しないビットマップである DIBSection を使用することです。残念ながら、DIBSections に対する MFC サポートはありません。これを使用するには、Win32 関数 CreateDIBSection() を使用する必要があります。

ビットマップを 32 ビット RGBA (つまり、ピクセルあたり 4 バイト: 赤、緑、青、アルファ チャネル用に 1 つずつ) としてロードすることから始めます。コントロールで、適切なサイズの DIBSection を作成します。次に、ペイントルーチンで

  • ビットマップ データを DIBSection のビットマップ データにコピーし、アルファ チャネル バイトを使用してビットマップ イメージを背景色とブレンドします。
  • デバイス コンテキストを作成し、そこに DIBSection を選択します。
  • BitBlt() を使用して、新しいデバイス コンテキストからペイント デバイス コンテキストにコピーします。

アルファチャンネルの値を見るだけで、生のビットマップデータを指定してマスクを作成できます-ここで何を求めているのかわかりません。

于 2008-11-21T18:06:28.553 に答える
1

背景色とアルファブレンドを行ってから、アルファチャネルを取り出してコントロールにペイントする必要があります。

アルファチャネルは、画像の4バイトごとに配置する必要があります。これをマスクに直接使用することも、4バイトごとに新しいマスク画像にコピーすることもできます。

于 2008-11-21T00:13:03.943 に答える
1

AlphaBlend 機能を使用すると、非常に簡単にペイントできます。

マスクに関しては、ビットマップのビットを取得し、関心のある各ピクセルのアルファ チャネル バイトを調べる必要があります。

于 2008-11-21T23:39:24.840 に答える
1

あなたは正しい道を進んでいますが、2 つのことを修正する必要があります。

まず、CBitmap::LoadBitmap の代わりに ::LoadImage( .. LR_CREATEDIBSECTION ..) を使用します。2 つ目は、ビットマップ内のすべてのピクセルの RGB 値をそれぞれの A 値に「事前に乗算」する必要があることです。これは AlphaBlend 関数の要件です。この MSDN ページの AlphaFormat の説明を参照してください。T

lpngには、DIB データの事前乗算を行う作業コードがあります。

于 2009-01-19T07:02:24.523 に答える
1

RGB チャンネルとアルファ チャンネルを事前に乗算する最適化された方法は、計算された乗算結果を含む [256][256] 配列を設定することです。最初の次元はアルファ値で、2 番目は R/G/B 値です。配列内の値は必要な乗算済みの値です。

この配列を正しく設定すると、次のように必要な値を計算できます。

R = multiplicationLookup[alpha][R];
G = multiplicationLookup[alpha][G];
B = multiplicationLookup[alpha][B];
于 2008-12-02T10:15:34.570 に答える