| 方法 | 用途 |
get_Handle | 取得 GDI 位圖控制代碼 (HBITMAP 或 HPALETTE) |
get_hPal | 取得調色盤控制代碼 |
get_Type | 圖片類型 (1=Bitmap, 2=Metafile, 3=Icon) |
get_Width/get_Height | 尺寸 (HiMetric 單位, 0.01 mm),需轉換像素 |
Render | 直接繪製到目標 DC,支援縮放、裁切 |
Load/SaveAsFile | 從 Stream 載入/儲存 |
完整載入並繪製流程
#include // IPicture 定義
#pragma comment(lib, "olepro32.lib") // OleLoadPicture
void DrawPicture(CDC* pDC, LPCTSTR szFile, int x, int y, int w, int h) {
// 1. 建立檔案 Stream
LPSTREAM pStream = NULL;
HRESULT hr = CreateStreamOnHGlobal(NULL, TRUE, &pStream);
if (FAILED(hr)) return;
CFile file;
if (!file.Open(szFile, CFile::modeRead | CFile::shareDenyNone)) { pStream->Release(); return; }
DWORD dwSize = (DWORD)file.GetLength();
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, dwSize);
LPVOID pData = GlobalLock(hGlobal);
file.Read(pData, dwSize);
file.Close();
GlobalUnlock(hGlobal);
hr = pStream->Write(pData, dwSize, NULL);
GlobalFree(hGlobal);
if (FAILED(hr)) { pStream->Release(); return; }
LARGE_INTEGER li = { 0 };
pStream->Seek(li, STREAM_SEEK_SET, NULL);
// 2. 載入 IPicture
IPicture* pPicture = NULL;
hr = OleLoadPicture(pStream, dwSize, TRUE, IID_IPicture, (LPVOID*)&pPicture);
pStream->Release();
if (FAILED(hr) || !pPicture) return;
// 3. 繪製 (Render 參數為 HiMetric 單位)
long hmWidth, hmHeight;
pPicture->get_Width(&hmWidth);
pPicture->get_Height(&hmHeight);
// 轉換 HiMetric → 像素 (依目標 DC 解析度)
int nWidth = MulDiv(hmWidth, pDC->GetDeviceCaps(LOGPIXELSX), 2540);
int nHeight = MulDiv(hmHeight, pDC->GetDeviceCaps(LOGPIXELSY), 2540);
// 目標矩形 (像素)
RECT rcDest = { x, y, x + (w>0?w:nWidth), y + (h>0?h:nHeight) };
// 來源矩形 (HiMetric, 整張圖)
RECT rcSrc = { 0, 0, hmWidth, hmHeight };
hr = pPicture->Render(pDC->m_hDC,
rcDest.left, rcDest.top, rcDest.right - rcDest.left, rcDest.bottom - rcDest.top,
rcSrc.left, rcSrc.top, rcSrc.right - rcSrc.left, rcSrc.bottom - rcSrc.top, NULL);
pPicture->Release();
}
MFC 封裝類別 CPicture (參考 MSDN 範例)
class CPicture {
IPicture* m_pPicture;
public:
CPicture() : m_pPicture(NULL) {}
~CPicture() { if (m_pPicture) m_pPicture->Release(); }
BOOL Load(LPCTSTR szFile) {
// ... 同上 CreateStreamOnHGlobal + OleLoadPicture ...
}
BOOL LoadFromResource(UINT nResID, LPCTSTR szType = _T("JPG")) {
// 從資源載入:FindResource/LoadResource/LockResource → CreateStreamOnHGlobal
}
void Render(CDC* pDC, CRect rectDest, CRect rectSrc = CRect(0,0,0,0)) {
if (!m_pPicture) return;
long hmW, hmH; m_pPicture->get_Width(&hmW); m_pPicture->get_Height(&hmH);
RECT rcSrc = { 0, 0, hmW, hmH };
if (!rectSrc.IsRectEmpty()) rcSrc = rectSrc;
m_pPicture->Render(pDC->m_hDC, rectDest.left, rectDest.top, rectDest.Width(), rectDest.Height(),
rcSrc.left, rcSrc.top, rcSrc.right, rcSrc.bottom, NULL);
}
CSize GetSizeInPixels(CDC* pDC) {
long hmW, hmH; m_pPicture->get_Width(&hmW); m_pPicture->get_Height(&hmH);
return CSize(MulDiv(hmW, pDC->GetDeviceCaps(LOGPIXELSX), 2540),
MulDiv(hmH, pDC->GetDeviceCaps(LOGPIXELSY), 2540));
}
};
優缺點分析
| 優點 | 缺點 |
| 零依賴,系統內建 | 功能有限:無法存取像素資料、無法編碼寫入、無動畫 GIF 支援 (僅第一幀) |
| 支援常見格式 (JPG/GIF/PNG/BMP/TIFF/ICO/WMF/EMF) | 依賴 IE/系統版本,舊系統可能不支援 PNG |
| Render 直接繪製,支援縮放/裁切 | 大圖載入較慢 (全解碼至記憶體) |
| 可從資源/檔案/Stream/URL 載入 | 多執行緒下需注意 COM 單元模型 (STA) |
現代替代方案
- GDI+ (
Gdiplus::Image): 系統內建 (WinXP+),功能更強 (像素存取、編碼、Metafile、動畫 GIF)。
- WIC (Windows Imaging Component): Win7+ 系統級影像編解碼架構,高效能、可擴充格式。
- 第三方庫: stb_image (單檔案)、OpenCV、FreeImage、CxImage — 功能最完整、跨平台。
- 上一篇文章: 透明位圖繪製:TransparentBlt API 與手動遮罩法 (動態生成單色遮罩) 完整教學
- 下一篇文章: 位圖複製到剪貼板:CF_BITMAP、CF_DIB、CF_PALETTE 三種格式完整實作
Copyright ©
程式碼之家 All Rights Reserved