// Spludlow Software // Copyright © Samuel P. Ludlow 2020 All Rights Reserved // Distributed under the terms of the GNU General Public License version 3 // Distributed WITHOUT ANY WARRANTY; without implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE // https://www.spludlow.co.uk/LICENCE.TXT // The Spludlow logo is a registered trademark of Samuel P. Ludlow and may not be used without permission // v1.14 using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using System.Xml; using System.IO; using System.Drawing; namespace Spludlow.Drawing { public class SVG : IDisposable { public static void Test() { string targetFilename = @"D:\out.svg"; //Spludlow.Printing.PrintDoc doc = new Printing.PrintDoc("A4"); using (SVG doc = new SVG(targetFilename, new SizeF(200, 100))) { doc.Rectangle(10, 10, 40, 20, 1, Color.Black, Color.BlueViolet); doc.NewPage(); doc.Rectangle(10, 10, 40, 20, 1, Color.Black, Color.Red); } //Spludlow.Printing.Printer.Print(doc, "svg:" + targetFilename); } private string _Filename; private StringBuilder _Output; private System.Drawing.ColorConverter _CC = new ColorConverter(); public SVG(string filename, System.Drawing.SizeF size) { this.StartNew(filename, size); } public SVG(string filename, string pageSize) { System.Drawing.SizeF size = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize); this.StartNew(filename, size); } public SVG(string filename, string pageSize, bool landscape) { System.Drawing.SizeF size = Spludlow.Printing.PageSizes.PageSizeMillimeters(pageSize, landscape); this.StartNew(filename, size); } private void StartNew(string filename, System.Drawing.SizeF size) { this._Filename = filename; this._Output = new StringBuilder(); // baseProfile=\"tiny\" string width = size.Width.ToString(); string height = size.Height.ToString(); _Output.AppendLine(""); _Output.AppendLine(""); _Output.AppendLine(""); //_Output.AppendLine(""); //_Output.AppendLine(""); } public void Rectangle(float x, float y, float width, float height, float lineWidth, System.Drawing.Color lineColour, System.Drawing.Color fillColour) { // // string lineColourHtml = "#" + Spludlow.Drawing.Colour.Encode(lineColour).Substring(2); string fillColourHtml = "#" + Spludlow.Drawing.Colour.Encode(fillColour).Substring(2); _Output.AppendLine(""); } public void NewPage() { //_Output.AppendLine(""); //_Output.AppendLine(""); } public void Close() { //_Output.AppendLine(""); //_Output.AppendLine(""); _Output.AppendLine(""); File.WriteAllText(this._Filename, this._Output.ToString(), Encoding.UTF8); } public void Dispose() { Close(); } } } public class SvgDocument : XmlDocument { public SvgDocument(float width, float height, string stylePath) { if (stylePath == "") { this.LoadXml("" + Environment.NewLine + "" + Environment.NewLine + ""); } else { this.LoadXml("" + Environment.NewLine + "" + Environment.NewLine + "" + Environment.NewLine + ""); } AddAtribToNode(this.DocumentElement, "width", width.ToString()); AddAtribToNode(this.DocumentElement, "height", height.ToString()); AddAtribToNode(this.DocumentElement, "viewbox", "0 0 " + width.ToString() + " " + height.ToString()); } public void DrawRectangle(float x, float y, float width, float height, string style) { XmlNode node = this.CreateElement("rect"); AddAtribToNode(node, "x", x.ToString()); AddAtribToNode(node, "y", y.ToString()); AddAtribToNode(node, "width", width.ToString()); AddAtribToNode(node, "height", height.ToString()); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawRoundedRectangle( float x, float y, float width, float height, float rx, float ry, string style) { XmlNode node = this.CreateElement("rect"); AddAtribToNode(node, "x", x.ToString()); AddAtribToNode(node, "y", y.ToString()); AddAtribToNode(node, "width", width.ToString()); AddAtribToNode(node, "height", height.ToString()); AddAtribToNode(node, "rx", rx.ToString()); AddAtribToNode(node, "ry", ry.ToString()); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawCircle(float cx, float cy, float radius, string style) { XmlNode node = this.CreateElement("circle"); AddAtribToNode(node, "cx", cx.ToString()); AddAtribToNode(node, "cy", cy.ToString()); AddAtribToNode(node, "r", radius.ToString()); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawEllipse(decimal cx, decimal cy, decimal rx, decimal ry, string style) { XmlNode node = this.CreateElement("ellipse"); AddAtribToNode(node, "cx", cx.ToString()); AddAtribToNode(node, "cy", cy.ToString()); AddAtribToNode(node, "rx", rx.ToString()); AddAtribToNode(node, "ry", ry.ToString()); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawLine(decimal x1, decimal y1, decimal x2, decimal y2, string style) { XmlNode node = this.CreateElement("line"); AddAtribToNode(node, "x1", x1.ToString()); AddAtribToNode(node, "y1", y1.ToString()); AddAtribToNode(node, "x2", x2.ToString()); AddAtribToNode(node, "y2", y2.ToString()); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawPolyLine(PointF[] points, string style) { string pointString = ""; for (int i = 0; i < points.Length; ++i) { if (pointString != "") { pointString += ", "; } pointString += points[i].X.ToString() + ", " + points[i].Y.ToString(); } XmlNode node = this.CreateElement("polyline"); AddAtribToNode(node, "points", pointString); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawPolygon(PointF[] points, string style) { string pointString = ""; for (int i = 0; i < points.Length; ++i) { if (pointString != "") { pointString += ", "; } pointString += points[i].X.ToString() + ", " + points[i].Y.ToString(); } XmlNode node = this.CreateElement("polygon"); AddAtribToNode(node, "points", pointString); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawText(string text, decimal x, decimal y, string style) { XmlNode node = this.CreateElement("text"); AddAtribToNode(node, "x", x.ToString()); AddAtribToNode(node, "y", y.ToString()); AddAtribToNode(node, "style", style); node.InnerText = text; this.DocumentElement.AppendChild(node); } public void DrawArc(decimal x1, decimal y1, decimal x2, decimal y2, decimal rx, decimal ry, decimal rotation, bool largArcFlag, bool sweepFlag, string style) { int laf = 0; if (largArcFlag == true) { laf = 1; } int sf = 0; if (sweepFlag == true) { sf = 1; } XmlNode node = this.CreateElement("path"); string arcString = "M " + x1.ToString() + ", " + y1.ToString() + " A " + rx.ToString() + ", " + ry.ToString() + " " + rotation.ToString() + " " + laf.ToString() + ", " + sf.ToString() + " " + x2.ToString() + ", " + y2.ToString(); AddAtribToNode(node, "d", arcString); AddAtribToNode(node, "style", style); this.DocumentElement.AppendChild(node); } public void DrawSlice(decimal x, decimal y, decimal rx, decimal ry, decimal startAngle, decimal endAngle, decimal push, string style, string classAtrib) { // Convert angles to radians decimal radStartAngle = (startAngle - 90) * (decimal)(Math.PI / 180); decimal radEndAngle = (endAngle - 90) * (decimal)(Math.PI / 180); // If want to push the slice away from the centre if (push > 0) { // Work out angle for vector of push away from the middle decimal pushAngle = radStartAngle + (radEndAngle - radStartAngle) / 2; // Adjust X and Y for push x += (decimal)Math.Cos((double)pushAngle) * (rx * push); y += (decimal)Math.Sin((double)pushAngle) * (ry * push); } // Get first point of arc decimal x1 = x + (decimal)Math.Cos((double)radStartAngle) * rx; decimal y1 = y + (decimal)Math.Sin((double)radStartAngle) * ry; // Get second point of arc decimal x2 = x + (decimal)Math.Cos((double)radEndAngle) * rx; decimal y2 = y + (decimal)Math.Sin((double)radEndAngle) * ry; // Work out the Large arc flag int laf = 0; if (endAngle - startAngle >= 180) { laf = 1; } // Create a node XmlNode node = this.CreateElement("path"); // Build the path string arcString = "M " + x.ToString() + ", " + y.ToString() + // Move to centre " L " + x1.ToString() + ", " + y1.ToString() + // Line to First Point " A " + rx.ToString() + ", " + ry.ToString() + // Arc to second point " 0 " + laf.ToString() + ", 1" + " " + x2.ToString() + ", " + y2.ToString() + " Z"; // Close back to centre // Add attributes to the node AddAtribToNode(node, "d", arcString); if (style != "") { AddAtribToNode(node, "style", style); } if (classAtrib != "") { AddAtribToNode(node, "class", classAtrib); } this.DocumentElement.AppendChild(node); } private void AddAtribToNode(XmlNode node, string name, string val) { XmlNode attr = this.CreateNode(XmlNodeType.Attribute, name, null); attr.Value = val; node.Attributes.SetNamedItem(attr); } }