Image类的序列化
作者:贺小明

下载本文是示例代码

利用GDI+图形设备接口提供的Image类我们可以很方便地显示JPEGGIF等文件格式的图片,但美中不足的是Image类未提供序列化数据的功能,如果要将从JPEGGIF等格式的文件中读取的图片数据保存到我们自己开发的应用程序文档中,并能从文档中读取已经保存的图片数据并正确的显示出来,就必须实现Image类数据的序列化。 假如在你的文档类中有个指向Image类的成员指针变量m_pImage用于显示图片,那么在文档类的序列化函数Serialize(CArchive& ar)中加入以下的代码就能实现m_pImage所指向的图片数据的序列化:

if (ar.IsStoring())

{

        HGLOBAL m_hMem = GlobalAlloc(GMEM_MOVEABLE, 0);

        IStream *pstm=NULL;

        CreateStreamOnHGlobal(m_hMem, TRUE, &pstm);

        CLSID clsid;

        USES_CONVERSION;

        GetCodecClsid(A2W("image/bmp"), &clsid);

        m_pImage->Save(pstm,&clsid,NULL);

        if (pstm==NULL)

               return;

        LARGE_INTEGER liBeggining = { 0 };

        pstm->Seek(liBeggining, STREAM_SEEK_SET, NULL);

        DWORD wTemp=GlobalSize(m_hMem);

        LPBYTE lpData = (LPBYTE)GlobalLock(m_hMem);

        ar << wTemp;

        ar.Write(lpData,wTemp);

        pstm->Release();

        GlobalUnlock(m_hMem);

}

else

{

        DWORD wTemp;

        ar >> wTemp;

        HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, wTemp);

        if (m_hMem == NULL)

               return;

        IStream *pstm=NULL;

        CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);

        if (pstm==NULL)

               return;

        BYTE* pmem = (BYTE*)GlobalLock(m_hMem);

        ar.Read(pmem,wTemp);

        if (m_pImage) {

                       delete m_pImage;

                       m_pImage = NULL;

           }

        using namespace Gdiplus;

        m_pImage = Image::FromStream(pstm, FALSE);

        pstm->Release();

        GlobalUnlock(m_hMem);

        //注意此处不能加GlobalFree(m_hMem);否则图片显示不出来。

其中函数GetCodecClsid的实现代码如下:

int GetCodecClsid(const WCHAR* format, CLSID* pClsid)

{

   UINT  num = 0;          // number of image encoders

   UINT  size = 0;         // size of the image encoder array in bytes

   using namespace Gdiplus;

   ImageCodecInfo* pImageCodecInfo = NULL;

   GetImageEncodersSize(&num, &size);

   if(size == 0)

      return -1;  // Failure

   pImageCodecInfo = (ImageCodecInfo*)(malloc(size));

   if(pImageCodecInfo == NULL)

      return -1;  // Failure

   GetImageEncoders(num, size, pImageCodecInfo);

   for(UINT j = 0; j < num; ++j)

   {

      if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )

      {

         *pClsid = pImageCodecInfo[j].Clsid;

         return j;  // Success

      }   

   } // for

   return -1;  // Failure

} // GetCodecClsid

形参format用以说明图片数据的保存格式,可以取以下一些值:"image/bmp"(位图格式),"image/jpeg"JPEG格式),"image/gif"GIF格式)等。