- 使用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)