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

GDI+ Image 類別序列化實作:將圖片存入文檔

     編輯:關於VC++

問題背景

Gdiplus::Image 可輕鬆顯示 JPEG/GIF/PNG,但缺乏原生序列化支援。若需將圖片內容儲存至應用程式文檔(CArchive),必須自行實作序列化/反序列化邏輯。

解決方案:IStream + 全域記憶體

流程:

  1. 建立 HGLOBAL 可移動記憶體
  2. CreateStreamOnHGlobal 包裝成 IStream
  3. Image::Save(stream, CLSID_encoder) 以 BMP 格式寫入串流
  4. 序列化:寫入資料長度 + 原始位元組
  5. 反序列化:讀取位元組 → HGLOBAL → IStream → Image::FromStream

完整 Serialize 實作

void CDoc::Serialize(CArchive& ar) {
    if (ar.IsStoring()) {
        HGLOBAL hMem = GlobalAlloc(GMEM_MOVEABLE, 0);
        IStream* pStm = NULL;
        CreateStreamOnHGlobal(hMem, TRUE, &pStm);
        CLSID clsid; GetCodecClsid(L"image/bmp", &clsid); // BMP 編碼器
        m_pImage->Save(pStm, &clsid, NULL);

        LARGE_INTEGER li = {0}; pStm->Seek(li, STREAM_SEEK_SET, NULL);
        DWORD len = GlobalSize(hMem);
        BYTE* pData = (BYTE*)GlobalLock(hMem);
        ar << len; ar.Write(pData, len);
        pStm->Release(); GlobalUnlock(hMem);
    } else {
        DWORD len; ar >> len;
        HGLOBAL hMem = GlobalAlloc(GMEM_FIXED, len);
        IStream* pStm = NULL;
        CreateStreamOnHGlobal(hMem, FALSE, &pStm);
        BYTE* pData = (BYTE*)GlobalLock(hMem);
        ar.Read(pData, len);
        if (m_pImage) { delete m_pImage; m_pImage = NULL; }
        m_pImage = Image::FromStream(pStm, FALSE);
        pStm->Release(); GlobalUnlock(hMem);
        // 注意:此處不可 GlobalFree(hMem),否則圖片無法顯示
    }
}

編碼器查詢函式 GetCodecClsid

int GetCodecClsid(const WCHAR* mime, CLSID* pClsid) {
    UINT n=0, sz=0; GetImageEncodersSize(&n, &sz);
    ImageCodecInfo* pInfo = (ImageCodecInfo*)malloc(sz);
    GetImageEncoders(n, sz, pInfo);
    for (UINT i=0; i

支援 MIME:image/bmp、image/jpeg、image/gif、image/png、image/tiff。

關鍵提醒

  • 反序列化時 不可釋放 HGLOBAL,Image 內部仍引用該記憶體
  • 專案需連結 gdiplus.lib 並初始化 GdiplusStartup
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved