简介
对于移动设备而言,.NET Compact Framework 即使不是最佳的 API,也是极好的 API。它的图形引擎受到很大的限制,以便提高呈现速度和降低内存消耗。但是,它似乎远远无法满足用户日益增长的对更好的图形体验的要求。尝试去获得 .NET Compact Framework 中的一些高级矢量图形呈现功能可能是一项乏味的任务。开发人员具有两个选择:
1.求助于本机代码。例如,Pocket PC Game API 可能是一项不错的选择。它的性能令人印象深刻。有关详细信息,请参阅位于以下位置的一篇非常全面的文章:http://msdn.microsoft.com/mobility/samples/default.aspx?pull=/library/en-us/dnnetcomp/html/gmangame.asp。问题在于本机代码不支持矢量图形呈现,并且与某些设备不兼容。此外,它可能无法与 Pocket PC 仿真程序协同工作。您可以想象调试这样的程序有多么困难。
2.请等待下一代移动图形引擎问世。据我所知,Windows CE 5 中将包含一个强大的 Direct3D Mobile引擎。这对于移动游戏开发人员来说是一个好消息,但是 Direct3D 不适合于二维图形。它太复杂了,因而无法在一般应用程序中应用。
我们所需要的是像 GDI+ 这样强大而易于使用的二维图形引擎。因此,我从零开始开发 XrossOne GDI+ 项目。它完全是用 C# 托管代码编写的,不包含任何本机代码或不安全的代码。经过几个月的艰苦工作之后,我终于可以在本文开头提供可下载的原始版本。
开始工作
从该项目一开始,我就一直铭记 XrossOne GDI+ 引擎应当对不同的手持设备和平台保持中立。结果,它可以与 Pocket PC、Windows CE、Smartphones、Windows .NET 和 Mono 兼容。您可以将同一个运行库复制到不同的目标,而它仍然可以正常工作。
下表概括了总体体系结构。
层 命名空间
XrossOne GDI+ API XrossOne.Drawing
基于定点的二维图形引擎 XrossOne.DrawingFP
16.16 定点计算引擎 XrossOne.FixedPoint
XrossOne GDI+ 中有三个层。最低层为“16.16 定点计算引擎”。其中一个主类 — MathFP — 是从 Beartronics J2ME 库 改编而来的。一些函数已经进行了优化,其中包括 sqrt、atan 和 PointFP.Distancecalculation。在命名空间 XrossOne.FixedPoint 下面,有其他三个类:SingleFP、DoubleFP 和 MatrixFP。SingleFP 是一个用于 16.16 定点数的 Helper 类。它为在定点类型和标准类型(int、float、string)之间进行转换提供了方便。MatrixFP 是为定点二维变换编写的。因为定点计算的精度较低,所以级联变换可能会损失一些精确性。例如,在大多数情况下,两次求逆运算无法还原原始矩阵。DoubleFP 的存在是为了使该库完备,但尚未使用。
“基于定点的二维图形引擎”是 XrossOne GDI+ 的内核。它实现了很多复杂的矢量图形算法,例如,反锯齿绘图、线帽/联接装饰、二维变换、渐变填充、Alpha 通道合成等等。这里可以找到本机 GDI+ 中的大多数高级功能。但是,您只应在少数情况下直接使用它,因为它的基于定点的接口对于程序员而言不够友好,但是不必过分担心这种情况。有一个封装良好的 API 可供使用。您可以在 XrossOne.Drawing 命名空间中找到它们。XrossOne.Drawing 中的类非常类似于 System.Drawing 中的类,不同之处在于每个类的末尾有一个字母“X”。例如,XrossOne.Drawing.PenX 类等效于 System.Drawing.Pen。有一个用于将 GDI+ 程序转换到 XrossOne GDI+ 的小窍门。在 using 节中,将 XrossOne GDI+ 类重命名为它们的等效类。例如:
using Pen = XrossOne.Drawing.PenX;
using LinearGradientBrush = XrossOne.Drawing. LinearGradientBrushX;
using Matrix = XrossOne.Drawing.MatrixX;
主要功能
反锯齿矢量图形绘图
通过 XrossOne Mobile GDI+ 可以呈现所有种类的二维几何图形,例如,线段、矩形、多边形、椭圆、扇形、贝塞尔样条曲线、基数样条曲线等等。但是,扇形、贝塞尔样条曲线和基数样条曲线在 .NET Compact Framework 中不可用。此外,所有图形在呈现时都自动进行反锯齿处理。这有助于获得超级平滑质量。在 .NET Compact Framework 中,画笔的宽度被固定为 1 个像素。这一限制在 XrossOne GDI+ 中不存在。画笔的不同大小可以应用于所有图形的轮廓,如图 1 所示。
图 1. 反锯齿矢量图形绘图
代码示例 1
//Clear the background and reset the transform state
gx.Clear(Color.White);
gx.ResetTransform();
//Draw skew grid as the background
PenX pen = new PenX(Utils.FromArgb(0x40, Color.LightGray), 5);
for (int i = -Height; i < Width + Height; i+=20)
{
gx.DrawLine(pen, i, 0, i + Height, Height);
gx.DrawLine(pen, i, 0, i - Height, Height);
}
//Draw a DarkMagenta rectangle with a 10.5-pixel pen
Color c = Utils.FromArgb(0x80, Color.DarkMagenta);
pen = new PenX(c, 10.5f);
gx.DrawRectangle(pen, 50, 20, 150, 200);
//Fill a GreenYellow rectangle
c = Utils.FromArgb(0xA0, Color.GreenYellow);
BrushX brush = new SolidBrushX(c);
gx.FillRectangle(brush, 120, 50, 90, 150);
//Draw a BlueViolet ellipse with a 10.5-pixel pen
c = Utils.FromArgb(0x80, Color.BlueViolet);
pen = new PenX(c, 10.5f);
gx.DrawEllipse(pen, 50, 20, 150, 80);
//Fill a Red ellipse
c = Utils.FromArgb(0xA0, Color.Red);
brush = new SolidBrushX(c);
gx.FillEllipse(brush, 20, 50, 80, 150);
//Draw a HotPink pie from 156.5 degree to -280.9 degree
pen.Color = Utils.FromArgb(0xA0, Color.HotPink);
gx.DrawPie(pen, 3.6f, 120.3f, 200.8f, 130.1f, 156.5f, -280.9f);
//Draw Orange Bezier curves
c = Utils.FromArgb(0xA0, Color.Orange);
pen = new PenX(c, 16);
Point start = new Point(70, 100);
Point control1 = new Point(100, 10);
Point control2 = new Point(150, 50);
Point end1 = new Point(200, 200);
Point control3 = new Point(100, 150);
Point control4 = new Point(50, 200);
Point end2 = new Point(10, 150);
Point[] bezierPoints ={start, control1, control2, end1, control3, control4, end2};
pen.EndCap = LineCapX.Round;
gx.DrawBeziers(pen, bezierPoints);
//Refresh
Invalidate();
XrossOne GDI+ 和本机 GDI+ 的矢量图形输出是相同的,但基数样条曲线除外。我的算法取自 Jean-Yves Queinec 撰写的文章 Smoothing Algorithm Using Bezier Curves。因此,您可能发现在它们的输出之间存在一些差异,如下面的图 2 所示。
图 2. DrawCurve/DrawClosedCurve 的输出
尽管大多数矢量图形呈现函数都已经得到实现,但仍然有一些工作需要完成。某些函数(DrawString、DrawImage、DrawPath 等等)直到下一个版本才可用。
渐变填充
在本机 GDI+ 中有五种画刷 — SolidBrush、LinearGradientBrush、PathGradientBrush、TextureBrush 和 HatchBrush。但是,在该版本中,只有 SolidBrush 和 LinearGradientBrush 可用。XrossOne GDI+ 支持 RadialGradientBrush 而不是 PathGradientBrush。下面的图 5 演示了渐变填充。
图 5. 渐变填充
代码示例 4
//Clear the background and reset the transform state
gx.Clear(Color.White);
gx.ResetTransform();
//Fill a rectangle with a black-white LinearGradientBrushX
Rectangle r = new Rectangle(20, 50, 300, 100);
Color c1 = Color.Black;
Color c2 = Color.White;
BrushX brush1 = new LinearGradientBrushX(r, c1, c2, 30F);
gx.FillRectangle(brush1, r);
//Fill a rectangle with a 7-color LinearGradientBrushX
r = new Rectangle(90, 100, 150, 100);
LinearGradientBrushX br = new LinearGradientBrushX(r,Color.Black,Color.Black, 60F);
ColorBlendX cb = new ColorBlendX();
cb.Positions=new float[7];
int i=0;
for(float f=0;f<=1;f+=1.0f/6)
cb.Positions[i++]=f;
cb.Colors=new Color[]
{Color.Red,Color.Orange,Color.Yellow,Color.Green,Color.Blue,Color.Indigo,Color.Violet};
br.InterpolationColors=cb;
gx.TranslateTransform(160, 10);
gx.RotateTransform(60F);
gx.FillRectangle(br, r);
//Fill a rectangle with a 7-color RadialGradientBrushX
r.Y += 50;
RadialGradientBrushX brush2 = new RadialGradientBrushX(r, Color.Black,Color.Black, 220F);
brush2.InterpolationColors = cb;
gx.RotateTransform(-45F);
gx.TranslateTransform(-200, -170);
gx.FillRectangle(brush2, r);
//Refresh
Invalidate();
Alpha 通道合成
System.Drawing 命名空间中的 Color 结构在 .NET Framework 和 .NET Compact Framework 中都可用。区别在于 .NET Compact Framework 中禁用了 alpha 成分并且色调-饱和度-亮度 (HSB) 值不可用。幸运的是,alpha 通道合成可以完美地与 XrossOne GDI+ 协同工作(您可能已经从前面的图形示例中推断出这一点)。
性能 DrawLine 2.604 ms 0.901 ms 189.0% DrawRect 3.705 ms 1.602 ms 131.3% DrawPolygon 3.205 ms 1.502 ms 113.4% DrawEllipse 6.409 ms 2.403 ms 166.7% DrawBezier 3.505 ms 1.602 ms 118.8% DrawCurve 4.006 ms 1.402 ms 185.7% DrawPie 6.810 ms 2.003 ms 240.0% TranslateTransform 10.615 ms 3.405 ms 211.7% ScaleTransform 4.106 ms 0.801 ms 412.6% RotateTransform 7.811 ms 1.803 ms 333.2% LinearGradient (1) 9.013 ms 2.103 ms 328.6% LinearGradient (2) 8.012 ms 1.803 ms 344.4%
手持 PC 的 CPU 的功能确实通常要比标准 PC 的 CPU 差很多。繁重的计算可能使手持设备的响应速度降低,从而可能使用户变得不胜其烦。换句话说,性能对于手持设备软件而言至关重要。因此,在重大场合下使用 XrossOne Mobile GDI+ 之前,您可能希望分析它的总体性能。因为 GDI+ 中大多数对应于 .NET Compact Framework 的等效函数都不可用,所以基准测试是针对 .NET Framework 在 XrossOne Mobile GDI+ 和 GDI+ 之间进行的。测试是在下列类别中执行的:矢量图形呈现、二维变换和渐变填充。测试方案在相同的条件下执行。您可以在下载软件包中找到基准测试程序,并且可以在 http://www.xrossone.com/projects.php?menu=4 快速查看它们的图形输出。
XrossOne Mobile GDI+ 完全是用 C# 托管代码编写的,它的总体性能可以接受(参见下表),尽管二维变换和渐变填充需要在以后的版本中进一步优化。
方案
XrossOne Mobile GDI+
GDI+ for .NET Framework
系统开销