最近做了一个程序要实现在网络中传输图片,这就必须要将图片文件转化为相应的数据,通过几番查找找到了一个方法。以下一一说来。
先说下基本的实现原理,我用到了GDI+的Image类,用它来从磁盘或资源中加载图片,然后将Image转化为IStream ,最后将IStream转化为内存数据LPVOID。从内存数据转化为Image的过程正好相反,先将LPVOID转化为IStream,再从IStream构建Image,并最终显示出来。
以下为所用到的函数,做了一下封装:
- inline int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);
- inline BOOL Mem2Hglobal(LPVOID lpBuf, HGLOBAL hGlobal, UINT nSize);
- inline BOOL Stream2Mem(IStream* pstream, void **pOutbuf, UINT* pSize);
- inline Image* ImageFromMem(LPVOID lpdata, UINT nSize);
- inline LPVOID Image2Mem(Image* pImage, void** pOutbuf, UINT *pSize, LPCTSTR lpEncoder = _T("p_w_picpath/png"));
- BOOL Mem2Hglobal(LPVOID lpBuf, HGLOBAL hGlobal, UINT nSize)
- {
- LPVOID lpDest = GlobalLock(hGlobal);
- if(lpDest == NULL)
- {
- return FALSE;
- }
- memcpy(lpDest, lpBuf, nSize);
- GlobalUnlock(hGlobal);
- return TRUE;
- }
- BOOL Stream2Mem(IStream* pstream, void **pOutbuf, UINT* pSize)
- {
- ULARGE_INTEGER ulnSize;
- LARGE_INTEGER lnOffset;
- lnOffset.QuadPart = 0;
- if(pstream->Seek(lnOffset, STREAM_SEEK_END, &ulnSize) != S_OK)
- {
- return FALSE;
- }
- if(pstream->Seek(lnOffset, STREAM_SEEK_SET, NULL) != S_OK)
- {
- return FALSE;
- }
- *pOutbuf = malloc((size_t)ulnSize.QuadPart);
- *pSize = (UINT) ulnSize.QuadPart;
- ULONG bytesRead;
- if(pstream->Read(*pOutbuf, (ULONG)ulnSize.QuadPart, &bytesRead ) != S_OK )
- {
- free(*pOutbuf);
- return FALSE;
- }
- return TRUE;
- }
- LPVOID Image2Mem(Image* pImage, void** pOutbuf, UINT *pSize, LPCTSTR lpEncoder)
- {
- IStream *pstream = NULL;
- if( ::CreateStreamOnHGlobal( NULL, TRUE, &pstream ) != S_OK )
- {
- return NULL;
- }
- CLSID jpgClsid;
- GetEncoderClsid(lpEncoder, &jpgClsid);
- Status state = pImage->Save(pstream, &jpgClsid);
- if( state != Gdiplus::Ok )
- {
- pstream->Release();
- return NULL;
- }
- if(!Stream2Mem(pstream, pOutbuf, pSize))
- {
- pstream->Release();
- return NULL;
- }
- return *pOutbuf;
- }
- Image* ImageFromMem(LPVOID lpdata, UINT nSize)
- {
- IStream *pstream = NULL;
- HGLOBAL m_hGlobal = ::GlobalAlloc(GMEM_MOVEABLE, nSize);
- if(m_hGlobal == NULL)
- {
- return NULL;
- }
- if(!Mem2Hglobal(lpdata, m_hGlobal, nSize))
- {
- ::GlobalFree(m_hGlobal);
- m_hGlobal = NULL;
- return NULL;
- }
- if(::CreateStreamOnHGlobal(m_hGlobal, TRUE, &pstream) != S_OK)
- {
- ::GlobalFree(m_hGlobal);
- m_hGlobal = NULL;
- return NULL;
- }
- Image *pImage = Image::FromStream(pstream);
- pstream->Release();
- return pImage;
- }
- int GetEncoderClsid(const WCHAR* format, CLSID* pClsid)
- {
- UINT num = 0;
- UINT size = 0;
- ImageCodecInfo* pImageCodecInfo = NULL;
- GetImageEncodersSize(&num, &size);
- if(size == 0)
- {
- return -1;
- }
- pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
- if(pImageCodecInfo == NULL)
- {
- return -1;
- }
- GetImageEncoders(num, size, pImageCodecInfo);
- for(UINT j = 0; j < num; ++j)
- {
- if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 )
- {
- *pClsid = pImageCodecInfo[j].Clsid;
- free(pImageCodecInfo);
- return j;
- }
- }
- free(pImageCodecInfo);
- return -1;
- }
- //从Image转化为LPVOID,调用
- LPVOID Image2Mem(Image* pImage, void** pOutbuf, UINT *pSize, LPCTSTR lpEncoder = _T("p_w_picpath/png"));
- //从LPVOID构建Image,调用
- Image* ImageFromMem(LPVOID lpdata, UINT nSize);
完。