65.9K
CodeProject 正在变化。 阅读更多。
Home

SVGImage 控件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.89/5 (44投票s)

2010年7月7日

CPOL

5分钟阅读

viewsIcon

353881

downloadIcon

10894

一个用于显示 SVG 图像的 WPF 控件。

svgimage_01.jpg

引言

SVG(可缩放矢量图形)是一种基于 XML 的图形格式。

这个小程序最初是一个简单的 SVG 到 XAML 转换器。我查看了一些简单的 SVG 文件,注意到它与 XAML 定义的图形相似,于是决定编写一个转换器。然而,我很快意识到 SVG 是一种非常复杂的格式,同时,我也没有找到将 SVG 转换为 XAML 来显示图像的充分理由,因此,我开始着手开发 SVGSVGRenderSVGImage 类。

  • SVG 类是用于读取和解析 XML 文件的类。
  • SVGRender 类根据 SVG 类的信息创建 WPF Drawing 对象。
  • SVGImage 是图像控件。图像控件可以通过文件名加载图像 - SetImage(filename) - 或者通过 SetImage(Drawing) 设置 Drawing 对象,这允许多个控件共享同一个绘图实例。

该控件只有几个属性:SizeTypeImageSource

  • SizeType - 控制图像如何拉伸以填充控件
    • None:图像不缩放。图像位置会移动,使得图像边界框的左上角移动到图像控件的左上角。
    • ContentToSizeNoStretch:图像会被缩放以适应控件,但不会拉伸。X 或 Y 方向会按比例缩放以填充整个宽度或高度。
    • ContentToSizeStretch:图像将被拉伸以填充整个宽度和高度。
    • SizeToContent:控件的大小会被调整以适应未缩放的图像。如果图像大于控件的最大尺寸,则控件会被设置为最大尺寸,并且图像会被缩放。

    对于 NoneContentToSizeNoStretch,可以使用 Horizontal/VerticalContentAlignment 属性来定位图像在控件内的位置。

  • ImageSource - 此属性与 SetImage(drawing) 相同,并公开出来以便通过绑定设置源。

SVG 格式

在编写任何解析器之前,最好先对要解析的格式有一个深入的了解。因此,我查找了一些文档,并找到了这个 SVG 规范的链接:

我还发现了这本在线书籍(也提供 PDF 格式下载):

以及这个免费的 SVG 编辑器:

在花了一些时间阅读之后,我准备开始编写解析器了。

解析过程快速概览

主入口点是 SVG 构造函数 (SVGReader.cs),它接受一个文件名。这里唯一值得关注的是,我必须将 XmlResolver 设置为 null,以避免在读取我在线找到的各种 SVG 文件时出现异常。

doc.XmlResolver = null; 

每个 XML 节点随后在静态方法 Group.AddToList (Shape.cs) 中进行解析。这里会根据 XML 标签创建一个新的 Shape 对象,然后将该对象本身传递给 XML 节点以完成解析。

所有基本形状都实现在 Shapes.cs 中,而更复杂的 Path 形状则实现在 PathShape.cs 中。

最后,实际的 WPF Drawing 对象在 SVGRender 类中生成。

SVGRender.LoadGroup 创建一个单一的 DrawingGroup 对象,其中包含每个 SVG 形状的一个子组,每个形状被转换为一个 Geometry,然后包装在一个 GeometryDrawing 对象中以设置填充和描边样式。

基本上就是这样了。

TSpan

2010/7/29 - 在 text 元素中添加了对 tspan 的基本支持。

并非 tspan 支持的所有不同属性都已实现,仅支持字体、样式和描边/填充颜色。

每个 tspan 元素都可以被视为一个独立的文本元素,具备样式、描边和填充属性,因此它继承自基类 Shape。

TextShape.ParseTSpan 中完成带有 tspan 元素的文本解析。

渲染部分并未针对嵌套形状(除了组)进行设计,期望一个形状对应一个几何图形。TSpan 有点不同;当构建几何图形时,每个 tspan 元素(即使是嵌套的)都会被添加到同一个 GeometryGroup 中。每个几何图形可以具有不同的属性,这些属性是 tspan 形状本身的属性。我没有重新设计 SVGRender 如何通过迭代形状来创建绘图,而是选择使用附加属性将 tspan 元素(形状)直接附加到每个构建的几何图形上,然后在创建绘图时从几何图形中“提取”形状。

if (shape is ClipArtViewer.TextShape)
{
       GeometryGroup gp = TextRender.BuildTextGeometry(shape as ClipArtViewer.TextShape);
       if (gp != null)
       {
              foreach (Geometry gm in gp.Children)
              {
                     TextShape.TSpan.Element tspan = TextRender.GetElement(gm);
                     if (tspan != null)
                           grp.Children.Add(NewDrawingItem(tspan, gm));
                     else
                           grp.Children.Add(NewDrawingItem(shape, gm));
              }
       }
}

最后

SVG 解析器和渲染器仍然不完整,但目前的状态已经可以读取我迄今为止在网上找到的大多数“简单”SVG 文件。SVG Essentials 书籍中的以下章节已实现:

  • 第 3 章 - 基本形状
  • 第 5 章 - 坐标系统变换
  • 第 6 章 - 路径
  • 第 7 章 - 图案和渐变(仅实现了渐变)

我将继续进行此项工作,下一步可能是添加对 text 元素的支持。

注意!示例文件夹中的一些 SVG 文件是从网上免费获取的。

修订历史

  • 2010/7/9 - 添加了对 <use><image> 标签的支持。<use> 只能引用内部组。<image> 引用的文件名必须相对于 CSV 文件当前位置。已添加 SVG Essentials 的示例 4.5、4.6 和 4.8。
  • svgimage_02.jpg

  • 2010/7/11 - 添加了对简单文本和格式化的支持。仍然缺少对字间距/词间距、tspan、沿路径文本以及其他高级格式选项的支持。
  • svgimage_03.jpg

  • 2010/7/13 - 上传了新的 zip 文件,移除了 TestForm 文件。
  • 2010/7/18 - 添加了对字间距和词间距的支持。
  • svgimage_04.jpg

    为了文本格式化,我不得不使用低级别的 GlyphRun,因为 FormattedText 没有提供对字间距和词间距相同的控制。

    我添加了一个新类 TextRender.BuildTextGeometry (在 TextRender.cs 中),它使用一本免费电子书中找到的 GlyphRun 示例来构建文本的几何图形:http://books.google.com/books?id=558i6t1dKEAC&pg=PA485&source=gbs_toc_r&cad=4#v=onepage&q&f=false,并进行了一些小修改以适应我的需求。

  • 7/29/2010
  • svgimage_05.jpg

    我终于完成了在 text 元素中对 tspan 的基本支持。并非 tspan 支持的所有不同属性都已实现,仅支持字体、样式和描边/填充颜色。

© . All rights reserved.