internal override void Write(StringBuilder sb, SvgConverter conv) { if (_Center.HasValue) { sb.AppendFormat("rotate({0},{1},{2}) ", conv.ToSvgValue(-_Angle), conv.ToSvgLength(_Center.Value.X), conv.ToSvgLength(-_Center.Value.Y)); } else { sb.AppendFormat("rotate({0}) ", conv.ToSvgValue(_Angle)); } }
internal static SvgMatrixTransform Create(double[] values, SvgConverter conv) { if (values.Length >= 6) { return(new SvgMatrixTransform(new[] { values[0], values[1], values[2], values[3], values[4] * conv.Scale, values[5] * conv.Scale })); } return(null); }
internal override Pnt2d?Write(StringBuilder sb, Pnt2d?lastPnt, SvgConverter conv) { if (!(lastPnt.HasValue && conv.AreEqual(lastPnt.Value, Start))) { sb.AppendFormat("M{0},{1} ", conv.ToSvgLength(Start.X), conv.ToSvgLength(-Start.Y)); } sb.AppendFormat("A{0},{1} {2} {3} {4} {5},{6} ", conv.ToSvgLength(RadiusX), conv.ToSvgLength(RadiusY), conv.ToSvgValue(Angle), (uint)Size, (uint)Sweep, conv.ToSvgLength(End.X), conv.ToSvgLength(-End.Y)); return(End); }
internal static IEnumerable <SvgTransform> Create(string transformString, SvgConverter conv) { var transformParts = transformString.Split(_TransformSplitChars); for (int i = 0; i < transformParts.Length - 1; i += 2) { if (!conv.TrySplitValues(transformParts[i + 1], out var values, false)) { continue; } SvgTransform transform; switch (transformParts[i].ToLower().Trim()) { case "matrix": transform = SvgMatrixTransform.Create(values, conv); break; case "translate": transform = SvgTranslateTransform.Create(values, conv); break; case "scale": transform = SvgScaleTransform.Create(values, conv); break; case "rotate": transform = SvgRotateTransform.Create(values, conv); break; case "skewx": transform = SvgSkewXTransform.Create(values, conv); break; case "skewy": transform = SvgSkewYTransform.Create(values, conv); break; default: Messages.Warning($"Unknown transform type {transformParts[i]} found in SVG file."); continue; } if (transform != null) { yield return(transform); } } }
internal override void Write(XmlWriter writer, SvgConverter conv) { writer.WriteStartElement("path"); var sb = new StringBuilder(); Pnt2d?lastPnt = null; foreach (var segment in Segments) { lastPnt = segment.Write(sb, lastPnt, conv); } writer.WriteAttributeString("d", sb.ToString().Trim()); base.Write(writer, conv); writer.WriteEndElement(); }
//-------------------------------------------------------------------------------------------------- void _CalculateScale(XmlReader reader, SvgConverter conv) { var viewBox = reader.GetAttribute("viewBox"); if (viewBox.IsNullOrWhiteSpace() || !conv.TrySplitValues(viewBox, out var viewBoxValues, false)) { Messages.Warning("SVG document has not defined a ViewBox. The scaling may be incorrect."); return; } double fScaleX = 1.0; double fScaleY = 1.0; if (conv.TryConvertToMillimeter(reader.GetAttribute("width"), out var width, false) && conv.TryConvertToMillimeter(reader.GetAttribute("height"), out var height, false)) { fScaleX = width / viewBoxValues[2]; fScaleY = height / viewBoxValues[3]; }
internal override bool Read(XmlReader reader, SvgConverter conv) { var data = reader.GetAttribute("d"); if (!base.Read(reader, conv)) { return(false); } if (!data.IsNullOrEmpty()) { Segments.AddRange(SvgPathSegment.Create(data, conv)); } Segments.ForEach(seg => seg.Transform(conv)); conv.PopTransform(); return(Segments.Count > 0); }
//-------------------------------------------------------------------------------------------------- public MemoryStream WriteToStream() { var conv = new SvgConverter() { DotsPerInch = DotsPerInch, Scale = 25.4 / DotsPerInch }; var xmlWriterSettings = new XmlWriterSettings { Encoding = Encoding.UTF8, Indent = true, IndentChars = " ", }; var stream = new MemoryStream(); var writer = XmlWriter.Create(stream, xmlWriterSettings); writer.WriteStartDocument(); writer.WriteDocType("svg", "-//W3C//DTD SVG 1.1//EN", "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd", null); writer.WriteStartElement("svg", XmlnsSvg); writer.WriteAttributeString("width", $"{conv.ToSvgValue(Width)}mm"); // Use AngleToSvg to get unscaled values writer.WriteAttributeString("height", $"{conv.ToSvgValue(Height)}mm"); writer.WriteAttributeString("viewBox", $"0, 0, {conv.ToSvgLength(Width)}, {conv.ToSvgLength(Height)}"); writer.WriteAttributeString("version", "1.1"); writer.WriteAttributeString("xmlns", "xlink", null, "http://www.w3.org/1999/xlink"); writer.WriteAttributeString("xmlns", "xml", null, "http://www.w3.org/XML/1998/namespace"); writer.WriteAttributeString("xmlns", "sodipodi", null, XmlnsSodipodi); writer.WriteAttributeString("xmlns", "inkscape", null, XmlnsInkscape); writer.WriteStartElement("namedview", XmlnsSodipodi); writer.WriteAttributeString("document-units", XmlnsInkscape, "mm"); writer.WriteEndElement(); base.Write(writer, conv); writer.WriteEndElement(); writer.Close(); return(stream); }
internal override bool Read(XmlReader reader, SvgConverter conv) { bool res = false; string sx = reader.GetAttribute("cx") ?? "0"; string sy = reader.GetAttribute("cy") ?? "0"; string sr = reader.GetAttribute("r"); if (!base.Read(reader, conv)) { return(false); } if (!sx.IsNullOrEmpty() && !sy.IsNullOrEmpty() && !sr.IsNullOrEmpty()) { Center = new Pnt2d(conv.FromSvgLength(sx), conv.FromSvgLength(sy)); conv.Transform(ref Center); Radius = conv.FromSvgLength(sr); res = true; } conv.PopTransform(); return(res); }
internal virtual void Write(XmlWriter writer, SvgConverter conv) { if (!ID.IsNullOrEmpty()) { writer.WriteAttributeString("id", ID); } Style?.Write(writer, conv); if (Transforms.Count > 0) { var sb = new StringBuilder(); foreach (var transform in Transforms) { transform.Write(sb, conv); } writer.WriteAttributeString("transform", sb.ToString().Trim()); } foreach (var child in Children) { child.Write(writer, conv); } }
internal virtual bool Read(XmlReader reader, SvgConverter conv) { var transformString = reader.GetAttribute("transform"); if (!transformString.IsNullOrEmpty()) { Transforms.AddRange(SvgTransform.Create(transformString, conv)); } conv.PushTransform(Transforms); var depth = reader.Depth; reader.Read(); while (!reader.EOF && reader.Depth > depth) { if (reader.NodeType != XmlNodeType.Element) { reader.Read(); continue; } SvgElement newElement = null; switch (reader.LocalName.ToLower()) { case "g": newElement = new SvgGroupElement(); break; case "circle": newElement = new SvgCircleElement(); break; case "ellipse": newElement = new SvgEllipseElement(); break; case "path": newElement = new SvgPathElement(); break; case "line": newElement = new SvgLineElement(); break; case "rect": newElement = new SvgRectElement(); break; } if (newElement != null) { if (newElement.Read(reader, conv)) { Children.Add(newElement); } } else { reader.Skip(); } } return(true); }
internal virtual void Transform(SvgConverter conv) { conv.Transform(ref Start); conv.Transform(ref End); }
internal override void Write(StringBuilder sb, SvgConverter conv) { sb.AppendFormat("translate({0},{1}) ", conv.ToSvgLength(_Tx), conv.ToSvgLength(-_Ty)); }
public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv) { if (!conv.TrySplitValues(commandString.Substring(1), out var values, true)) { yield break; } bool isRelative = commandString[0] == 'm'; int valuePos = 0; Pnt2d endPoint = new Pnt2d(); if (valuePos < values.Length) { endPoint = new Pnt2d(values[valuePos], values[valuePos + 1]); if (isRelative && lastSegment != null) { endPoint += lastSegment.End; } yield return(new SvgPathSegMoveto(endPoint)); valuePos += 2; } // subsequent value pairs are implicit lineto's while (valuePos < values.Length) { var startPoint = endPoint; endPoint = new Pnt2d(values[valuePos], values[valuePos + 1]); if (isRelative) { endPoint += startPoint; } yield return(new SvgPathSegLineto(startPoint, endPoint)); valuePos += 2; } }
internal static IEnumerable <SvgPathSegment> Create(string pathString, SvgConverter conv) { SvgPathSegment lastSegment = null; SvgPathSegment firstSegment = null; int next = 0; while (next < pathString.Length) { int start = next; next = pathString.IndexOfAny(_PathCommands, start + 1); if (next == -1) { next = pathString.Length; } IEnumerable <SvgPathSegment> newSegments = null; var commandString = pathString.Substring(start, next - start); switch (char.ToLower(commandString[0])) { case 'm': newSegments = SvgPathSegMoveto.Create(lastSegment, commandString, conv); break; case 'l': case 'h': case 'v': newSegments = SvgPathSegLineto.Create(lastSegment, commandString, conv); break; case 'c': case 's': newSegments = SvgPathSegCurvetoCubic.Create(lastSegment, commandString, conv); break; case 'q': case 't': newSegments = SvgPathSegCurvetoQuadratic.Create(lastSegment, commandString, conv); break; case 'a': newSegments = SvgPathSegArc.Create(lastSegment, commandString, conv); break; case 'z': lastSegment = SvgPathSegClosePath.Create(firstSegment, lastSegment); yield return(lastSegment); firstSegment = null; continue; } if (newSegments == null) { continue; } foreach (var segment in newSegments) { if (firstSegment == null) { firstSegment = segment; } lastSegment = segment; yield return(segment); } } }
internal override void Write(StringBuilder sb, SvgConverter conv) { sb.AppendFormat("scale({0},{1}) ", conv.ToSvgValue(_Sx), conv.ToSvgValue(_Sy)); }
internal abstract Pnt2d?Write(StringBuilder sb, Pnt2d?lastPnt, SvgConverter conv);
public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv) { if (!conv.TrySplitValues(commandString.Substring(1), out var values, true)) { yield break; } int valuePos = 0; while (valuePos < values.Length) { var start = lastSegment?.End ?? Pnt2d.Origin; Pnt2d c1; Pnt2d c2; Pnt2d end; if (char.ToLower(commandString[0]) == 'c') { c1 = new Pnt2d(values[valuePos], values[valuePos + 1]); c2 = new Pnt2d(values[valuePos + 2], values[valuePos + 3]); end = new Pnt2d(values[valuePos + 4], values[valuePos + 5]); valuePos += 6; if (char.IsLower(commandString[0])) { c1 += start; c2 += start; end += start; } lastSegment = new SvgPathSegCurvetoCubic(start, c1, c2, end); yield return(lastSegment); } else if (char.ToLower(commandString[0]) == 's') { c2 = new Pnt2d(values[valuePos], values[valuePos + 1]); end = new Pnt2d(values[valuePos + 2], values[valuePos + 3]); valuePos += 4; if (char.IsLower(commandString[0])) { c2 += start; end += start; } if (lastSegment is SvgPathSegCurvetoCubic lastSeg) { c1 = lastSeg.C2; } else { c1 = c2; } lastSegment = new SvgPathSegCurvetoCubic(start, c1, c2, end); yield return(lastSegment); } } }
internal abstract void Write(StringBuilder sb, SvgConverter conv);
public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv) { if (!conv.TrySplitValues(commandString.Substring(1), out var values, false)) { yield break; } int valuePos = 0; while (valuePos < values.Length) { var start = new Pnt2d(); if (lastSegment != null) { start = lastSegment.End; } double rx = values[0] * conv.Scale; double ry = values[1] * conv.Scale; double angle = values[2]; SvgArcSize size = values[3] == 0 ? SvgArcSize.Small : SvgArcSize.Large; SvgArcSweep sweep = values[4] == 0 ? SvgArcSweep.Negative : SvgArcSweep.Positive; Pnt2d end = new Pnt2d(values[5] * conv.Scale, values[6] * conv.Scale); if (char.IsLower(commandString[0])) { end += start; } valuePos += 7; lastSegment = new SvgPathSegArc(start, rx, ry, angle, size, sweep, end); yield return(lastSegment); } }
internal override void Transform(SvgConverter conv) { conv.Transform(ref C1); conv.Transform(ref C2); base.Transform(conv); }
internal override void Write(StringBuilder sb, SvgConverter conv) { sb.AppendFormat("skewy({0}) ", conv.ToSvgValue(_Skew)); }
public static IEnumerable <SvgPathSegment> Create(SvgPathSegment lastSegment, string commandString, SvgConverter conv) { if (!conv.TrySplitValues(commandString.Substring(1), out var values, true)) { yield break; } int valuePos = 0; while (valuePos < values.Length) { var start = lastSegment?.End ?? Pnt2d.Origin; SvgPathSegLineto segment = null; switch (commandString[0]) { case 'L': segment = new SvgPathSegLineto(start, new Pnt2d(values[valuePos], values[valuePos + 1])); valuePos += 2; break; case 'l': segment = new SvgPathSegLineto(start, start + new Pnt2d(values[valuePos], values[valuePos + 1])); valuePos += 2; break; case 'H': segment = new SvgPathSegLineto(start, new Pnt2d(values[valuePos], start.Y)); valuePos += 1; break; case 'h': segment = new SvgPathSegLineto(start, start + new Pnt2d(values[valuePos], 0)); valuePos += 1; break; case 'V': segment = new SvgPathSegLineto(start, new Pnt2d(start.X, values[valuePos])); valuePos += 1; break; case 'v': segment = new SvgPathSegLineto(start, start + new Pnt2d(0, values[valuePos])); valuePos += 1; break; } yield return(segment); lastSegment = segment; } }
internal override Pnt2d?Write(StringBuilder sb, Pnt2d?lastPnt, SvgConverter conv) { sb.AppendFormat("M{0},{1} ", conv.ToSvgLength(End.X), conv.ToSvgLength(-End.Y)); return(End); }