Introduction
SVG (Scalable Vector Graphic) is an XML based graphic format.
This little project started out as a simple SVG to XAML converter. I looked at some simple SVG files and noticed the similarity to XAML defined graphic, and decided to write a converter. However, I soon realized that SVG is a very complex format, and at the same time, I found no good reason for converting to XAML just to show the image on the screen, so instead, I started working on the SVG
, SVGRender
and the SVGImage
classes.
- The
SVG
class is the class that reads and parses the XML file.
SVGRender
is the class that creates the WPF Drawing
object based on the information from the SVG
class.
SVGImage
is the image control. The image control can either load the image from a filename - SetImage(filename)
- or by setting the Drawing
object through SetImage(Drawing)
, which allows multiple controls to share the same drawing instance.
The control only has a couple of properties, SizeType
and ImageSource
.
SizeType
- controls how the image is stretched to fill the control
None
: The image is not scaled. The image location is translated so the top left corner of the image bounding box is moved to the top left corner of the image control.
ContentToSizeNoStretch
: The image is scaled to fit the control without any stretching. Either X or Y direction will be scaled to fill the entire width or height.
ContentToSizeStretch
: The image will be stretched to fill the entire width and height.
SizeToContent
: The control will be resized to fit the un-scaled image. If the image is larger than the max size for the control, the control is set to max size and the image is scaled.
For None
and ContentToSizeNoStretch
, the Horizontal/VerticalContentAlignment
properties can be used to position the image within the control.
ImageSource
- This property is the same as SetImage(drawing)
, and is exposed to allow for the source to be set through binding.
The SVG format
Before writing any parser, it is a good idea to try and get a good understanding of the format you are going to parse, so I looked around for some documentation and came across this link which is the specification for SVG:
I also found this online book (also available for download in PDF format):
and this free SVG editor:
And after spending some time reading, I was ready to get started on the parser.
A quick walkthrough of the parsing
The main entry point is the SVG constructor (SVGReader.cs) which takes a filename. The only point of interest here is that I had to set the XmlResolver
to null
to avoid getting exceptions while reading different SVG files I found online.
doc.XmlResolver = null;
Each XML node is then parsed in the static method Group.AddToList
(Shape.cs). Here, a new Shape
object is created based on the XML tag, and the object itself is then passed the XML node to complete the parsing.
All basic shapes are implemented in Shapes.cs, while the more complex Path
shape is implemented in PathShape.cs.
Finally, the actual WPF Drawing
object is generated in the SVGRender
class.
SVGRender.LoadGroup
creates a single DrawingGroup
object which contains a child group for each of the SVG shapes, where each shape is converted into a Geometry
and then wrapped in a GeometryDrawing
object to set the fill and stroke style.
That is pretty much it.
TSpan
7/29/2010 - added basic support for tspan
in the text
element.
Not all the different attributes supported by tspan
are implemented, only font, style, and stroke/fill color.
Each tspan
element can be thought of as an individual text element, complete with style, stroke, and fill attributes, and for this reason, it is derived from the base shape.
Parsing of a text with tspan
elements is done in TextShape.ParseTSpan
.
The rendering part is not designed for nested shapes (except for groups), but expect one shape, one geometry. TSpan
is a bit different; each tspan
element (even if nested) is added to the same GeometryGroup
when the geometries are build. Each geometry can have different attributes which are the attributes on the tspan
shape itself. Instead of redesigning how the SVGRender
creates the drawing by iterating though the shapes, I chose to attach the tspan
element (shape) itself directly to each of the build geometries using attached properties and then 'extract' the shape from the geometry when creating the drawing.
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));
}
}
}
Finally
The SVG parser and render is still not complete, but it is in a state where it can read most 'simple' SVG files I have found online so far. Of the chapters in the SVG Essentials book, the following chapters have been implemented:
- Chapter 3 - Basic shapes
- Chapter 5 - Transforming the coordinate system
- Chapter 6 - Path
- Chapter 7 - Patterns and gradients (only gradients is implemented)
I will continue working on this, and the next step is probably to add support for the text
element.
Note! Some of the SVG files in the sample folder were found as free files online.
Revision history
- 7/9/10 - Added support for
<use>
and <image>
tags. Only internal groups can be referenced by <use>
. The filename referenced by <image>
must be relative to the current location of the CSV file. Examples 4.5, 4.6, and 4.8 from SVG Essentials have been added.
- 7/11/10 - Added support for simple text and formatting. Still missing support for word / letter spacing, tspan, text along a path, and other advanced format options.
- 7/13/10 - Uploaded new zip file with the TestForm file removed.
- 7/18/10 - Added support for letter spacing and word spacing.
For text formatting, I had to use the low level GlyphRun
, as FormattedText
does not provide the same control over letter and word spacing.
I added a new class TextRender.BuildTextGeometry
(in TextRender.cs) which builds the geometry for the text using a GlyphRun example I found in this free eBook: http://books.google.com/books?id=558i6t1dKEAC&pg=PA485&source=gbs_toc_r&cad=4#v=onepage&q&f=false, with some slight modifications to fit my needs.
- 7/29/2010
I finally got around to add basic support for tspan
in the text
element. Not all the different attributes supported by tspan
are implemented, only font, style, and stroke/fill color.