diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 00000000..a7484158 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,5 @@ +# Auto detect text files and perform LF normalization +* text=auto + +# Declare files that will always have CRLF line endings on checkout. +*.sln text eol=crlf diff --git a/NGraphics/Brush.cs b/NGraphics/Brush.cs index 3e642b3c..95591003 100644 --- a/NGraphics/Brush.cs +++ b/NGraphics/Brush.cs @@ -40,7 +40,7 @@ public class GradientStop public double Offset; public Color Color; public GradientStop () - { + { } public GradientStop (double offset, Color color) { @@ -58,7 +58,7 @@ public void AddStop (double offset, Color color) } public void AddStops (IEnumerable stops) { - Stops.AddRange(stops); + Stops.AddRange (stops); } } @@ -66,9 +66,11 @@ public class RadialGradientBrush : GradientBrush { public Point Center; public Point Focus; - public Size Radius; + public Size Radius; public bool Absolute = false; + public Transform GradientTransform { get; set; } + public RadialGradientBrush () { } @@ -99,25 +101,25 @@ public RadialGradientBrush (Point relCenter, Size relRadius, Color startColor, C Stops.Add (new GradientStop (0, startColor)); Stops.Add (new GradientStop (0.5, midColor)); Stops.Add (new GradientStop (1, endColor)); - } + } public RadialGradientBrush (Color startColor, Color midColor, Color endColor) : this (new Point (0.5, 0.5), new Size (0.5), startColor, midColor, endColor) { } - public Point GetAbsoluteCenter (Rect frame) - { - if (Absolute) return Center; - return frame.TopLeft + Center * frame.Size; - } - public Size GetAbsoluteRadius (Rect frame) - { - if (Absolute) return Radius; - return Radius * frame.Size; - } - public Point GetAbsoluteFocus (Rect frame) - { - if (Absolute) return Focus; - return frame.TopLeft + Focus * frame.Size; + public Point GetAbsoluteCenter (Rect frame) + { + if (Absolute) return Center; + return frame.TopLeft + Center * frame.Size; + } + public Size GetAbsoluteRadius (Rect frame) + { + if (Absolute) return Radius; + return Radius * frame.Size; + } + public Point GetAbsoluteFocus (Rect frame) + { + if (Absolute) return Focus; + return frame.TopLeft + Focus * frame.Size; } } @@ -127,6 +129,8 @@ public class LinearGradientBrush : GradientBrush public Point End; public bool Absolute = false; + public Transform GradientTransform { get; set; } + public LinearGradientBrush () { } @@ -150,16 +154,16 @@ public LinearGradientBrush (Point relStart, Point relEnd, Color startColor, Colo Stops.Add (new GradientStop (0, startColor)); Stops.Add (new GradientStop (0.5, midColor)); Stops.Add (new GradientStop (1, endColor)); - } - public Point GetAbsoluteStart (Rect frame) - { - if (Absolute) return Start; - return frame.TopLeft + Start * frame.Size; - } - public Point GetAbsoluteEnd (Rect frame) - { - if (Absolute) return End; - return frame.TopLeft + End * frame.Size; - } + } + public Point GetAbsoluteStart (Rect frame) + { + if (Absolute) return Start; + return frame.TopLeft + Start * frame.Size; + } + public Point GetAbsoluteEnd (Rect frame) + { + if (Absolute) return End; + return frame.TopLeft + End * frame.Size; + } } } diff --git a/NGraphics/SvgReader.cs b/NGraphics/SvgReader.cs index 0811775d..c6f0a063 100644 --- a/NGraphics/SvgReader.cs +++ b/NGraphics/SvgReader.cs @@ -17,7 +17,7 @@ public class SvgReader public Graphic Graphic { get; private set; } readonly Dictionary defs = new Dictionary (); -// readonly XNamespace ns; + // readonly XNamespace ns; public SvgReader (System.IO.TextReader reader, double pixelsPerInch = 160.0) { @@ -33,10 +33,12 @@ void Read (XDocument doc) // // Find the defs (gradients) // - foreach (var d in svg.Descendants ()) { + foreach (var d in svg.Descendants ()) + { var idA = d.Attribute ("id"); - if (idA != null) { - defs [ReadString (idA).Trim ()] = d; + if (idA != null) + { + defs[ReadString (idA).Trim ()] = d; } } @@ -51,14 +53,17 @@ void Read (XDocument doc) var viewBox = new Rect (size); var viewBoxA = svg.Attribute ("viewBox") ?? svg.Attribute ("viewPort"); - if (viewBoxA != null) { + if (viewBoxA != null) + { viewBox = ReadRectangle (viewBoxA.Value); } - if (widthA != null && widthA.Value.Contains ("%")) { + if (widthA != null && widthA.Value.Contains ("%")) + { size.Width *= viewBox.Width; } - if (heightA != null && heightA.Value.Contains ("%")) { + if (heightA != null && heightA.Value.Contains ("%")) + { size.Height *= viewBox.Height; } @@ -87,7 +92,8 @@ void AddElement (IList list, XElement e, Pen inheritPen, Brush inheritB bool hasPen, hasBrush; ApplyStyle (e.Attributes ().ToDictionary (k => k.Name.LocalName, v => v.Value), ref pen, out hasPen, ref brush, out hasBrush); var style = ReadString (e.Attribute ("style")); - if (!string.IsNullOrWhiteSpace (style)) { + if (!string.IsNullOrWhiteSpace (style)) + { ApplyStyle (style, ref pen, out hasPen, ref brush, out hasBrush); } pen = hasPen ? pen : inheritPen; @@ -97,184 +103,193 @@ void AddElement (IList list, XElement e, Pen inheritPen, Brush inheritB // // Elements // - switch (e.Name.LocalName) { - case "text": - { - var x = ReadNumber (e.Attribute ("x")); - var y = ReadNumber (e.Attribute ("y")); - var font = new Font (); - var fontFamily = ReadTextFontFamily(e); - if (!string.IsNullOrEmpty(fontFamily)) - font.Family = fontFamily; - var fontSize = ReadTextFontSize(e); - if (fontSize >= 0) - font.Size = fontSize; - TextAlignment textAlignment = ReadTextAlignment(e); - var txt = new Text (new Rect (new Point (x, y), new Size (double.MaxValue, double.MaxValue)), font, textAlignment, pen, brush); - ReadTextSpans (txt, e); - r = txt; - } + switch (e.Name.LocalName) + { + case "text": + { + var x = ReadNumber (e.Attribute ("x")); + var y = ReadNumber (e.Attribute ("y")); + var font = new Font (); + var fontFamily = ReadTextFontFamily (e); + if (!string.IsNullOrEmpty (fontFamily)) + font.Family = fontFamily; + var fontSize = ReadTextFontSize (e); + if (fontSize >= 0) + font.Size = fontSize; + TextAlignment textAlignment = ReadTextAlignment (e); + var txt = new Text (new Rect (new Point (x, y), new Size (double.MaxValue, double.MaxValue)), font, textAlignment, pen, brush); + ReadTextSpans (txt, e); + r = txt; + } break; - case "rect": - { - var x = ReadNumber (e.Attribute ("x")); - var y = ReadNumber (e.Attribute ("y")); - var width = ReadNumber (e.Attribute ("width")); - var height = ReadNumber (e.Attribute ("height")); - var rx = ReadNumber (e.Attribute ("rx")); - var ry = ReadNumber (e.Attribute ("ry")); - if (ry == 0) { - ry = rx; + case "rect": + { + var x = ReadNumber (e.Attribute ("x")); + var y = ReadNumber (e.Attribute ("y")); + var width = ReadNumber (e.Attribute ("width")); + var height = ReadNumber (e.Attribute ("height")); + var rx = ReadNumber (e.Attribute ("rx")); + var ry = ReadNumber (e.Attribute ("ry")); + if (ry == 0) + { + ry = rx; + } + r = new Rectangle (new Rect (new Point (x, y), new Size (width, height)), new Size (rx, ry), pen, brush); } - r = new Rectangle (new Rect (new Point (x, y), new Size (width, height)), new Size (rx, ry), pen, brush); - } break; - case "ellipse": - { - var cx = ReadNumber (e.Attribute ("cx")); - var cy = ReadNumber (e.Attribute ("cy")); - var rx = ReadNumber (e.Attribute ("rx")); - var ry = ReadNumber (e.Attribute ("ry")); - r = new Ellipse (new Point (cx - rx, cy - ry), new Size (2 * rx, 2 * ry), pen, brush); - } + case "ellipse": + { + var cx = ReadNumber (e.Attribute ("cx")); + var cy = ReadNumber (e.Attribute ("cy")); + var rx = ReadNumber (e.Attribute ("rx")); + var ry = ReadNumber (e.Attribute ("ry")); + r = new Ellipse (new Point (cx - rx, cy - ry), new Size (2 * rx, 2 * ry), pen, brush); + } break; - case "circle": - { - var cx = ReadNumber (e.Attribute ("cx")); - var cy = ReadNumber (e.Attribute ("cy")); - var rr = ReadNumber (e.Attribute ("r")); - r = new Ellipse (new Point (cx - rr, cy - rr), new Size (2 * rr, 2 * rr), pen, brush); - } + case "circle": + { + var cx = ReadNumber (e.Attribute ("cx")); + var cy = ReadNumber (e.Attribute ("cy")); + var rr = ReadNumber (e.Attribute ("r")); + r = new Ellipse (new Point (cx - rr, cy - rr), new Size (2 * rr, 2 * rr), pen, brush); + } break; - case "path": - { - var dA = e.Attribute ("d"); - if (dA != null && !string.IsNullOrWhiteSpace (dA.Value)) { - var p = new Path (pen, brush); - ReadPath (p, dA.Value); - r = p; + case "path": + { + var dA = e.Attribute ("d"); + if (dA != null && !string.IsNullOrWhiteSpace (dA.Value)) + { + var p = new Path (pen, brush); + ReadPath (p, dA.Value); + r = p; + } } - } break; - case "polygon": - { - var pA = e.Attribute ("points"); - if (pA != null && !string.IsNullOrWhiteSpace (pA.Value)) { - var path = new Path (pen, brush); - ReadPoints (path, pA.Value, true); - r = path; + case "polygon": + { + var pA = e.Attribute ("points"); + if (pA != null && !string.IsNullOrWhiteSpace (pA.Value)) + { + var path = new Path (pen, brush); + ReadPoints (path, pA.Value, true); + r = path; + } } - } break; - case "polyline": - { - var pA = e.Attribute ("points"); - if (pA != null && !string.IsNullOrWhiteSpace (pA.Value)) { - var path = new Path (pen, brush); - ReadPoints (path, pA.Value, false); - r = path; + case "polyline": + { + var pA = e.Attribute ("points"); + if (pA != null && !string.IsNullOrWhiteSpace (pA.Value)) + { + var path = new Path (pen, brush); + ReadPoints (path, pA.Value, false); + r = path; + } } - } - break; - case "g": - { - var g = new Group (); - var groupId = e.Attribute("id"); - if (groupId != null && !string.IsNullOrEmpty(groupId.Value)) - g.Id = groupId.Value; - AddElements (g.Children, e.Elements (), pen, brush); - r = g; - } break; - case "use": - { - var href = ReadString (e.Attributes ().FirstOrDefault (x => x.Name.LocalName == "href")); - if (!string.IsNullOrWhiteSpace (href)) { - XElement useE; - if (defs.TryGetValue (href.Trim ().Replace ("#", ""), out useE)) { - var useList = new List (); - AddElement (useList, useE, pen, brush); - r = useList.FirstOrDefault (); + case "g": + { + var g = new Group (); + var groupId = e.Attribute ("id"); + if (groupId != null && !string.IsNullOrEmpty (groupId.Value)) + g.Id = groupId.Value; + AddElements (g.Children, e.Elements (), pen, brush); + r = g; + } + break; + case "use": + { + var href = ReadString (e.Attributes ().FirstOrDefault (x => x.Name.LocalName == "href")); + if (!string.IsNullOrWhiteSpace (href)) + { + XElement useE; + if (defs.TryGetValue (href.Trim ().Replace ("#", ""), out useE)) + { + var useList = new List (); + AddElement (useList, useE, pen, brush); + r = useList.FirstOrDefault (); + } } } - } break; - case "title": - Graphic.Title = ReadString (e); + case "title": + Graphic.Title = ReadString (e); break; - case "desc": - case "description": - Graphic.Description = ReadString (e); + case "desc": + case "description": + Graphic.Description = ReadString (e); break; - case "defs": - // Already read in earlier pass + case "defs": + // Already read in earlier pass break; - case "namedview": - case "metadata": - case "image": - // Ignore + case "namedview": + case "metadata": + case "image": + // Ignore break; case "line": - { - var x1 = ReadNumber ( e.Attribute("x1") ); - var x2 = ReadNumber ( e.Attribute("x2") ); - var y1 = ReadNumber ( e.Attribute("y1") ); - var y2 = ReadNumber ( e.Attribute("y2") ); - var p = new Path (pen, null); - p.MoveTo (x1, y1); - p.LineTo (x2, y2); - r = p; - } + { + var x1 = ReadNumber (e.Attribute ("x1")); + var x2 = ReadNumber (e.Attribute ("x2")); + var y1 = ReadNumber (e.Attribute ("y1")); + var y2 = ReadNumber (e.Attribute ("y2")); + var p = new Path (pen, null); + p.MoveTo (x1, y1); + p.LineTo (x2, y2); + r = p; + } break; case "foreignObject": - { - var x = ReadNumber ( e.Attribute("x") ); - var y = ReadNumber ( e.Attribute("y") ); - var width = ReadNumber ( e.Attribute("width") ); - var height = ReadNumber ( e.Attribute("height") ); - r = new ForeignObject(new Point(x, y), new Size(width, height)); - } + { + var x = ReadNumber (e.Attribute ("x")); + var y = ReadNumber (e.Attribute ("y")); + var width = ReadNumber (e.Attribute ("width")); + var height = ReadNumber (e.Attribute ("height")); + r = new ForeignObject (new Point (x, y), new Size (width, height)); + } break; case "pgf": - { - var id = e.Attribute("id"); - System.Diagnostics.Debug.WriteLine("Ignoring pgf element" + (id != null ? ": '" + id.Value + "'" : "")); - } + { + var id = e.Attribute ("id"); + System.Diagnostics.Debug.WriteLine ("Ignoring pgf element" + (id != null ? ": '" + id.Value + "'" : "")); + } break; case "switch": - { - // Evaluate requiredFeatures, requiredExtensions and systemLanguage - foreach (var ee in e.Elements()) { - var requiredFeatures = ee.Attribute("requiredFeatures"); - var requiredExtensions = ee.Attribute("requiredExtensions"); - var systemLanguage = ee.Attribute("systemLanguage"); - // currently no support for any of these restrictions - if (requiredFeatures == null && requiredExtensions == null && systemLanguage == null) - AddElement (list, ee, pen, brush); + // Evaluate requiredFeatures, requiredExtensions and systemLanguage + foreach (var ee in e.Elements ()) + { + var requiredFeatures = ee.Attribute ("requiredFeatures"); + var requiredExtensions = ee.Attribute ("requiredExtensions"); + var systemLanguage = ee.Attribute ("systemLanguage"); + // currently no support for any of these restrictions + if (requiredFeatures == null && requiredExtensions == null && systemLanguage == null) + AddElement (list, ee, pen, brush); + } } - } break; - // color definition that can be referred to by other elements + // color definition that can be referred to by other elements case "linearGradient": break; - default: - throw new NotSupportedException ("SVG element \"" + e.Name.LocalName + "\" is not supported"); + default: + throw new NotSupportedException ("SVG element \"" + e.Name.LocalName + "\" is not supported"); } - if (r != null) { + if (r != null) + { r.Transform = ReadTransform (ReadString (e.Attribute ("transform"))); - var ida = e.Attribute("id"); - if (ida != null && !string.IsNullOrEmpty (ida.Value)) { + var ida = e.Attribute ("id"); + if (ida != null && !string.IsNullOrEmpty (ida.Value)) + { r.Id = ida.Value.Trim (); } list.Add (r); @@ -285,20 +300,22 @@ void AddElement (IList list, XElement e, Pen inheritPen, Brush inheritB void ApplyStyle (string style, ref Pen pen, out bool hasPen, ref Brush brush, out bool hasBrush) { - var d = ParseStyle(style); + var d = ParseStyle (style); ApplyStyle (d, ref pen, out hasPen, ref brush, out hasBrush); } - Dictionary ParseStyle(string style) + Dictionary ParseStyle (string style) { var d = new Dictionary (); - var kvs = style.Split (new[]{ ';' }, StringSplitOptions.RemoveEmptyEntries); - foreach (var kv in kvs) { + var kvs = style.Split (new[] { ';' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var kv in kvs) + { var m = keyValueRe.Match (kv); - if (m.Success) { - var k = m.Groups [1].Value; - var v = m.Groups [2].Value; - d [k] = v; + if (m.Success) + { + var k = m.Groups[1].Value; + var v = m.Groups[2].Value; + d[k] = v; } } return d; @@ -320,14 +337,16 @@ void ApplyStyle (Dictionary style, ref Pen pen, out bool hasPen, // Pen attributes // var strokeWidth = GetString (style, "stroke-width"); - if (!string.IsNullOrWhiteSpace (strokeWidth)) { + if (!string.IsNullOrWhiteSpace (strokeWidth)) + { if (pen == null) pen = new Pen (); pen.Width = ReadNumber (strokeWidth); } var strokeOpacity = GetString (style, "stroke-opacity"); - if (!string.IsNullOrWhiteSpace (strokeOpacity)) { + if (!string.IsNullOrWhiteSpace (strokeOpacity)) + { if (pen == null) pen = new Pen (); pen.Color = pen.Color.WithAlpha (ReadNumber (strokeOpacity)); @@ -337,18 +356,23 @@ void ApplyStyle (Dictionary style, ref Pen pen, out bool hasPen, // Pen // var stroke = GetString (style, "stroke").Trim (); - if (string.IsNullOrEmpty (stroke)) { + if (string.IsNullOrEmpty (stroke)) + { // No change hasPen = false; - } else if (stroke.Equals("none", StringComparison.OrdinalIgnoreCase)) { + } + else if (stroke.Equals ("none", StringComparison.OrdinalIgnoreCase)) + { hasPen = true; pen = null; - } else { + } + else { hasPen = true; if (pen == null) pen = new Pen (); Color color; - if (Colors.TryParse (stroke, out color)) { + if (Colors.TryParse (stroke, out color)) + { if (pen.Color.Alpha == 1) pen.Color = color; else @@ -360,7 +384,8 @@ void ApplyStyle (Dictionary style, ref Pen pen, out bool hasPen, // Brush attributes // var fillOpacity = GetString (style, "fill-opacity"); - if (!string.IsNullOrWhiteSpace (fillOpacity)) { + if (!string.IsNullOrWhiteSpace (fillOpacity)) + { if (brush == null) brush = new SolidBrush (); var sb = brush as SolidBrush; @@ -372,76 +397,94 @@ void ApplyStyle (Dictionary style, ref Pen pen, out bool hasPen, // Brush // var fill = GetString (style, "fill").Trim (); - if (string.IsNullOrEmpty (fill)) { + if (string.IsNullOrEmpty (fill)) + { // No change hasBrush = false; - } else if (fill.Equals("none", StringComparison.OrdinalIgnoreCase)) { + } + else if (fill.Equals ("none", StringComparison.OrdinalIgnoreCase)) + { hasBrush = true; brush = null; - } else { + } + else { hasBrush = true; Color color; - if (Colors.TryParse (fill, out color)) { + if (Colors.TryParse (fill, out color)) + { var sb = brush as SolidBrush; - if (sb == null) { + if (sb == null) + { brush = new SolidBrush (color); - } else { + } + else { if (sb.Color.Alpha == 1) sb.Color = color; else sb.Color = color.WithAlpha (sb.Color.Alpha); } - } else { + } + else { var urlM = fillUrlRe.Match (fill); - if (urlM.Success) { - var id = urlM.Groups [1].Value.Trim (); - brush = GetGradientBrush(id, null); - } else { + if (urlM.Success) + { + var id = urlM.Groups[1].Value.Trim (); + brush = GetGradientBrush (id, null); + } + else { throw new NotSupportedException ("Fill " + fill); } } } } - protected GradientBrush GetGradientBrush(string fill, GradientBrush child) + protected GradientBrush GetGradientBrush (string fill, GradientBrush child) { XElement defE; - if (defs.TryGetValue (fill, out defE)) { + if (defs.TryGetValue (fill, out defE)) + { GradientBrush brush = null; - switch (defE.Name.LocalName) { - case "linearGradient": - brush = CreateLinearGradientBrush (defE); + switch (defE.Name.LocalName) + { + case "linearGradient": + brush = CreateLinearGradientBrush (defE); break; - case "radialGradient": - brush = CreateRadialGradientBrush (defE); + case "radialGradient": + brush = CreateRadialGradientBrush (defE); break; - default: - throw new NotSupportedException ("Fill " + defE.Name); + default: + throw new NotSupportedException ("Fill " + defE.Name); } if (child != null) - { + { if (child is RadialGradientBrush && brush is RadialGradientBrush) { ((RadialGradientBrush)brush).Center = ((RadialGradientBrush)child).Center; ((RadialGradientBrush)brush).Focus = ((RadialGradientBrush)child).Focus; ((RadialGradientBrush)brush).Radius = ((RadialGradientBrush)child).Radius; - } else if (child is LinearGradientBrush && brush is LinearGradientBrush) + ((RadialGradientBrush)brush).Absolute = ((RadialGradientBrush)child).Absolute; + ((RadialGradientBrush)brush).GradientTransform = ((RadialGradientBrush)child).GradientTransform; + } + else if (child is LinearGradientBrush && brush is LinearGradientBrush) { ((LinearGradientBrush)brush).Start = ((LinearGradientBrush)child).Start; ((LinearGradientBrush)brush).End = ((LinearGradientBrush)child).End; + ((LinearGradientBrush)brush).Absolute = ((LinearGradientBrush)child).Absolute; + ((LinearGradientBrush)brush).GradientTransform = ((LinearGradientBrush)child).GradientTransform; } - brush.AddStops(child.Stops); + brush.AddStops (child.Stops); } XNamespace xlink = "http://www.w3.org/1999/xlink"; - var parent = defE.Attribute(xlink + "href"); - if (parent != null && !string.IsNullOrEmpty(parent.Value)) + var parent = defE.Attribute (xlink + "href"); + if (parent != null && !string.IsNullOrEmpty (parent.Value)) { - brush = GetGradientBrush(parent.Value.Substring(1), brush); + brush = GetGradientBrush (parent.Value.Substring (1), brush); } return brush; - } else { + } + else { throw new Exception ("Invalid fill url reference: " + fill); } } @@ -453,57 +496,69 @@ Transform ReadTransform (string raw) var s = raw.Trim (); - var calls = s.Split (new[]{ ')' }, StringSplitOptions.RemoveEmptyEntries); + var calls = s.Split (new[] { ')' }, StringSplitOptions.RemoveEmptyEntries); var t = Transform.Identity; - foreach (var c in calls) { - var args = c.Split (new[]{ '(', ',', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + foreach (var c in calls) + { + var args = c.Split (new[] { '(', ',', ' ', '\t', '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); var nt = Transform.Identity; - switch (args [0]) { - case "matrix": - if (args.Length == 7) { - nt = new Transform ( - ReadNumber(args[1]), - ReadNumber(args[2]), - ReadNumber(args[3]), - ReadNumber(args[4]), - ReadNumber(args[5]), - ReadNumber(args[6])); - } else { - throw new NotSupportedException ("Matrices are expected to have 6 elements, this one has " + (args.Length - 1)); - } + switch (args[0]) + { + case "matrix": + if (args.Length == 7) + { + nt = new Transform ( + ReadNumber (args[1]), + ReadNumber (args[2]), + ReadNumber (args[3]), + ReadNumber (args[4]), + ReadNumber (args[5]), + ReadNumber (args[6])); + } + else { + throw new NotSupportedException ("Matrices are expected to have 6 elements, this one has " + (args.Length - 1)); + } break; - case "translate": - if (args.Length >= 3) { - nt = Transform.Translate (new Size (ReadNumber (args [1]), ReadNumber (args [2]))); - } else if (args.Length >= 2) { - nt = Transform.Translate (new Size (ReadNumber (args[1]), 0)); - } + case "translate": + if (args.Length >= 3) + { + nt = Transform.Translate (new Size (ReadNumber (args[1]), ReadNumber (args[2]))); + } + else if (args.Length >= 2) + { + nt = Transform.Translate (new Size (ReadNumber (args[1]), 0)); + } break; - case "scale": - if (args.Length >= 3) { - nt = Transform.Scale (new Size (ReadNumber (args[1]), ReadNumber (args[2]))); - } else if (args.Length >= 2) { - var sx = ReadNumber (args [1]); - nt = Transform.Scale (new Size (sx, sx)); - } + case "scale": + if (args.Length >= 3) + { + nt = Transform.Scale (new Size (ReadNumber (args[1]), ReadNumber (args[2]))); + } + else if (args.Length >= 2) + { + var sx = ReadNumber (args[1]); + nt = Transform.Scale (new Size (sx, sx)); + } break; - case "rotate": - var a = ReadNumber (args [1]); - if (args.Length >= 4) { - var x = ReadNumber (args [2]); - var y = ReadNumber (args [3]); - var t1 = Transform.Translate (new Size (x, y)); - var t2 = Transform.Rotate (a); - var t3 = Transform.Translate (new Size (-x, -y)); - nt = t1 * t2 * t3; - } else { - nt = Transform.Rotate (a); - } + case "rotate": + var a = ReadNumber (args[1]); + if (args.Length >= 4) + { + var x = ReadNumber (args[2]); + var y = ReadNumber (args[3]); + var t1 = Transform.Translate (new Size (x, y)); + var t2 = Transform.Rotate (a); + var t3 = Transform.Translate (new Size (-x, -y)); + nt = t1 * t2 * t3; + } + else { + nt = Transform.Rotate (a); + } break; - default: - throw new NotSupportedException ("Can't transform " + args[0]); + default: + throw new NotSupportedException ("Can't transform " + args[0]); } t = t * nt; } @@ -513,39 +568,50 @@ Transform ReadTransform (string raw) void ReadTextSpans (Text txt, XElement e) { - foreach (XNode c in e.Nodes ()) { - if (c.NodeType == XmlNodeType.Text) { + foreach (XNode c in e.Nodes ()) + { + if (c.NodeType == XmlNodeType.Text) + { txt.Spans.Add (new TextSpan (((XText)c).Value)); - } else if (c.NodeType == XmlNodeType.Element) { + } + else if (c.NodeType == XmlNodeType.Element) + { var ce = (XElement)c; - if (ce.Name.LocalName == "tspan") { + if (ce.Name.LocalName == "tspan") + { var tspan = new TextSpan (ce.Value); var x = ReadOptionalNumber (ce.Attribute ("x")); var y = ReadOptionalNumber (ce.Attribute ("y")); - if (x.HasValue && y.HasValue) { + if (x.HasValue && y.HasValue) + { tspan.Position = new Point (x.Value, y.Value); } var font = txt.Font; var ffamily = ReadTextFontFamily (ce); - if (!string.IsNullOrWhiteSpace (ffamily)) { + if (!string.IsNullOrWhiteSpace (ffamily)) + { font = font.WithFamily (ffamily); } var fweight = ReadTextFontWeight (ce); - if (!string.IsNullOrWhiteSpace (fweight)) { + if (!string.IsNullOrWhiteSpace (fweight)) + { font = font.WithWeight (fweight); } var fstyle = ReadTextFontStyle (ce); - if (!string.IsNullOrWhiteSpace (fstyle)) { + if (!string.IsNullOrWhiteSpace (fstyle)) + { font = font.WithStyle (fstyle); } var fsize = ReadTextFontSize (ce); - if (fsize > 0) { + if (fsize > 0) + { font = font.WithSize (fsize); } - if (font != txt.Font) { + if (font != txt.Font) + { tspan.Font = font; } @@ -557,48 +623,63 @@ void ReadTextSpans (Text txt, XElement e) } static readonly char[] WSC = new char[] { ',', ' ', '\t', '\n', '\r' }; + static readonly string matchPathNumbers = @"([-+]?((\d*\.\d+)|(\d+))([eE][-+]?\d+)?)"; - static Regex pathRegex = new Regex(@"[MLHVCSQTAZmlhvcsqtaz][^MLHVCSQTAZmlhvcsqtaz]*", RegexOptions.Singleline); - static Regex negativeNumberRe = new Regex("(?<=[0-9])-"); + static Regex pathRegex = new Regex (@"[MLHVCSQTAZmlhvcsqtaz][^MLHVCSQTAZmlhvcsqtaz]*", RegexOptions.Singleline); + static Regex negativeNumberRe = new Regex ("(?<=[0-9])-"); void ReadPath (Path p, string pathDescriptor) { - Match m = pathRegex.Match(pathDescriptor); - while(m.Success) + Match m = pathRegex.Match (pathDescriptor); + while (m.Success) { + var match = m.Value.TrimStart (); var op = match[0]; - if (op == 'z' || op == 'Z') { - p.Close (); - } else { - // make sure negative numbers are split properly - match = negativeNumberRe.Replace(match.Substring(1), " -"); - var args = match.Split(WSC, StringSplitOptions.RemoveEmptyEntries); + if (op != ' ') + { + var args = Regex.Matches (match, matchPathNumbers) + .Cast () + .Select (ml => ml.Value) + .Where ((string arg) => !String.IsNullOrWhiteSpace (arg)) + .ToArray (); Point previousPoint = new Point (); + Point subPathStartPoint = new Point (); //NEEDED FOR SUBPATHS + int index = 0; - while(index < args.Length) + while (index < args.Length) { - if (p.Operations.Count > 0 && !(p.Operations.Last() is ClosePath)) - previousPoint = p.Operations.Last().EndPoint; + if (p.Operations.Count > 0 && !(p.Operations.Last () is ClosePath)) + previousPoint = p.Operations.Last ().EndPoint; - if ((op == 'M' || op == 'm') && args.Length >= index+2) { - var point = new Point (ReadNumber (args [index]), ReadNumber (args [index+1])); + if ((op == 'M' || op == 'm') && args.Length >= index + 2) + { + var point = new Point (ReadNumber (args[index]), ReadNumber (args[index + 1])); + subPathStartPoint = new Point (point.X, point.Y); //NEEDED FOR SUBPATHS if (op == 'm') + { + subPathStartPoint += point; //NEEDED FOR SUBPATHS point += previousPoint; + } p.MoveTo (point); index += 2; - } else if ((op == 'L' || op == 'l') && args.Length >= index+2) { - var point = new Point (ReadNumber (args [index]), ReadNumber (args [index+1])); + op = (char)(((int)op) - 1); // Change op from M to L (and m to l). This is needed because in the SVG 1.1 syntax if you place multiple pairs of coordinates after a moveto, all the pairs after the first are presumed to be preceded by a lineto. + } + else if ((op == 'L' || op == 'l') && args.Length >= index + 2) + { + var point = new Point (ReadNumber (args[index]), ReadNumber (args[index + 1])); if (op == 'l') point += previousPoint; p.LineTo (point); index += 2; - } else if ((op == 'C' || op == 'c') && args.Length >= index+6) { - var c1 = new Point (ReadNumber (args [index]), ReadNumber (args [index+1])); - var c2 = new Point (ReadNumber (args [index+2]), ReadNumber (args [index+3])); - var pt = new Point (ReadNumber (args [index+4]), ReadNumber (args [index+5])); + } + else if ((op == 'C' || op == 'c') && args.Length >= index + 6) + { + var c1 = new Point (ReadNumber (args[index]), ReadNumber (args[index + 1])); + var c2 = new Point (ReadNumber (args[index + 2]), ReadNumber (args[index + 3])); + var pt = new Point (ReadNumber (args[index + 4]), ReadNumber (args[index + 5])); if (op == 'c') { c1 += previousPoint; @@ -607,9 +688,11 @@ void ReadPath (Path p, string pathDescriptor) } p.CurveTo (c1, c2, pt); index += 6; - } else if ((op == 'S' || op == 's') && args.Length >= index+4) { - var c = new Point (ReadNumber (args [index]), ReadNumber (args [index+1])); - var pt = new Point (ReadNumber (args [index+2]), ReadNumber (args [index+3])); + } + else if ((op == 'S' || op == 's') && args.Length >= index + 4) + { + var c = new Point (ReadNumber (args[index]), ReadNumber (args[index + 1])); + var pt = new Point (ReadNumber (args[index + 2]), ReadNumber (args[index + 3])); if (op == 's') { c += previousPoint; @@ -617,57 +700,71 @@ void ReadPath (Path p, string pathDescriptor) } p.ContinueCurveTo (c, pt); index += 4; - } else if ((op == 'A' || op == 'a') && args.Length >= index+7) { - var r = new Size (ReadNumber (args [index]), ReadNumber (args [index+1])); - // var xr = ReadNumber (args [i + 2]); - var laf = ReadNumber (args [index+3]) != 0; - var swf = ReadNumber (args [index+4]) != 0; - var pt = new Point (ReadNumber (args [index+5]), ReadNumber (args [index+6])); + } + else if ((op == 'A' || op == 'a') && args.Length >= index + 7) + { + var r = new Size (ReadNumber (args[index]), ReadNumber (args[index + 1])); + // var xr = ReadNumber (args [i + 2]); + var laf = ReadNumber (args[index + 3]) != 0; + var swf = ReadNumber (args[index + 4]) != 0; + var pt = new Point (ReadNumber (args[index + 5]), ReadNumber (args[index + 6])); if (op == 'a') pt += previousPoint; p.ArcTo (r, laf, swf, pt); index += 7; - } else if ((op == 'V' || op == 'v') && args.Length >= index+1 && p.Operations.Count > 0) { + } + else if ((op == 'V' || op == 'v') && args.Length >= index + 1 && p.Operations.Count > 0) + { var previousX = previousPoint.X; - var y = ReadNumber(args[index]); + var y = ReadNumber (args[index]); if (op == 'v') y += previousPoint.Y; - var point = new Point(previousX, y); - p.LineTo(point); + var point = new Point (previousX, y); + p.LineTo (point); index += 1; - } else if ((op == 'H' || op == 'h') && args.Length >= index+1 && p.Operations.Count > 0) { + } + else if ((op == 'H' || op == 'h') && args.Length >= index + 1 && p.Operations.Count > 0) + { var previousY = previousPoint.Y; - var x = ReadNumber(args[index]); + var x = ReadNumber (args[index]); if (op == 'h') x += previousPoint.X; - var point = new Point(x, previousY); - p.LineTo(point); + var point = new Point (x, previousY); + p.LineTo (point); index += 1; - } else { + } + else if ((op == 'Z' || op == 'z') && args.Length >= index + 1 && p.Operations.Count > 0) + { + p.Close (); + p.MoveTo (subPathStartPoint); //NEEDED FOR SUBPATHS + } + else { throw new NotSupportedException ("Path Operation " + op); } } } - m = m.NextMatch(); + m = m.NextMatch (); } } void ReadPoints (Path p, string pathDescriptor, bool closePath) { - var args = pathDescriptor.Split (new[]{' '}, StringSplitOptions.RemoveEmptyEntries); + var args = pathDescriptor.Split (new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); var i = 0; var n = args.Length; if (n == 0) throw new Exception ("No points specified"); - while (i < n) { - var xy = args[i].Split(new[]{','}, StringSplitOptions.RemoveEmptyEntries); + while (i < n) + { + var xy = args[i].Split (new[] { ',' }, StringSplitOptions.RemoveEmptyEntries); var x = 0.0; var y = 0.0; var di = 1; - if (xy.Length == 1) { - x = ReadNumber (args [i]); - y = ReadNumber (args [i + 1]); + if (xy.Length == 1) + { + x = ReadNumber (args[i]); + y = ReadNumber (args[i + 1]); di = 2; } else { @@ -675,9 +772,11 @@ void ReadPoints (Path p, string pathDescriptor, bool closePath) y = ReadNumber (xy[1]); } - if (i == 0) { + if (i == 0) + { p.MoveTo (x, y); - } else { + } + else { p.LineTo (x, y); } i += di; @@ -717,13 +816,19 @@ RadialGradientBrush CreateRadialGradientBrush (XElement e) var r = ReadNumber (e.Attribute ("r")); b.Radius = new Size (r); - var gradientUnits = e.Attribute("gradientUnits"); + var gradientUnits = e.Attribute ("gradientUnits"); if (gradientUnits != null) { b.Absolute = gradientUnits.Value == "userSpaceOnUse"; } - // TODO: check gradientTransform attribute + //Read transformation defined in the GradientTransform attribute if present + Transform GradientTransform = Transform.Identity; + if (e.Attribute ("gradientTransform") != null) + { + GradientTransform = ReadTransform (e.Attribute ("gradientTransform").Value); + b.GradientTransform = GradientTransform; + } ReadStops (e, b.Stops); @@ -739,13 +844,19 @@ LinearGradientBrush CreateLinearGradientBrush (XElement e) b.End.X = ReadNumber (e.Attribute ("x2")); b.End.Y = ReadNumber (e.Attribute ("y2")); - var gradientUnits = e.Attribute("gradientUnits"); + var gradientUnits = e.Attribute ("gradientUnits"); if (gradientUnits != null) { b.Absolute = gradientUnits.Value == "userSpaceOnUse"; } - // TODO: check gradientTransform attribute + //Read transformation defined in the gradientTransform attribute if present + Transform GradientTransform = Transform.Identity; + if (e.Attribute ("gradientTransform") != null) + { + GradientTransform = ReadTransform (e.Attribute ("gradientTransform").Value); + b.GradientTransform = GradientTransform; + } ReadStops (e, b.Stops); @@ -755,32 +866,33 @@ LinearGradientBrush CreateLinearGradientBrush (XElement e) void ReadStops (XElement e, List stops) { var ns = e.Name.Namespace; - foreach (var se in e.Elements (ns + "stop")) { + foreach (var se in e.Elements (ns + "stop")) + { var s = new GradientStop (); s.Offset = ReadNumber (se.Attribute ("offset")); double alpha = 1.0; - var styleAttribute = se.Attribute("style"); + var styleAttribute = se.Attribute ("style"); if (styleAttribute != null) { - var styleSettings = styleAttribute.Value.Split(';'); - foreach(var style in styleSettings) + var styleSettings = styleAttribute.Value.Split (';'); + foreach (var style in styleSettings) { - if (style.Contains("stop-color") && style.IndexOf(':') != -1) + if (style.Contains ("stop-color") && style.IndexOf (':') != -1) { - s.Color = ReadColor(style.Substring(style.IndexOf(':')+1)); + s.Color = ReadColor (style.Substring (style.IndexOf (':') + 1)); } - else if (style.Contains("stop-opacity") && style.IndexOf(':') != -1) + else if (style.Contains ("stop-opacity") && style.IndexOf (':') != -1) { - alpha = ReadNumber(style.Substring(style.IndexOf(':')+1)); + alpha = ReadNumber (style.Substring (style.IndexOf (':') + 1)); } } } - var stopColorAttribute = se.Attribute("stop-color"); + var stopColorAttribute = se.Attribute ("stop-color"); if (stopColorAttribute != null) s.Color = ReadColor (stopColorAttribute.Value); - var opacityAttribute = se.Attribute("stop-opacity"); + var opacityAttribute = se.Attribute ("stop-opacity"); if (opacityAttribute != null) - alpha = ReadNumber(opacityAttribute.Value); + alpha = ReadNumber (opacityAttribute.Value); s.Color.Alpha = alpha; stops.Add (s); } @@ -795,16 +907,16 @@ Color ReadColor (XElement e, string attrib) return ReadColor (a.Value); } - Regex rgbRe = new Regex("([0-9]+).*?([0-9]+).*?([0-9]+)"); + Regex rgbRe = new Regex ("([0-9]+).*?([0-9]+).*?([0-9]+)"); Color ReadColor (string raw) { - if (string.IsNullOrWhiteSpace (raw) || raw.Equals("none", StringComparison.OrdinalIgnoreCase)) + if (string.IsNullOrWhiteSpace (raw) || raw.Equals ("none", StringComparison.OrdinalIgnoreCase)) return Colors.Clear; var s = raw.Trim (); - if (s.Length == 7 && s [0] == '#') + if (s.Length == 7 && s[0] == '#') { var r = int.Parse (s.Substring (1, 2), NumberStyles.HexNumber, icult); @@ -814,12 +926,12 @@ Color ReadColor (string raw) return new Color (r / 255.0, g / 255.0, b / 255.0, 1); } - var match = rgbRe.Match(s); + var match = rgbRe.Match (s); if (match.Success && match.Groups.Count == 4) { - var r = int.Parse( match.Groups[1].Value ); - var g = int.Parse( match.Groups[2].Value ); - var b = int.Parse( match.Groups[3].Value ); + var r = int.Parse (match.Groups[1].Value); + var g = int.Parse (match.Groups[2].Value); + var b = int.Parse (match.Groups[3].Value); return new Color (r / 255.0, g / 255.0, b / 255.0, 1); } @@ -836,15 +948,14 @@ string ReadTextFontAttr (XElement element, string attr) string value = null; if (element != null) { - var attrib = element.Attribute(attr); - if (attrib != null && !string.IsNullOrWhiteSpace(attrib.Value)) - value = attrib.Value.Trim(); - else - { - var style = element.Attribute("style"); - if (style != null && !string.IsNullOrWhiteSpace(style.Value)) + var attrib = element.Attribute (attr); + if (attrib != null && !string.IsNullOrWhiteSpace (attrib.Value)) + value = attrib.Value.Trim (); + else { + var style = element.Attribute ("style"); + if (style != null && !string.IsNullOrWhiteSpace (style.Value)) { - value = GetString(ParseStyle(style.Value), "attr"); + value = GetString (ParseStyle (style.Value), "attr"); } } } @@ -867,20 +978,19 @@ string ReadTextFontStyle (XElement element) return ReadTextFontAttr (element, "font-style"); } - double ReadTextFontSize(XElement element) + double ReadTextFontSize (XElement element) { double value = -1; if (element != null) { - var attrib = element.Attribute("font-size"); - if (attrib != null && !string.IsNullOrWhiteSpace(attrib.Value)) - value = ReadNumber(attrib.Value); - else - { - var style = element.Attribute("style"); - if (style != null && !string.IsNullOrWhiteSpace(style.Value)) + var attrib = element.Attribute ("font-size"); + if (attrib != null && !string.IsNullOrWhiteSpace (attrib.Value)) + value = ReadNumber (attrib.Value); + else { + var style = element.Attribute ("style"); + if (style != null && !string.IsNullOrWhiteSpace (style.Value)) { - value = ReadNumber(GetString(ParseStyle(style.Value), "font-size", "-1")); + value = ReadNumber (GetString (ParseStyle (style.Value), "font-size", "-1")); } } } @@ -888,30 +998,30 @@ double ReadTextFontSize(XElement element) return value; } - TextAlignment ReadTextAlignment(XElement element) + TextAlignment ReadTextAlignment (XElement element) { string value = null; if (element != null) { - var attrib = element.Attribute("text-anchor"); - if (attrib != null && !string.IsNullOrWhiteSpace(attrib.Value)) + var attrib = element.Attribute ("text-anchor"); + if (attrib != null && !string.IsNullOrWhiteSpace (attrib.Value)) value = attrib.Value; - else - { - var style = element.Attribute("style"); - if (style != null && !string.IsNullOrWhiteSpace(style.Value)) + else { + var style = element.Attribute ("style"); + if (style != null && !string.IsNullOrWhiteSpace (style.Value)) { - value = GetString (ParseStyle(style.Value), "text-anchor"); + value = GetString (ParseStyle (style.Value), "text-anchor"); } } } - switch (value) { - case "end": + switch (value) + { + case "end": return TextAlignment.Right; - case "middle": + case "middle": return TextAlignment.Center; - default: + default: return TextAlignment.Left; } } @@ -930,8 +1040,8 @@ double ReadNumber (XAttribute a) return ReadNumber (a.Value); } - Regex unitRe = new Regex("px|pt|em|ex|pc|cm|mm|in"); - Regex percRe = new Regex("%"); + Regex unitRe = new Regex ("px|pt|em|ex|pc|cm|mm|in"); + Regex percRe = new Regex ("%"); double ReadNumber (string raw) { @@ -941,26 +1051,39 @@ double ReadNumber (string raw) var s = raw.Trim (); var m = 1.0; - if (unitRe.IsMatch(s)) { - if (s.EndsWith ("in", StringComparison.Ordinal)) { + if (unitRe.IsMatch (s)) + { + if (s.EndsWith ("in", StringComparison.Ordinal)) + { m = PixelsPerInch; - } else if (s.EndsWith ("cm", StringComparison.Ordinal)) { + } + else if (s.EndsWith ("cm", StringComparison.Ordinal)) + { m = PixelsPerInch / 2.54; - } else if (s.EndsWith ("mm", StringComparison.Ordinal)) { + } + else if (s.EndsWith ("mm", StringComparison.Ordinal)) + { m = PixelsPerInch / 25.4; - } else if (s.EndsWith ("pt", StringComparison.Ordinal)) { + } + else if (s.EndsWith ("pt", StringComparison.Ordinal)) + { m = PixelsPerInch / 72.0; - } else if (s.EndsWith ("pc", StringComparison.Ordinal)) { + } + else if (s.EndsWith ("pc", StringComparison.Ordinal)) + { m = PixelsPerInch / 6.0; } s = s.Substring (0, s.Length - 2); - } else if (percRe.IsMatch(s)) { + } + else if (percRe.IsMatch (s)) + { s = s.Substring (0, s.Length - 1); m = 0.01; } double v; - if (!double.TryParse (s, NumberStyles.Float, icult, out v)) { + if (!double.TryParse (s, NumberStyles.Float, icult, out v)) + { v = 0; } return m * v; @@ -973,14 +1096,16 @@ Rect ReadRectangle (string s) var r = new Rect (); var p = s.Split (WS, StringSplitOptions.RemoveEmptyEntries); if (p.Length > 0) - r.X = ReadNumber (p [0]); + r.X = ReadNumber (p[0]); if (p.Length > 1) - r.Y = ReadNumber (p [1]); + r.Y = ReadNumber (p[1]); if (p.Length > 2) - r.Width = ReadNumber (p [2]); + r.Width = ReadNumber (p[2]); if (p.Length > 3) - r.Height = ReadNumber (p [3]); + r.Height = ReadNumber (p[3]); return r; } } + + } diff --git a/Platforms/NGraphics.Android/AndroidPlatform.cs b/Platforms/NGraphics.Android/AndroidPlatform.cs index 9ec41eff..d7da4741 100644 --- a/Platforms/NGraphics.Android/AndroidPlatform.cs +++ b/Platforms/NGraphics.Android/AndroidPlatform.cs @@ -22,7 +22,8 @@ public IImageCanvas CreateImageCanvas (Size size, double scale = 1.0, bool trans var pixelWidth = (int)Math.Ceiling (size.Width * scale); var pixelHeight = (int)Math.Ceiling (size.Height * scale); var bitmap = Bitmap.CreateBitmap (pixelWidth, pixelHeight, Bitmap.Config.Argb8888); - if (!transparency) { + if (!transparency) + { bitmap.EraseColor (Colors.Black.Argb); } return new BitmapCanvas (bitmap, scale); @@ -45,8 +46,9 @@ public IImage CreateImage (Color[] colors, int width, double scale = 1.0) var pixelWidth = width; var pixelHeight = colors.Length / width; var acolors = new int[pixelWidth * pixelHeight]; - for (var i = 0; i < colors.Length; i++) { - acolors [i] = colors [i].Argb; + for (var i = 0; i < colors.Length; i++) + { + acolors[i] = colors[i].Argb; } var bitmap = Bitmap.CreateBitmap (acolors, pixelWidth, pixelHeight, Bitmap.Config.Argb8888); return new BitmapImage (bitmap, scale); @@ -70,10 +72,11 @@ public static TextPaint GlobalGetFontPaint (Font font, TextAlignment alignment) public static TextMetrics GlobalMeasureText (string text, Font font) { - var paint = GlobalGetFontPaint(font, TextAlignment.Left); + var paint = GlobalGetFontPaint (font, TextAlignment.Left); var w = paint.MeasureText (text); var fm = paint.GetFontMetrics (); - return new TextMetrics { + return new TextMetrics + { Width = w, Ascent = -fm.Ascent, Descent = fm.Descent @@ -89,10 +92,12 @@ public TextMetrics MeasureText (string text, Font font) public class BitmapImage : IImage { readonly Bitmap bitmap; -// readonly double scale; + // readonly double scale; - public Bitmap Bitmap { - get { + public Bitmap Bitmap + { + get + { return bitmap; } } @@ -100,12 +105,13 @@ public Bitmap Bitmap { public BitmapImage (Bitmap bitmap, double scale = 1.0) { this.bitmap = bitmap; -// this.scale = scale; + // this.scale = scale; } public void SaveAsPng (string path) { - using (var f = System.IO.File.OpenWrite (path)) { + using (var f = System.IO.File.OpenWrite (path)) + { bitmap.Compress (Bitmap.CompressFormat.Png, 100, f); } } @@ -119,7 +125,7 @@ public Size Size { get { - return new Size(bitmap.Width, bitmap.Height); + return new Size (bitmap.Width, bitmap.Height); } } @@ -166,23 +172,31 @@ public CanvasCanvas (Canvas graphics) public void SaveState () { - graphics.Save (SaveFlags.Matrix|SaveFlags.Clip); + graphics.Save (SaveFlags.Matrix | SaveFlags.Clip); } public void Transform (Transform transform) - { + { var t = new Matrix (); t.SetValues (new[] { (float)transform.A, (float)transform.C, (float)transform.E, (float)transform.B, (float)transform.D, (float)transform.F, 0, 0, 1, }); - graphics.Concat(t); + graphics.Concat (t); + } + + public Matrix AndroidMatrixFromTransform (Transform t) + { + Matrix m = new Matrix (); + m.SetValues (new float[] { (float)t.A, (float)t.C, (float)t.E, (float)t.B, (float)t.D, (float)t.F, 0f, 0f, 1f }); + return m; } + public void RestoreState () { graphics.Restore (); } - + Paint GetImagePaint (double alpha) { var paint = new Paint (PaintFlags.AntiAlias); @@ -197,10 +211,11 @@ Paint GetPenPaint (Pen pen) paint.SetARGB (pen.Color.A, pen.Color.R, pen.Color.G, pen.Color.B); paint.StrokeWidth = (float)pen.Width; - if (pen.DashPattern != null && pen.DashPattern.Any ()) { - var dashPathEffect = new DashPathEffect(pen.DashPattern.ToArray(), 0); - paint.SetPathEffect(dashPathEffect); - } + if (pen.DashPattern != null && pen.DashPattern.Any ()) + { + var dashPathEffect = new DashPathEffect (pen.DashPattern.ToArray (), 0); + paint.SetPathEffect (dashPathEffect); + } return paint; } @@ -215,54 +230,79 @@ void AddBrushPaint (Paint paint, Brush brush, Rect bb) paint.SetStyle (Paint.Style.Fill); var sb = brush as SolidBrush; - if (sb != null) { + if (sb != null) + { paint.SetARGB (sb.Color.A, sb.Color.R, sb.Color.G, sb.Color.B); return; } var lgb = brush as LinearGradientBrush; - if (lgb != null) { + if (lgb != null) + { var n = lgb.Stops.Count; - if (n >= 2) { - var locs = new float [n]; - var comps = new int [n]; - for (var i = 0; i < n; i++) { - var s = lgb.Stops [i]; - locs [i] = (float)s.Offset; - comps [i] = s.Color.Argb; + if (n >= 2) + { + var locs = new float[n]; + var comps = new int[n]; + for (var i = 0; i < n; i++) + { + var s = lgb.Stops[i]; + locs[i] = (float)s.Offset; + comps[i] = s.Color.Argb; } var p1 = lgb.Absolute ? lgb.Start : bb.Position + lgb.Start * bb.Size; var p2 = lgb.Absolute ? lgb.End : bb.Position + lgb.End * bb.Size; var lg = new LinearGradient ( - (float)p1.X, (float)p1.Y, - (float)p2.X, (float)p2.Y, - comps, - locs, - Shader.TileMode.Clamp); + (float)p1.X, (float)p1.Y, + (float)p2.X, (float)p2.Y, + comps, + locs, + Shader.TileMode.Clamp); + + //Apply GradientTransform if present + if (lgb.GradientTransform != null) + { + Matrix matrix = new Matrix (); + matrix.PreConcat (AndroidMatrixFromTransform (lgb.GradientTransform)); + lg.SetLocalMatrix (matrix); + } + + paint.SetShader (lg); } return; } var rgb = brush as RadialGradientBrush; - if (rgb != null) { + if (rgb != null) + { var n = rgb.Stops.Count; - if (n >= 2) { - var locs = new float [n]; - var comps = new int [n]; - for (var i = 0; i < n; i++) { - var s = rgb.Stops [i]; - locs [i] = (float)s.Offset; - comps [i] = s.Color.Argb; + if (n >= 2) + { + var locs = new float[n]; + var comps = new int[n]; + for (var i = 0; i < n; i++) + { + var s = rgb.Stops[i]; + locs[i] = (float)s.Offset; + comps[i] = s.Color.Argb; } var p1 = rgb.GetAbsoluteCenter (bb); var r = rgb.GetAbsoluteRadius (bb); var rg = new RadialGradient ( - (float)p1.X, (float)p1.Y, - (float)r.Max, - comps, - locs, - Shader.TileMode.Clamp); + (float)p1.X, (float)p1.Y, + (float)r.Max, + comps, + locs, + Shader.TileMode.Clamp); + + //Apply GradientTransform if present + if (rgb.GradientTransform != null) + { + Matrix matrix = new Matrix (); + matrix.PreConcat (AndroidMatrixFromTransform (rgb.GradientTransform)); + rg.SetLocalMatrix (matrix); + } paint.SetShader (rg); } @@ -287,10 +327,10 @@ public void DrawText (string text, Rect frame, Font font, TextAlignment alignmen var fm = paint.GetFontMetrics (); var h = fm.Ascent + fm.Descent; var point = alignment == TextAlignment.Left - ? frame.TopLeft - : alignment == TextAlignment.Center - ? (frame.TopLeft + frame.TopRight) / 2 - : frame.TopRight; + ? frame.TopLeft + : alignment == TextAlignment.Center + ? (frame.TopLeft + frame.TopRight) / 2 + : frame.TopRight; var fr = new Rect (point, new Size (w, h)); AddBrushPaint (paint, brush, fr); graphics.DrawText (text, (float)point.X, (float)point.Y, paint); @@ -300,15 +340,18 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul if (pen == null && brush == null) return; - using (var path = new global::Android.Graphics.Path ()) { + using (var path = new global::Android.Graphics.Path ()) + { var bb = new BoundingBoxBuilder (); Point? prevPoint = null; - foreach (var op in ops) { + foreach (var op in ops) + { var mt = op as MoveTo; - if (mt != null) { + if (mt != null) + { var p = mt.Point; path.MoveTo ((float)p.X, (float)p.Y); bb.Add (p); @@ -316,63 +359,70 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul continue; } var lt = op as LineTo; - if (lt != null) { + if (lt != null) + { var p = lt.Point; path.LineTo ((float)p.X, (float)p.Y); bb.Add (p); prevPoint = p; continue; - } + } var at = op as ArcTo; - if (at != null) { + if (at != null) + { var p = at.Point; - if (!prevPoint.HasValue) { - throw new NotSupportedException("Cannot begin path with Arc."); + if (!prevPoint.HasValue) + { + throw new NotSupportedException ("Cannot begin path with Arc."); } var pp = prevPoint.Value; Point c1, c2; - at.GetCircles(pp, out c1, out c2); + at.GetCircles (pp, out c1, out c2); var circleCenter = at.LargeArc ^ !at.SweepClockwise ? c2 : c1; - var rect = new Rect(circleCenter - at.Radius, at.Radius * 2); + var rect = new Rect (circleCenter - at.Radius, at.Radius * 2); - var startAngle = Conversions.RadToDeg((float)Math.Atan2(pp.Y - circleCenter.Y, pp.X - circleCenter.X)); - var endAngle = Conversions.RadToDeg((float)Math.Atan2(p.Y - circleCenter.Y, p.X - circleCenter.X)); + var startAngle = Conversions.RadToDeg ((float)Math.Atan2 (pp.Y - circleCenter.Y, pp.X - circleCenter.X)); + var endAngle = Conversions.RadToDeg ((float)Math.Atan2 (p.Y - circleCenter.Y, p.X - circleCenter.X)); var sweepAngle = endAngle - startAngle; - if (at.SweepClockwise && sweepAngle < 0) { + if (at.SweepClockwise && sweepAngle < 0) + { // If we want to go CW, sweepAngle needs to be positive sweepAngle += 360.0f; } - else if (!at.SweepClockwise && sweepAngle > 0) { + else if (!at.SweepClockwise && sweepAngle > 0) + { // If we want to go CCW, sweepAngle needs to be negative sweepAngle -= 360.0f; } - path.AddArc(Conversions.GetRectF(rect), startAngle, sweepAngle); + path.AddArc (Conversions.GetRectF (rect), startAngle, sweepAngle); bb.Add (p); prevPoint = p; continue; } - var ct = op as CurveTo; - if (ct != null) { - var p = ct.Point; - var c1 = ct.Control1; - var c2 = ct.Control2; - path.CubicTo ((float)c1.X, (float)c1.Y, (float)c2.X, (float)c2.Y, (float)p.X, (float)p.Y); + var ct = op as CurveTo; + if (ct != null) + { + var p = ct.Point; + var c1 = ct.Control1; + var c2 = ct.Control2; + path.CubicTo ((float)c1.X, (float)c1.Y, (float)c2.X, (float)c2.Y, (float)p.X, (float)p.Y); bb.Add (p); bb.Add (c1); bb.Add (c2); prevPoint = p; - continue; - } - var cp = op as ClosePath; - if (cp != null) { + continue; + } + var cp = op as ClosePath; + if (cp != null) + { path.Close (); continue; } @@ -382,11 +432,13 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul var frame = bb.BoundingBox; - if (brush != null) { + if (brush != null) + { var paint = GetBrushPaint (brush, frame); graphics.DrawPath (path, paint); } - if (pen != null) { + if (pen != null) + { var paint = GetPenPaint (pen); graphics.DrawPath (path, paint); } @@ -400,30 +452,38 @@ public void DrawRectangle (Rect frame, Size corner, Pen pen = null, Brush brush var bottom = (float)(frame.Y + frame.Height); var rx = (float)corner.Width; var ry = (float)corner.Height; - if (brush != null) { + if (brush != null) + { var paint = GetBrushPaint (brush, frame); - if (rx > 0 || ry > 0) { + if (rx > 0 || ry > 0) + { graphics.DrawRoundRect (new RectF (left, top, right, bottom), rx, ry, paint); - } else { + } + else { graphics.DrawRect (left, top, right, bottom, paint); } } - if (pen != null) { + if (pen != null) + { var paint = GetPenPaint (pen); - if (rx > 0 || ry > 0) { + if (rx > 0 || ry > 0) + { graphics.DrawRoundRect (new RectF (left, top, right, bottom), rx, ry, paint); - } else { + } + else { graphics.DrawRect (left, top, right, bottom, paint); } } } public void DrawEllipse (Rect frame, Pen pen = null, Brush brush = null) { - if (brush != null) { + if (brush != null) + { var paint = GetBrushPaint (brush, frame); graphics.DrawOval (Conversions.GetRectF (frame), paint); } - if (pen != null) { + if (pen != null) + { var paint = GetPenPaint (pen); graphics.DrawOval (Conversions.GetRectF (frame), paint); } @@ -431,7 +491,8 @@ public void DrawEllipse (Rect frame, Pen pen = null, Brush brush = null) public void DrawImage (IImage image, Rect frame, double alpha = 1.0) { var ii = image as BitmapImage; - if (ii != null) { + if (ii != null) + { var paint = GetImagePaint (alpha); var isize = new Size (ii.Bitmap.Width, ii.Bitmap.Height); var scale = frame.Size / isize; @@ -445,17 +506,17 @@ public void DrawImage (IImage image, Rect frame, double alpha = 1.0) public static class Conversions { - public static PointF GetPointF (this Point point) - { - return new PointF ((float)point.X, (float)point.Y); - } + public static PointF GetPointF (this Point point) + { + return new PointF ((float)point.X, (float)point.Y); + } public static RectF GetRectF (this Rect frame) { return new RectF ((float)frame.X, (float)frame.Y, (float)(frame.X + frame.Width), (float)(frame.Y + frame.Height)); } - - public static float RadToDeg(float rad) + + public static float RadToDeg (float rad) { return rad / (float)Math.PI * 180.0f; } diff --git a/Platforms/NGraphics.Mac/ApplePlatform.cs b/Platforms/NGraphics.Mac/ApplePlatform.cs index c9d237c7..739c8303 100644 --- a/Platforms/NGraphics.Mac/ApplePlatform.cs +++ b/Platforms/NGraphics.Mac/ApplePlatform.cs @@ -13,14 +13,16 @@ namespace NGraphics { public class ApplePlatform : IPlatform { - public string Name { - get { + public string Name + { + get + { #if __IOS__ - return "iOS"; - #else + return "iOS"; +#else return "Mac"; #endif - } + } } public Task OpenFileStreamForWritingAsync (string path) @@ -50,12 +52,16 @@ public IImage CreateImage (Color[] colors, int width, double scale = 1.0) var colorSpace = CGColorSpace.CreateDeviceRGB (); var bitmap = new CGBitmapContext (IntPtr.Zero, pixelWidth, pixelHeight, bitsPerComp, bytesPerRow, colorSpace, bitmapInfo); var data = bitmap.Data; - unsafe { - fixed (Color *c = colors) { - for (var y = 0; y < pixelHeight; y++) { - var s = (byte*)c + 4*pixelWidth*y; - var d = (byte*)data + bytesPerRow*y; - for (var x = 0; x < pixelWidth; x++) { + unsafe + { + fixed (Color* clors) + { + for (var y = 0; y < pixelHeight; y++) + { + var s = (byte*)c + 4 * pixelWidth * y; + var d = (byte*)data + bytesPerRow * y; + for (var x = 0; x < pixelWidth; x++) + { var b = *s++; var g = *s++; var r = *s++; @@ -68,15 +74,17 @@ public IImage CreateImage (Color[] colors, int width, double scale = 1.0) } } } - var image = bitmap.ToImage (); + var image = bitmap.Tomage (); return new CGImageImage (image, scale); } public IImage LoadImage (Stream stream) { var mem = new MemoryStream ((int)stream.Length); stream.CopyTo (mem); - unsafe { - fixed (byte *x = mem.GetBuffer ()) { + unsafe + { + fixed (byte* x = mem.GetBuffer ()) + { var provider = new CGDataProvider (new IntPtr (x), (int)mem.Length, false); var image = CGImage.FromPNG (provider, null, false, CGColorRenderingIntent.Default); return new CGImageImage (image, 1); @@ -87,9 +95,11 @@ public IImage LoadImage (string path) { var provider = new CGDataProvider (path); CGImage image; - if (System.IO.Path.GetExtension (path).ToLowerInvariant () == ".png") { + if (System.IO.Path.GetExtension (path).ToLowerInvariant () == ".png") + { image = CGImage.FromPNG (provider, null, false, CGColorRenderingIntent.Default); - } else { + } + else { image = CGImage.FromJPEG (provider, null, false, CGColorRenderingIntent.Default); } return new CGImageImage (image, 1); @@ -97,24 +107,28 @@ public IImage LoadImage (string path) public static TextMetrics GlobalMeasureText (string text, Font font) { - if (string.IsNullOrEmpty(text)) + if (string.IsNullOrEmpty (text)) return new TextMetrics (); if (font == null) - throw new ArgumentNullException("font"); + throw new ArgumentNullException ("font"); - using (var atext = new NSMutableAttributedString (text)) { + using (var atext = new NSMutableAttributedString (text)) + { - atext.AddAttributes (new CTStringAttributes { + atext.AddAttributes (new CTStringAttributes + { ForegroundColorFromContext = true, Font = font.GetCTFont (), }, new NSRange (0, text.Length)); - using (var l = new CTLine (atext)) { + using (var l = new CTLine (atext)) + { nfloat asc, desc, lead; var len = l.GetTypographicBounds (out asc, out desc, out lead); - return new TextMetrics { + return new TextMetrics + { Width = len, Ascent = asc, Descent = desc, @@ -179,8 +193,10 @@ public void SaveAsPng (string path) { if (string.IsNullOrEmpty (path)) throw new ArgumentException ("path"); - using (var dest = CGImageDestination.Create (NSUrl.FromFilename (path), "public.png", 1)) { - if (dest == null) { + using (var dest = CGImageDestination.Create (NSUrl.FromFilename (path), "public.png", 1)) + { + if (dest == null) + { throw new InvalidOperationException (string.Format ("Could not create image destination {0}.", path)); } dest.AddImage (image); @@ -192,10 +208,13 @@ public void SaveAsPng (Stream stream) { if (stream == null) throw new ArgumentNullException (); - - using (var data = new NSMutableData ()) { - using (var dest = CGImageDestination.Create (data, "public.png", 1)) { - if (dest == null) { + + using (var data = new NSMutableData ()) + { + using (var dest = CGImageDestination.Create (data, "public.png", 1)) + { + if (dest == null) + { throw new InvalidOperationException (string.Format ("Could not create image destination from {0}.", stream)); } dest.AddImage (image); @@ -215,7 +234,7 @@ public class CGContextCanvas : ICanvas public CGContextCanvas (CGContext context) { this.context = context; -// context.InterpolationQuality = CGInterpolationQuality.High; + // context.InterpolationQuality = CGInterpolationQuality.High; context.TextMatrix = CGAffineTransform.MakeScale (1, -1); } @@ -230,6 +249,13 @@ public void Transform (Transform transform) (nfloat)transform.C, (nfloat)transform.D, (nfloat)transform.E, (nfloat)transform.F)); } + public CGAffineTransform ConvertTransformToAppleCGAffineTransform (Transform transform) + { + return new CGAffineTransform ( + (nfloat)transform.A, (nfloat)transform.B, + (nfloat)transform.C, (nfloat)transform.D, + (nfloat)transform.E, (nfloat)transform.F); + } public void RestoreState () { context.RestoreState (); @@ -238,23 +264,24 @@ public void RestoreState () CGGradient CreateGradient (IList stops) { var n = stops.Count; - var locs = new nfloat [n]; - var comps = new nfloat [4 * n]; - for (var i = 0; i < n; i++) { - var s = stops [i]; - locs [i] = (nfloat)s.Offset; - comps [4 * i + 0] = (nfloat)s.Color.Red; - comps [4 * i + 1] = (nfloat)s.Color.Green; - comps [4 * i + 2] = (nfloat)s.Color.Blue; - comps [4 * i + 3] = (nfloat)s.Color.Alpha; + var locs = new nfloat[n]; + var comps = new nfloat[4 * n]; + for (var i = 0; i < n; i++) + { + var s = stops[i]; + locs[i] = (nfloat)s.Offset; + comps[4 * i + 0] = (nfloat)s.Color.Red; + comps[4 * i + 1] = (nfloat)s.Color.Green; + comps[4 * i + 2] = (nfloat)s.Color.Blue; + comps[4 * i + 3] = (nfloat)s.Color.Alpha; } var cs = CGColorSpace.CreateDeviceRGB (); return new CGGradient (cs, comps, locs); } - private static NSString NSFontAttributeName = new NSString("NSFontAttributeName"); + private static NSString NSFontAttributeName = new NSString ("NSFontAttributeName"); - public TextMetrics MeasureText(string text, Font font) + public TextMetrics MeasureText (string text, Font font) { return ApplePlatform.GlobalMeasureText (text, font); } @@ -268,28 +295,32 @@ public void DrawText (string text, Rect frame, Font font, TextAlignment alignmen SetBrush (brush); - using (var atext = new NSMutableAttributedString (text)) { + using (var atext = new NSMutableAttributedString (text)) + { - atext.AddAttributes (new CTStringAttributes { + atext.AddAttributes (new CTStringAttributes + { ForegroundColorFromContext = true, - StrokeColor = pen != null ? pen.Color.GetCGColor () : null, + StrokeColor = pen != null ? pen.Color.GetCGClor () : null, Font = font.GetCTFont (), }, new NSRange (0, text.Length)); - using (var l = new CTLine (atext)) { + using (var l = new CTLine (atext)) + { nfloat asc, desc, lead; var len = l.GetTypographicBounds (out asc, out desc, out lead); var pt = frame.TopLeft; - switch (alignment) { - case TextAlignment.Left: - pt.X = frame.X; + switch (alignment) + { + case TextAlignment.Left: + pt.X = frame.X; break; - case TextAlignment.Center: - pt.X = frame.X + (frame.Width - len) / 2; + case TextAlignment.Center: + pt.X = frame.X + (frame.Width - len) / 2; break; - case TextAlignment.Right: - pt.X = frame.Right - len; + case TextAlignment.Right: + pt.X = frame.Right - len; break; } @@ -308,7 +339,8 @@ void DrawElement (Func add, Pen pen = null, Brush brush = null) return; var lgb = brush as LinearGradientBrush; - if (lgb != null) { + if (lgb != null) + { var cg = CreateGradient (lgb.Stops); context.SaveState (); var frame = add (); @@ -317,13 +349,24 @@ void DrawElement (Func add, Pen pen = null, Brush brush = null) var size = frame.Size; var start = Conversions.GetCGPoint (lgb.Absolute ? lgb.Start : frame.Position + lgb.Start * size); var end = Conversions.GetCGPoint (lgb.Absolute ? lgb.End : frame.Position + lgb.End * size); + + //Apply GradientTransform if present + if (lgb.GradientTransform != null) + { + CGAffineTransform matrix = CGAffineTransform.MakeIdentity (); + CGAffineTransform m = ConvertTransformToAppleCGAffineTransform (lgb.GradientTransform); + matrix.Multiply (m); + context.ConcatCTM (matrix); + }; + context.DrawLinearGradient (cg, start, end, options); context.RestoreState (); brush = null; } var rgb = brush as RadialGradientBrush; - if (rgb != null) { + if (rgb != null) + { var cg = CreateGradient (rgb.Stops); context.SaveState (); var frame = add (); @@ -333,6 +376,16 @@ void DrawElement (Func add, Pen pen = null, Brush brush = null) var start = Conversions.GetCGPoint (rgb.GetAbsoluteCenter (frame)); var r = (nfloat)rgb.GetAbsoluteRadius (frame).Max; var end = Conversions.GetCGPoint (rgb.GetAbsoluteFocus (frame)); + + //Apply GradientTransform if present + if (rgb.GradientTransform != null) + { + CGAffineTransform matrix = CGAffineTransform.MakeIdentity (); + CGAffineTransform m = ConvertTransformToAppleCGAffineTransform (rgb.GradientTransform); + matrix.Multiply (m); + context.ConcatCTM (matrix); + }; + context.DrawRadialGradient (cg, start, 0, end, r, options); context.RestoreState (); brush = null; @@ -357,13 +410,16 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul if (pen == null && brush == null) return; - DrawElement (() => { + DrawElement (() => + { var bb = new BoundingBoxBuilder (); - foreach (var op in ops) { + foreach (var op in ops) + { var mt = op as MoveTo; - if (mt != null) { + if (mt != null) + { var p = mt.Point; if (!IsValid (p.X) || !IsValid (p.Y)) continue; @@ -372,7 +428,8 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul continue; } var lt = op as LineTo; - if (lt != null) { + if (lt != null) + { var p = lt.Point; if (!IsValid (p.X) || !IsValid (p.Y)) continue; @@ -381,7 +438,8 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul continue; } var at = op as ArcTo; - if (at != null) { + if (at != null) + { var p = at.Point; if (!IsValid (p.X) || !IsValid (p.Y)) continue; @@ -393,27 +451,30 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul var circleCenter = at.LargeArc ^ !at.SweepClockwise ? c2 : c1; - var startAngle = (float)Math.Atan2(pp.Y - circleCenter.Y, pp.X - circleCenter.X); - var endAngle = (float)Math.Atan2(p.Y - circleCenter.Y, p.X - circleCenter.X); + var startAngle = (float)Math.Atan2 (pp.Y - circleCenter.Y, pp.X - circleCenter.X); + var endAngle = (float)Math.Atan2 (p.Y - circleCenter.Y, p.X - circleCenter.X); - if (!IsValid (circleCenter.X) || !IsValid (circleCenter.Y) || !IsValid (startAngle) || !IsValid (endAngle)) { + if (!IsValid (circleCenter.X) || !IsValid (circleCenter.Y) || !IsValid (startAngle) || !IsValid (endAngle)) + { context.MoveTo ((nfloat)p.X, (nfloat)p.Y); continue; } - context.AddArc((nfloat)circleCenter.X, (nfloat)circleCenter.Y, (nfloat)at.Radius.Min, startAngle, endAngle, at.SweepClockwise); + context.AddArc ((nfloat)circleCenter.X, (nfloat)circleCenter.Y, (nfloat)at.Radius.Min, startAngle, endAngle, at.SweepClockwise); bb.Add (p); continue; } var ct = op as CurveTo; - if (ct != null) { + if (ct != null) + { var p = ct.Point; if (!IsValid (p.X) || !IsValid (p.Y)) continue; var c1 = ct.Control1; var c2 = ct.Control2; - if (!IsValid (c1.X) || !IsValid (c1.Y) || !IsValid (c2.X) || !IsValid (c2.Y)) { + if (!IsValid (c1.X) || !IsValid (c1.Y) || !IsValid (c2.X) || !IsValid (c2.Y)) + { context.MoveTo ((nfloat)p.X, (nfloat)p.Y); continue; } @@ -424,7 +485,8 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul continue; } var cp = op as ClosePath; - if (cp != null) { + if (cp != null) + { context.ClosePath (); continue; } @@ -440,11 +502,13 @@ public void DrawPath (IEnumerable ops, Pen pen = null, Brush brush = nul void AddRoundedRect (CGRect rrect, CGSize corner) { var rx = corner.Width; - if (rx * 2 > rrect.Width) { + if (rx * 2 > rrect.Width) + { rx = rrect.Width / 2; } var ry = corner.Height; - if (ry * 2 > rrect.Height) { + if (ry * 2 > rrect.Height) + { ry = rrect.Height / 2; } var path = CGPath.FromRoundedRect (rrect, rx, ry); @@ -455,8 +519,10 @@ public void DrawRectangle (Rect frame, Size corner, Pen pen = null, Brush brush if (pen == null && brush == null) return; - DrawElement (() => { - if (corner.Width > 0 || corner.Height > 0) { + DrawElement (() => + { + if (corner.Width > 0 || corner.Height > 0) + { AddRoundedRect (Conversions.GetCGRect (frame), Conversions.GetCGSize (corner)); } else { @@ -470,7 +536,8 @@ public void DrawEllipse (Rect frame, Pen pen = null, Brush brush = null) if (pen == null && brush == null) return; - DrawElement (() => { + DrawElement (() => + { context.AddEllipseInRect (Conversions.GetCGRect (frame)); return frame; }, pen, brush); @@ -479,7 +546,8 @@ public void DrawImage (IImage image, Rect frame, double alpha = 1.0) { var cgi = image as CGImageImage; - if (cgi != null) { + if (cgi != null) + { var i = cgi.Image; var h = frame.Height; context.SaveState (); @@ -494,12 +562,14 @@ public void DrawImage (IImage image, Rect frame, double alpha = 1.0) CGPathDrawingMode SetPenAndBrush (Pen pen, Brush brush) { var mode = CGPathDrawingMode.Fill; - if (brush != null) { + if (brush != null) + { SetBrush (brush); if (pen != null) mode = CGPathDrawingMode.FillStroke; } - if (pen != null) { + if (pen != null) + { SetPen (pen); if (brush == null) mode = CGPathDrawingMode.Stroke; @@ -512,22 +582,24 @@ void SetPen (Pen pen) context.SetStrokeColor ((nfloat)pen.Color.Red, (nfloat)pen.Color.Green, (nfloat)pen.Color.Blue, (nfloat)pen.Color.Alpha); context.SetLineWidth ((nfloat)pen.Width); - if (pen.DashPattern != null && pen.DashPattern.Any ()) { - var pattern = pen.DashPattern - .Select (dp => (nfloat)dp) - .ToArray (); + if (pen.DashPattern != null && pen.DashPattern.Any ()) + { + var pattern = pen.DashPattern + .Select (dp => (nfloat)dp) + .ToArray (); - context.SetLineDash (0, pattern, pattern.Length); - } - else { - context.SetLineDash(0, null, 0); - } - } + context.SetLineDash (0, pattern, pattern.Length); + } + else { + context.SetLineDash (0, null, 0); + } + } void SetBrush (Brush brush) { var sb = brush as SolidBrush; - if (sb != null) { + if (sb != null) + { context.SetFillColor ((nfloat)sb.Color.Red, (nfloat)sb.Color.Green, (nfloat)sb.Color.Blue, (nfloat)sb.Color.Alpha); } } @@ -577,7 +649,7 @@ public static Color GetColor (this CGColor color) return Color.FromRGB (c[0], c[1], c[2], c[3]); } #if __IOS__ || __TVOS__ - public static UIKit.UIColor GetUIColor (this Color color) + public static UIKit.UIColor GetUIColor (this Color color) { return UIKit.UIColor.FromRGBA (color.R, color.G, color.B, color.A); } @@ -592,7 +664,7 @@ public static UIKit.UIImage GetUIImage (this IImage image) var c = (CGImageImage)image; return new UIKit.UIImage (c.Image, (nfloat)c.Scale, UIKit.UIImageOrientation.Up); } - #else +#else public static AppKit.NSImage GetNSImage (this IImage image) { var c = (CGImageImage)image;