- 使用GDI+在記憶體中轉換圖檔類型
- 作者:盧偉
- 微軟新推出的GDI+功能強大,本文僅對圖檔轉換加以讨論,不足之處請大家指出,本人QQ:394777271。
- 圖檔類型的轉換支援:bmp、dib、png、gif、jpeg/jpg、tiff、emf等。以下是詳細步驟。
- 首先,在StdAfx.h中靜态調用diplus.lib,即由編譯系統完成對DLL的加載,應用程式結束時解除安裝DLL的編碼。如下:
- #ifndef ULONG_PTR
- #define ULONG_PTR unsigned long*
- #include "GdiPlus.h"
- using namespace Gdiplus;
- #pragma comment(lib, "gdiplus.lib")
- #endif
- 在類的頭檔案中定義,以下成員變量,用來初始化GDI+的使用和結束使用。
- GdiplusStartupInput m_gdiplusStartupInput;
- ULONG_PTR m_gdiplusToken;
- 然後在OnCreate()函數中加入初始化GDI+的函數:
- GdiplusStartup(&m_gdiplusToken, &m_gdiplusStartupInput, NULL);
- 在OnDestroy()函數中加入結束GDI+使用的函數:
- GdiplusShutdown(m_gdiplusToken);
- 接着,定義轉換函數:
- BOOL MBmpToMImage(CMemFile& cbfBmp, CMemFile& cbfImage, CString strType)
- 其中:
- CMemFile& cbfBmp表示原位圖檔案;
- CMemFile& cbfImage表示轉換後的圖形檔案;
- CString strType表示轉換的圖檔類型。
- 該函數中主要的處理為以下幾步:
- 1. 将原位圖檔案轉換為IStream
- 2. 定義Image類執行個體,并使用第1步獲得的IStream初始化
- 3. 擷取轉換的圖檔類型的CLSID
- 4. 将Image以轉換的圖檔類型儲存到IStream中
- 5. 将IStream轉換為CMemFile記憶體檔案(也可為CFile)
- 詳細代碼如下:
- BOOL MBmpToMImage(CMemFile& cbfBmp, CMemFile& cbfImage, CString strType)
- {
- int iBmpSize = cbfBmp.GetLength();
- HGLOBAL hMemBmp = GlobalAlloc(GMEM_FIXED, iBmpSize);
- if (hMemBmp == NULL) return FALSE;
- IStream* pStmBmp = NULL;
- CreateStreamOnHGlobal(hMemBmp, FALSE, &pStmBmp);
- if (pStmBmp == NULL)
- {
- GlobalFree(hMemBmp);
- return FALSE;
- }
- BYTE* pbyBmp = (BYTE *)GlobalLock(hMemBmp);
- cbfBmp.SeekToBegin();
- cbfBmp.Read(pbyBmp, iBmpSize);
- Image* imImage = NULL;
- imImage = Image::FromStream(pStmBmp, FALSE);
- if (imImage == NULL)
- {
- GlobalUnlock(hMemBmp);
- GlobalFree(hMemBmp);
- return FALSE;
- }
- USES_CONVERSION;
- CLSID clImageClsid;
- GetImageCLSID(A2W("image/"+strType.GetBuffer(0)), &clImageClsid);
- HGLOBAL hMemImage = GlobalAlloc(GMEM_MOVEABLE, 0);
- if (hMemImage == NULL)
- {
- pStmBmp->Release();
- GlobalUnlock(hMemBmp);
- GlobalFree(hMemBmp);
- if (imImage != NULL) delete imImage;
- return FALSE;
- }
- IStream* pStmImage = NULL;
- CreateStreamOnHGlobal(hMemImage, TRUE, &pStmImage);
- if (pStmImage == NULL)
- {
- pStmBmp->Release();
- GlobalUnlock(hMemBmp);
- GlobalFree(hMemBmp);
- GlobalFree(hMemImage);
- if (imImage != NULL) delete imImage
- return FALSE;
- }
- imImage->Save(pStmImage, &clJpgClsid);
- if (pStmImage == NULL)
- {
- pStmBmp->Release();
- pStmImage>Release();
- GlobalUnlock(hMemBmp);
- GlobalFree(hMemBmp);
- GlobalFree(hMemImage;
- if (imImage != NULL) delete imImage;
- return FALSE;
- }
- LARGE_INTEGER liBegin = {0};
- pStmImage->Seek(liBegin, STREAM_SEEK_SET, NULL);
- BYTE* pbyImage = (BYTE *)GlobalLock(hMemImage);
- cbfImage.SeekToBegin();
- cbfImage.Write(pbyImage, GlobalSize(hMemImage));
- if (imImage != NULL) delete imImage;
- pStmBmp->Release();
- pStmImage->Release();
- GlobalUnlock(hMemBmp);
- GlobalUnlock(hMemImage);
- GlobalFree(hMemBmp);
- GlobalFree(hMemImage);
- return TRUE;
- }
- 最新評論 [發表評論] [文章投稿] 檢視所有評論 推薦給好友 列印
- 原文有許多筆誤,更正如下:
- 1、GetImageCLSID(A2W("image/"+strType.GetBuffer(0)), &clImageClsid);
- ——————————〉
- GetImageCLSID(A2W(("image/"+strType).GetBuffer(0)), &clImageClsid);
- 2、imImage->Save(pStmImage, &clJpgClsid);
- ——————————〉
- imImage->Save(pStmImage, &clImageClsid);
- 3、if (imImage != NULL) delete imImage
- ---------------------〉 少了分号
- if (imImage != NULL) delete imImage;
- 4、
- // GDI+
- #ifndef ULONG_PTR
- #define ULONG_PTR unsigned long*
- #include "GdiPlus.h"
- using namespace Gdiplus;
- #pragma comment(lib, "gdiplus.lib")
- #endif
- ---------------------->
- #ifndef ULONG_PTR
- #define ULONG_PTR unsigned long*
- #include "GdiPlus.h"
- using namespace Gdiplus;
- #pragma comment(lib, "gdiplus.lib")
- #include <atlconv.h>
- #endif
- 建議發文章的人,最好還是要調試一下,否則,會使讀者有些小麻煩。。。 :) ( Mycro 發表于 2005-2-2 11:19:00)
- To liutian_32:我現在需要做一個圖檔格式轉換的東東。請問是否可以加入gdiplus.dll這個庫後,你的代碼中的函數救可以直接調用了,因為SDK太大,沒法下載下傳。謝謝!急…… ( andyming 發表于 2004-9-30 10:51:00)
- 一年前我就已經用過了. ( 墨林 發表于 2004-8-31 19:39:00)
- 這個東西是platform sdk 中gdi+中的示例,通過在微軟的網站下在最新的SDK更新庫的幫助就可以得到. ( 墨林 發表于 2004-8-31 19:39:00)
- BOOL GetImageCLSID(const WCHAR* format, CLSID* pCLSID)
- {
- UINT num = 0;
- UINT size = 0;
- ImageCodecInfo* pImageCodecInfo = NULL;
- GetImageEncodersSize(&num, &size);
- if(size == 0){
- return FALSE;
- }
- pImageCodecInfo = (ImageCodecInfo *)(malloc(size));
- if(pImageCodecInfo == NULL)
- return FALSE;
- GetImageEncoders(num, size, pImageCodecInfo);
- // Find for the support of format for image in the windows
- for(UINT i = 0; i < num; ++i)
- {
- //MimeType: Depiction for the program image
- if( wcscmp(pImageCodecInfo[i].MimeType, format) == 0)
- {
- *pCLSID = pImageCodecInfo[i].Clsid;
- free(pImageCodecInfo);
- return TRUE;
- }
- }
- free(pImageCodecInfo);
- return FALSE;
- } ( luwei103 發表于 2004-7-23 13:02:00)
- GetEncoderClsid函數是MSDN裡提供的,需要加到你的工程裡 ( luwei103 發表于 2004-7-23 12:49:00)
- 為什麼我這裡說GetEncoderCLSID函數未定義呢?需要包含什麼頭檔案?在幫助上發現也沒包含什麼特别檔案呢 ( 村長大人 發表于 2004-7-22 10:45:00)
- 轉換圖檔類型當然簡單了,
- 但
- 1、你必須在你的工程中加入對GDI+的調用即釋放
- 2、這裡給出的是在記憶體中實作轉換,MSDN中給的例子是
- 通過在硬碟上儲存實作的轉換,在記憶體中相比在硬碟 上實作轉換,效率誰都知道把。如果僅僅是實作圖檔類型的轉換MSDN上面有,誰還會拿來發表阿
- 3、相關的Demo我會近期在網站上釋出。 ( luwei103 發表于 2004-7-19 11:20:00)
- 更正:
- GetEncoderClsid(L"image/jpeg", &pngClsid);//這裡的圖檔可以是其它格式
- 應改為:GetEncoderClsid(L"image/bmp", &pngClsid) ( liutian_32 發表于 2004-7-16 14:56:00)
- 如果使用GDI+的話,應該沒有那麼麻煩吧,
- void CMyDlg::OnLButtonDown(UINT nFlags, CPoint point)
- {
- // TODO: 在此添加消息處理程式代碼和/或調用預設值
- Image img(L"d://12.jpg");//這裡的圖檔可以是其它格式
- CLSID pngClsid;
- GetEncoderClsid(L"image/jpeg", &pngClsid);//這裡的圖檔可以是其它格式
- ,此處轉化為BMP格式
- img.Save(L"d://12_0.bmp", &pngClsid, NULL);
- CDialog::OnLButtonDown(nFlags, point);
- }
- GetEncoderClsid函數是MSDN裡提供的,需要加到你的工程裡,真正你要寫的隻有滑鼠事件中的4行代碼,根本不要那麼複雜 ( liutian_32 發表于 2004-7-16 14:55:00)