优化性能:二维图形和图像处理
WPF 提供了多种可按应用程序要求进行优化的 2D 图形和图像处理功能。 本主题提供有关这些方面性能优化的信息。
绘图和形状
WPF 提供 Drawing 和 Shape 对象来表示图形绘制内容。 但是,Drawing 对象是比 Shape 对象更为简单的构造,且提供更好的性能特征。
通过 Shape 可将图形形状绘制到屏幕。 因为其派生自 FrameworkElement 类,所以 Shape 对象可用于面板和大多数控件内。
WPF 为图形和绘制服务提供多层访问。 在顶层,Shape 对象易于使用,且提供了布局和事件处理等众多实用功能。 WPF 提供了许多现成可用的形状对象。 所有形状对象都继承自 Shape 类。 可用的形状对象包括 Ellipse、Line、Path、Polygon、Polyline 和 Rectangle。
另一方面,Drawing 对象不是派生自 FrameworkElement 类,且对于绘制形状、图像和文本提供了更轻量的实现。
有四种类型的 Drawing 对象:
GeometryDrawing 绘制形状。
ImageDrawing 绘制图像。
GlyphRunDrawing 绘制文本。
DrawingGroup 绘制其他图形。 使用绘图组将其他绘图合并到单个复合绘图。
GeometryDrawing 对象用于绘制几何内容。 Geometry 类及其派生的具体类(例如 CombinedGeometry、EllipseGeometry 和 PathGeometry)提供绘制 2D 图形的方式以及命中测试和剪裁支持。 几何对象可用于定义控件的区域或定义应用于图像的剪裁区域等。 几何对象可以是简单区域(例如矩形和圆形),或者是由两个或多个几何对象创建的复合区域。 通过合并 PathSegment 派生对象(例如 ArcSegment、BezierSegment 和 QuadraticBezierSegment),可创建更复杂的几何区域。
表面上看,Geometry 类和 Shape 类非常相似。 二者都用于绘制 2D 图形,且都具有相似的具体派生类,例如 EllipseGeometry 和 Ellipse。 但是,这两个类集之间存在重大区别。 一方面,Geometry 类缺少 Shape 类的部分功能,例如绘制自身的功能。 若要绘制几何对象,必须使用另一个类(例如 DrawingContext、Drawing 或 Path(值得注意的是 Path 是一个 Shape))来执行绘制操作。 填充、笔划和笔划粗细等绘制属性位于绘制几何对象的类上,而形状对象中包含这些属性。 可以这样来理解这种差别:几何对象定义区域(例如圆形),而形状对象定义区域、定义如何填充区域和设置区域边框并参与布局系统。
由于 Shape 对象派生自 FrameworkElement 类,因此使用这些对象会使应用程序的内存消耗显著增加。 如果对于图形内容确实不需要 FrameworkElement 功能,请考虑使用更轻量的 Drawing 对象。
有关 Drawing 对象的详细信息,请参阅 Drawing 对象概述。
StreamGeometry 对象
在创建几何形状时,StreamGeometry 对象是对 PathGeometry 的轻量替代。 需要描述复杂几何时使用 StreamGeometry。 StreamGeometry 非常适合用于处理许多 PathGeometry 对象,且与使用众多单独的 PathGeometry 对象相比,其性能更佳。
以下示例使用特性语法在 XAML 中创建三角形 StreamGeometry。
<Page xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
<StackPanel>
<Path Data="F0 M10,100 L100,100 100,50Z"
StrokeThickness="1" Stroke="Black"/>
</StackPanel>
</Page>
有关 StreamGeometry 对象的详细信息,请参阅使用 StreamGeometry 创建形状。
DrawingVisual 对象
DrawingVisual 对象是一个轻量绘图类,用于绘制形状、图像或文本。 此类之所以为轻量类是因为它不提供布局或事件处理,从而性能得以提升。 因此,绘图非常适用于背景和剪贴画。 有关详细信息,请参阅使用 DrawingVisual 对象。
映像
WPF 图像处理大幅改进了 Windows 先前版本的图像处理功能。 显示位图或在公共控件上使用图像等图像处理功能以前主要由 Microsoft Windows 图形设备接口 (GDI) 或 Microsoft Windows GDI+ 应用程序编程接口 (API) 处理。 这些 API 提供基线图像处理功能,但缺少编解码器扩展性支持和高保真图像支持等功能。 WPF 图像处理 API 已经过重新设计,克服了 GDI 和 GDI+ 的缺点,提供一组新的 API,用于在应用程序内显示和使用图像。
使用图像时,为使性能更佳,请考虑以下建议:
如果应用程序要求显示缩略图,请考虑创建一个缩略版图像。 默认情况下,WPF 会加载图像并将其解码到最大尺寸。 如果仅需要图像的缩略版本,WPF 会先将图像解码为完整尺寸,然后将其缩放为缩略图大小,这个过程是多余的。 若要避免这个多余的过程,可请求 WPF 将图像解码到缩略图大小,或者请求 WPF 加载缩略图大小的图像。
请务必将图像解码到所需大小而不是默认大小。 如上所述,请求 WPF 将图像解码为所需大小而不是默认的最大尺寸。 这样不仅会减小应用程序的工作集,还会减慢其执行速度。
如果可能,请将多个图像合并到单个图像中,例如由多个图像构成的胶卷条。
有关详细信息,请参阅 图像概述。
BitmapScalingMode
对任何位图缩放进行动画处理时,默认的高质量图像重采样算法有时可能由于消耗过多系统资源导致帧速率下降,继而导致动画明显变慢。 通过将 RenderOptions 对象的 BitmapScalingMode 属性设置为 LowQuality,缩放位图时可创建更为流畅的动画。 处理图像时,LowQuality 模式会通知 WPF 绘制引擎从质量优化算法切换至速度优化算法。
下面的示例演示如何为图像对象设置 BitmapScalingMode。
// Set the bitmap scaling mode for the image to render faster.
RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.LowQuality);
' Set the bitmap scaling mode for the image to render faster.
RenderOptions.SetBitmapScalingMode(MyImage, BitmapScalingMode.LowQuality)
CachingHint
默认情况下,WPF 不会缓存 TileBrush 对象的绘制内容,例如 DrawingBrush 和 VisualBrush。 在静态方案中,内容和场景中 TileBrush 的使用皆不会发生改变,这样具有一定意义,因为可节省视频内存。 以非静态方式使用具有静态内容的 TileBrush 时(例如静态 DrawingBrush 或 VisualBrush 映射到旋转 3D 对象的图面时),这样做的意义不大。 WPF 的默认行为是对每个帧重新绘制 DrawingBrush 或 VisualBrush 的整个内容(即使内容未改变也是如此)。
通过将 RenderOptions 对象的 CachingHint 属性设置为 Cache,可使用缓存版平铺画笔对象来提升性能。
CacheInvalidationThresholdMinimum 和 CacheInvalidationThresholdMaximum 属性值为相对大小值,这些值决定由于比例更改而应何时重新生成 TileBrush 对象。 例如,通过将 CacheInvalidationThresholdMaximum 属性设置为 2.0,TileBrush 的缓存仅需在其大小超过当前缓存大小两倍时重新生成。
如下示例演示如何对 DrawingBrush 使用缓存提示选项。
DrawingBrush drawingBrush = new DrawingBrush();
// Set the caching hint option for the brush.
RenderOptions.SetCachingHint(drawingBrush, CachingHint.Cache);
// Set the minimum and maximum relative sizes for regenerating the tiled brush.
// The tiled brush will be regenerated and re-cached when its size is
// 0.5x or 2x of the current cached size.
RenderOptions.SetCacheInvalidationThresholdMinimum(drawingBrush, 0.5);
RenderOptions.SetCacheInvalidationThresholdMaximum(drawingBrush, 2.0);
Dim drawingBrush As New DrawingBrush()
' Set the caching hint option for the brush.
RenderOptions.SetCachingHint(drawingBrush, CachingHint.Cache)
' Set the minimum and maximum relative sizes for regenerating the tiled brush.
' The tiled brush will be regenerated and re-cached when its size is
' 0.5x or 2x of the current cached size.
RenderOptions.SetCacheInvalidationThresholdMinimum(drawingBrush, 0.5)
RenderOptions.SetCacheInvalidationThresholdMaximum(drawingBrush, 2.0)