首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> VC >> 關於VC++

VC++ 對話框透明位圖繪製:MaskBlt 與雙重 BitBlt 實現前景透明合成

     編輯:關於VC++

介面設計常需將不規則圖形(如角色、圖示)疊加於背景上,需實現位圖「透明色」不繪製、前景正常顯示。本文詳細解析 Windows GDI 透明位圖繪製原理(掩碼位圖法),並提供封裝於 CStatic 衍生類 CTransparentImage 的完整實作代碼。

透明位圖效果

圖 1:對話框上透明顯示不規則位圖(紫色背景未繪製)

一、透明位圖核心原理:三次 BitBlt 運算

建立兩個記憶體 DC:

  • Image DC:載入原始位圖。
  • Mask DC:建立單色位圖(1 bit/像素),作為掩碼。

掩碼製作:將 Image DC 以 SRCCOPY 複製到 Mask DC,並將背景色設為透明色(如 RGB(255,0,255)),GDI 會自動將透明色轉為白色(1),非透明色轉為黑色(0)。

繪製三步驟(ROP 碼運算):

  1. Image DC --SRCINVERT--> 目標 DC:目標反相(前景變反色,背景不變)。
  2. Mask DC --SRCAND--> 目標 DC:掩碼白色(透明區)保留目標,黑色(前景)清零目標。
  3. Image DC --SRCINVERT--> 目標 DC:前景反相還原,背景維持原樣。

若裝置不支援 MaskBlt,可用等效的四次 BitBlt 組合(複製目標→Mask AND→Image XOR→目標 OR)。

二、CTransparentImage 類別實作

class CTransparentImage : public CStatic {
    DECLARE_MESSAGE_MAP()
protected:
    afx_msg void OnPaint();
};

BEGIN_MESSAGE_MAP(CTransparentImage, CStatic)
    ON_WM_PAINT()
END_MESSAGE_MAP()

void CTransparentImage::OnPaint() {
    HBITMAP hBmp = GetBitmap();
    if (!hBmp) { Default(); return; }

    CPaintDC dc(this);
    CRect rc; GetClientRect(&rc);

    // 雙緩衝 DC
    CDC bufDC; bufDC.CreateCompatibleDC(&dc);
    CBitmap bufBmp; bufBmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
    CBitmap* pOldBuf = bufDC.SelectObject(&bufBmp);

    // Mask DC
    CDC maskDC; maskDC.CreateCompatibleDC(&dc);
    CBitmap maskBmp; maskBmp.CreateBitmap(rc.Width(), rc.Height(), 1, 1, NULL);
    CBitmap* pOldMask = maskDC.SelectObject(&maskBmp);

    // 填充透明色(品紅)
    bufDC.FillSolidRect(&rc, RGB(255,0,255));

    // 載入原始位圖到記憶體 DC
    CDC memDC; memDC.CreateCompatibleDC(&dc);
    CBitmap* pOldMem = memDC.SelectObject(CBitmap::FromHandle(hBmp));
    bufDC.BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
    memDC.SelectObject(pOldMem);

    // 製作掩碼:設背景色為透明色,複製到 Mask DC
    COLORREF oldBk = bufDC.SetBkColor(RGB(255,0,255));
    maskDC.BitBlt(0, 0, rc.Width(), rc.Height(), &bufDC, 0, 0, SRCCOPY);
    bufDC.SetBkColor(oldBk);

    // 嘗試 MaskBlt(支援硬體加速)
    if (!dc.MaskBlt(0, 0, rc.Width(), rc.Height(), &bufDC, 0, 0, maskBmp, 0, 0, 0x00AA0029)) {
        // 回退:四次 BitBlt 模擬
        CDC cpyDC; cpyDC.CreateCompatibleDC(&dc);
        CBitmap cpyBmp; cpyBmp.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
        CBitmap* pOldCpy = cpyDC.SelectObject(&cpyBmp);
        cpyDC.BitBlt(0, 0, rc.Width(), rc.Height(), &dc, 0, 0, SRCCOPY);
        cpyDC.BitBlt(0, 0, rc.Width(), rc.Height(), &maskDC, 0, 0, SRCAND);
        bufDC.BitBlt(0, 0, rc.Width(), rc.Height(), &maskDC, 0, 0, SRCINVERT);
        cpyDC.BitBlt(0, 0, rc.Width(), rc.Height(), &bufDC, 0, 0, SRCPAINT);
        dc.BitBlt(0, 0, rc.Width(), rc.Height(), &cpyDC, 0, 0, SRCCOPY);
        cpyDC.SelectObject(pOldCpy);
    }

    // 清理
    maskDC.SelectObject(pOldMask);
    bufDC.SelectObject(pOldBuf);
}

三、使用步驟

  1. 建立對話框專案,匯入位圖資源 IDB_DRAGON(背景色建議統一為 RGB(255,0,255))。
  2. 對話框加入 Picture Control (IDC_STATIC),屬性設 Type: Bitmap、Image: IDB_DRAGON。
  3. Class Wizard 為該控制項新增變數類別 CTransparentImage(基類 CStatic)。
  4. 編譯執行,觀察位圖背景色消失,前景與對話框背景融合。

四、關鍵點總結

步驟GDI 函數ROP 碼說明
填充透明色FillSolidRect-統一背景色為品紅
複製原圖BitBltSRCCOPYImage DC → Buffer DC
產生掩碼BitBltSRCCOPYBuffer DC → Mask DC (SetBkColor 關鍵)
透明合成MaskBltROP4_TRANSPARENTBLIT單次硬體加速合成
軟體模擬4×BitBltSRCAND/XOR/PAINT相容舊顯卡/驅動

五、現代替代方案

  • Alpha Blending:AlphaBlend() 支援 32-bit 位圖(含 Alpha 通道),邊緣抗鋸齒、半透明效果更佳。
  • GDI+:Graphics::DrawImage() 原生支援 PNG/透明色,代碼更簡潔。
  • Layered Window:WS_EX_LAYERED + UpdateLayeredWindow() 實現視窗級透明/不規則視窗。

六、總結

本文完整呈現了經典 GDI 透明位圖繪製流程:掩碼製作、三次 ROP 運算、MaskBlt 與軟體回退。封裝於 CStatic 衍生類中,即插即用。雖現代專案建議改用 Alpha Blending 或 GDI+,但理解 ROP 運算邏輯對圖形程式設計仍具核心價值。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved