优化性能:二维图形和图像处理
更新:2007 年 11 月
WPF 提供了多种二维图形和图像处理功能,可以针对您的应用程序要求优化这些功能。本主题提供有关二维图形和图像处理性能优化的信息。
本主题包括下列各节。
- 绘图和形状
- StreamGeometry 对象
- DrawingVisual 对象
- 图像
- 相关主题
绘图和形状
WPF 提供了 Drawing 和 Shape 这两个对象以表示绘图内容。不过,Drawing 对象比 Shape 对象结构简单并且性能特性更为优良。
使用 Shape,可以在屏幕上绘制图形形状。由于 Shape 对象派生于 FrameworkElement 类,因此它们可以在面板和大多数控件中使用。
WPF 提供了对图形和呈现服务的若干层访问。在顶层,Shape 对象很容易使用,并且提供了许多有用的功能,例如布局和事件处理。WPF 提供了大量随时可用的形状对象。所有形状对象都是从 Shape 类继承的。可用的形状对象有 Ellipse、Line、Path、Polygon、Polyline 和 Rectangle。
Drawing 对象不是派生自 FrameworkElement 类,相比而言它更轻量地实现形状、图像和文本的呈现。
有以下四种类型的 Drawing 对象:
GeometryDrawing:绘制形状。
ImageDrawing:绘制图像。
GlyphRunDrawing:绘制文本。
DrawingGroup:绘制其他绘图。使用绘图组可以将其他绘图组合成一个复合绘图。
GeometryDrawing 对象用于呈现几何图形内容。Geometry 类以及从中派生的具体类(如 CombinedGeometry、EllipseGeometry 和 PathGeometry)提供二维图形的呈现方式,此外还提供命中测试和剪辑支持。例如,Geometry 对象可用于定义控件的区域,或者定义要应用到图像的剪辑区域。Geometry 对象可以是简单的区域(如矩形和圆形),也可以是基于两个或多个几何图形对象创建的复合区域。通过组合 PathSegment 派生的对象(例如 ArcSegment、BezierSegment 和 QuadraticBezierSegment),可以创建较复杂的几何图形区域。
从表面上看,Geometry 类和 Shape 类十分相似。它们都可用来呈现二维图形,并且从其自身派生的具体类也很相似,例如 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="https://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="https://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 对象。
图像
与以前版本的 Windows 中的图像处理功能相比,WPF 图像处理功能有很大的改进。图像处理功能(例如在常用控件上显示位图或使用图像)主要由 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);
CachingHint
默认情况下,WPF 不缓存 TileBrush 对象(例如 DrawingBrush 和 VisualBrush)的已呈现内容。在内容或场景中对 TileBrush 的使用均不更改的静态情况下,此功能很有用,因为它可以节省视频内存。在以非静态方式使用具有静态内容的 TileBrush 时(例如当静态的 DrawingBrush 或 VisualBrush 映射到旋转三维对象的表面时),此功能的作用不大。WPF 的默认行为是逐帧重新呈现 DrawingBrush 或 VisualBrush 的整个内容,即使内容没有更改也是如此。
通过将 RenderOptions 对象的 CachingHint 属性设置为 Cache,可以使用图块画笔对象的缓存版本来提高性能。
CacheInvalidationThresholdMinimum 和 CacheInvalidationThresholdMaximum 属性值是相对大小值,可确定由于缩放比例更改而应重新生成 TileBrush 对象的时间。例如,如果将 CacheInvalidationThresholdMaximum 属性设置为 2.0,则仅当 TileBrush 的缓存大小超过当前缓存大小的两倍时,才需要重新生成。
下面的示例演示如何将缓存提示选项用于 DrawingBrush。
// Set the minimum and maximum relative sizes for regenerating the tiled brush.
RenderOptions.SetCacheInvalidationThresholdMinimum(drawingBrush, 0.5);
RenderOptions.SetCacheInvalidationThresholdMaximum(drawingBrush, 2.0);
// The tiled brush will be regenerated when the size is
// 0.5x, 0.25x (and so forth)
// and
// 2x, 4x, 8x (and so forth)
// of the original size.
// Set the caching hint option for the brush.
RenderOptions.SetCachingHint(drawingBrush, CachingHint.Cache);