123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176 |
- using System.Globalization;
- using System.Xml;
- using System.Xml.Linq;
- using Drawie.Numerics;
- using PixiEditor.SVG.Elements;
- using PixiEditor.SVG.Features;
- using PixiEditor.SVG.Units;
- namespace PixiEditor.SVG;
- public class SvgParser
- {
- private static Dictionary<string, Type> wellKnownElements = new()
- {
- { "ellipse", typeof(SvgEllipse) },
- { "rect", typeof(SvgRectangle) },
- { "circle", typeof(SvgCircle) },
- { "line", typeof(SvgLine) },
- { "path", typeof(SvgPath) },
- { "g", typeof(SvgGroup) },
- { "mask", typeof(SvgMask) },
- { "image", typeof(SvgImage) },
- { "svg", typeof(SvgDocument) },
- { "text", typeof(SvgText) }
- };
- public string Source { get; set; }
- public SvgParser(string xml)
- {
- Source = xml;
- }
- public SvgDocument? Parse()
- {
- XDocument document = XDocument.Parse(Source);
- using var reader = document.CreateReader();
- XmlNodeType node = reader.MoveToContent();
- if (node != XmlNodeType.Element || reader.LocalName != "svg")
- {
- return null;
- }
-
- SvgDocument root = (SvgDocument)ParseElement(reader)!;
- RectD bounds = ParseBounds(reader); // this takes into account viewBox, width, height, x, y
-
- root.ViewBox.Unit = new SvgRectUnit(bounds);
- while (reader.Read())
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- SvgElement? element = ParseElement(reader);
- if (element != null)
- {
- root.Children.Add(element);
- if (element is IElementContainer container)
- {
- ParseChildren(reader, container, element.TagName);
- }
- }
- }
- }
- return root;
- }
- private void ParseChildren(XmlReader reader, IElementContainer container, string tagName)
- {
- while (reader.Read())
- {
- if (reader.NodeType == XmlNodeType.Element)
- {
- SvgElement? element = ParseElement(reader);
- if (element != null)
- {
- container.Children.Add(element);
- if (element is IElementContainer childContainer)
- {
- ParseChildren(reader, childContainer, element.TagName);
- }
- }
- }
- else if (reader.NodeType == XmlNodeType.EndElement && reader.Name == tagName)
- {
- break;
- }
- }
- }
- private SvgElement? ParseElement(XmlReader reader)
- {
- if (wellKnownElements.TryGetValue(reader.LocalName, out Type elementType))
- {
- SvgElement element = (SvgElement)Activator.CreateInstance(elementType);
- if (reader.MoveToFirstAttribute())
- {
- element.ParseData(reader);
- }
- return element;
- }
- return null;
- }
- private RectD ParseBounds(XmlReader reader)
- {
- string viewBox = reader.GetAttribute("viewBox");
- string width = reader.GetAttribute("width");
- string height = reader.GetAttribute("height");
- string x = reader.GetAttribute("x");
- string y = reader.GetAttribute("y");
- if (viewBox == null && width == null && height == null && x == null && y == null)
- {
- return new RectD(0, 0, 0, 0);
- }
- double finalX = 0;
- double finalY = 0;
- double finalWidth = 0;
- double finalHeight = 0;
- if (viewBox != null)
- {
- string[] parts = viewBox.Split(' ').Where(s => !string.IsNullOrWhiteSpace(s)).ToArray();
- if (parts.Length == 4)
- {
- finalX = double.Parse(parts[0], CultureInfo.InvariantCulture);
- finalY = double.Parse(parts[1], CultureInfo.InvariantCulture);
- finalWidth = double.Parse(parts[2], CultureInfo.InvariantCulture);
- finalHeight = double.Parse(parts[3], CultureInfo.InvariantCulture);
- }
- }
- if (x != null)
- {
- if (double.TryParse(x, CultureInfo.InvariantCulture, out double xValue))
- {
- finalX = xValue;
- }
- }
- if (y != null)
- {
- if (double.TryParse(y, CultureInfo.InvariantCulture, out double yValue))
- {
- finalY = yValue;
- }
- }
- if (width != null)
- {
- if (double.TryParse(width, CultureInfo.InvariantCulture, out double widthValue))
- {
- finalWidth = widthValue;
- }
- }
- if (height != null)
- {
- if (double.TryParse(height, CultureInfo.InvariantCulture, out double heightValue))
- {
- finalHeight = heightValue;
- }
- }
- return new RectD(finalX, finalY, finalWidth, finalHeight);
- }
- }
|