在 VC++ 中動態顯示 BMP 圖片主要有三種途徑:資源嵌入、檔案載入 (GDI)、記憶體數據直接繪製 (DIB)。本文以 320×240 256 灰階圖為例,對比三種方法的優劣與適用場景,提供可直接複製的代碼片段。
.rc 加入 BMP,ID 為 IDB_MYIMAGE。CBitmap bmp; bmp.LoadBitmap(IDB_MYIMAGE);支援 BMP/ICON/CUR,可選 LR_CREATEDIBSECTION 獲得可操作像素的 DIB Section。
// 1. 載入
HBITMAP hBmp = (HBITMAP)::LoadImage(NULL, _T("pic.bmp"), IMAGE_BITMAP, 0, 0,
LR_LOADFROMFILE | LR_CREATEDIBSECTION);
if (!hBmp) return;
// 2. 繪製到視窗 DC
CDC* pDC = GetDC();
CDC memDC; memDC.CreateCompatibleDC(pDC);
CRect rect; GetClientRect(&rect);
HBITMAP hOld = (HBITMAP)memDC.SelectObject(hBmp);
// 伸縮繪製至客戶區 (或原尺寸 BitBlt)
pDC->StretchBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, 320, 240, SRCCOPY);
// 或原尺寸: pDC->BitBlt(0,0,320,240,&memDC,0,0,SRCCOPY);
memDC.SelectObject(hOld);
memDC.DeleteDC();
ReleaseDC(pDC);
DeleteObject(hBmp); // 釋放 GDI 物件
灰階圖優勢: 內建調色盤,無需手動建立 RGBQUAD 表,LoadImage 自動處理。
適用場景:硬體採集卡回傳原始像素緩衝區 BYTE* pBuffer,無檔案頭,需手動構建 BITMAPINFOHEADER。
// 1. 構建 BITMAPINFO (含調色盤)
LPBITMAPINFO pBmi = (LPBITMAPINFO)new BYTE[sizeof(BITMAPINFOHEADER) + 256*sizeof(RGBQUAD)];
pBmi->bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
pBmi->bmiHeader.biWidth = 320;
pBmi->bmiHeader.biHeight = -240; // 負值 = 自上而下 (Top-down DIB)
pBmi->bmiHeader.biPlanes = 1;
pBmi->bmiHeader.biBitCount = 8; // 256 灰階
pBmi->bmiHeader.biCompression = BI_RGB;
pBmi->bmiHeader.biSizeImage = 0;
// 灰階調色盤
for (int i=0; i<256; i++) {
pBmi->bmiColors[i].rgbBlue = i;
pBmi->bmiColors[i].rgbGreen = i;
pBmi->bmiColors[i].rgbRed = i;
pBmi->bmiColors[i].rgbReserved = 0;
}
// 2. 直接繪製到螢幕 DC (無需兼容 DC)
CDC* pDC = GetDC();
::StretchDIBits(pDC->m_hDC,
10, 10, 640, 480, // 目標矩形 (放大 2 倍)
0, 0, 320, 240, // 來源矩形
pBuffer, // 像素指標
pBmi, DIB_RGB_COLORS, SRCCOPY);
ReleaseDC(pDC);
delete[] pBmi;
| 維度 | 資源嵌入 | LoadImage 檔案 | 記憶體 DIB |
|---|---|---|---|
| 部署 | 單一 EXE | 需攜帶圖片檔 | 無檔案 (記憶體/串流) |
| 運行時切換 | 困難 | 容易 | 極易 (換指標) |
| 效能 | 一般 | 良好 | 最高 (零拷貝) |
| 適用場景 | 圖標、工具列固定圖片 | 一般圖片瀏覽、報表 | 即時影像、採集卡、視訊流 |
| 調色盤處理 | 自動 | 自動 | 手動構建 (灰階簡單) |
CBitmap::CreateBitmap 第三、四參數必須為 1,1 才能建立單色位圖,不適用於灰階/彩色,請改用 CreateDIBSection 或 LoadImage。HBITMAP/HDC 用畢必須 DeleteObject/DeleteDC/ReleaseDC,否則 GDI 物件洩漏導致系統資源耗盡 (幾十秒內崩潰)。biHeight 設負值表示 Top-down DIB,配合採集卡行序通常一致,避免影像上下翻轉。根據專案需求選擇:固定資源用方法一,一般檔案用方法二,高效即時影像用方法三。