1第15章GDI+高级编程本章介绍GDI+的路径、区域、变换、图像处理和图元文件等高级编程内容。路径由许多不同类型的点所构成,用于表示复杂的不规则图形。区域是由矩形、椭圆、多边形等几何形状组合构成的一种封闭图形,可用于复杂图形的绘制、剪裁和击中测试等。Graphics类可对绘制的图形进行平移、旋转和伸缩变换。矩阵类Matrix则可用于图形、图像、颜色、路径、区域等对象的变换。GDI+的图像处理功能强大,可以加载、保存和操作多种格式的图像。GDI+的图元文件格式为EMF+,可用来保存和重放绘图记录,也能用于交互绘图的重绘操作。15.1路径路径(path)是一系列相互连接的直线和曲线,由许多不同类型的点所构成,用于表示复杂的不规则图形,也叫做图形路径(graphicspath)。路径可以被画轮廓和填充,也可以用于创建区域和路径渐变刷等。在GDI中也有路径(本书未讲),但是它只是作为DC的一种状态才能存在。独立的路径对象,则是GDI+的新特点。15.1.1图形路径在GDI+中,路径由图形路径类GraphicsPath表示,它是GDI+基类GdiplusBase的直接派生类。1.构造函数GraphicsPath类有三个构造函数:GraphicsPath(FillModefillMode=FillModeAlternate);//构造一个空路径GraphicsPath(constPoint*points,constBYTE*types,INTcount,FillModefillMode=FillModeAlternate);//构造含指定整数型点数组的路径GraphicsPath(constPointF*points,constBYTE*types,INTcount,FillModefillMode=FillModeAlternate);//构造含指定浮数型点数组的路径2其中:填充模式参数fillMode在上一章的画填充多边形和曲线时已经讲过,枚举类型FillMode除了可取这里的默认值FillModeAlternate(交替填充模式)之外,还有一个可取的值是FillModeWinding(环绕替填充模式)。点数组参数points,可以是整数类型的,也可以是浮点数类型的。点类型数组参数types,主要点类型有路径起点、直线端点和贝塞尔点。计数参数count为数组points和types的元素数,这两种数组中的元素数必须一致。2.点的种类构造函数中,点的类型取值为枚举类型PathPointType常量;typedefenum{PathPointTypeStart=0,//起点PathPointTypeLine=1,//直线端点PathPointTypeBezier=3,//贝塞尔(曲线的控制)点PathPointTypePathTypeMask=0x7,//点类型掩码(只保留低三位)PathPointTypePathDashMode=0x10,//未使用PathPointTypePathMarker=0x20,//标记点(用于路径分段)PathPointTypeCloseSubpath=0x80,//闭子路径(图形)的终点PathPointTypeBezier3=3//同PathPointTypeBezier}PathPointType;其中,主要的点类型有起点、直线端点、贝塞尔点、标记点和闭子路径终点。其他曲线类型(如弧、椭圆和基样条曲线等)在路径中都是用贝塞尔曲线来表示的。路径是由点组成的,但这里的点,不光指其坐标位置,还包括点的类型。同样的点坐标,不同的点类型,最后得到的路径可能大相径庭。例如,同一组点,定义两个路径,一个的点类型全是直线端点,另一个的起点之后有3个贝塞尔点,最后才是两个直线点(参见图15-1,其中自定义画点列方法DrawPoints,在画曲线时用过,源码参见14.6.5的1.):Pointpoints[]={Point(40,140),Point(275,200),Point(105,225),Point(190,300),Point(50,350),3Point(20,180)};//定义点数组//定义点类型数组(为了节省篇幅,有些直接用了枚举的整数值)BYTElineTypes[]={PathPointTypeLine,1,1,1,1,1};BYTEtypes[]={PathPointTypeStart,PathPointTypeBezier,3,3,PathPointTypeLine,1};GraphicsPathpath1(points,lineTypes,6),//创建直线路径path2(points,types,6);//创建复合路径Graphicsgraph(pDC-m_hDC);//创建图形对象//填充直线路径、画直线、画点列graph.FillPath(&SolidBrush(Color::Lime),&path1);graph.DrawLines(&Pen(Color::Violet),points,6);DrawPoints(graph,Color::Red,4,points,6);graph.TranslateTransform(300,0);//右移300像素//填充复合路径、画直线、画点列graph.FillPath(&SolidBrush(Color::Aqua),&path2);graph.DrawLines(&Pen(Color::Magenta),points,6);DrawPoints(graph,Color::Red,4,points,6);图15-1点类型3.路径的构成前面已经讲过,路径是一系列相互连接的直线和曲线,它们最终都是由有序点列所组成。可以利用GraphicsPath类的后两个构造函数,将点数组直接加入路径中。不过,路径中的直线和曲线等图形,一般是通过调用路径类的若干添加图形方法给加进来的。每个被加入的图形都可以是一个子路径(subpath)。路径对象,会将被加入图形(包括封闭图形)中的点尾首相接,连成一条完整的路径。4在路径中的图形都是开图形(起点和终点可能是同一个点,例如矩形、椭圆、多边形和闭曲线等),可以调用图形路径类的CloseFigure或CloseAllFigures方法:StatusCloseFigure(VOID);//关闭当前子路径StatusCloseAllFigures(VOID);//关闭所有子路径来显式闭合路径对象中的当前子路径或所有子路径。例如(参见图15-2):Graphicsgraph(pDC-m_hDC);//创建图形像对象Penpen(Color::Blue);//定义蓝色笔GraphicsPathpath;//创建路径对象path.AddLine(10.0f,50.0f,200.0f,50.0f);//加水平直线//path.StartFigure();//断开两条直线之间的连接(即分成两个子路径)path.AddLine(60.0f,10.0f,60.0f,80.0f);//加垂直直线path.AddEllipse(10,100,200,120);//加椭圆path.AddBezier(Point(220,200),Point(250,150),Point(300,50),Point(400,200));//加贝塞尔曲线intn=path.GetPointCount();//获取路径中的点数Point*points=newPoint[n];//新建点数组path.GetPathPoints(points,n);//获取路径中的点//path.SetFillMode(FillModeWinding);//设置填充模式//填充(开)路径//graph.FillPath(&SolidBrush(Color::Aqua),&path);graph.DrawLines(&Pen(Color::Green),points,n);//画折线//path.CloseAllFigures();//关闭所有子路径graph.DrawPath(&pen,&path);//画路径轮廓DrawPoints(graph,Color::Red,4,points,n);//画路径中的点4.添加图形图形路径类GraphicsPath中的下列方法,用于添加图形到路径中(重载和参数都与Graphics类中对应的绘图方法相同,但是前缀都改成了Add):5点列与路径填充(开)路径开(子)路径闭(子)路径图15-2路径的构成加直线:AddLine加折线:AddLines加多边形:AddPolygon加矩形:AddRectangle加矩形组:AddRectangles加弧:AddArc加饼:AddPie加椭圆:AddEllipse加贝塞尔曲线:AddBezier加相连的多段贝塞尔曲线:AddBeziers加基样条曲线:AddCurve加闭基样条曲线:AddClosedCurve加串:AddString5.绘制路径可以用Graphics类的方法DrawPath来画路径的轮廓,用其另一个方法FillPath来填充路径的内部(对开路径,会先自动封闭,然后再进行填充):StatusDrawPath(constPen*pen,constGraphicsPath*path);StatusFillPath(constBrush*brush,constGraphicsPath*path);当然你也可以用GraphicsPath类的方法SetFillMode和GetFillMode来设置不同的填充模式或者获取当前的填充模式:StatusSetFillMode(FillModefillmode);6FillModeGetFillMode(VOID);关于画路径轮廓和填充路径的例子,前面已经有了很多,这里就不再列举了。6.获取点信息在创建路径并添加各种几何图形或字符串之后,我们可以调用如下一些GraphicsPath类的方法,来获取路径中的点的信息。包括点的坐标信息和点的类型信息:INTGetPointCount(VOID);//获取路径中的总点数StatusGetPathPoints(Point*points,INTcount);//获取路径中(指定数目的)整数点数组StatusGetPathPoints(PointF*points,INTcount);//获取路径中(指定数目的)浮点数点数组StatusGetPathTypes(BYTE*types,INTcount);//获取路径中(指定数目的)点类型数组例如:GraphicsPathpath;……//添加若干图形到路径intn=path.GetPointCount();Point*points=newPoint[n];path.GetPathPoints(points,n);graph.DrawLines(&Pen(Color::Green),points,n);DrawPoints(graph,Color::Red,4,points,n);15.1.2路径渐变刷路径可以表示复杂的图形,可以用于绘制这些图形的轮廓和填充,也可以用于创建区域(在下一节介绍)和颜色渐变刷。后者在前面美术字部分的彩心字符串例中(参见14.8.35.),我们已经用过。与其它具体刷(如实心刷、条纹刷和纹理刷等)类一样,路径渐变(梯度)刷类PathGradientBrush,也是Brush类的派生类。它有3个构造函数:PathGradientBrush(constGraphicsPath*path);PathGradientBrush(constPoint*points,INTcount,WrapModewrapMode=WrapModeClamp);PathGradientBrush(constPointF*points,INTcount,7WrapModewrapMode=WrapModeClamp);第