VC++GDI+编程详解.docx
《VC++GDI+编程详解.docx》由会员分享,可在线阅读,更多相关《VC++GDI+编程详解.docx(55页珍藏版)》请在冰豆网上搜索。
![VC++GDI+编程详解.docx](https://file1.bdocx.com/fileroot1/2023-2/11/0fad0b7b-b6c9-4889-870e-a43af9e9b696/0fad0b7b-b6c9-4889-870e-a43af9e9b6961.gif)
VC++GDI+编程详解
VC下使用GDI+进行
图像程序设计
孙涛整理
GDI+介绍
Microsoft®Windows®GDI+是WindowsXP或者WindowsServer2003操作系统的子系统。
它负责在屏幕和打印机上显示信息。
GDI+是一个应用程序编程接口,它是一个C++类。
如同它的名字暗示一样,GDI+是Windows图形设备接口(GDI)的继承者,这个图形设备接口包括早期的Windows版本。
WindowsXP或者WindowsServer2003为了支持以前的应用程序还支持GDI,但是新的应用程序开发人员应该去使用GDI+去作他们的图像处理工作。
因为GDI+对GDI的很多性能进行了优化,同时还提供了其他的一些特性。
一个图形设备接口,例如GDI+,允许应用程序开发人员在打印机或屏幕上显示信息,而不用去考虑显示设备的具体细节。
应用程序开发人员调用GDI+classes提供的方法(methods),这些方法将依次传到指定的设备驱动程序上。
GDI+让应用程序与图形硬件分离开,并且它可以开发人员创建独立于设备的应用程序。
1.GDI+的三个部分
--------------------------------------------------------------------------------
●2D矢量图(2-Dvectorgraphics)
●图像(Imaging)
●印刷格式(Typography)
2D矢量图2-Dvectorgraphics
矢量图形包括坐标系统中的系列点指定的绘图基元(例如,直线、曲线和图形)。
例如,直线可通过它的两个端点来指定,而矩形可通过确定其左上角位置的点并给出其宽度和高度的一对数字来指定。
简单路径可由通过直线连接的点的数组来指定。
贝塞尔样条是由四个控制点指定的复杂曲线。
GDI+提供了存储基元自身相关信息的类(和结构)、存储基元绘制方式相关信息的类,以及实际进行绘制的类。
例如,Rectangle结构存储矩形的位置和尺寸;Pen类存储有关线条颜色、线条粗细和线型的信息;而Graphics类具有用于绘制直线、矩形、路径和其他图形的方法。
还有几种Brush类,它们存储有关如何使用颜色或图案来填充封闭图形和路径的信息。
您可以在图元文件中记录矢量图像(图形命令的序列)。
GDI+提供了Metafile类,可用于记录、显示和保存图元文件。
MetafileHeader和MetaHeader类允许您检查图元文件头中存储的数据。
图像处理(Imaging)
某些种类的图片很难或者根本无法用矢量图形技术来显示。
例如,工具栏按钮上的图片和显示为图标的图片就难以指定为直线和曲线的集合。
拥挤的棒球运动场的高分辨率数字照片会更难以使用矢量技术来制作。
这种类型的图像可存储为位图,即代表屏幕上单个点颜色的数字数组。
GDI+提供了Bitmap类,可用于显示、操作和保存位图。
版式
版式关系到使用各种字体、字号和样式来显示文本。
GDI+为这种复杂任务提供了大量的支持。
GDI+中的新功能之一是子像素消除锯齿,它可以使文本在LCD屏幕上呈现时显得比较平滑。
2.基于类的接口结构
--------------------------------------------------------------------------------
GDI+的托管类接口包含大约60个类、50个枚举和8个结构。
Graphics类是GDI+的核心功能,它是实际绘制直线、曲线、图形、图像和文本的类。
许多类与Graphics类一起使用。
例如,Graphics.DrawLine方法接收Pen对象,该对象中存有所要绘制的线条的属性(颜色、宽度、虚线线型和外观)。
Graphics.FillRectangle方法可以接收指向LinearGradientBrush对象(它使用Graphics对象以渐变色填充矩形)的指针。
Font和StringFormat对象影响Graphics对象绘制文本的方式。
Matrix对象存储并操作Graphics对象的全局变形,该对象用于旋转、缩放和翻转图像。
GDI+为组织图形数据提供了几种结构(例如,Rectangle、Point和Size)。
而且,某些类的主要作用是结构化数据类型。
例如,BitmapData类是Bitmap类的助手,而PathData类是GraphicsPath类的助手。
GDI+定义了几种枚举,它们是相关常量的集合。
例如,LineJoin枚举包含元素Bevel、Miter和Round,它们指定可用于连接两个线条的样式。
GDI+提供了少量不依附于任何类的函数。
比如GdiplusStartup和GdiplusShutdown函数。
在你要调用GDI+前,必须先调用GdiplusStartup。
当你使用完GDI+后,你必须调用GdiplusShutdown。
GDI+的新增特性?
--------------------------------------------------------------------------------
Microsoft®Windows®GDI+是不同于GDI的。
首先,GDI+通过提供新的一些性能,在GDI的上进行扩充。
比如gradientbrushes和alphablending.其次,编程的模式已经重新修改了,并且图形编程更容易更灵活。
1.新特性
--------------------------------------------------------------------------------
下面将介绍Microsoft®Windows®GDI+的几个新的特性。
渐变画笔(GradientBrushes)
通过提供用于填充图形、路径和区域的线性渐变画笔和路径渐变画笔,GDI+扩展了GDI的功能。
渐变画笔还可用于绘制直线、曲线和路径。
线性渐变画笔可用于使用颜色来填充图形,画笔在图形中移动时,颜色会逐渐改变。
例如,假定您通过指定图形左边为蓝色、右边为绿色创建了一个水平渐变画笔。
当您用水平渐变画笔填充该图形时,随着画笔从图形的左边移至右边,颜色就会由蓝色逐渐变为绿色。
用类似方法定义的垂直渐变画笔填充的图形,颜色从上到下变化。
下面的插图显示了用水平渐变画笔填充的椭圆和用斜式渐变画笔填充的区域。
用路径渐变画笔填充图形时,可选择不同的方法来指定当您从图形的一部分至另一部分移动画笔时颜色的变化方式。
一种选择是指定中心颜色和边缘颜色,以使在您从图形中间向外边缘移动画笔时,像素逐渐从一种颜色变化到另一种颜色。
下面的插图显示了用路径渐变画笔填充的路径(该路径是用一对贝塞尔样条创建的)。
基数样条(CardinalSplines)
GDI+支持在GDI中不支持的基数样条。
基数样条是一连串单独的曲线,这些曲线连接起来形成一条较大的曲线。
样条由点的数组指定,并通过该数组中的每一个点。
基数样条平滑地(没有锐角)通过数组中的每一个点,因此,比通过连接直线创建的路径更精准。
下面的插图显示了两个路径,一个以基数样条的形式创建,另一个通过连接直线创建。
独立的路径对象
在GDI中,路径属于设备上下文,并且会在绘制时被毁坏。
利用GDI+,绘图由Graphics对象执行,而您可以创建并维护几个与Graphics对象分开的GraphicsPath对象。
绘图操作不会破坏GraphicsPath对象,因此您可以多次使用同一个GraphicsPath对象来绘制路径。
变形和矩阵对象
GDI+提供了Matrix对象,它是一种可以使变形(旋转、平移,等等)简易灵活的强大工具。
矩阵对象与所变形对象联合使用。
例如,GraphicsPath对象具有Transform方法,此方法接收Matrix对象作为参数。
单一的3×3矩阵可存储一种变形或一个变形序列。
下面的插图显示了一个路径在执行两种变形前后的情况。
缩放区域
GDI+通过对区域的支持极大地扩展了GDI。
在GDI中,区域存储在设备坐标中,而且,可应用于区域的唯一变形是平移。
GDI+在全局坐标中存储区域,且允许区域发生任何可存储在变形矩阵中的变形(例如缩放)。
下面的插图显示一个区域在执行三种变形(缩放、旋转和平移)前后的情况。
Alpha混合
请注意,在上图中,您可以在变形区域(用蓝色阴影画笔填充)中看到未变形区域(用红色填充)。
这是由GDI+支持的alpha混合实现的。
使用alpha混合,您可以指定填充颜色的透明度。
透明色与背景色相混合—填充色越透明,背景色的透出程度就越高。
下面的插图显示四个用相同颜色(红色)填充、但透明层次不同的椭圆。
对多图像格式的支持
BMP、GraphicsInterchangeFormat(GIF)、JPEG、Exif、PNG、TIFF、ICON、WMF
EMF。
2.编程模式的变化
--------------------------------------------------------------------------------
以下章节描述了使用GDI+编程与使用GDI编程的几点不同之处。
设备上下文、句柄和图形对象
如果您使用过GDI(Windows的以前版本中包括的图形设备接口)编写程序,就会熟悉设备上下文的知识。
设备上下文是Windows使用的一种结构,用于存储与特殊显示设备的功能和指定如何在该设备上绘制项目的属性相关的信息。
用于视频显示的设备上下文还与显示的特定窗口关联。
首先,您获得一个设备上下文的句柄(HDC),然后将该句柄作为参数传递至实际进行绘制的GDI函数。
您还可将此句柄作为参数传递给获取或设置设备上下文属性的GDI函数。
使用GDI+,您不需要再使用句柄或设备上下文,而是只需创建一个Graphics对象,然后以您熟悉的面向对象样式myGraphicsObject.DrawLine(parameters)调用其方法。
正如设备上下文位于GDI的核心,Graphics对象也位于GDI+的核心。
设备上下文和Graphics对象的作用相似,但在使用设备上下文(GDI)的、基于句柄的编程模式和使用Graphics对象(GDI+)的、面向对象的编程模型之间存在一些基本的差异。
Graphics对象(像设备上下文一样)与屏幕上的特定窗口关联,并具有指定如何绘制项目的属性(例如,SmoothingMode和TextRenderingHint)。
但是,Graphics对象不受钢笔、画笔、路径、图像或字体的约束,这与设备上下文不同。
例如,使用设备上下文绘制线条之前,必须先调用SelectObject以使钢笔对象和设备上下文关联。
这是指将钢笔选入设备上下文中。
在设备上下文中绘制的所有线条均使用该钢笔,直到您选择另一支不同的钢笔为止。
在GDI+中,将Pen对象作为参数传递给Graphics类的DrawLine方法。
您可以在一系列DrawLine调用的每个调用中使用不同的Pen对象,而不必使给定的Pen对象与Graphics对象关联。
绘制线条的两种方法
下面每个示例都在位置(20,10)和位置(200,100)之间绘制了一条宽为3的红色线条。
第一个示例调用GDI,第二个示例通过托管类接口调用GDI+。
使用GDI绘制线条
要使用GDI绘制线条,需要两个对象:
设备上下文和钢笔。
通过调用BeginPaint,可以获得设备上下文句柄;通过调用CreatePen,则可以获得钢笔句柄。
下一步,调用SelectObject以将钢笔选入设备上下文。
调用MoveToEx,将钢笔位置设在(20,10),然后调用LineTo,在钢笔位置与位置(200,100)之间绘制一条线条。
请注意,MoveToEx和LineTo均将hdc(设备上下文的句柄)作为参数接收。
HDChdc;
PAINTSTRUCTps;
HPENhPen;
...
hdc=BeginPaint(hWnd,&ps);
hPen=CreatePen(PS_SOLID,3,RGB(255,0,0));
SelectObject(hdc,hPen);
MoveToEx(hdc,20,10,NULL);
LineTo(hdc,200,100);
EndPaint(hWnd,&ps);
使用GDI+和托管类接口绘制线条
用GDI+的C++类接口来画线,你需要一个Graphics对象和一个Pen对象。
你不要去获得这些对象的句柄。
你去创建一个Graphics对象和一个Pen对象。
调用Graphics对象的Graphics:
:
DrawLine方法。
Graphics:
:
DrawLine方法的第一个参数,就是指向你的Pen对象的指针。
HDChdc;
PAINTSTRUCTps;
Pen*myPen;
Graphics*myGraphics;
hdc=BeginPaint(hWnd,&ps);
myPen=newPen(Color(255,255,0,0),3);
myGraphics=newGraphics(hdc);
myGraphics->DrawLine(myPen,20,10,200,100);
deletemyGraphics;
deletemyPen;
EndPaint(hWnd,&ps);
作为参数的钢笔、画笔、路径、图像和字体
前面的示例显示:
创建和维护Pen对象可以与提供绘制方法的Graphics对象分开。
创建和维护Brush、GraphicsPath、Image和Font对象也可以与Graphics对象分开。
Graphics类提供的许多绘制方法都将Brush、GraphicsPath、Image或Font对象作为参数接收。
例如,Brush对象作为参数传递至FillRectangle方法,GraphicsPath对象作为参数传递至DrawPath方法。
同样,Image和Font对象传递至DrawImage和DrawString方法。
这与GDI不同,在GDI中,需要将画笔、路径、图像或字体选入设备上下文,然后将设备上下文的句柄作为参数传递至绘制函数。
方法重载
许多GDI+方法都是重载的,即,若干方法共享同一名称,却有不同的参数列表。
例如,Graphics类的DrawLine方法来自下列表单:
StatusDrawLine(INconstPen*pen,
INREALx1,
INREALy1,
INREALx2,
INREALy2);
StatusDrawLine(INconstPen*pen,
INconstPointF&pt1,
INconstPointF&pt2);
StatusDrawLine(INconstPen*pen,
ININTx1,
ININTy1,
ININTx2,
ININTy2);
StatusDrawLine(INconstPen*pen,
INconstPoint&pt1,
INconstPoint&pt2);
以上四种DrawLine变体均接收Pen对象、起点坐标和终点坐标。
前两种变体将坐标作为浮点数接收,而后两种变体将坐标作为整数接收。
第一种和第三种变体将坐标作为四个单个数字的列表接收,而第二种和第四种变体则将坐标作为一对Point(或PointF)对象接收。
无当前位置
请注意,前面所述的DrawLine方法中显示:
线条的起点和终点均被作为参数接收。
这与GDI方案不同,在GDI中,调用MoveToEx(hdc,x1,y1,NULL)来设置当前钢笔位置之后,再调用LineTo(hdc,x2,y2)以绘制一条从(x1,y1)到(x2,y2)的线条。
GDI+从总体上已经放弃了当前位置的概念。
绘制和填充的不同方法
论及绘制轮廓和填充图形内部时,GDI+要比GDI更灵活。
GDI有一个Rectangle函数,可一步完成绘制轮廓和填充矩形内部。
轮廓由当前选定的钢笔绘制,而内部则由当前选定的画笔来填充。
hBrush=CreateHatchBrush(HS_CROSS,RGB(0,0,255));
hPen=CreatePen(PS_SOLID,3,RGB(255,0,0));
SelectObject(hdc,hBrush);
SelectObject(hdc,hPen);
Rectangle(hdc,100,50,200,80);
GDI+使用不同的方法来绘制轮廓和填充矩形内部。
Graphics类的DrawRectangle方法将Pen对象作为其参数之一,而FillRectangle方法将Brush对象作为其参数之一。
HatchBrush*myHatchBrush=newHatchBrush(
HatchStyleCross,
Color(255,0,255,0),
Color(255,0,0,255));
Pen*myPen=newPen(Color(255,255,0,0),3);
myGraphics.FillRectangle(myHatchBrush,100,50,100,30);
myGraphics.DrawRectangle(myPen,100,50,100,30);
请注意,GDI+中的FillRectangle和DrawRectangle方法接收指定矩形左边缘、上边缘、宽和高的参数。
这与GDI的Rectangle函数不同,Rectangle函数接收指定矩形左边缘、右边缘、上边缘和下边缘的参数。
另请注意,GDI+中Color类的FromArgb方法有四个参数。
后三个参数是常见的红色、绿色和蓝色值。
第一个参数是alpha值,它指定所绘制颜色与背景颜色的混合程度。
构造区域
GDI提供几种用于创建区域的函数:
CreateRectRgn、CreateEllpticRgn、CreateRoundRectRgn、CreatePolygonRgn和CreatePolyPolygonRgn。
您或许希望GDI+中的Region类也有类似的构造函数,将矩形、椭圆、圆角矩形和多边形作为参数接收,但事实并非如此。
GDI+中的Region类提供一个接收Rectangle对象的构造函数和另一个接收GraphicsPath对象的构造函数。
如果您想基于椭圆、圆角矩形或多边形构造区域,可以通过创建一个GraphicsPath对象(例如包含椭圆的对象),然后将其传递至Region构造函数来轻松实现。
GDI+通过组合图形和路径,使得构成复杂区域十分简单。
Region类具有Union和Intersect方法,可用于扩展具有路径的现有区域或其他区域。
GDI+方案一个很好的功能就是GraphicsPath对象在作为参数传递至Region构造函数时不会被破坏(在GDI中,可以使用PathToRegion函数将路径转换为区域,但在此过程中,路径将被破坏)。
另外,GraphicsPath对象在作为参数传递给Union或Intersect方法时也不会被破坏,因此,在一些单独的区域中,您可以将给定的路径作为构造块使用。
此过程如下面的示例所示。
假定onePath是一个已初始化的GraphicsPath对象(简单或复杂)。
Regionregion1(rect1);
Regionregion2(rect2);
region1.Union(onePath);
region2.Intersect(onePath);
直线、曲线和图形
--------------------------------------------------------------------------------
GDI+的矢量图形部分用于绘制直线、曲线,并用于绘制和填充图形。
1.矢量图形概述
--------------------------------------------------------------------------------
GDI+在坐标系统中绘制直线、矩形和其他图形。
您可以从各种各样的坐标系统中选择,但默认坐标系统的原点是在左上角,并且x轴指向右边,y轴指向下边。
默认坐标系统的度量单位是像素。
计算机监视器是在一个点的矩形数组上创建其显示,这些点被称为图片元素或像素。
各台监视器屏幕上显示的像素数量都是不同的,并且用户通常在一定程度上可以配置单独一台监视器上显示的像素数量。
在使用GDI+绘制直线、矩形或曲线时,要提供有关要绘制的项目的某些关键信息。
例如,您可以通过提供两个点来指定一条直线,而且您可以通过提供一个点、高度和宽度来指定一个矩形。
GDI+与显示驱动程序软件一同工作来确定要显示直线、矩形或曲线必须打开哪些像素。
下面的插图显示了已打开的用于显示从点(4,2)到点(12,8)的直线的像素。
在实践中,人们发现某些基本构造块对于创建二维图片尤其有用。
下面列出了全部由GDI+支持的这些构造块:
●线
●矩形
●椭圆
●弧线
●多边形
●基数样条
●贝塞尔样条
GDI+中的Graphics类提供了以下用于绘制前面列表中项目的方法:
DrawLine、DrawRectangle、DrawEllipse、DrawPolygon、DrawArc、DrawCurve(用于基数样条)和DrawBezier。
这些方法中的每一种都是重载的,即每种方法都支持几个不同的参数列表。
例如,DrawLine方法的一个变体接收一个Pen对象和四个整数,而DrawLine方法的另一个变体接收一个Pen对象和两个Point对象。
绘制线条、矩形和贝塞尔样条的方法具有可在单个调用中绘制多个项目的复数同伴方法:
DrawLines、DrawRectangles和DrawBeziers。
DrawCurve方法也有一个同伴方法DrawClosedCurve,它能够通过连接曲线的终点和起点来关闭该曲线。
Graphics类的所有绘制方法与Pen对象共同工作。
要进行绘制,必须至少创建两个对象:
一个Graphics对象和一个Pen对象。
Pen对象存储要绘制项目的属性,例如,线宽和颜色。
Pen对象作为参数之一传递到绘制方法。
例如,如下面的示例所示,DrawRectangle方法的一个变体接收一个Pen对象和四个整数,该示例绘制一个宽100、高50且左上角位于(20,