Click here to Skip to main content
15,886,199 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 204.7K   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.Css;
using SharpVectors.Dom.Svg;

using SharpVectors.Renderers.Wpf;

namespace SharpVectors.Renderers.Texts
{
    public sealed class WpfPathTextRenderer : WpfTextRenderer
    {
        #region Private Fields

        #endregion

        #region Constructors and Destructor

        public WpfPathTextRenderer(SvgTextElement textElement, WpfTextRendering textRendering)
            : base(textElement, textRendering)
        {
        }

        #endregion

        #region Public Methods

        public override void RenderSingleLineText(SvgTextContentElement element,
            ref Point ctp, string text, double rotate, WpfTextPlacement placement)
        {
            this.RenderTextPath((SvgTextPathElement)element, ref ctp, rotate, placement);
        }

        public override void RenderTextRun(SvgTextContentElement element,
            ref Point ctp, string text, double rotate, WpfTextPlacement placement)
        {
        }

        #endregion

        #region Private Methods

        private void RenderTextPath(SvgTextPathElement textPath, ref Point ctp,
            double rotate, WpfTextPlacement placement)
        {
            if (textPath.ChildNodes == null || textPath.ChildNodes.Count == 0)
            {
                return;
            }

            SvgElement targetPath = textPath.ReferencedElement as SvgElement;
            if (targetPath == null)
            {
                return;
            }

            PathGeometry pathGeometry = WpfRendering.CreateGeometry(targetPath, true) as PathGeometry;
            if (pathGeometry == null)
            {
                return;
            }

            this.IsTextPath = true;

            WpfTextOnPathDrawing pathDrawing = new WpfTextOnPathDrawing();

            pathDrawing.BeginTextPath();

            XmlNodeType nodeType = XmlNodeType.None;

            foreach (XmlNode child in textPath.ChildNodes)
            {
                nodeType = child.NodeType;
                if (nodeType == XmlNodeType.Text)
                {
                    RenderTextPath(textPath, pathDrawing, GetText(textPath, child),
                        new Point(ctp.X, ctp.Y), rotate, placement);
                }
                else if (nodeType == XmlNodeType.Element)
                {
                    string nodeName = child.Name;
                    if (String.Equals(nodeName, "tref"))
                    {
                        RenderTRefPath((SvgTRefElement)child, pathDrawing, ref ctp);
                    }
                    else if (String.Equals(nodeName, "tspan"))
                    {
                        RenderTSpanPath((SvgTSpanElement)child, pathDrawing, ref ctp);
                    }
                }
            }

            WpfTextStringFormat stringFormat = GetTextStringFormat(_textElement);

            ISvgAnimatedLength pathOffset  = textPath.StartOffset;
            SvgTextPathMethod pathMethod   = (SvgTextPathMethod)textPath.Method.BaseVal;
            SvgTextPathSpacing pathSpacing = (SvgTextPathSpacing)textPath.Spacing.BaseVal;
            pathDrawing.DrawTextPath(_textContext, pathGeometry, pathOffset,
                stringFormat.Alignment, pathMethod, pathSpacing);

            pathDrawing.EndTextPath();
        }

        private void RenderTRefPath(SvgTRefElement element, WpfTextOnPathDrawing pathDrawing,
            ref Point ctp)
        {
            WpfTextPlacement placement = GetCurrentTextPosition(element, ctp);
            ctp           = placement.Location;
            double rotate = placement.Rotation;
            if (!placement.HasPositions)
            {
                placement = null; // Render it useless.
            }

            this.RenderTextPath(element, pathDrawing, GetTRefText(element),
                new Point(ctp.X, ctp.Y), rotate, placement);
        }

        private void RenderTSpanPath(SvgTSpanElement element, WpfTextOnPathDrawing pathDrawing,
            ref Point ctp)
        {
            WpfTextPlacement placement = GetCurrentTextPosition(element, ctp);
            ctp           = placement.Location;
            double rotate = placement.Rotation;
            if (!placement.HasPositions)
            {
                placement = null; // Render it useless.
            }

            string sBaselineShift = element.GetPropertyValue("baseline-shift").Trim();
            double shiftBy = 0;

            if (sBaselineShift.Length > 0)
            {
                SvgTextElement textElement = (SvgTextElement)element.SelectSingleNode("ancestor::svg:text",
                    element.OwnerDocument.NamespaceManager);

                double textFontSize = GetComputedFontSize(textElement);
                if (sBaselineShift.EndsWith("%"))
                {
                    shiftBy = SvgNumber.ParseNumber(sBaselineShift.Substring(0,
                        sBaselineShift.Length - 1)) / 100f * textFontSize;
                }
                else if (sBaselineShift == "sub")
                {
                    shiftBy = -0.6F * textFontSize;
                }
                else if (sBaselineShift == "super")
                {
                    shiftBy = 0.6F * textFontSize;
                }
                else if (sBaselineShift == "baseline")
                {
                    shiftBy = 0;
                }
                else
                {
                    shiftBy = SvgNumber.ParseNumber(sBaselineShift);
                }
            }

            foreach (XmlNode child in element.ChildNodes)
            {
                if (child.NodeType == XmlNodeType.Text)
                {
                    ctp.Y -= shiftBy;
                    RenderTextPath(element, pathDrawing, GetText(element, child),
                        new Point(ctp.X, ctp.Y), rotate, placement);
                    ctp.Y += shiftBy;
                }
            }
        }

        private void RenderTextPath(SvgTextContentElement element, WpfTextOnPathDrawing pathDrawing,
            string text, Point origin, double rotate, WpfTextPlacement placement)
        {
            if (String.IsNullOrEmpty(text))
            {
                return;
            }

            double emSize         = GetComputedFontSize(element);
            FontFamily fontFamily = GetTextFontFamily(element, emSize);

            FontStyle fontStyle = GetTextFontStyle(element);
            FontWeight fontWeight = GetTextFontWeight(element);

            FontStretch fontStretch = GetTextFontStretch(element);

            WpfTextStringFormat stringFormat = GetTextStringFormat(element);

            // Fix the use of Postscript fonts...
            WpfFontFamilyVisitor fontFamilyVisitor = _drawContext.FontFamilyVisitor;
            if (!String.IsNullOrEmpty(_actualFontName) && fontFamilyVisitor != null)
            {
                WpfFontFamilyInfo currentFamily = new WpfFontFamilyInfo(fontFamily, fontWeight,
                    fontStyle, fontStretch);
                WpfFontFamilyInfo familyInfo = fontFamilyVisitor.Visit(_actualFontName,
                    currentFamily, _drawContext);
                if (familyInfo != null && !familyInfo.IsEmpty)
                {
                    fontFamily  = familyInfo.Family;
                    fontWeight  = familyInfo.Weight;
                    fontStyle   = familyInfo.Style;
                    fontStretch = familyInfo.Stretch;
                }
            }

            WpfSvgPaint fillPaint = new WpfSvgPaint(_drawContext, element, "fill");
            Brush textBrush = fillPaint.GetBrush();

            WpfSvgPaint strokePaint = new WpfSvgPaint(_drawContext, element, "stroke");
            Pen pen = strokePaint.GetPen();

            TextDecorationCollection textDecors = GetTextDecoration(element);
            TextAlignment alignment = stringFormat.Alignment;

            pathDrawing.FontSize = emSize;

            pathDrawing.FontFamily  = fontFamily;
            pathDrawing.FontWeight  = fontWeight;
            pathDrawing.FontStretch = fontStretch;

            pathDrawing.Foreground = textBrush;

            pathDrawing.AddTextPath(text, origin);
        }

        #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