2024年1月15日发(作者:)
ybdesire@
在VC++6.0中将JPG格式图片转换成BMP格式
思路:利用GDI+来完成
难点: (1)配置GDI开发环境,添加配置代码
(2)在当文档程序中添加转换代码
注意:本文档由ybdesire参考网上资料撰写完成,代码已经做过测试,可直接复制张贴
实现过程:
一、 配置GDI开发环境
(1) 下载GDI+ SDK for Visual C++ 6.0
/code/legacy/gdi/
下载的GDIPlus文件夹中有Includes,Lib文件夹和文件。
将Includes和Lib中的文件分别拷到VC6安装目录中的VC98include和lib文件夹中;新建MFC项目后,才使用,到时候将它拷到对应工程的debug文件夹下。
(2) 新建MFC单文档应用程序show:
1、在StdAfx.h 中添加如下代码
#include
#define ULONG_PTR ULONG
#include
using namespace Gdiplus;
#pragma comment(lib, "")
2、如(1)中所说,将拷贝到本工程的Debug或Release目录下
3、在show.h中的class CShowApp : public CWinApp中添加
private:
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_pGdiToken;
4、在中的BOOL CShowApp::InitInstance()中添加
GdiplusStartup(&m_pGdiToken,&m_gdiplusStartupInput,NULL);
5、为CShowApp添加名字为ExitInstance的虚函数的,并在ExitInstance中添加如下退出GDI+的代码
GdiplusShutdown(m_pGdiToken);
1
ybdesire@
return CWinApp::ExitInstance();
(3) 测试GDI+是否配置成功
void CShowView::OnDraw(CDC* pDC)
{
}
若能成功运行,表明GDI+配置成功
CShowDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
Graphics graphics(pDC->m_hDC);
Pen pen(Color(255, 0, 255));
ne(&pen, 0, 0, 200, 100);
二、 添加转换代码,实现将打开的JPG格式文件保存成BMP格式文件
(1)在CSshowView中添加如下成员变量
{
}
{
UINT num=0;
UINT size=0;
ImageCodecInfo* pImageCodecInfo=NULL;
GetImageEncodersSize(&num,&size);
if(size==0)
2、在CSshowView中添加GetImageCLSID函数
int CShowView::GetImageCLSID(const WCHAR *format, CLSID *pCLSID)
//在GDI+中,有关字符的参数类型全部都是WCHAR类型的
//该函数是将传统字符串进行转换
static WCHAR buffer[1024];
wcsset(buffer,0);
MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,1024);
return buffer;
CString strOpenFileName;
1、在CSshowView中添加ToWChar函数
(2)在CSshowView中添加如下成员函数
WCHAR* CShowView::ToWChar(char *str)
2
ybdesire@
return FALSE; // 编码信息不可用
// 分配内存
pImageCodecInfo=(ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo==NULL)
return FALSE; // 分配失败
// 获得系统中可用的编码方式的所有信息
GetImageEncoders(num,size,pImageCodecInfo);
// 在可用编码信息中查找 format 格式是否被支持
for(UINT i=0;i { //MimeType: 编码方式的具体描述 if (wcscmp(pImageCodecInfo[ i] .MimeType,format)==0) { *pCLSID=pImageCodecInfo[i].Clsid; free(pImageCodecInfo); return TRUE; } } free(pImageCodecInfo); return FALSE; } 3、在MFC ClassWixard中重载OnFileOpen() void CShowView::OnFileOpen() { static char szFilter[ ]="常见图像格式文件(*.*)|*.*|"; CFileDialog dlgChoseImage(1,NULL,NULL,NULL,szFilter); if(l() ==IDOK) { strOpenFileName=hName(); // 打开文件后立即在窗口中显示 (重绘客户窗口) this->Invalidate() ; } } 3 ybdesire@ { )); CString strFileSave; // 将其他格式的图像全部另存为 BMP 文件 static char szFilter[ ]= "位图(*.BMP)|*.BMP|"; CFileDialog if(l() ==IDOK) { strFileSave=hName(); CLSID clsid; if(GetImageCLSID(L"image/bmp", &clsid)) { if( y() ) { } // 建立图形对象 Graphics graphics(GetDC()->m_hDC); // 装入当前已经打开的图像文件 Image AfxMessageBox("当前没有打开图像文件, 不能进行保存!"); return; 4、在MFC ClassWixard中重载OnFileSave() void CShowView::OnFileSave() image(ToWChar(fer(gth() )dlgChoseImage(0,"BMP",strOpenFileName,NULL,szFilter); (ToWChar(fer(gth() } } // 将保存后的图像进行显示 strOpenFileName=strFileSave; this->Invalidate() ; )), &clsid, NULL); } 4 ybdesire@ 参考资料 [1]/poonjun/archive/2009/01/04/ [2]/DavidHu/articles/ [3]/?board=VisualC&num=785 [4]《图像格式转换在数字仪表识别系统中的应用》 刘 娜, 汪仁煌, 庞 然 /*-------------------------------------------------------------*/ 扩展知识阅读 [3] 色彩鲜艳漂亮的高品质图像,一个个形象的Windows图标,高速运动、活灵活现的三维 动画,这些生动的图形无一不显示着程序设计者的艺术才华。在程序设计中,图像处理 已经成了每个程序员的必修课,所以,对于每个程序员来说,熟悉“BMP”、“GIF”、 “JPEG”图像格式及具体应用、调色板、图像文件头格式、图像压缩算法等概念似乎已 经成了工作中不可缺少的基础知识。面对如此多的图像格式,如果要全部掌握其具体细 节,好像这对程序员有些不公。在VC中编程显示一幅位图,下列的步骤是不可少的:装 入位图、获得位图的大小信息、启用设备环境、位传输,所需的程序代码显得千篇一律 的冗长。如果想要装入的位图另存为其他格式的图像文件……?两个字:头疼!而这一 切都是因为GDI本身的局限性所造成。 随着Windows 2000的推出,上面的情况有了大大的改观:你可以不必了解每种图像格式 的具体含义,照样可以写出多格式图像浏览或转换程序,这一切,全部都依赖于Window s 2000及后继版中所使用的GDI+技术。首先来看看GDI+的具体技术细节及GDI+编程 特点。 Windows 2000在用户界面方面包括了几个重大的改进,可能你已经注意到了有阴影的鼠 标、渐入的工具条快速提示、透明的窗口、平滑地窗口变化等。Windows 2000在界面上 之所以有这么大的改进,完全是因为Windows2000采用了一种GDI(graphics device in terface :图形设备接口)。这种GDI,以前叫GDI2k,现在有了一个更好听的名字:GD I+。GDI+是一种新型的图形设备接口,它的主要特点在于它能够创建全新的用户桌面 体系、能够轻易地完成二维或三维的图形处理,为桌面带来一种数字化的图片。 GDI+ 同时也提供了增强的图形处理技术,如常见的:alpha blending、 纹理、贴图、增强的 文本及图片显示技术。实际上,GDI+主要的特色就在于强调通过硬件加速来达到良好的 视觉感受! 同传统的GDI不同,GDI+中引入了对COM(组件对象模型)技术的支持,通过COM技术, GDI+简化了对图像文件的访问(打开、保存)程序:通过调用COM组件来实现的,GDI+ 扮演的只是指挥者,而非操作员。对于图像文件,GDI+所关心的不是图像文件的文件头 信息,不论欲打开的文件格式是什么类型,GDI+首先要做的是在注册中查看该图像格式 的编码(或解码)信息是否已经注册(HKEY_CLASSES_ROOTMIMEDatabaseContent Ty pe),如果已经注册,就通过该编码信息调用COM组件,就这么简单。这种技术其实早就 5 ybdesire@ 在微软的其他软件中已经使用了,如IE。“体验”过NIMDA病毒的朋友可能对“audio/w av”这段代码并不陌生,NIMDA就是靠它来伪装自己的:让IE认为附件是WAV文件而自动 打开可执行程序。这其实也是IE使用COM技术的一个突出表现。 配合GDI+的推出,微软也同时发布了相应的SDK,如果你已经安装了最新的Microsoft PlatForm SDK或已经开始使用VS .NET,GDI+ SDK已经在你的系统中了。如果没有的话 ,可以到/progtool上去下载GDI+的头文件和库文件。在使用 GDI+之后,, 再有没有必要去考虑什么句柄、设备环境这样的概念了。你只需要简单地 创建一个图形对象(Graphics object),然后直接调用该对象的方法(methods)进行 绘图即可。图形对象是GDI+中核心,正如DC之于GDI那样。图形对象和DC有许多相似的 地方,在使用上遵循着相同的使用规则,但是两者在本质上已经有很大的区别。一个是 基于句柄的GDI,一个是基于组件对象模型的GDI+。使用GDI+的SDK编程,必须得按照下 面的规范来进行:使用GDI+的名空间(namespace Gdiplus)、在使用GDI+函数时必须 进行GDI+的初始化,使用完毕之后也得销毁GDI+,这种规范在下面所列的程序中有详 细的说明。 前面说到了GDI+是通过在注册中查看编码信息来访问图像文件的,在GDI+的SDK中,编 码信息是储存在 ImageCodecInfo类中的,在这个类中,有编码的CLSID(COM组件的GUI D标识码)、编码方式描述等。在GDI中,在注册表中访问编码信息通常使用以下两个函 数来实现: 1、查看系统中可用的图像编码信息(数量及大小) Status GetImageEncodersSize( UINT* numEncoders, //存储编码器数量的地址 UINT* size //存储编码信息所需内存大小 ); 2、得到所有的编码信息 Status GetImageEncoders( UINT numEncoders,//可用编码器数量 UINT size,//储存编码器信息所需内存(由ImageCodecInfo类组成的数组的大小) ImageCodecInfo* encoders//编码器信息指针 ); 在GetImageEncoders函数中,参数numEncoders和size都是由GetImageEncodersSize所返 回的。下面的代码就能够在注册表中查找具体格式图像的编码方式: int GetImageCLSID(const WCHAR* format, CLSID* pCLSID) {//得到格式为format的图像文件的编码值,访问该格式图像的COM组件的 //GUID值保存在pCLSID中 UINT num = 0; 6 ybdesire@ 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); //在可用编码信息中查找format格式是否被支持 for(UINT i = 0; i < num; ++i) { //MimeType:编码方式的具体描述 if( wcscmp(pImageCodecInfo[i].MimeType, format) == 0 ) { *pCLSID = pImageCodecInfo[i].Clsid; free(pImageCodecInfo); return TRUE; } } free(pImageCodecInfo); return FALSE; } 有了这种认识,实现多格式的图像的浏览与转换就并不是什么难事了。为了讲述的方便 ,首先在VC中建立一个SDI项目ImageShow,首先对使用GDI+申明和初始化及销毁进行代 码编制,具体代码如下: #include "Gdiplus.h" using namespace Gdiplus; CImageShowView::CImageShowView() { //初始化GDI+ GdiplusStartupInput gdiplusStartupInput; ULONG_PTR gdiplusToken; GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL); 7 ybdesire@ } CImageShowView::~CImageShowView() { //销毁GDI+ ULONG_PTR gdiplusToken; GdiplusShutdown(gdiplusToken); } 接着通过类向导(Class Wizard),重载“文件”菜单中的“打开”和“另存为”两项, 为了编程的简单,本程序只将当前打开的图像文件直接存为BMP文件(实际上保存成其他格式的文件也很简单,只不过是对文件名进行分析而已)。另外,为了在打开和保存文 件进行文件名的传递,首先应在CImageShowView类中加入一全局变量“CString strOpe nFileName”。“打开”和“另存为”两项的响应代码如下,大家通过代码中的注释部份 理解编程思路,应该不会有什么问题: WCHAR* ToWChar(char * str) { //在GDI+中,有关字符的参数类型全部都是WCHAR类型的 //该函数是将传统字符串进行转换 static WCHAR buffer[1024]; wcsset(buffer,0); MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,1024); return buffer; } void CImageShowView::OnFileOpen() { //本程序能够打开各类常见格式的图像文件 static char szFilter[]="常见格式图形文件(*.*)|*.*|"; CFileDialog dlgChoseImage(1,NULL,NULL,NULL,szFilter); if(l()==IDOK) { strOpenFileName=hName(); //打开文件后立即在窗口中显示(重绘客户窗口) this->Invalidate(); } } void CImageShowView::OnFileSaveAs() 8 ybdesire@ { if(y()) { AfxMessageBox("当前没有打开图像文件,不能进行保存!"); return; } //建立图形对像 Graphics graphics(GetDC()->m_hDC); //装入当前已经打开的图形文件 Image image(ToWChar(fer(gth()))) ; CString strFileSave; //当其他格式的图像全部另存为BMP文件 static char szFilter[]="位图(*.BMP)|*.BMP|"; CFileDialog dlgChoseImage(0,"BMP",NULL,NULL,szFilter); if(l()==IDOK) { strFileSave=hName(); CLSID clsid; if(GetImageCLSID(L"image/bmp", &clsid)) { (ToWChar(fer(gth())), &clsid, NULL); //将保存后的图像进行显示 strOpenFileName=strFileSave; this->Invalidate(); } } } 最后,为了显示浏览图像转换前后的效果,还应该在窗口中分另绘制转换前后的图像,这很容易,只需要在OnDraw函数中添加绘制代码,如下所述: void CImageShowView::OnDraw(CDC* pDC) { CImageShowDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); 9 ybdesire@ //如果没有选择显示图形文件,则不用重绘 if(y()) return; //显示当前打开的图像文件的全名 this->GetParent()->SetWindowText(strOpenFileName); //建立图形对象 Graphics graphics(pDC->m_hDC); //装入图形文件 Image image(ToWChar(fer(gth()))) ; Point destPoints[3] = { Point(0, 0), Point(th(), 0), Point(0, ght()) }; Point* pdestPoints = destPoints; //在指定区域pdestPoints显示图像 age(&image, pdestPoints, 3); } 在编译上面的程序之前,应该将文件连编到项目中去,否则将会出现“LIN K 2001”编译错误。该程序在Visual Studio 6.0、Windows2000/XP下调试通过,它能 够显示或转换的图像格式有BMP、GIF、JPEG 、Exif 、PNG 、TIFF 、ICON、WMF 、EMF 等等。需要说明的是,本文只就GDI+编程的基本原理进行阐述,其实,GDI+的应用远 不止于此。在GDI+的背后,有你意想不到的惊奇! 瞧,这程序运行起来是不是有些象ACDSee之类的图像浏览程序?如果对本程序进行些改 进,你也以做出功能更加强劲的图像处理程序。本文中所提到的程序,在我的主页“国 税之家”()的“个人世界”中可以下下载到 。有关GDI+的编程序帮助信息,大家可以到微软的MSDN网站去查阅。如果你有Visual Studio .NET,这就最好,因为所附的MSDN for Visual 7.0中有GDI+编程 所需的全部信息 10


发布评论