diff --git a/global.json b/global.json
index 0ddf69c7e5..7346bdc280 100644
--- a/global.json
+++ b/global.json
@@ -1,3 +1,6 @@
{
- "projects": [ "src" ]
+ "projects": [ "src" ],
+ "sdk": {
+ "version": "1.0.0-preview2-003121"
+ }
}
\ No newline at end of file
diff --git a/src/ImageSharp/Drawing/Brushes/Brushes.cs b/src/ImageSharp/Drawing/Brushes/Brushes.cs
new file mode 100644
index 0000000000..ba256ad027
--- /dev/null
+++ b/src/ImageSharp/Drawing/Brushes/Brushes.cs
@@ -0,0 +1,302 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Brushes
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// A collection of methods for creating brushes
+ ///
+ public class Brushes
+ {
+ ///
+ /// Create as brush that will paint a solid color
+ ///
+ /// The color.
+ /// A Brush
+ public static SolidBrush Solid(Color color)
+ => new SolidBrush(color);
+
+ ///
+ /// Create as brush that will paint a Percent10 Hatch Pattern with
+ /// in the specified foreground color and a transparent background
+ ///
+ /// Color of the foreground.
+ /// A Brush
+ public static PatternBrush Percent10(Color foreColor)
+ => new PatternBrush(Brushes.Percent10(foreColor, Color.Transparent));
+
+ ///
+ /// Create as brush that will paint a Percent10 Hatch Pattern with
+ /// in the specified foreground and background colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Percent10(Color foreColor, Color backColor)
+ => new PatternBrush(Brushes.Percent10(foreColor, backColor));
+
+ ///
+ /// Create as brush that will paint a Percent20 Hatch Pattern with
+ /// in the specified foreground color and a transparent background
+ ///
+ /// Color of the foreground.
+ /// A Brush
+ public static PatternBrush Percent20(Color foreColor)
+ => new PatternBrush(Brushes.Percent20(foreColor, Color.Transparent));
+
+ ///
+ /// Create as brush that will paint a Percent20 Hatch Pattern with
+ /// in the specified foreground and background colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Percent20(Color foreColor, Color backColor)
+ => new PatternBrush(Brushes.Percent20(foreColor, backColor));
+
+ ///
+ /// Create as brush that will paint a Horizontal Hatch Pattern with
+ /// in the specified foreground color and a transparent background
+ ///
+ /// Color of the foreground.
+ /// A Brush
+ public static PatternBrush Horizontal(Color foreColor)
+ => new PatternBrush(Brushes.Horizontal(foreColor, Color.Transparent));
+
+ ///
+ /// Create as brush that will paint a Horizontal Hatch Pattern with
+ /// in the specified foreground and background colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Horizontal(Color foreColor, Color backColor)
+ => new PatternBrush(Brushes.Horizontal(foreColor, backColor));
+
+ ///
+ /// Create as brush that will paint a Min Hatch Pattern with
+ /// in the specified foreground color and a transparent background
+ ///
+ /// Color of the foreground.
+ /// A Brush
+ public static PatternBrush Min(Color foreColor)
+ => new PatternBrush(Brushes.Min(foreColor, Color.Transparent));
+
+ ///
+ /// Create as brush that will paint a Min Hatch Pattern with
+ /// in the specified foreground and background colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Min(Color foreColor, Color backColor)
+ => new PatternBrush(Brushes.Min(foreColor, backColor));
+
+ ///
+ /// Create as brush that will paint a Vertical Hatch Pattern with
+ /// in the specified foreground color and a transparent background
+ ///
+ /// Color of the foreground.
+ /// A Brush
+ public static PatternBrush Vertical(Color foreColor)
+ => new PatternBrush(Brushes.Vertical(foreColor, Color.Transparent));
+
+ ///
+ /// Create as brush that will paint a Vertical Hatch Pattern with
+ /// in the specified foreground and background colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Vertical(Color foreColor, Color backColor)
+ => new PatternBrush(Brushes.Vertical(foreColor, backColor));
+
+ ///
+ /// Create as brush that will paint a Forward Diagonal Hatch Pattern with
+ /// in the specified foreground color and a transparent background
+ ///
+ /// Color of the foreground.
+ /// A Brush
+ public static PatternBrush ForwardDiagonal(Color foreColor)
+ => new PatternBrush(Brushes.ForwardDiagonal(foreColor, Color.Transparent));
+
+ ///
+ /// Create as brush that will paint a Forward Diagonal Hatch Pattern with
+ /// in the specified foreground and background colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush ForwardDiagonal(Color foreColor, Color backColor)
+ => new PatternBrush(Brushes.ForwardDiagonal(foreColor, backColor));
+
+ ///
+ /// Create as brush that will paint a Backward Diagonal Hatch Pattern with
+ /// in the specified foreground color and a transparent background
+ ///
+ /// Color of the foreground.
+ /// A Brush
+ public static PatternBrush BackwardDiagonal(Color foreColor)
+ => new PatternBrush(Brushes.BackwardDiagonal(foreColor, Color.Transparent));
+
+ ///
+ /// Create as brush that will paint a Backward Diagonal Hatch Pattern with
+ /// in the specified foreground and background colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush BackwardDiagonal(Color foreColor, Color backColor)
+ => new PatternBrush(Brushes.BackwardDiagonal(foreColor, backColor));
+ }
+
+ ///
+ /// A collection of methods for creating brushes.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// A Brush
+ public partial class Brushes
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ // note 2d arrays when configured using initalizer look inverted
+ // ---> Y axis
+ // ^
+ // | X - axis
+ // |
+ private static readonly bool[,] Percent10Pattern = new bool[,]
+ {
+ { true, false, false, false },
+ { false, false, false, false },
+ { false, false, true, false },
+ { false, false, false, false }
+ };
+
+ private static readonly bool[,] Percent20Pattern = new bool[,]
+ {
+ { true, false, true, false },
+ { false, false, false, false },
+ { false, true, false, true },
+ { false, false, false, false }
+ };
+
+ private static readonly bool[,] HorizontalPattern = new bool[,]
+ {
+ { false, true, false, false },
+ { false, true, false, false },
+ { false, true, false, false },
+ { false, true, false, false }
+ };
+
+ private static readonly bool[,] MinPattern = new bool[,]
+ {
+ { false, false, false, true },
+ { false, false, false, true },
+ { false, false, false, true },
+ { false, false, false, true }
+ };
+
+ private static readonly bool[,] VerticalPattern = new bool[,]
+ {
+ { false, false, false, false },
+ { true, true, true, true },
+ { false, false, false, false },
+ { false, false, false, false }
+ };
+
+ private static readonly bool[,] ForwardDiagonalPattern = new bool[,]
+ {
+ { true, false, false, false },
+ { false, true, false, false },
+ { false, false, true, false },
+ { false, false, false, true }
+ };
+
+ private static readonly bool[,] BackwardDiagonalPattern = new bool[,]
+ {
+ { false, false, false, true },
+ { false, false, true, false },
+ { false, true, false, false },
+ { true, false, false, false }
+ };
+
+ ///
+ /// Create as brush that will paint a solid color
+ ///
+ /// The color.
+ /// A Brush
+ public static SolidBrush Solid(TColor color)
+ => new SolidBrush(color);
+
+ ///
+ /// Create as brush that will paint a Percent10 Hatch Pattern within the specified colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Percent10(TColor foreColor, TColor backColor)
+ => new PatternBrush(foreColor, backColor, Percent10Pattern);
+
+ ///
+ /// Create as brush that will paint a Percent20 Hatch Pattern within the specified colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Percent20(TColor foreColor, TColor backColor)
+ => new PatternBrush(foreColor, backColor, Percent20Pattern);
+
+ ///
+ /// Create as brush that will paint a Horizontal Hatch Pattern within the specified colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Horizontal(TColor foreColor, TColor backColor)
+ => new PatternBrush(foreColor, backColor, HorizontalPattern);
+
+ ///
+ /// Create as brush that will paint a Min Hatch Pattern within the specified colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Min(TColor foreColor, TColor backColor)
+ => new PatternBrush(foreColor, backColor, MinPattern);
+
+ ///
+ /// Create as brush that will paint a Vertical Hatch Pattern within the specified colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush Vertical(TColor foreColor, TColor backColor)
+ => new PatternBrush(foreColor, backColor, VerticalPattern);
+
+ ///
+ /// Create as brush that will paint a Forward Diagonal Hatch Pattern within the specified colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush ForwardDiagonal(TColor foreColor, TColor backColor)
+ => new PatternBrush(foreColor, backColor, ForwardDiagonalPattern);
+
+ ///
+ /// Create as brush that will paint a Backward Diagonal Hatch Pattern within the specified colors
+ ///
+ /// Color of the foreground.
+ /// Color of the background.
+ /// A Brush
+ public static PatternBrush BackwardDiagonal(TColor foreColor, TColor backColor)
+ => new PatternBrush(foreColor, backColor, BackwardDiagonalPattern);
+ }
+}
diff --git a/src/ImageSharp/Drawing/Brushes/IBrush.cs b/src/ImageSharp/Drawing/Brushes/IBrush.cs
new file mode 100644
index 0000000000..fc48bb2f1d
--- /dev/null
+++ b/src/ImageSharp/Drawing/Brushes/IBrush.cs
@@ -0,0 +1,35 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing
+{
+ using System;
+ using Processors;
+
+ ///
+ /// Brush represents a logical configuration of a brush whcih can be used to source pixel colors
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ ///
+ /// A brush is a simple class that will return an that will perform the
+ /// logic for converting a pixel location to a .
+ ///
+ public interface IBrush
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ ///
+ /// Creates the applicator for this brush.
+ ///
+ /// The region the brush will be applied to.
+ /// The brush applicator for this brush
+ ///
+ /// The when being applied to things like shapes would usually be the
+ /// bounding box of the shape not necessarily the bounds of the whole image
+ ///
+ IBrushApplicator CreateApplicator(RectangleF region);
+ }
+}
diff --git a/src/ImageSharp/Drawing/Brushes/PatternBrush.cs b/src/ImageSharp/Drawing/Brushes/PatternBrush.cs
new file mode 100644
index 0000000000..535dd2eb16
--- /dev/null
+++ b/src/ImageSharp/Drawing/Brushes/PatternBrush.cs
@@ -0,0 +1,146 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Brushes
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Numerics;
+ using System.Threading.Tasks;
+ using Processors;
+
+ ///
+ /// Provides an implementaion of a pattern brush for painting patterns.
+ ///
+ public partial class PatternBrush : PatternBrush
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Color of the fore.
+ /// Color of the back.
+ /// The pattern.
+ public PatternBrush(Color foreColor, Color backColor, bool[,] pattern)
+ : base(foreColor, backColor, pattern)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The brush.
+ internal PatternBrush(PatternBrush brush)
+ : base(brush)
+ {
+ }
+ }
+
+ ///
+ /// Provides an implementaion of a pattern brush for painting patterns.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ public partial class PatternBrush : IBrush
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ private readonly TColor foreColor;
+ private readonly TColor backColor;
+ private readonly bool[,] pattern;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Color of the fore.
+ /// Color of the back.
+ /// The pattern.
+ public PatternBrush(TColor foreColor, TColor backColor, bool[,] pattern)
+ {
+ this.foreColor = foreColor;
+ this.backColor = backColor;
+ this.pattern = pattern;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The brush.
+ internal PatternBrush(PatternBrush brush)
+ : this(brush.foreColor, brush.backColor, brush.pattern)
+ {
+ }
+
+ ///
+ /// Creates the applicator for this bursh.
+ ///
+ /// The region the brush will be applied to.
+ ///
+ /// The brush applicator for this brush
+ ///
+ ///
+ /// The when being applied to things like shapes would ussually be the
+ /// bounding box of the shape not necessarily the bounds of the whole image
+ ///
+ public IBrushApplicator CreateApplicator(RectangleF region)
+ {
+ return new PatternBrushApplicator(this.foreColor, this.backColor, this.pattern);
+ }
+
+ private class PatternBrushApplicator : IBrushApplicator
+ {
+ private readonly int xLength;
+ private readonly int yLength;
+ private readonly bool[,] pattern;
+ private readonly TColor backColor = default(TColor);
+ private readonly TColor foreColor = default(TColor);
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// Color of the fore.
+ /// Color of the back.
+ /// The pattern.
+ public PatternBrushApplicator(TColor foreColor, TColor backColor, bool[,] pattern)
+ {
+ this.foreColor = foreColor;
+ this.backColor = backColor;
+ this.pattern = pattern;
+
+ this.xLength = this.pattern.GetLength(0);
+ this.yLength = this.pattern.GetLength(1);
+ }
+
+ ///
+ /// Gets the color for a single pixel.
+ ///
+ /// The point.
+ ///
+ /// The color
+ ///
+ public TColor GetColor(Vector2 point)
+ {
+ var x = (int)point.X % this.xLength;
+ var y = (int)point.Y % this.yLength;
+
+ if (this.pattern[x, y])
+ {
+ return this.foreColor;
+ }
+ else
+ {
+ return this.backColor;
+ }
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ // noop
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Drawing/Brushes/Processors/IBrushApplicator.cs b/src/ImageSharp/Drawing/Brushes/Processors/IBrushApplicator.cs
new file mode 100644
index 0000000000..834bbde870
--- /dev/null
+++ b/src/ImageSharp/Drawing/Brushes/Processors/IBrushApplicator.cs
@@ -0,0 +1,28 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Processors
+{
+ using System;
+ using System.Numerics;
+
+ ///
+ /// primitive that converts a point in to a color for discoving the fill color based on an implmentation
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ ///
+ public interface IBrushApplicator : IDisposable // disposable will be required if/when there is an ImageBrush
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ ///
+ /// Gets the color for a single pixel.
+ ///
+ /// The point.
+ /// The color
+ TColor GetColor(Vector2 point);
+ }
+}
diff --git a/src/ImageSharp/Drawing/Brushes/SolidBrush.cs b/src/ImageSharp/Drawing/Brushes/SolidBrush.cs
new file mode 100644
index 0000000000..8e64ad6e23
--- /dev/null
+++ b/src/ImageSharp/Drawing/Brushes/SolidBrush.cs
@@ -0,0 +1,107 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Brushes
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Numerics;
+ using System.Threading.Tasks;
+ using Processors;
+
+ ///
+ /// Provides an implementaion of a solid brush for painting solid color areas.
+ ///
+ public class SolidBrush : SolidBrush
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color.
+ public SolidBrush(Color color)
+ : base(color)
+ {
+ }
+ }
+
+ ///
+ /// Provides an implementaion of a solid brush for painting solid color areas.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ public class SolidBrush : IBrush
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ private readonly TColor color;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color.
+ public SolidBrush(TColor color)
+ {
+ this.color = color;
+ }
+
+ ///
+ /// Gets the color.
+ ///
+ ///
+ /// The color.
+ ///
+ public TColor Color => this.color;
+
+ ///
+ /// Creates the applicator for this brush.
+ ///
+ /// The region the brush will be applied to.
+ ///
+ /// The brush applicator for this brush
+ ///
+ ///
+ /// The when being applied to things like shapes would ussually be the
+ /// bounding box of the shape not necessarily the bounds of the whole image
+ ///
+ public IBrushApplicator CreateApplicator(RectangleF region)
+ {
+ return new SolidBrushApplicator(this.color);
+ }
+
+ private class SolidBrushApplicator : IBrushApplicator
+ {
+ private TColor color;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color.
+ public SolidBrushApplicator(TColor color)
+ {
+ this.color = color;
+ }
+
+ ///
+ /// Gets the color for a single pixel.
+ ///
+ /// The point.
+ ///
+ /// The color
+ ///
+ public TColor GetColor(Vector2 point)
+ {
+ return this.color;
+ }
+
+ ///
+ /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
+ ///
+ public void Dispose()
+ {
+ // noop
+ }
+ }
+ }
+}
diff --git a/src/ImageSharp/Drawing/Draw.cs b/src/ImageSharp/Drawing/Draw.cs
new file mode 100644
index 0000000000..8410b60ed3
--- /dev/null
+++ b/src/ImageSharp/Drawing/Draw.cs
@@ -0,0 +1,421 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using Drawing;
+ using Drawing.Brushes;
+ using Drawing.Paths;
+ using Drawing.Pens;
+ using Drawing.Processors;
+ using Drawing.Shapes;
+ using Processors;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Draws the outline of the polygon with the provided pen.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The shape.
+ /// The Image
+ public static Image DrawPolygon(this Image source, IPen pen, IShape shape)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.Process(new DrawPathProcessor(pen, shape));
+ }
+
+ ///
+ /// Draws the outline of the polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The shape.
+ /// The Image
+ public static Image DrawPolygon(this Image source, IBrush brush, float thickness, IShape shape)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(new Pen(brush, thickness), shape);
+ }
+
+ ///
+ /// Draws the outline of the polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The shape.
+ /// The Image
+ public static Image DrawPolygon(this Image source, TColor color, float thickness, IShape shape)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(new SolidBrush(color), thickness, shape);
+ }
+
+ ///
+ /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawPolygon(this Image source, IBrush brush, float thickness, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawPolygon(this Image source, TColor color, float thickness, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(new SolidBrush(color), thickness, points);
+ }
+
+ ///
+ /// Draws the provided Points as a closed Linear Polygon with the provided Pen.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The points.
+ /// The Image
+ public static Image DrawPolygon(this Image source, IPen pen, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(pen, new Polygon(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawPolygon(this Image source, IBrush brush, float thickness, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(new Pen(brush, thickness), new Polygon(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as a closed Linear Polygon with the provided brush at the provided thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawPolygon(this Image source, TColor color, float thickness, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(new SolidBrush(color), thickness, points);
+ }
+
+ ///
+ /// Draws the provided Points as a closed Linear Polygon with the provided Pen.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The points.
+ /// The Image
+ public static Image DrawPolygon(this Image source, IPen pen, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPolygon(pen, new Polygon(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the path with the provided pen.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The path.
+ /// The Image
+ public static Image DrawPath(this Image source, IPen pen, IPath path)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.Process(new DrawPathProcessor(pen, path));
+ }
+
+ ///
+ /// Draws the path with the bursh at the privdied thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The path.
+ /// The Image
+ public static Image DrawPath(this Image source, IBrush brush, float thickness, IPath path)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(new Pen(brush, thickness), path);
+ }
+
+ ///
+ /// Draws the path with the bursh at the privdied thickness.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The path.
+ /// The Image
+ public static Image DrawPath(this Image source, TColor color, float thickness, IPath path)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(new SolidBrush(color), thickness, path);
+ }
+
+ ///
+ /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawLines(this Image source, IBrush brush, float thickness, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(new Pen(brush, thickness), new Path(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawLines(this Image source, TColor color, float thickness, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawLines(new SolidBrush(color), thickness, points);
+ }
+
+ ///
+ /// Draws the provided Points as an open Linear path with the supplied pen
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The points.
+ /// The Image
+ public static Image DrawLines(this Image source, IPen pen, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(pen, new Path(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawLines(this Image source, IBrush brush, float thickness, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(new Pen(brush, thickness), new Path(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as an open Linear path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawLines(this Image source, TColor color, float thickness, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawLines(new SolidBrush(color), thickness, points);
+ }
+
+ ///
+ /// Draws the provided Points as an open Linear path with the supplied pen
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The points.
+ /// The Image
+ public static Image DrawLines(this Image source, IPen pen, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(pen, new Path(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawBeziers(this Image source, IBrush brush, float thickness, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(new Pen(brush, thickness), new Path(new BezierLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawBeziers(this Image source, TColor color, float thickness, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawBeziers(new SolidBrush(color), thickness, points);
+ }
+
+ ///
+ /// Draws the provided Points as an open Bezier path with the supplied pen
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The points.
+ /// The Image
+ public static Image DrawBeziers(this Image source, IPen pen, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(pen, new Path(new BezierLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawBeziers(this Image source, IBrush brush, float thickness, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(new Pen(brush, thickness), new Path(new BezierLineSegment(points)));
+ }
+
+ ///
+ /// Draws the provided Points as an open Bezier path at the provided thickness with the supplied brush
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The thickness.
+ /// The points.
+ /// The Image
+ public static Image DrawBeziers(this Image source, TColor color, float thickness, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawBeziers(new SolidBrush(color), thickness, points);
+ }
+
+ ///
+ /// Draws the provided Points as an open Bezier path with the supplied pen
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The pen.
+ /// The points.
+ /// The Image
+ public static Image DrawBeziers(this Image source, IPen pen, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.DrawPath(pen, new Path(new BezierLineSegment(points)));
+ }
+ }
+}
diff --git a/src/ImageSharp/Drawing/Fill.cs b/src/ImageSharp/Drawing/Fill.cs
new file mode 100644
index 0000000000..e8fc7f2e4b
--- /dev/null
+++ b/src/ImageSharp/Drawing/Fill.cs
@@ -0,0 +1,150 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp
+{
+ using Drawing;
+ using Drawing.Brushes;
+ using Drawing.Paths;
+ using Drawing.Processors;
+ using Drawing.Shapes;
+ using Processors;
+
+ ///
+ /// Extension methods for the type.
+ ///
+ public static partial class ImageExtensions
+ {
+ ///
+ /// Flood fills the image with the specified brush.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The Image
+ public static Image Fill(this Image source, IBrush brush)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.Process(new FillProcessor(brush));
+ }
+
+ ///
+ /// Flood fills the image with the specified color.
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The Image
+ public static Image Fill(this Image source, TColor color)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.Fill(new SolidBrush(color));
+ }
+
+ ///
+ /// Flood fills the image in the shape o fhte provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The shape.
+ /// The Image
+ public static Image Fill(this Image source, IBrush brush, IShape shape)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.Process(new FillShapeProcessor(brush, shape));
+ }
+
+ ///
+ /// Flood fills the image in the shape o fhte provided polygon with the specified brush..
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The shape.
+ /// The Image
+ public static Image Fill(this Image source, TColor color, IShape shape)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ return source.Fill(new SolidBrush(color), shape);
+ }
+
+ ///
+ /// Flood fills the image in the shape of a Linear polygon described by the points
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The points.
+ /// The Image
+ public static Image FillPolygon(this Image source, IBrush brush, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ // using Polygon directly instead of LinearPolygon as its will have less indirection
+ return source.Fill(brush, new Polygon(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Flood fills the image in the shape of a Linear polygon described by the points
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The points.
+ /// The Image
+ public static Image FillPolygon(this Image source, TColor color, PointF[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ // using Polygon directly instead of LinearPolygon as its will have less indirection
+ return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Flood fills the image in the shape of a Linear polygon described by the points
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The brush.
+ /// The points.
+ /// The Image
+ public static Image FillPolygon(this Image source, IBrush brush, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ // using Polygon directly instead of LinearPolygon as its will have less indirection
+ return source.Fill(brush, new Polygon(new LinearLineSegment(points)));
+ }
+
+ ///
+ /// Flood fills the image in the shape of a Linear polygon described by the points
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ /// The source.
+ /// The color.
+ /// The points.
+ /// The Image
+ public static Image FillPolygon(this Image source, TColor color, Point[] points)
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ // using Polygon directly instead of LinearPolygon as its will have less indirection
+ return source.Fill(new SolidBrush(color), new Polygon(new LinearLineSegment(points)));
+ }
+ }
+}
diff --git a/src/ImageSharp/Drawing/Paths/BezierLineSegment.cs b/src/ImageSharp/Drawing/Paths/BezierLineSegment.cs
new file mode 100644
index 0000000000..6439b9da1e
--- /dev/null
+++ b/src/ImageSharp/Drawing/Paths/BezierLineSegment.cs
@@ -0,0 +1,128 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Paths
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Numerics;
+
+ using Brushes;
+
+ ///
+ /// Represents a line segment that conistst of control points that will be rendered as a cubic bezier curve
+ ///
+ ///
+ public class BezierLineSegment : ILineSegment
+ {
+ // code for this taken from http://devmag.org.za/2011/04/05/bzier-curves-a-tutorial/
+ private const int SegmentsPerCurve = 50;
+
+ private List linePoints;
+
+ private int curveCount; // how many bezier curves in this path?
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ public BezierLineSegment(IEnumerable points)
+ : this(points?.Select(x => x.ToVector2()).ToArray())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ public BezierLineSegment(IEnumerable points)
+ : this(points?.Select(x => x.ToVector2()).ToArray())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ public BezierLineSegment(params PointF[] points)
+ : this(points?.Select(x => x.ToVector2()).ToArray())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ internal BezierLineSegment(Vector2[] points)
+ {
+ Guard.NotNull(points, nameof(points));
+ Guard.MustBeGreaterThanOrEqualTo(points.Length, 4, nameof(points));
+
+ this.curveCount = (points.Length - 1) / 3;
+ this.linePoints = this.GetDrawingPoints(points);
+ }
+
+ ///
+ /// Returns the current a simple linear path.
+ ///
+ ///
+ /// Returns the current as simple linear path.
+ ///
+ public IEnumerable AsSimpleLinearPath()
+ {
+ return this.linePoints;
+ }
+
+ private List GetDrawingPoints(Vector2[] controlPoints)
+ {
+ // TODO we need to calculate an optimal SegmentsPerCurve value
+ // depending on the calcualted length of this curve
+ var maxPoints = (int)Math.Ceiling(SegmentsPerCurve * (float)this.curveCount);
+
+ List drawingPoints = new List(maxPoints); // set a default size to be efficient?
+
+ var targetPoint = controlPoints.Length - 3;
+ for (int i = 0; i < targetPoint; i += 3)
+ {
+ Vector2 p0 = controlPoints[i];
+ Vector2 p1 = controlPoints[i + 1];
+ Vector2 p2 = controlPoints[i + 2];
+ Vector2 p3 = controlPoints[i + 3];
+
+ // only do this for the first end point. When i != 0, this coincides with the end point of the previous segment,
+ if (i == 0)
+ {
+ drawingPoints.Add(this.CalculateBezierPoint(0, p0, p1, p2, p3));
+ }
+
+ for (int j = 1; j <= SegmentsPerCurve; j++)
+ {
+ float t = j / (float)SegmentsPerCurve;
+ drawingPoints.Add(this.CalculateBezierPoint(t, p0, p1, p2, p3));
+ }
+ }
+
+ return drawingPoints;
+ }
+
+ private Vector2 CalculateBezierPoint(float t, Vector2 p0, Vector2 p1, Vector2 p2, Vector2 p3)
+ {
+ float u = 1 - t;
+ float tt = t * t;
+ float uu = u * u;
+ float uuu = uu * u;
+ float ttt = tt * t;
+
+ Vector2 p = uuu * p0; // first term
+
+ p += 3 * uu * t * p1; // second term
+ p += 3 * u * tt * p2; // third term
+ p += ttt * p3; // fourth term
+
+ return p;
+ }
+ }
+}
diff --git a/src/ImageSharp/Drawing/Paths/ILineSegment.cs b/src/ImageSharp/Drawing/Paths/ILineSegment.cs
new file mode 100644
index 0000000000..db348fc1a4
--- /dev/null
+++ b/src/ImageSharp/Drawing/Paths/ILineSegment.cs
@@ -0,0 +1,25 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Paths
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// Represents a simple path segment
+ ///
+ public interface ILineSegment
+ {
+ ///
+ /// Converts the into a simple linear path..
+ ///
+ /// Returns the current as simple linear path.
+ IEnumerable AsSimpleLinearPath();
+ }
+}
diff --git a/src/ImageSharp/Drawing/Paths/IPath.cs b/src/ImageSharp/Drawing/Paths/IPath.cs
new file mode 100644
index 0000000000..3eaeb5c200
--- /dev/null
+++ b/src/ImageSharp/Drawing/Paths/IPath.cs
@@ -0,0 +1,51 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Paths
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// Represents a logic path that can be drawn
+ ///
+ public interface IPath : ILineSegment
+ {
+ ///
+ /// Gets the bounds enclosing the path
+ ///
+ ///
+ /// The bounds.
+ ///
+ RectangleF Bounds { get; }
+
+ ///
+ /// Gets a value indicating whether this instance is closed.
+ ///
+ ///
+ /// true if this instance is closed; otherwise, false.
+ ///
+ bool IsClosed { get; }
+
+ ///
+ /// Gets the length of the path
+ ///
+ ///
+ /// The length.
+ ///
+ float Length { get; }
+
+ ///
+ /// Calcualtes the distance along and away from the path for a specified point.
+ ///
+ /// The x.
+ /// The y.
+ /// Returns details about the point and its distance away from the path.
+ PointInfo Distance(int x, int y);
+ }
+}
diff --git a/src/ImageSharp/Drawing/Paths/InternalPath.cs b/src/ImageSharp/Drawing/Paths/InternalPath.cs
new file mode 100644
index 0000000000..079ebdcf42
--- /dev/null
+++ b/src/ImageSharp/Drawing/Paths/InternalPath.cs
@@ -0,0 +1,279 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Paths
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Linq;
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// Internal logic for interigating linear paths.
+ ///
+ internal class InternalPath
+ {
+ private readonly Vector2[] points;
+ private readonly bool closedPath;
+ private readonly Lazy totalDistance;
+
+ private float[] constant;
+ private float[] multiple;
+ private float[] distance;
+ private object locker = new object();
+ private bool calculated = false;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The segments.
+ /// if set to true [is closed path].
+ internal InternalPath(IEnumerable segments, bool isClosedPath)
+ {
+ Guard.NotNull(segments, nameof(segments));
+
+ this.points = this.Simplify(segments);
+ this.closedPath = isClosedPath;
+
+ var minX = this.points.Min(x => x.X);
+ var maxX = this.points.Max(x => x.X);
+ var minY = this.points.Min(x => x.Y);
+ var maxY = this.points.Max(x => x.Y);
+
+ this.Bounds = new RectangleF(minX, minY, maxX - minX, maxY - minY);
+ this.totalDistance = new Lazy(this.CalculateLength);
+ }
+
+ ///
+ /// Gets the bounds.
+ ///
+ ///
+ /// The bounds.
+ ///
+ public RectangleF Bounds
+ {
+ get;
+ }
+
+ ///
+ /// Gets the length.
+ ///
+ ///
+ /// The length.
+ ///
+ public float Length => this.totalDistance.Value;
+
+ ///
+ /// Gets the points.
+ ///
+ ///
+ /// The points.
+ ///
+ internal Vector2[] Points => this.points;
+
+ ///
+ /// Calculates the distance from the path.
+ ///
+ /// The point.
+ /// Returns the distance from the path
+ public PointInfo DistanceFromPath(Vector2 point)
+ {
+ this.CalculateConstants();
+
+ var internalInfo = default(PointInfoInternal);
+ internalInfo.DistanceSquared = float.MaxValue; // set it to max so that CalculateShorterDistance can reduce it back down
+
+ var polyCorners = this.points.Length;
+
+ if (!this.closedPath)
+ {
+ polyCorners -= 1;
+ }
+
+ int closestPoint = 0;
+ for (var i = 0; i < polyCorners; i++)
+ {
+ var next = i + 1;
+ if (this.closedPath && next == polyCorners)
+ {
+ next = 0;
+ }
+
+ if (this.CalculateShorterDistance(this.points[i], this.points[next], point, ref internalInfo))
+ {
+ closestPoint = i;
+ }
+ }
+
+ return new PointInfo
+ {
+ DistanceAlongPath = this.distance[closestPoint] + Vector2.Distance(this.points[closestPoint], point),
+ DistanceFromPath = (float)Math.Sqrt(internalInfo.DistanceSquared),
+ SearchPoint = point,
+ ClosestPointOnPath = internalInfo.PointOnLine
+ };
+ }
+
+ ///
+ /// Points the in polygon.
+ ///
+ /// The point.
+ /// Returns true if the point is inside the closed path.
+ public bool PointInPolygon(Vector2 point)
+ {
+ // you can only be inside a path if its "closed"
+ if (!this.closedPath)
+ {
+ return false;
+ }
+
+ if (!this.Bounds.Contains(point.X, point.Y))
+ {
+ return false;
+ }
+
+ this.CalculateConstants();
+
+ var poly = this.points;
+ var polyCorners = poly.Length;
+
+ var j = polyCorners - 1;
+ bool oddNodes = false;
+
+ for (var i = 0; i < polyCorners; i++)
+ {
+ if ((poly[i].Y < point.Y && poly[j].Y >= point.Y)
+ || (poly[j].Y < point.Y && poly[i].Y >= point.Y))
+ {
+ oddNodes ^= (point.Y * this.multiple[i]) + this.constant[i] < point.X;
+ }
+
+ j = i;
+ }
+
+ return oddNodes;
+ }
+
+ private Vector2[] Simplify(IEnumerable segments)
+ {
+ return segments.SelectMany(x => x.AsSimpleLinearPath()).ToArray();
+ }
+
+ private float CalculateLength()
+ {
+ float length = 0;
+ var polyCorners = this.points.Length;
+
+ if (!this.closedPath)
+ {
+ polyCorners -= 1;
+ }
+
+ for (var i = 0; i < polyCorners; i++)
+ {
+ var next = i + 1;
+ if (this.closedPath && next == polyCorners)
+ {
+ next = 0;
+ }
+
+ length += Vector2.Distance(this.points[i], this.points[next]);
+ }
+
+ return length;
+ }
+
+ private void CalculateConstants()
+ {
+ // http://alienryderflex.com/polygon/ source for point in polygon logic
+ if (this.calculated)
+ {
+ return;
+ }
+
+ lock (this.locker)
+ {
+ if (this.calculated)
+ {
+ return;
+ }
+
+ var poly = this.points;
+ var polyCorners = poly.Length;
+ this.constant = new float[polyCorners];
+ this.multiple = new float[polyCorners];
+ this.distance = new float[polyCorners];
+ int i, j = polyCorners - 1;
+
+ this.distance[0] = 0;
+
+ for (i = 0; i < polyCorners; i++)
+ {
+ this.distance[j] = this.distance[i] + Vector2.Distance(poly[i], poly[j]);
+ if (poly[j].Y == poly[i].Y)
+ {
+ this.constant[i] = poly[i].X;
+ this.multiple[i] = 0;
+ }
+ else
+ {
+ var subtracted = poly[j] - poly[i];
+ this.constant[i] = (poly[i].X - ((poly[i].Y * poly[j].X) / subtracted.Y)) + ((poly[i].Y * poly[i].X) / subtracted.Y);
+ this.multiple[i] = subtracted.X / subtracted.Y;
+ }
+
+ j = i;
+ }
+
+ this.calculated = true;
+ }
+ }
+
+ private bool CalculateShorterDistance(Vector2 start, Vector2 end, Vector2 point, ref PointInfoInternal info)
+ {
+ var diffEnds = end - start;
+
+ float lengthSquared = diffEnds.LengthSquared();
+ var diff = point - start;
+
+ var multiplied = diff * diffEnds;
+ var u = (multiplied.X + multiplied.Y) / lengthSquared;
+
+ if (u > 1)
+ {
+ u = 1;
+ }
+ else if (u < 0)
+ {
+ u = 0;
+ }
+
+ var multipliedByU = diffEnds * u;
+
+ var pointOnLine = start + multipliedByU;
+
+ var d = pointOnLine - point;
+
+ var dist = d.LengthSquared();
+
+ if (info.DistanceSquared > dist)
+ {
+ info.DistanceSquared = dist;
+ info.PointOnLine = pointOnLine;
+ return true;
+ }
+
+ return false;
+ }
+
+ private struct PointInfoInternal
+ {
+ public float DistanceSquared;
+ public Vector2 PointOnLine;
+ }
+ }
+}
diff --git a/src/ImageSharp/Drawing/Paths/LinearLineSegment.cs b/src/ImageSharp/Drawing/Paths/LinearLineSegment.cs
new file mode 100644
index 0000000000..6813098251
--- /dev/null
+++ b/src/ImageSharp/Drawing/Paths/LinearLineSegment.cs
@@ -0,0 +1,83 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Paths
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Linq;
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// Represents a seriese of control points that will be joined by staight lines
+ ///
+ ///
+ public class LinearLineSegment : ILineSegment
+ {
+ private Vector2[] points;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ public LinearLineSegment(IEnumerable points)
+ : this(points?.Select(x => x.ToVector2()).ToArray())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ public LinearLineSegment(IEnumerable points)
+ : this(points?.Select(x => x.ToVector2()).ToArray())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ public LinearLineSegment(params PointF[] points)
+ : this(points?.Select(x => x.ToVector2()).ToArray())
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The start.
+ /// The end.
+ internal LinearLineSegment(Vector2 start, Vector2 end)
+ : this(new[] { start, end })
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The points.
+ internal LinearLineSegment(Vector2[] points)
+ {
+ Guard.NotNull(points, nameof(points));
+ Guard.MustBeGreaterThanOrEqualTo(points.Count(), 2, nameof(points));
+
+ this.points = points;
+ }
+
+ ///
+ /// Converts the into a simple linear path..
+ ///
+ ///
+ /// Returns the current as simple linear path.
+ ///
+ public IEnumerable AsSimpleLinearPath()
+ {
+ return this.points;
+ }
+ }
+}
diff --git a/src/ImageSharp/Drawing/Paths/Path.cs b/src/ImageSharp/Drawing/Paths/Path.cs
new file mode 100644
index 0000000000..90ecf5846e
--- /dev/null
+++ b/src/ImageSharp/Drawing/Paths/Path.cs
@@ -0,0 +1,81 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Paths
+{
+ using System;
+ using System.Collections;
+ using System.Collections.Generic;
+ using System.Collections.ObjectModel;
+ using System.Linq;
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// A aggragate of s making a single logical path
+ ///
+ ///
+ public class Path : IPath
+ {
+ private readonly InternalPath innerPath;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The segment.
+ internal Path(params ILineSegment[] segment)
+ {
+ this.innerPath = new InternalPath(segment, false);
+ }
+
+ ///
+ /// Gets the bounds enclosing the path
+ ///
+ ///
+ /// The bounds.
+ ///
+ public RectangleF Bounds => this.innerPath.Bounds;
+
+ ///
+ /// Gets a value indicating whether this instance is closed.
+ ///
+ ///
+ /// true if this instance is closed; otherwise, false.
+ ///
+ public bool IsClosed => false;
+
+ ///
+ /// Gets the length of the path
+ ///
+ ///
+ /// The length.
+ ///
+ public float Length => this.innerPath.Length;
+
+ ///
+ /// Returns the current a simple linear path.
+ ///
+ ///
+ /// Returns the current as simple linear path.
+ ///
+ public IEnumerable AsSimpleLinearPath()
+ {
+ return this.innerPath.Points;
+ }
+
+ ///
+ /// Calcualtes the distance along and away from the path for a specified point.
+ ///
+ /// The x.
+ /// The y.
+ ///
+ /// Returns details about the point and its distance away from the path.
+ ///
+ public PointInfo Distance(int x, int y)
+ {
+ return this.innerPath.DistanceFromPath(new Vector2(x, y));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Drawing/Paths/PointInfo.cs b/src/ImageSharp/Drawing/Paths/PointInfo.cs
new file mode 100644
index 0000000000..3bae73e22f
--- /dev/null
+++ b/src/ImageSharp/Drawing/Paths/PointInfo.cs
@@ -0,0 +1,39 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Paths
+{
+ using System;
+ using System.Collections.Generic;
+ using System.Linq;
+ using System.Numerics;
+ using System.Threading.Tasks;
+
+ ///
+ /// Returns some meta data about the nearest point on a path from a vector
+ ///
+ public struct PointInfo
+ {
+ ///
+ /// The search point
+ ///
+ public Vector2 SearchPoint;
+
+ ///
+ /// The distance along path is away from the start of the path
+ ///
+ public float DistanceAlongPath;
+
+ ///
+ /// The distance is away from .
+ ///
+ public float DistanceFromPath;
+
+ ///
+ /// The closest point to that lies on the path.
+ ///
+ public Vector2 ClosestPointOnPath;
+ }
+}
diff --git a/src/ImageSharp/Drawing/Pens/IPen.cs b/src/ImageSharp/Drawing/Pens/IPen.cs
new file mode 100644
index 0000000000..38b9056aac
--- /dev/null
+++ b/src/ImageSharp/Drawing/Pens/IPen.cs
@@ -0,0 +1,31 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Pens
+{
+ using System;
+ using Processors;
+
+ ///
+ /// interface preresenting a Pen
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ public interface IPen
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ ///
+ /// Creates the applicator for applying this pen to an Image
+ ///
+ /// The region the pen will be applied to.
+ /// Returns a the applicator for the pen.
+ ///
+ /// The when being applied to things like shapes would ussually be the
+ /// bounding box of the shape not necorserrally the shape of the whole image
+ ///
+ IPenApplicator CreateApplicator(RectangleF region);
+ }
+}
diff --git a/src/ImageSharp/Drawing/Pens/Pen.cs b/src/ImageSharp/Drawing/Pens/Pen.cs
new file mode 100644
index 0000000000..591707efa2
--- /dev/null
+++ b/src/ImageSharp/Drawing/Pens/Pen.cs
@@ -0,0 +1,315 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Drawing.Pens
+{
+ using System;
+ using System.Numerics;
+
+ using Brushes;
+ using Drawing.Processors;
+ using Paths;
+ using Processors;
+
+ ///
+ /// Represenets a in the color space.
+ ///
+ public partial class Pen : Pen
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color.
+ /// The width.
+ public Pen(Color color, float width)
+ : base(color, width)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The brush.
+ /// The width.
+ public Pen(IBrush brush, float width)
+ : base(brush, width)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The brush.
+ /// The width.
+ /// The pattern.
+ public Pen(IBrush brush, float width, float[] pattern)
+ : base(brush, width, pattern)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The pen.
+ internal Pen(Pen pen)
+ : base(pen)
+ {
+ }
+ }
+
+ ///
+ /// Provides a pen that can apply a pattern to a line with a set brush and thickness
+ ///
+ /// The type of the color.
+ /// The type of the packed.
+ ///
+ /// The pattern will be in to the form of new float[]{ 1f, 2f, 0.5f} this will be
+ /// converted into a pattern that is 3.5 times longer that the width with 3 sections
+ /// section 1 will be width long (making a square) and will be filled by the brush
+ /// section 2 will be width * 2 long and will be empty
+ /// section 3 will be width/2 long and will be filled
+ /// the the pattern will imidiatly repeat without gap.
+ ///
+ public partial class Pen : IPen
+ where TColor : struct, IPackedPixel
+ where TPacked : struct
+ {
+ private static readonly float[] EmptyPattern = new float[0];
+ private readonly float[] pattern;
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color.
+ /// The width.
+ /// The pattern.
+ public Pen(TColor color, float width, float[] pattern)
+ : this(new SolidBrush(color), width, pattern)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The brush.
+ /// The width.
+ /// The pattern.
+ public Pen(IBrush brush, float width, float[] pattern)
+ {
+ this.Brush = brush;
+ this.Width = width;
+ this.pattern = pattern;
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The color.
+ /// The width.
+ public Pen(TColor color, float width)
+ : this(new SolidBrush(color), width)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The brush.
+ /// The width.
+ public Pen(IBrush brush, float width)
+ : this(brush, width, EmptyPattern)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the