色彩鲜艳漂亮的高品质图像,一个个形象生动的Windows图标,高速运动、活灵活现的三维动画,这些无一不显示出程序设计者的艺术才华。在程序设计中,图像处理已经成为每个程序员的必修课。

在VC中编程显示一幅位图,下列步骤是不可缺少的: 装入位图、获得位图的大小信息、启用设备环境、位传输等,所需的程序代码一般比较冗长而且复杂。如果想将装入的位图另存为其他格式的图像文件,代码就更长了。这一切都是因为GDI本身的局限性造成的。

GDI+技术

随着Windows 2000的推出,上述情况有了极大的改观: 程序员不必了解每种图像格式的具体含义,照样可以写出多格式图像浏览或转换程序,这一切全都依赖于Windows 2000及后继版中所使用的GDI+技术。

和传统的GDI不同,GDI+中引入了对COM(组件对象模型)技术的支持,通过COM技术,GDI+简化了对图像文件的访问(打开、保存)。它是通过调用COM组件来实现的,GDI+扮演的只是指挥者,而非操作员。对于图像文件,GDI+所关心的不是图像文件的文件头信息,不论要打开的文件格式是什么类型,GDI+首先要做的是在注册表中查看该图像格式的编码(或解码)信息是否已经注册(HKEY_CLASSES_ROOT\MIME\Database\Content Type)。如果已经注册,就通过该编码信息调用COM组件,就这么简单。这种技术早就在微软的其他软件中使用了(如IE)。“体验”过Nimda病毒的朋友可能对“audio/wav”这段代码并不陌生,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组件的GUID标识码)、编码方式描述等。对于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;

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;

}

实现多格式的图像浏览和转换

有了前面的知识,实现多格式的图像的浏览与转换就不是什么难事了。

1.在VC中创建一个SDI项目ImageShow,对GDI+声明和初始化及销毁进行代码编制,具体代码如下:

#i nclude “Gdiplus.h”

using namespace Gdiplus;

CImageShowView::CImageShowView()

{

//初始化GDI+

GdiplusStartupInput gdiplusStartupInput;

ULONG_PTR gdiplusToken;

GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

}

CImageShowView::~CImageShowView()

{

//销毁GDI+

ULONG_PTR gdiplusToken;

GdiplusShutdown(gdiplusToken);

}

2. 通过类向导(Class Wizard),重载“文件”菜单中的“打开”和“另存为”两项。为了编程的简单,本程序只将当前打开的图像文件直接存为BMP文件(实际上保存为其他格式的文件也很简单,只不过是对文件名进行分析而已)。另外,为了在打开和保存文件时进行文件名的传递,还应在CImageShowView类中加入一全局变量“CString strOpenFileName”。“打开”和“另存为”两菜单的对应代码如下:

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()

{

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”,NULL,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();

}

}

}

3.为了浏览图像转换前后的效果,还应该在窗口中分别绘制转换前后的图像,这需要在OnDraw函数中添加绘制代码,如下所示:

void CImageShowView::OnDraw(CDC* pDC)

{

CImageShowDoc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

//如果没有选择显示图像文件,则不用重绘

if(strOpenFileName.IsEmpty())

return;

//显示当前打开的图像文件的全名

this->GetParent()->SetWindowText(strOpenFileName);

//建立图像对象

Graphics graphics(pDC->m_hDC);

//装入图形文件

Image image(ToWChar(strOpenFileName.GetBuffer(strOpenFileName.GetLength())));

Point destPoints[3] =

{

Point(0, 0),

Point(image.GetWidth(), 0),

Point(0, image.GetHeight())

};

Point* pdestPoints = destPoints;

//在指定区域pdestPoints显示图像

graphics.DrawImage(&image, pdestPoints, 3);

}

在编译上面的程序之前,应该将Gdiplus.lib文件连编到项目中去,否则将会出现“LINK 2001”编译错误。上述程序在Visual Studio 6.0、Windows 2000/XP下调试通过,它能够显示或转换的图像格式有BMP、GIF、JPEG、Exif、PNG、TIFF、ICON、WMF、EMF等等。需要说明的是,本文只就GDI+编程的基本原理进行了阐述,事实上,GDI+的应用远不止此。

结束语

如果对本程序进行些改进,还可以编制出功能更加强大的图像处理程序。本文中所提到的程序,在笔者的主页“国税之家”([url]http://nationaltax.home.chinaren.com[/url])的“个人世界”中可以下载到。有关GDI+编程的帮助信息,大家可以到微软的MSDN网站去查阅。

本文转自 张宇 51CTO博客,原文链接:http://blog.51cto.com/zhangyu/33872,如需转载请自行联系原作者

VC实现多格式图像的转换相关推荐

  1. opencv——PNG格式图像读取转换函数

    暑假培训学习了opencv,放图像时,PNG格式的Alpha通道没用啊图都自己去p颜色,用来加载时变颜色 工作量太大了,,于是花了一下午弄了个简易功能的PNG格式文件读取转化加载函数. 注:这里主要是 ...

  2. 基于C++的 将BMP位图转换成JPG格式图像

    VC++ 将BMP位图转换成JPG格式图像,源码中同时包括了自定义控件的源码. 项目源代码: 操作步骤:运行程序前,首先将源程序附带的"JPGXControl1.ocx"文件拷贝到 ...

  3. LabVIEW读写各类格式图像的方法(基础篇—1)

    目录 1.读写各类格式图像的方法 1.1.LabVIEW集成图像读写函数 1.2.Nl Vision图像读写函数 2.小试牛刀 图像数据被采集至内存缓冲区后,机器视觉软件即可对其施加各种图像预处理.图 ...

  4. PS 图像尺寸|点阵格式图像|矢量格式图像|图像格式的选择

    一.图像尺寸 像素作为图像的一种尺寸,只存在于电脑中,如同RGB色彩模式一样只存在于电脑中. 像素是一种虚拟的单位,现实生活中是没有像素这个单位的. 传统长度单位:毫米.厘米.分米.米.公里.光年. ...

  5. 使用C++实现YUV格式图像与RGB格式图像之间相互转换

    使用C++实现YUV格式图像与RGB格式图像之间相互转换 一.RGB与YUV转换公式 1.RGB转YUV 1)RGB转换亮度与色差信号公试: 2)归一化为YUV的转化公试为: 2.YUV转RGB 二. ...

  6. YUV / RGB 格式及快速转换

    YUV是指亮度参量和色度参量分开表示的像素格式,而这样分开的好处就是不但可以避免相互干扰,还可以降低色度的采样率而不会对图像质量影响太大. YUV是一个比较笼统地说法,针对它的具体排列方式,可以分为很 ...

  7. 全网最详细 Python如何读取NIFTI格式图像(.nii文件)和 .npy格式文件和pkl标签文件内容

    在医学图像处理中,我们经常使用一种NIFTI格式图像(.nii文件),现在我们来看看 什么是.nii文件? 该如何读取.nii文件? 1. NIFTI格式图像 什么是NIFTI(Neuroimagin ...

  8. videocapture 保存图片_RoboMaster视觉教程OpenCV(二)读取视频图像与转换

    RoboMaster视觉教程OpenCV(二)读取视频图像与转换 在Robomaster比赛中,读取视频或者图像是极其重要的.因为我们需要在热身赛的时候用摄像头保存一段视频或者图片.之后根据视频中的光 ...

  9. 解码(五):sws_getContext和sws_scale像素格式和尺寸转换函数详解

    视频像素格式和尺寸转换 sws_getContext(像素格式转换上下文),提供了两个函数 sws_getContext像素格式上下文初始化代码演示 如下代码: //表示是视频if (cc == vc ...

最新文章

  1. 做动态图表没有数据?用Python就能获取
  2. RNN-循环神经网络和LSTM_01基础
  3. API网关—Spring Cloud Zuul
  4. c语言中的标准数据类型,C语言中的基本数据类型
  5. 关于机器学习的最佳科普文章:《从机器学习谈起》
  6. 如何查看npm配置?
  7. Qt Creator 设置默认编码格式为 UTF-8
  8. android framework 触摸屏事件传递
  9. Linux自学,第一天
  10. 计算机考研408二战
  11. 深度残差网络+自适应参数化ReLU激活函数:调参记录2
  12. page8-JQ的点击隐藏与显示
  13. JZOJ 3339. 【NOI2013模拟】wyl8899和法法塔的游戏【NIM博弈】【暴力】
  14. 斯坦福大学自然语言处理第一课“引言(Introduction)”
  15. 利用SSRF攻击Redis
  16. 三星GT-P1000完美刷机教程,附ROM刷机包下载
  17. 喜报!中国工商银行长春分行荣获吉林省“巾帼建功”先进集体称号
  18. MySQL的异步、半异步、组复制
  19. pyepics Device:PVs的集合
  20. U3D Animator 组件控制动画的播放暂停,动态添加帧事件

热门文章

  1. c访问mysql数据库_C语言访问MySQL数据库的方法
  2. jQuery+CSS五类验证码(字母、数字、滑动、点击)
  3. 2021年南菁高中高考成绩查询,2021年无锡高考各高中成绩及本科升学率数据排名及分析...
  4. oracle存储过程的创建与调用,Oracle 存储过程创建及调用
  5. php1到5000排序,常用的排序算法(一)--快速排序(PHP实现)
  6. 修改system.img的大小限制
  7. 只要32万8,国产特斯拉带回家,官方:月供低至1100
  8. 2500万美元和AI专家!谷歌出钱出人,要用AI做“对社会有益”的事情
  9. 全面超越人类!Google称霸SQuAD,BERT横扫11大NLP测试
  10. SoPlus回顾 | 行业大咖论道AI,探讨未来行业发展趋势