Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles
(untagged)

SVGImage Control

0.00/5 (No votes)
29 Jul 2010 1  
A WPF control for showing SVG images.

svgimage_01.jpg

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.
  • svgimage_02.jpg

  • 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.
  • svgimage_03.jpg

  • 7/13/10 - Uploaded new zip file with the TestForm file removed.
  • 7/18/10 - Added support for letter spacing and word spacing.
  • svgimage_04.jpg

    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
  • svgimage_05.jpg

    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.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here