網路傳輸、資料庫 Blob、壓縮包解壓等場景下,圖片數據常以 BYTE* 緩衝區形式存在於記憶體中,無實體檔案。本文展示如何利用 GDI+ IStream + OleLoadPicture (支援 JPEG/GIF/BMP/TIFF/PNG) 直接從記憶體解碼並繪製到視窗,無需落地檔案。
GlobalAlloc(GMEM_MOVEABLE) 分配可移動全域記憶體。GlobalLock 鎖定獲取指標,memcpy 複製圖片數據,GlobalUnlock。CreateStreamOnHGlobal 將 HGLOBAL 包裝為 IStream* (COM 串流介面)。OleLoadPicture 從串流解碼獲取 IPicture*。Graphics::DrawImage 繪製 (或 IPicture::Render)。
// 需包含: #include using namespace Gdiplus;
// 鏈接: gdiplus.lib
// 專案屬性: C/C++ -> Code Generation -> Runtime Library: Multi-threaded (/MT 或 /MD)
void DrawImageFromMemory(HWND hWnd, const BYTE* pImgData, int nSize, int destW, int destH) {
// 1. GDI+ 初始化 (每進程一次,建議在 App 啟動時做)
ULONG_PTR gdiToken;
GdiplusStartupInput gdiInput;
GdiplusStartup(&gdiToken, &gdiInput, NULL);
// 2. 配置全域記憶體並複製數據
HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, nSize);
if (!hMem) { GdiplusShutdown(gdiToken); return; }
BYTE* pMem = (BYTE*)GlobalLock(hMem);
memcpy(pMem, pImgData, nSize);
GlobalUnlock(hMem);
// 3. 建立 IStream
IStream* pStream = NULL;
HRESULT hr = CreateStreamOnHGlobal(hMem, TRUE, &pStream); // TRUE: 釋放流時自動釋放 hMem
if (FAILED(hr)) { GdiplusShutdown(gdiToken); return; }
// 4. 定位流開頭
LARGE_INTEGER liZero = {0}; ULARGE_INTEGER uliNewPos;
pStream->Seek(liZero, STREAM_SEEK_SET, &uliNewPos);
// 5. OleLoadPicture 解碼 (支援 JPEG/GIF/BMP/TIFF/PNG/ICO/WMF/EMF)
IPicture* pPic = NULL;
hr = OleLoadPicture(pStream, nSize, TRUE, IID_IPicture, (void**)&pPic);
pStream->Release(); // 釋放流 (若 TRUE 也釋放了 hMem)
if (FAILED(hr) || !pPic) {
GdiplusShutdown(gdiToken);
return;
}
// 6. GDI+ 繪製 (高質量縮放/抗鋸齒)
HDC hdc = GetDC(hWnd);
Graphics g(hdc);
Image img(pStream); // 注意: 此處需重新建立流或用 IPicture::Render
// 更簡單: 直接用 IPicture::Render
RECT rc = {0, 0, destW, destH};
long hmW, hmH;
pPic->get_Width(&hmW); pPic->get_Height(&hmH); // HIMETRIC 單位
pPic->Render(hdc, 0, 0, destW, destH, 0, hmH, hmW, -hmH, &rc);
ReleaseDC(hWnd, hdc);
// 7. 清理
pPic->Release();
GdiplusShutdown(gdiToken);
}
GdiplusStartup/GdiplusShutdown,不要在每次繪製時重複調用 (效能差、可能導致 Token 耗盡)。OleLoadPicture 返回 IPicture (舊 COM),功能足夠;若需高階特效 (旋轉、矩陣變換、Alpha 混合),可用 Image::FromStream (需流可 Seek)。OleLoadPicture 對損壞數據敏感,可能拋出存取違規 (SEH 異常),建議包裹 __try/__except 或驗證數據完整性 (如 JPEG SOI/EOI 標記)。GlobalAlloc 限制 2GB (32位進程),超大圖片需分塊串流或臨時檔案。IMAGE/BLOB 欄位讀取即時顯示。此技術是「零落地」圖片顯示的核心基石。