文件GDIPLUS开发文档.docx
《文件GDIPLUS开发文档.docx》由会员分享,可在线阅读,更多相关《文件GDIPLUS开发文档.docx(281页珍藏版)》请在冰豆网上搜索。
文件GDIPLUS开发文档
【关键字】文件
第6章GDI+
GDI+(GraphicsDeviceInterfacePlus图形设备接口加)是WindowsXP和WindowsServer2003操作系统的子系统,也是.NET框架的重要组成部分,负责在屏幕和打印机上绘制图形图像和显示信息。
顾名思义,GDI+是Windows早期版本所提供的图形设备接口GDI的后续版本。
GDI+是一种应用程序编程接口(API),通过一套部署为托管代码的类来展现。
这套类被称为GDI+的“托管类接口”。
GDI+最早是于2001年随WindowsXP一起推出的一种API,后来又被包装进.NET框架的托管类库之中,成为.NET中窗体绘图的主要工具。
GDI+不但在功能上比GDI要强大很多,而且在代码编写方面也更简单,因此会很快成为Windows图形图像程序开发的首选。
本章将介绍GDI+的特点和新增功能,以及GDI+API的具体使用方法,包括二维矢量图形的绘制、图像处理的应用、以及文字的显示。
6.1概述
GDI+与GDI一样,都具有设备无关性。
应用程序的程序员可利用GDI+这样的图形设备接口在屏幕或打印机上显示信息,而不需要考虑特定显示设备的具体情况。
应用程序的程序员调用GDI+类提供的方法,而这些方法又反过来相应地调用特定的设备驱动程序。
GDI+将应用程序与图形硬件隔离,而正是这种隔离允许开发人员创建设备无关的应用程序。
GDI+的体系结构
本节首先介绍GDI+的几个主要新增的特性及其功能,然后说明它给Windows图形图像程序的开发模式带来的变化,最后给出一个代码实例,介绍如何在VC++中使用GDI+进行程序开发。
1.GDI+的功能
GDI+主要提供了以下三种功能:
1)二维矢量图形
矢量图形包括坐标系统中的系列点指定的绘图基元(如直线、曲线和图形)。
例如,直线可通过它的两个端点来指定,而矩形可通过确定其左上角位置的点并给出其宽度和高度的一对数字来指定。
简单路径可由通过直线连接的点的数组来指定。
贝塞尔样条是由四个控制点指定的复杂曲线。
GDI+提供了存储基元自身相关信息的类(结构)、存储基元绘制方式相关信息的类,以及实际进行绘制的类。
例如,Rectangle结构存储矩形的位置和尺寸;Pen类存储有关线条颜色、线条粗细和线型的信息;而Graphics类具有用于绘制直线、矩形、路径和其它图形的方法(类似于GDI中的CDC类)。
还有几种Brush类,它们存储有关如何使用颜色或图案来填充封闭图形和路径的信息。
用户可以在图元文件中记录矢量图像(图形命令的序列)。
GDI+提供了Metafile类,可用于记录、显示和保存图元文件。
MetafileHeader和MetaHeader类允许您检查图元文件头中存储的数据。
2)图像处理
某些种类的图片很难或者根本无法用矢量图形技术来显示。
例如,工具栏按钮上的图片和显示为图标的图片就难以指定为直线和曲线的集合。
拥挤的棒球运动场的高分辨率数字照片会更难以使用矢量技术来制作。
这种类型的图像可存储为位图,即代表屏幕上单个点颜色的数字数组。
GDI+提供了Image、Bitmap和Metafile类,可用于显示、操作和保存位图。
它们支持众多的图像文件格式,还可以进行多种图像处理的操作。
3)文字显示版式
就是使用各种字体、字号和样式来显示文本。
GDI+为这种复杂任务提供了大量的支持。
GDI+中的新功能之一是子像素消除锯齿,它可以使文本在LCD屏幕上呈现时显得比较平滑。
4)功能汇总
GDI+的C++封装包含54个类、12个函数、6类(226个)图像常量、55种枚举和19种结构。
GDI+的托管类接口则包含大约60个类、50个枚举和8个结构。
这两种封装中的Graphics类都是GDI+的核心功能,它是实际绘制直线、曲线、图形、图像和文本的类。
通过这些类和接口可以实现:
●使用笔绘制线条和形状
●使用刷填充形状
●使用图像、位图和图元文件
●α混合线条和填充
●字体和文本
●构造并绘制曲线
●用颜色渐变的梯度刷填充形状
●构造并绘制轨迹
●变换
●图形容器
●区域
●重新着色
●读取元数据
等非常丰富强大的功能。
2.GDI+新增特性
1)渐变画刷
渐变画刷(gradientbrush梯度刷)通过提供用于填充图形、路径和区域的线性渐变画笔和路径渐变画笔,GDI+扩展了GDI的功能。
渐变画笔还可用于绘制直线、曲线和路径。
线性渐变画笔可用于使用颜色来填充图形,画笔在图形中移动时,颜色会逐渐改变。
例如,假定通过指定图形左边为蓝色、右边为绿色,创建了一个水平渐变画笔。
当用水平渐变画笔填充该图形时,随着画笔从图形的左边移至右边,颜色就会由蓝色逐渐变为绿色。
用类似方法定义的垂直渐变画笔填充的图形,颜色从上到下变化。
图6-1显示了用水平渐变画笔填充的椭圆和用斜式渐变画笔填充的区域。
图6-1水平和斜式渐变画笔
用路径渐变画笔填充图形时,可选择不同的方法来指定当从图形的一部分至另一部分移动画笔时颜色的变化方式。
一种选择是指定中心颜色和边缘颜色,在从图形中间向外边缘移动画笔时,像素逐渐从一种颜色变化到另一种颜色。
图6-2显示了用路径渐变画笔填充的路径(该路径是用一对贝塞尔样条创建的)。
图6-2路径渐变画笔
2)基数样条函数
GDI+支持在GDI中不支持的基数样条(cardinalspines)。
基数样条是一连串单独的曲线,这些曲线连接起来形成一条较长的光滑曲线。
样条由点的数组指定,并通过该数组中的每一个点。
基数样条平滑地(没有锐角)通过数组中的每一个点,因此,比通过连接直线创建的路径更光滑精准。
图6-3显示了两个路径:
一个以基数样条的形式创建;另一个通过连接直线创建。
图6-3基数样条路径和折线路径
3)持久路径东西
在GDI中,路径属于设备上下文,并且会在绘制时被毁坏。
利用GDI+,绘图由Graphics东西执行,可以创建并维护几个与Graphics东西分开的持久的路径东西(persistentpathobject)——GraphicsPath东西。
绘图操作不会破坏GraphicsPath东西,因此可以多次使用同一个GraphicsPath东西来绘制路径。
4)变换和矩阵东西
GDI+提供了Matrix(矩阵)东西,它是一种可以使(缩放、旋转和平移等)变换(transformation)简易灵活的强大工具。
矩阵东西一般与变换东西联合使用。
例如,GraphicsPath东西具有Transform方法,此方法接收Matrix东西作为参数。
单一的3×3矩阵可存储一种变换或一个变换序列。
图6-4显示了一个路径在执行两种变换前后的情况。
图6-4路径的变换
5)可伸缩区域
GDI+通过对可伸缩区域(ScalableRegions)的支持极大地扩展了GDI。
在GDI中,区域被存储在设备坐标中,而且,可应用于区域的惟一变换是平移。
而GDI+在全局坐标中存储区域,并且允许区域发生任何可存储在变换矩阵中的变换(如缩放和旋转)。
图6-5显示一个区域在执行三种变换(缩放、旋转和平移)前后的情况。
图6-5区域的三种变换(缩放、旋转和平移)
6)α混色
在图6-5中,可以在变换区域(用蓝色阴影画笔填充)中看到未变换区域(用红色填充)。
这是由GDI+支持的α混色(AlphaBlending,透明混合)实现的。
使用α混色,可以指定填充颜色的透明度。
透明色与背景色相混合———填充色越透明,透出的背景色就越多。
图6-6显示四个用相同颜色(红色)填充、但透明层次不同的椭圆。
图6-6不同透明度
7)丰富的图像格式支持
GDI+提供Image、Bitmap和Metafile类,可以用不同的格式加载、保存和操作图像。
GDI+支持BMP、GIF、JPEG、EXIF、PNG、TIFF、ICON、WMF、EMF共9种常见的图像格式。
8)GDI+的不足
虽然,相对于GDI来说,GDI+确实增加了许多新特性,而且功能更强大,使用也更方便。
但是,这并不等于GDI+就能够完全代替GDI。
因为GDI+实际上GDI+是GDI的封装和扩展,GDI+的执行效率一般要低于GDI的。
另外,GDI+不支持图的位运算,那么就不能进行异或绘图等操作。
而且在VC中,GDI+还不支持双缓存机制(如内存DC和显示DC),这将大大影响GDI+在高速图形、图像、动画和视频等方面的应用。
3.编程模式的改变
GDI+的出现,也使基于GDI的编程模式产生了很大变化:
GDI+用一个“无状态模式”,取代了GDI中(需要先将各种工具和项目选入DC对象后,才能进行绘图的)“状态模式”。
主要体现在以下几个方面:
1)DC句柄和图形对象
设备上下文(DC=DeviceContext)是GDI中使用的一种结构,用于存储与特定显示设备的功能、以及指定如何在该设备上绘制项目之属性相关的信息。
用于屏幕显示的DC还与特定窗口相关联。
为了使用GDIAPI进行绘图,必须首先获得一个DC的句柄(HDC=HandletoaDC),然后将该句柄作为参数,传递给实际进行绘图的GDI函数。
还可以将此句柄作为参数,传递给获取和设置DC属性的GDI函数。
使用GDI+,不需要再(直接)使用句柄或设备上下文,而是只需(通过HDC)创建一个Graphics对象,然后用熟悉的面向对象方式来调用其中的各种绘图方法,例如:
myGraphicsObject.DrawLine(&pen,x1,y1,x2,y2);
正如DC是GDI的核心,Graphics对象也位于GDI+的核心。
DC和Graphics对象的作用相似,但在使用设备上下文(GDI)的基于句柄的编程模式和使用Graphics对象(GDI+)的面向对象的编程模型之间,存在一些基本的差异。
Graphics对象(像DC一样)与屏幕上的特定窗口关联,并具有指定如何绘制项目的属性(如SmoothingMode和TextRenderingHint)。
但是,Graphics对象不受笔、刷、路径、图像或字体的约束,这与设备上下文不同。
例如,使用设备上下文绘制线条之前,必须先调用SelectObject以使笔对象和DC关联,即将笔选入DC中。
在设备上下文中绘制的所有线条均使用该笔,直到选择另一支不同的笔为止。
在GDI+中,将Pen对象作为参数传递给Graphics类的DrawLine方法。
可以在一系列的DrawLine调用的每个调用中,使用不同的Pen对象,而不必将给定的Pen对象与Graphics对象关联。
2)绘制线条的两种方法
下面每个示例都从点(20,10)到点(200,100)绘制一条宽为3的红色线条。
第一个示例调用GDI,第二个示例则通过托管类接口调用GDI+;它们都有分别使用API和MFC的两个版本。
(1)用GDI画线
●API
要使用GDI绘制线条,需要两个对象:
设备上下文和笔。
在WM_PAINT的消息响应代码中,通过调用BeginPaint,可以获得设备上下文句柄;通过调用CreatePen,则可以获得笔句柄。
再调用SelectObject以将笔选入设备上下文。
调用MoveToEx,将笔的当前位置设在(20,10),然后调用LineTo,在笔的当前位置与位置(200,100)之间绘制一条线条。
请注意,所有这些函数和类型,都是全局的。
而且MoveToEx和LineTo均将hdc(设备上下文的句柄)作为参数接收。
WM_PAINT:
HDChdc;//DC句柄
PAINTSTRUCTps;//点结构
HPENhPen;//笔句柄
HPENhPenOld;//用于保存原笔的句柄
hdc=BeginPaint(hWnd,&ps);//获得DC句柄,开始绘制,其中hWnd为窗口句柄
hPen=CreatePen(PS_SOLID,3,RGB(255,0,0));//创建红色画笔,宽3
hPenOld=SelectObject(hdc,hPen);//选笔入DC
MoveToEx(hdc,20,10,NULL);//最后一个参数是返回用的旧当前点的结构指针
LineTo(hdc,200,100);//画线
SelectObject(hdc,hPenOld);//选原笔入DC
DeleteObject(hPen);//删除创建的笔
EndPaint(hWnd,&ps);//绘制结束
break;
●MFC
利用MFC进行GDI绘图,步骤与API的差不多,只是MFC将各种GDI功能封装到了不同的类中。
例如,笔的类为CPen、点的类为CPoint、设备上下文的类为CDC。
而且所有的绘图函数都被封在CDC类中,所以只能作为其对象的成员函数才能被使用,当然也就不用再带HDC句柄作为输入参数了。
voidCGdipDemoView:
:
OnDraw(CDC*pDC){
CGdipDrawDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)return;
//TODO:
在此处为本机数据添加绘制代码
CPenpen(PS_SOLID,3,RGB(255,0,0));//创建红色画笔,宽3
pDC->SelectObject(&pen);//选入DC
//pDC->SelectObject(newCPen(PS_SOLID,3,RGB(255,0,0)));//上两步可以合并
pDC->MoveTo(20,10);//将当前点移到直线的起点
pDC->LineTo(200,100);//画线
}
(2)用GDI+画线
●API
使用GDI+和托管类接口绘制线条,需要Graphics对象和Pen对象。
绘制线条涉及调用Graphics类的DrawLine方法。
DrawLine方法的第一个参数是Pen对象。
与前面GDI示例中显示的技术(将笔选入设备上下文)相比,这是一个更加简单而灵活的方案。
WM_PAINT:
HDChdc;
PAINTSTRUCTps;
Pen*myPen;
Graphics*myGraphics;
hdc=BeginPaint(hWnd,&ps);
myPen=newPen(0xffff0000,3);//创建一个笔,宽3,红色
myGraphics=newGraphics(hdc);//利用DC句柄创建图形对象
myGraphics->DrawLine(myPen,20,10,200,100);//调用图形对象的画线方法
EndPaint(hWnd,&ps);
break;
●MFC
利用MFC进行GDI+绘图,步骤与API的差不多。
只是代码改在OnDraw函数中,而且获取DC句柄的方法不同。
voidCGdipDemoView:
:
OnDraw(CDC*pDC){
CGdipDrawDoc*pDoc=GetDocument();
ASSERT_VALID(pDoc);
if(!
pDoc)return;
//TODO:
在此处为本机数据添加绘制代码
GraphicsmyGraphics(pDC->m_hDC);//利用DC句柄创建图形对象
PenmyPen(Color(255,0,0),3);//创建一个笔,宽3,红色
myGraphics.DrawLine(&myPen,20,10,200,100);//调用图形对象的画线方法
//上两步也可以合并:
//myGraphics.DrawLine(&Pen(Color(255,0,0),3),20,10,200,100);
}
3)作为参数的笔、刷、路径、图像和字体
前面的示例显示:
创建和维护Pen对象可以与提供绘制方法的Graphics对象分开。
创建和维护Brush、GraphicsPath、Image和Font对象也可以与Graphics对象分开,Graphics类提供的许多绘制方法都将这些对象作为参数接收。
例如,Brush对象作为参数传递至FillRectangle方法,GraphicPath对象作为参数传递至DrawPath方法。
同样,Image和Font对象传递至DrawImage和DrawString方法。
这与GDI不同,在GDI中,需要将笔、刷、路径、图像或字体选入DC,然后将DC的句柄作为参数传递至绘制函数或采用CDC类对象的函数来绘图。
4)方法重载
许多GDI+方法都是重载的,即,若干方法共享同一名称,却有不同的参数列表。
这一点与用MFC封装后的GDI类似,但是GDI+中的重载方法要更多一些。
(注意,在.NET、C#、Java和VB中,都把类的成员函数称为方法。
当我们在C++中,使用.NET框架类库中的类和功能时,也常常将其成员函数改称为方法。
)例如,画线的重载方法有:
StatusDrawLine(constPen*pen,REALx1,REALy1,REALx2,REALy2);
StatusDrawLine(constPen*pen,constPointF&pt1,constPointF&pt2);
StatusDrawLine(constPen*pen,INTx1,INTy1,INTx2,INTy2);
StatusDrawLine(constPen*pen,constPoint&pt1,constPoint&pt2);
其中,typedefintINT;classPoint{public:
INTX;INTY;……};
typedeffloatREAL;classPointF{public:
REALX;REALY;……};
5)无当前位置
前面所述的DrawLine方法中显示:
线条的起点和终点均被作为参数接收。
这与GDI方案不同,在GDI中,调用MoveToEx(hdc,x1,y1,NULL)或pDC->MoveTo(x1,y1)来设置当前笔位置之后,再调用LineTo(hdc,x2,y2)或pDC->LineTo(x2,y2)来绘制一条从(x1,y1)到(x2,y2)的线条。
GDI+从总体上已经放弃了当前位置的概念。
6)绘制和填充的不同方法
论及绘制轮廓和填充图形内部时,GDI+要比GDI更灵活。
GDI有一个Rectangle函数,可一步完成绘制轮廓和填充矩形内部。
轮廓由当前选定的笔绘制,而内部则由当前选定的刷来填充。
GDI+使用不同的方法来绘制轮廓和填充矩形内部。
Graphics类的DrawRectangle方法将Pen对象作为其参数之一,而FillRectangle方法将Brush对象作为其参数之一。
7)构造区域
GDI提供几种用于创建区域的函数(在MFC中,它们被封装在CRng类里):
CreateRect-Rgn、CreateEllpticRgn、CreateRoundRectRgn、CreatePolygonRgn和CreatePolyPolygonRgn。
您或许希望GDI+中的Region类也有类似的构造函数,将矩形、椭圆、圆角矩形和多边形作为参数接收,但事实并非如此。
GDI+中的Region类提供一个接收Rectangle对象的构造函数和另一个接收GraphicsPath对象的构造函数。
如果想基于椭圆、圆角矩形或多边形构造区域,可以通过创建一个GraphicsPath对象(可包含椭圆的对象等),然后将其传递至Region构造函数来轻松实现。
GDI+通过组合图形和路径,使得构成复杂区域十分简单。
Region类具有Union和Intersect方法,可用于扩展具有路径的现有区域或其它区域。
GDI+方案一个很好的功能就是GraphicsPath对象在作为参数传递至Region构造函数时不会被破坏(在GDI中,可以使用PathToRegion函数将路径转换为区域,但在此过程中,路径将被破坏)。
另外,GraphicsPath对象在作为参数传递给Union或Intersect方法时也不会被破坏,因此,在一些单独的区域中,可以将给定的路径作为构造块使用。
例如:
Regionregion1(rect1);
Regionregion2(rect2);
region1.Union(onePath);
region2.Intersect(onePath);
4.GDI+的使用
下面通过一个简单的例子,来说明如何使用GDI+进行应用程序开发。
1)GDI+开发包
若采用的是VisualC++2005,则已经包含了开发GDI+应用程序所需的所有东西。
包括:
●动态链接库文件gdiplus.dll
●静态链接库文件gdiplus.lib
●代码中所需要的头文件gdiplus*.h
●帮助文档gdicpp.chm和gdicpp.chi
如果你使用的操作系统是WindowsXP或WindowsServer2003,则GDI+所对应的动态链接库,已经被包含在其中。
gdiplus.dll一般位于操作系统的WinSxS(Windowsside-by-sideassembly,视窗并行程序集)目录中,例如:
C:
\WINDOWS\WinSxS\x86_,
C:
\WINDOWS\WinSxS\x86_,
而GDI的动态链接库gdi32.dll,却一般在操作系统的32位系统目录中:
F:
\WINDOWS\system32\gdi32.dll(272KB,
如果开发工具采用VisualC++6.0,而且操作系统是Windows2000,则需要安装GDI+的开发包。
如果你已经安装了.NET框架,则其中已经包含了该开发包。
如果还没有安装,则需要自己去微软的网站免费下载GDI+开发包或.NET框架(可能需要先通过微软的正版操作系统软件验证)。
2)VC中的设置
●在VS05中,选“项目/*属性”菜单项,打开项目的属性页窗口,先选“所有配置”,再选“配置属性/链接器/输入”项,在右边上部的“附加依赖项”栏的右边,键入GdiPlus.lib(参见下图)后按“应用”钮,最后按“确定”钮关闭对话框。
●在要使用GDI+的文件(如视图类的头文件或代码文件)头部包含GDI+的头文件:
#include
并加上使用GDI+命名空间的using指令(区分大小写,注意首字母大写):
usingnamespaceGdiplus;
下面是VC05中,GDI+头文件和动态链接库文件,缺省所在的目录:
C:
\ProgramFiles\MicrosoftVisualStudio8\VC\PlatformSDK\include\GdiPlus*.h
C:
\ProgramFiles\MicrosoftVisualStudio8\VC\PlatformSDK\Lib\GdiPlus.lib
下面是VC05中,GDI头文件和动态链接库文件,缺省所在的目录:
C:
\ProgramFiles\MicrosoftVisualStudio8\VC\PlatformSDK\include\WinGDI.h(API)
C:
\ProgramFiles\MicrosoftVisualStudio