ybdesire@gmail.com
在 VC++6.0 中将 JPG 格式图片转换成 BMP 格式
思路:利用 GDI+来完成
难点: (1)配置 GDI 开发环境,添加配置代码
(2)在当文档程序中添加转换代码
注意:本文档由 ybdesire 参考网上资料撰写完成,代码已经做过测试,可直接复制张贴
实现过程:
一、 配置 GDI 开发环境
(1) 下载 GDI+ SDK for Visual C++ 6.0
http://www.codeguru.com/code/legacy/gdi/GDIPlus.zip
下载的 GDIPlus 文件夹中有 Includes,Lib 文件夹和 gdiplus.dll 文件。
将 Includes 和 Lib 中的文件分别拷到 VC6 安装目录中的 VC98\include 和 lib 文
件夹中;新建 MFC 项目后,才使用 gdiplus.dll,到时候将它拷到对应工程的 debug
文件夹下。
(2) 新建 MFC 单文档应用程序 show:
1、在 StdAfx.h 中添加如下代码
#include
#define ULONG_PTR ULONG
#include
using namespace Gdiplus;
#pragma comment(lib, "gdiplus.lib")
2、如(1)中所说,将 gdiplus.dll 拷贝到本工程的 Debug 或 Release 目
录下
3、在 show.h 中的 class CShowApp : public CWinApp 中添加
private:
GdiplusStartupInput m_gdiplusStartupInput;
ULONG_PTR m_pGdiToken;
4、在 show.cpp 中的 BOOL CShowApp::InitInstance()中添加
GdiplusStartup(&m_pGdiToken,&m_gdiplusStartupInput,NULL);
5、为 CShowApp 添加名字为 ExitInstance 的虚函数的,并在 ExitInstance
中添加如下退出 GDI+的代码
GdiplusShutdown(m_pGdiToken);
1
ybdesire@gmail.com
return CWinApp::ExitInstance();
(3) 测试 GDI+是否配置成功
void CShowView::OnDraw(CDC* pDC)
{
CShowDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
Graphics graphics(pDC->m_hDC);
Pen pen(Color(255, 0, 255));
graphics.DrawLine(&pen, 0, 0, 200, 100);
}
若能成功运行,表明 GDI+配置成功
二、 添加转换代码,实现将打开的 JPG 格式文件保存成 BMP 格式文件
(1)在 CSshowView 中添加如下成员变量
CString strOpenFileName;
(2)在 CSshowView 中添加如下成员函数
1、在 CSshowView 中添加 ToWChar 函数
WCHAR* CShowView::ToWChar(char *str)
//在 GDI+中,有关字符的参数类型全部都是 WCHAR 类型的
//该函数是将传统字符串进行转换
static WCHAR buffer[1024];
wcsset(buffer,0);
MultiByteToWideChar(CP_ACP,0,str,strlen(str),buffer,1024);
return buffer;
{
}
2、在 CSshowView 中添加 GetImageCLSID 函数
int CShowView::GetImageCLSID(const WCHAR *format, CLSID *pCLSID)
{
UINT num=0;
UINT size=0;
ImageCodecInfo* pImageCodecInfo=NULL;
GetImageEncodersSize(&num,&size);
if(size==0)
2
ybdesire@gmail.com
return FALSE; // 编码信息不可用
// 分配内存
pImageCodecInfo=(ImageCodecInfo*)(malloc(size));
if(pImageCodecInfo==NULL)
return FALSE; // 分配失败
// 获得系统中可用的编码方式的所有信息
GetImageEncoders(num,size,pImageCodecInfo);
// 在可用编码信息中查找 format 格式是否被支持
for(UINT i=0;iInvalidate() ;
3
ybdesire@gmail.com
4、在 MFC ClassWixard 中重载 OnFileSave()
void CShowView::OnFileSave()
{
if( strOpenFileName.IsEmpty() )
{
}
AfxMessageBox("当前没有打开图像文件, 不能进行保存!");
return;
// 建立图形对象
Graphics graphics(GetDC()->m_hDC);
// 装入当前已经打开的图像文件
Image
image(ToWChar(strOpenFileName.GetBuffer(strOpenFileName.GetLength() ))
);
CString strFileSave;
// 将其他格式的图像全部另存为 BMP 文件
static char szFilter[ ]= "位图(*.BMP)|*.BMP|";
CFileDialog
dlgChoseImage(0,"BMP",strOpenFileName,NULL,szFilter);
if(dlgChoseImage.DoModal() ==IDOK)
{
strFileSave=dlgChoseImage.GetPathName();
CLSID clsid;
if(GetImageCLSID(L"image/bmp", &clsid))
{
image.Save(ToWChar(strFileSave.GetBuffer(strFileSave.GetLength() ))
, &clsid, NULL);
// 将保存后的图像进行显示
strOpenFileName=strFileSave;
this->Invalidate() ;
}
}
}
4
ybdesire@gmail.com
参考资料
[1]http://blog.csdn.net/poonjun/archive/2009/01/04/3701724.aspx
[2]http://www.cnblogs.com/DavidHu/articles/1191635.html
[3]http://www.smth.edu.cn/bbsgcon.php?board=VisualC&num=785
[4]《图像格式转换在数字仪表识别系统中的应用》 刘 娜, 汪仁煌, 庞 然
/*-------------------------------------------------------------*/
扩展知识阅读
[3] 色彩鲜艳漂亮的高品质图像,一个个形象的 Windows 图标,高速运动、活灵活现的三维
动画,这些生动的图形无一不显示着程序设计者的艺术才华。在程序设计中,图像处理
已经成了每个程序员的必修课,所以,对于每个程序员来说,熟悉“BMP”、“GIF”、
“JPEG”图像格式及具体应用、调色板、图像文件头格式、图像压缩算法等概念似乎已
经成了工作中不可缺少的基础知识。面对如此多的图像格式,如果要全部掌握其具体细
节,好像这对程序员有些不公。在 VC 中编程显示一幅位图,下列的步骤是不可少的:装
入位图、获得位图的大小信息、启用设备环境、位传输,所需的程序代码显得千篇一律
的冗长。如果想要装入的位图另存为其他格式的图像文件……?两个字:头疼!而这一
切都是因为 GDI 本身的局限性所造成。
随着 Windows 2000 的推出,上面的情况有了大大的改观:你可以不必了解每种图像格式
的具体含义,照样可以写出多格式图像浏览或转换程序,这一切,全部都依赖于 Window
s 2000 及后继版中所使用的 GDI+技术。首先来看看 GDI+的具体技术细节及 GDI+编程
特点。
Windows 2000 在用户界面方面包括了几个重大的改进,可能你已经注意到了有阴影的鼠
标、渐入的工具条快速提示、透明的窗口、平滑地窗口变化等。Windows
之所以有这么大的改进,完全是因为 Windows2000 采用了一种 GDI(graphics device in
terface :图形设备接口)。这种 GDI,以前叫 GDI2k,现在有了一个更好听的名字:GD
I+。GDI+是一种新型的图形设备接口,它的主要特点在于它能够创建全新的用户桌面
体系、能够轻易地完成二维或三维的图形处理,为桌面带来一种数字化的图片。 GDI+
同时也提供了增强的图形处理技术,如常见的:alpha blending、 纹理、贴图、增强的
文本及图片显示技术。实际上,GDI+主要的特色就在于强调通过硬件加速来达到良好的
2000 在界面上
视觉感受!
同传统的 GDI 不同,GDI+中引入了对 COM(组件对象模型)技术的支持,通过 COM 技术,
GDI+简化了对图像文件的访问(打开、保存)程序:通过调用 COM 组件来实现的,GDI+
扮演的只是指挥者,而非操作员。对于图像文件,GDI+所关心的不是图像文件的文件头
信息,不论欲打开的文件格式是什么类型,GDI+首先要做的是在注册中查看该图像格式
的编码(或解码)信息是否已经注册(HKEY_CLASSES_ROOT\MIME\Database\Content Ty
pe),如果已经注册,就通过该编码信息调用 COM 组件,就这么简单。这种技术其实早就
5
ybdesire@gmail.com
在微软的其他软件中已经使用了,如 IE。“体验”过 NIMDA 病毒的朋友可能对“audio/w
av”这段代码并不陌生,NIMDA 就是靠它来伪装自己的:让 IE 认为附件是 WAV 文件而自动
打开可执行程序。这其实也是 IE 使用 COM 技术的一个突出表现。
配合 GDI+的推出,微软也同时发布了相应的 SDK,如果你已经安装了最新的 Microsoft
PlatForm SDK 或已经开始使用 VS .NET,GDI+ SDK 已经在你的系统中了。如果没有的话
,可以到 http://noner.top263.net/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@gmail.com
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@gmail.com
}
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(dlgChoseImage.DoModal()==IDOK)
{
strOpenFileName=dlgChoseImage.GetPathName();
//打开文件后立即在窗口中显示(重绘客户窗口)
this->Invalidate();
}
}
void CImageShowView::OnFileSaveAs()
8