Click here to Skip to main content
15,896,118 members
Articles / Desktop Programming / WPF

SharpVectors - SVG# Reloaded: An Introduction

Rate me:
Please Sign up or sign in to vote.
4.98/5 (33 votes)
17 Nov 2010BSD10 min read 206K   21.7K   101  
A C# library for converting SVG to WPF and viewing SVG files in WPF Applications
using System;
using System.Xml;
using System.Linq;
using System.Text;
using System.Collections.Generic;

using System.Windows;
using System.Windows.Media;

using SharpVectors.Dom.Svg;
using SharpVectors.Dom.Css;

namespace SharpVectors.Renderers.Wpf
{
    public sealed class WpfPatternFill : WpfFill
    {
        #region Private Fields

        private XmlElement oldParent;
        private SvgPatternElement _patternElement;

        #endregion

        #region Constructors and Destructor

        public WpfPatternFill(SvgPatternElement patternElement)
		{
			_patternElement = patternElement;
        }

        #endregion

        #region Public Methods

        public override Brush GetBrush(WpfDrawingContext context)
        {
            Rect bounds = new Rect(0, 0, 1, 1);
            Drawing image = GetImage(context);
            Rect destRect = GetDestRect(bounds);            

            DrawingBrush tb  = new DrawingBrush(image);
            //tb.Viewbox = new Rect(0, 0, destRect.Width, destRect.Height);
            //tb.Viewport = new Rect(0, 0, destRect.Width, destRect.Height);
            tb.Viewbox       = destRect;
            tb.Viewport      = destRect;
            tb.ViewboxUnits  = BrushMappingMode.Absolute;
            tb.ViewportUnits = BrushMappingMode.Absolute;
            tb.TileMode      = TileMode.Tile;

            MatrixTransform transform = GetTransformMatrix(image.Bounds);
            if (transform != null && !transform.Matrix.IsIdentity)
            {
                tb.Transform = transform;
            }

            return tb;
        }

        #endregion

        #region Private Methods

        private SvgSvgElement MoveIntoSvgElement()
        {
            SvgDocument doc = _patternElement.OwnerDocument;
            SvgSvgElement svgElm = doc.CreateElement("", "svg", SvgDocument.SvgNamespace) as SvgSvgElement;

            XmlNodeList children = _patternElement.Children;
            if (children.Count > 0)
            {
                oldParent = children[0].ParentNode as XmlElement;
            }

            for (int i = 0; i < children.Count; i++)
            {
                svgElm.AppendChild(children[i]);
            }

            if (_patternElement.HasAttribute("viewBox"))
            {
                svgElm.SetAttribute("viewBox", _patternElement.GetAttribute("viewBox"));
            }
            //svgElm.SetAttribute("x", "0");
            //svgElm.SetAttribute("y", "0");
            svgElm.SetAttribute("x",      _patternElement.GetAttribute("x"));
            svgElm.SetAttribute("y",      _patternElement.GetAttribute("y"));
            svgElm.SetAttribute("width",  _patternElement.GetAttribute("width"));
            svgElm.SetAttribute("height", _patternElement.GetAttribute("height"));

            if (_patternElement.PatternContentUnits.AnimVal.Equals(SvgUnitType.ObjectBoundingBox))
            {
                svgElm.SetAttribute("viewBox", "0 0 1 1");
            }

            _patternElement.AppendChild(svgElm);

            return svgElm;
        }

        private void MoveOutOfSvgElement(SvgSvgElement svgElm)
        {
            while (svgElm.ChildNodes.Count > 0)
            {
                oldParent.AppendChild(svgElm.ChildNodes[0]);
            }

            _patternElement.RemoveChild(svgElm);
        }

        private Drawing GetImage(WpfDrawingContext context)
        {
            WpfDrawingRenderer renderer = new WpfDrawingRenderer();
            renderer.Window = _patternElement.OwnerDocument.Window as SvgWindow;

            WpfDrawingSettings settings = context.Settings.Clone();
            settings.TextAsGeometry = true;
            WpfDrawingContext patternContext = new WpfDrawingContext(true,
                settings);

            patternContext.Initialize(null, context.FontFamilyVisitor, null);

            SvgSvgElement elm = MoveIntoSvgElement();

            renderer.Render((SvgElement)elm, patternContext);
            Drawing img = renderer.Drawing;

            MoveOutOfSvgElement(elm);

            return img;
        }

        private double CalcPatternUnit(SvgLength length, SvgLengthDirection dir, Rect bounds)
        {
            if (_patternElement.PatternUnits.AnimVal.Equals(SvgUnitType.UserSpaceOnUse))
            {
                return length.Value;
            }
            else
            {
                double calcValue = length.ValueInSpecifiedUnits;
                if (dir == SvgLengthDirection.Horizontal)
                {
                    calcValue *= bounds.Width;
                }
                else
                {
                    calcValue *= bounds.Height;
                }
                if (length.UnitType == SvgLengthType.Percentage)
                {
                    calcValue /= 100F;
                }

                return calcValue;
            }
        }

        private Rect GetDestRect(Rect bounds)
        {
            Rect result = new Rect(0, 0, 0, 0);

            result.X = CalcPatternUnit(_patternElement.X.AnimVal as SvgLength,
                SvgLengthDirection.Horizontal, bounds);
            result.Y = CalcPatternUnit(_patternElement.Y.AnimVal as SvgLength,
                SvgLengthDirection.Vertical, bounds);

            result.Width = CalcPatternUnit(_patternElement.Width.AnimVal as SvgLength,
                SvgLengthDirection.Horizontal, bounds);
            result.Height = CalcPatternUnit(_patternElement.Height.AnimVal as SvgLength,
                SvgLengthDirection.Vertical, bounds);

            return result;
        }

        private MatrixTransform GetTransformMatrix(Rect bounds)
        {
            SvgMatrix svgMatrix = 
                ((SvgTransformList)_patternElement.PatternTransform.AnimVal).TotalMatrix;

            MatrixTransform transformMatrix = new MatrixTransform(svgMatrix.A, svgMatrix.B, svgMatrix.C,
                svgMatrix.D, svgMatrix.E, svgMatrix.F);

            double translateX = CalcPatternUnit(_patternElement.X.AnimVal as SvgLength,
                SvgLengthDirection.Horizontal, bounds);
            double translateY = CalcPatternUnit(_patternElement.Y.AnimVal as SvgLength,
                SvgLengthDirection.Vertical, bounds);

            transformMatrix.Matrix.TranslatePrepend(translateX, translateY);

            return transformMatrix;
        }

        #endregion
    }
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The BSD License


Written By
Engineer
Japan Japan
Systems Engineer

Comments and Discussions