如果要做下面这样的一个东西作为背景。你会如何做呢?
图 1. 目标背景效果
方案一,用 PS画出来。然后把这个 PNG图片作为背景色。这个方案可以,但是如果想让这个线的颜色可配置呢?如何线的粗细不确定呢?无论哪个问题,用像素图的方式都不好 解决。
方案二,用 WPF的矢量图绘制。这个方案可以比较容易地解决上面两 个问题。
但是无论我们用哪种方式,都不会把整个图的大小画出来。而是画是一个最小的图元,然后重复。 标量图方案
对于 PS画的标量而言,有下面这样的一个图就可以了。然后在要绘制 的区域内无限重复。尤其是做网页的上的材质都是这样,要知道图片的大小可不是比文字,全部绘制出来的话图片可能会很大。而且 Visual Designer改起来也会比较累。
图 2. PNG材质图片(放大后)
比如这个图叫 Twill.png,大小是 6*6。那么在 WPF中使用这个图元来建立图 1中材质的代码如下。
< DrawingBrush x : Key ="PicTwillBrush"
Stretch ="Fill" TileMode ="Tile"
Viewport ="0,0,6,6" ViewportUnits ="Absolute">
< DrawingBrush.Drawing >
< ImageDrawing ImageSource ="Textures/Twill.png" Rect ="0,0,6,6"/>
</ DrawingBrush.Drawing >
</ DrawingBrush >
默认情况下,这个用方案一实现的材质很完美,和图 1完美一样。但是 如果用 ViewBox把这个图片放下之后会出现下面的现象。
图 3. 实现渲染效果( ViewBox放大)
能看出图片已经是一块块的了。你可以把这个看作 WPF的 Bug。如果我是 QA我就会这么认为。虽然我也很理解这是平滑处理 +TitleMode渲染的结果——平滑算法没有把这个大图当成整个的一个图处理,而是单独地处理每一小块。但是我也相信这不是什么难以解决的问题。 所以它就是一个 Bug,没有什么好说的。只不过这是个小 Bug,不 Fix也就算了(因为有其它更严重的 Bug等着 MS的 Dev们),反正 有办法解决的。
一个不完全解决方案,可以使这个分块的视觉效果弱化 50.00%。 就是把图元改成这个样子。
图 4. 更好的 PNG材质
不一定是一块俩像素,一块 4个像素。不过两者个数之差越小越好。所 以最好是两条 3像素的线。然后视觉图会变成下面这个样子。
图 5. 显示效果( ViewBox放大)
比之前要好一些。至于原因读者自己分析一下吧。(包括那个 50.00%是 如何计算出来的)
所以有经验的材质设计者,即使能用简单的角衔接,也不会用,而只使用边衔接。(当然他们主要并不是为了这个原因)
上面讨论完了位图的作法。如果你的图片不需要支持缩放,而且又不嫌 PNG占用空间大的话,用 PNG图片还是很不错的方案的。
矢量图的实现方案
有人会觉得在 WPF做个矢量图太简单了。不就是用 Expression Design画么?对,没有错,但是问题你要画成什么个样子?因为矢量图的画法就多了。矢量的一个特点就是,图像不 再是以像素为单位的。而是一个完完整整的图形。我的第一感觉是这样的。(也许你的不是)
图 6. 向量材质图(根本不可行)
有人可能一眼就看出问题了,这种做法里,线的两头不是方的。多个这样的小图接起来,线看上去也不会是连续的。解决办法 和标量图的是一样的。就是使用边衔接。把图中的一条线分成两条。下面是两条做法。请读者自行判断哪种更好,并解释原因。
图 7. 可选向量材质图
上图的代码分别是:
< StreamGeometry x:Key = "SimpleTwill "> M3,0 L4,0 0,4 0,3 Z M3,6 L4,6 6,4 6,3 Z</ StreamGeometry >
和
< StreamGeometry x:Key = "BestTwill "> M2.5,0 L3.5,0 0,3.5 0,2.5Z M2.5,6 L3.5,6 6,3.5 6,2.5 Z</ StreamGeometry >
如果一开始你是用 Expression Design来画这个东 西,相信代码一定不会这么简洁的。 Expression Design最让人不能忍受的就是生成出来的 数据,常常有 1.00001这样的东西。
对应的 Brush代码是:
< DrawingBrush x:Key = "SimpleTwillBrush">
Stretch = "Fill " TileMode = "Tile "
Viewport = "0,0,6,6 " ViewportUnits = "Absolute ">
< DrawingBrush.Drawing >
< GeometryDrawing Brush = "Red " Geometry = "{StaticResource SimpleTwill} "/>
</ DrawingBrush.Drawing >
</ DrawingBrush >
但是无论向量图自身的定义是多么的“平滑”,不幸的是它最终还是要被渲染到以像素为单位的显示器上。更不幸的是,由于 向量图的定义一般不与显示器的像素格匹配,所以在渲染的过程中,势必要做处理。结果渲染出来的就是下面这个熊样了。
图 8. 向量材质渲染效果
最上面一条是期望的效果,下面两条就分别是由那两个向量图元定义出来的渲染效果。如果看不清楚,下面是他们俩的放大 图。(请读者自行判断上面的结果分别是基于哪个向量图元绘制的)
图 9. 向量材质渲染效果(放大图)
从图中可以看出,最终的渲染结果没有对齐到像素,严格来讲就是渲染结果不正确。(顺便说一下,请不要提 SnapsToDevicePixels这个属性,如果你觉得这个属性可以解决这个问题,只说明你还没有搞清楚这个属性是在什么时候发挥作用的。其实即使我这样说了,我 感觉还是会有人回复说要用这个属性,因为他们没有认真看文章。) 关于向量图的性能问题
而且,向量没有对齐到像素的另一个严重问题就是性能。这个性能差异用肉眼就可以看得出来。如果你拖拽窗口,会发布由上 面这两个向量渲染出来的背景在闪。(此测试方法理论上只在低配置系统上可行。)为什么会闪,因为它比对齐到像素的方式至少多计算 1倍的像素点,而且每个像素点的颜色都要重新计算一遍。这个计算量是很大的。
所以很多用 WPF做过开发的人,会发现如果直接用 Design绘制出来的复杂向量图做整个程序的背景,程序就会变得很卡,如果先转成 PNG之 类的图片,再用图片做背景,性能就会好得多。原因就在于此。使用向量,每个像素点的信息都要重新计算出来。而使用图片,如果图片大小和背景大小一样,则只 需要原模原样地把图片上的像素信息搬到显示器上就行了,不需要计算什么。
但是这并不能说向量图就一定性能低下。如果能把向量图,做得与像素点能对应起来,向量图也一样可以具有很好的性能。比 如上面的向量图闪,如果我们把向量图定义成下面这个样子就不会闪了。 高性能向量图方案
图 10. 像素对齐的向量材质图
这个向量的定义需要更多的代码,如下所示:
< StreamGeometry x:Key = "PixelTwill "> M0,2 L1,2 1,3 0,3 Z M1,1 L2,1 2,2 1,2 z M2,0 L3,0 3,1 2,1 Z M3,5 L4,5 4,6 3,6 Z M4,4 L5,4 5,5 4,5 Z M5,3 L6,3 6,4 5,4 Z</ StreamGeometry >
虽然看上去代码更多了,但是由于它对齐到了像素点,所以其实性能更好。根据肉眼观测,完全看不到闪烁现象。
但是这样的向量图已经失去了向量图的意义了,向量图的一个重点特点就是无极缩放。放大之后图像依然平滑。但是这个向量 图其实就和一个标量图的效果是一样的了——放大之后就会有锯齿出现。但是如果一个向量图不会放大,用这样方式还是很不错,既提前了性能,又保证了图像的清 晰、锐利。但是这样做的成本很高,做个小图还可以,做个大图就很不现实了。 图片模糊
无论是标量图还是矢量图,实现项目中常常会出现模糊。下一篇将会为大家介绍几种常见的导致模糊的情况和解决办法。
源地址:http://www.cnblogs.com/nankezhis ... exturesolution.html