利用 OLE 自動化介面 IPicture 搭配 OleLoadPicture,可直接從記憶體串流載入 JPG、BMP、GIF、PNG 等格式,無需第三方庫。適用於 MFC OnDraw 繪製至 CDC。
OnDraw)void CMyView::OnDraw(CDC* pDC)
{
IPicture *pPic = NULL;
IStream *pStm = NULL;
CFile file;
CFileStatus fs;
LONG cb = 0;
// 1. 開啟檔案並讀入 HGLOBAL
if (file.Open(_T("test.jpg"), CFile::modeRead) &&
file.GetStatus(_T("test.jpg"), fs) &&
(cb = fs.m_size) != -1)
{
HGLOBAL hGlobal = GlobalAlloc(GMEM_MOVEABLE, cb);
if (hGlobal)
{
LPVOID pvData = GlobalLock(hGlobal);
if (pvData)
{
file.ReadHuge(pvData, cb);
GlobalUnlock(hGlobal);
// 2. 建立串流並載入 IPicture
if (SUCCEEDED(CreateStreamOnHGlobal(hGlobal, TRUE, &pStm)))
{
if (SUCCEEDED(OleLoadPicture(pStm, fs.m_size, TRUE,
IID_IPicture, (LPVOID*)&pPic)))
{
// 3. 取得圖片尺寸 (HIMETRIC 單位: 0.01 mm)
OLE_XSIZE_HIMETRIC hmWidth;
OLE_YSIZE_HIMETRIC hmHeight;
pPic->get_Width(&hmWidth);
pPic->get_Height(&hmHeight);
// 4. 轉換為裝置像素並繪製
CRect rect;
GetClientRect(&rect);
double drawW = rect.Width();
double drawH = rect.Height();
// 保持長寬比縮放 (可選)
// double ratio = min(drawW/hmWidth, drawH/hmHeight) * ...;
HRESULT hr = pPic->Render(pDC->m_hDC,
0, 0, (long)drawW, (long)drawH,
0, hmHeight, hmWidth, -hmHeight, NULL);
if (FAILED(hr))
AfxMessageBox(_T("Render 失敗"));
pPic->Release();
}
else
AfxMessageBox(_T("OleLoadPicture 失敗"));
pStm->Release();
}
else
AfxMessageBox(_T("CreateStreamOnHGlobal 失敗"));
}
else
GlobalFree(hGlobal);
}
}
else
AfxMessageBox(_T("無法開啟圖片檔案"));
}
| API | 用途 |
|---|---|
GlobalAlloc/GlobalLock | 配置可移動全域記憶體,供 CreateStreamOnHGlobal 使用 |
CreateStreamOnHGlobal | 將 HGLOBAL 包裝為 IStream (COM 串流介面) |
OleLoadPicture | 從串流載入圖片,回傳 IPicture 介面指標 |
IPicture::get_Width/Height | 取得圖片原始尺寸 (HIMETRIC, 0.01mm) |
IPicture::Render | 繪製至 HDC,參數:目標矩形、來源座標 (HIMETRIC)、裁剪矩形 |
// HIMETRIC 轉像素 (對應 pDC 的對應模式)
int PixX = MulDiv(hmWidth, pDC->GetDeviceCaps(LOGPIXELSX), 2540);
int PixY = MulDiv(hmHeight, pDC->GetDeviceCaps(LOGPIXELSY), 2540);
pDC->m_hDC 有效、圖片格式支援、記憶體充足。OleLoadPicture 會完整解碼,大量圖片建議使用 GDI+ / WIC / libjpeg 非同步載入。IPicture 不支援 Alpha 通道渲染,需改用 Gdiplus::Image。HGLOBAL 大小限制 2GB,超大檔案需分段串流。