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

GDI 位圖與文字合成:以 SetDIBits/GetDIBits 實作文字疊加儲存

     編輯:關於VC++

需求:將文字繪製在載入的 BMP 圖像上,合成結果另存為新 BMP 檔,並支援滑鼠拖曳文字位置。本文採用 記憶體相容 DC + 相容位圖 + SetDIBits/GetDIBits 方案,避免檔案 I/O 中介,效能優於逐像素操作。

核心 API

函數用途
SetDIBits將原始 DIB 緩衝區像素寫入相容位圖
GetDIBits從相容位圖讀回像素到 DIB 緩衝區

流程:

  1. 載入 BMP → 解析 BITMAPINFOHEADER、像素緩衝 m_lpDIBits。
  2. 建立記憶體 DC (CreateCompatibleDC) 與相容位圖 (CreateCompatibleBitmap,尺寸同原圖)。
  3. SetDIBits 將原圖像素寫入相容位圖。
  4. 在記憶體 DC 上 TextOut 繪製文字 (支援透明背景、陰影效果)。
  5. GetDIBits 從相容位圖讀回合成後像素緩衝。
  6. 寫入新 BMP 檔 (更新檔頭、資訊頭、像素資料)。

關鍵程式碼片段

建立記憶體物件


void CreateMemObject(CDC* pDC, BITMAPINFO* lpbmi, int* pnLineChar)
{
    if (!m_pMemDC) { m_pMemDC = new CDC(); m_pMemDC->CreateCompatibleDC(pDC); }
    if (m_pMemBmp) { m_pMemDC->SelectObject(m_pOldBmp); delete m_pMemBmp; }
    
    m_pMemBmp = new CBitmap();
    m_pMemBmp->CreateCompatibleBitmap(pDC, 
        m_lpBMPHdr->biWidth, m_lpBMPHdr->biHeight);
    m_pOldBmp = m_pMemDC->SelectObject(m_pMemBmp);
    m_pMemDC->FillSolidRect(0, 0, 
        m_lpBMPHdr->biWidth, m_lpBMPHdr->biHeight, RGB(255,255,255));
    
    // 原圖像素寫入相容位圖
    SetDIBits(m_pMemDC->GetSafeHdc(), (HBITMAP)m_pMemBmp->m_hObject,
        0, m_lpBMPHdr->biHeight, (LPVOID)m_lpDIBits,
        (BITMAPINFO*)m_lpBMPHdr, DIB_RGB_COLORS);
}

繪製文字 (含陰影/描邊效果)


void SetBmpText(const CString& strText, BOOL bRepaint)
{
    m_strBmpText = strText;
    // 重新貼上原圖 (避免文字疊加殘留)
    SetDIBits(m_pMemDC->GetSafeHdc(), (HBITMAP)m_pMemBmp->m_hObject,
        0, m_lpBMPHdr->biHeight, (LPVOID)m_lpDIBits,
        (BITMAPINFO*)m_lpBMPHdr, DIB_RGB_COLORS);
    
    if (m_strBmpText.GetLength() > 0) {
        m_pMemDC->SetBkMode(TRANSPARENT);
        // 陰影:黑色偏移 (1,1)
        m_pMemDC->SetTextColor(RGB(0,0,0));
        m_pMemDC->TextOut(10, 10, m_strBmpText);
        // 主文字:白色
        m_pMemDC->SetTextColor(RGB(255,255,255));
        m_pMemMemDC->TextOut(11, 11, m_strBmpText);
    }
    if (bRepaint) Invalidate();
}

讀回合成結果並儲存


void SetSaveBmpPath(LPCTSTR pszPath)
{
    BYTE* pTemp = new BYTE[m_dwImageSize];
    ZeroMemory(pTemp, m_dwImageSize);
    
    int nCount = GetDIBits(m_pMemDC->GetSafeHdc(),
        (HBITMAP)m_pMemBmp->m_hObject, 0, m_lpBMPHdr->biHeight,
        (LPVOID)pTemp, (BITMAPINFO*)m_lpBMPHdr, DIB_RGB_COLORS);
    
    // pTemp 即為合成後像素資料,寫入檔案...
    delete[] pTemp;
}

效果展示

文字合成效果圖

白色文字帶黑色陰影,清晰可讀,位置可滑鼠拖曳調整。

已知限制與改進方向

  • ❌ 無法在相容 DC 選入自訂筆刷/字型 — SelectObject 失效。推測與 SetDIBits 重寫像素機制衝突。改用 BitBlt 或 GDI+ 可解。
  • ❌ 僅支援 24-bit 真彩色 BMP — GetDIBits 配合 DIB_RGB_COLORS 在 8/16-bit 格式表現異常。需依 biBitCount 分支處理調色盤。
  • ✅ 可改用 GDI+ (Graphics::DrawImage + DrawString) 完美支援任意格式、字型、抗鋸齒、透明度、旋轉等。

參考資源

BMP 檔案讀寫參考《VC 知識庫線上雜誌第 21 期》胡卓愷〈位圖檔案讀寫綜述〉。測試環境:Win2000 + VC6 + 174×218 24-bit BMP。

總結

以 SetDIBits/GetDIBits 實作圖文合成,邏輯清晰、效能尚可,適合簡單 24-bit BMP 處理。若需專業級文字排版、多格式支援、向量文字、抗鋸齒,強烈建議遷移至 GDI+ 或 Direct2D。完整原始碼含 BMP 載入/儲存、滑鼠拖曳文字位置、合成邏輯,請下載附件參考。

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