diff --git a/src/ImageSharp.Drawing/DrawPath.cs b/src/ImageSharp.Drawing/DrawPath.cs
deleted file mode 100644
index 09d3dbb02..000000000
--- a/src/ImageSharp.Drawing/DrawPath.cs
+++ /dev/null
@@ -1,110 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp
-{
- using Drawing;
- using Drawing.Brushes;
- using Drawing.Pens;
- using Drawing.Processors;
- using ImageSharp.PixelFormats;
-
- ///
- /// Extension methods for the type.
- ///
- public static partial class ImageExtensions
- {
- ///
- /// Draws the outline of the region with the provided pen.
- ///
- /// The type of the color.
- /// The image this method extends.
- /// The pen.
- /// The path.
- /// The options.
- /// The .
- public static Image Draw(this Image source, IPen pen, Drawable path, GraphicsOptions options)
- where TPixel : struct, IPixel
- {
- return source.Apply(new DrawPathProcessor(pen, path, options));
- }
-
- ///
- /// Draws the outline of the polygon with the provided pen.
- ///
- /// The type of the color.
- /// The image this method extends.
- /// The pen.
- /// The path.
- /// The .
- public static Image Draw(this Image source, IPen pen, Drawable path)
- where TPixel : struct, IPixel
- {
- return source.Draw(pen, path, GraphicsOptions.Default);
- }
-
- ///
- /// Draws the outline of the polygon with the provided brush at the provided thickness.
- ///
- /// The type of the color.
- /// The image this method extends.
- /// The brush.
- /// The thickness.
- /// The path.
- /// The options.
- /// The .
- public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path, GraphicsOptions options)
- where TPixel : struct, IPixel
- {
- return source.Draw(new Pen(brush, thickness), path, options);
- }
-
- ///
- /// Draws the outline of the polygon with the provided brush at the provided thickness.
- ///
- /// The type of the color.
- /// The image this method extends.
- /// The brush.
- /// The thickness.
- /// The path.
- /// The .
- public static Image Draw(this Image source, IBrush brush, float thickness, Drawable path)
- where TPixel : struct, IPixel
- {
- return source.Draw(new Pen(brush, thickness), path);
- }
-
- ///
- /// Draws the outline of the polygon with the provided brush at the provided thickness.
- ///
- /// The type of the color.
- /// The image this method extends.
- /// The color.
- /// The thickness.
- /// The path.
- /// The options.
- /// The .
- public static Image Draw(this Image source, TPixel color, float thickness, Drawable path, GraphicsOptions options)
- where TPixel : struct, IPixel
- {
- return source.Draw(new SolidBrush(color), thickness, path, options);
- }
-
- ///
- /// Draws the outline of the polygon with the provided brush at the provided thickness.
- ///
- /// The type of the color.
- /// The image this method extends.
- /// The color.
- /// The thickness.
- /// The path.
- /// The .
- public static Image Draw(this Image source, TPixel color, float thickness, Drawable path)
- where TPixel : struct, IPixel
- {
- return source.Draw(new SolidBrush(color), thickness, path);
- }
- }
-}
diff --git a/src/ImageSharp.Drawing/Drawable.cs b/src/ImageSharp.Drawing/Drawable.cs
deleted file mode 100644
index 62f5e62c1..000000000
--- a/src/ImageSharp.Drawing/Drawable.cs
+++ /dev/null
@@ -1,51 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing
-{
- ///
- /// Represents a path or set of paths that can be drawn as an outline.
- ///
- public abstract class Drawable
- {
- ///
- /// Gets the maximum number of intersections to could be returned.
- ///
- public abstract int MaxIntersections { get; }
-
- ///
- /// Gets the bounds.
- ///
- public abstract Rectangle Bounds { get; }
-
- ///
- /// Gets the point information for the specified x and y location.
- ///
- /// The x.
- /// The y.
- /// Information about the point in relation to a drawable edge
- public abstract PointInfo GetPointInfo(int x, int y);
-
- ///
- /// Scans the X axis for intersections.
- ///
- /// The x.
- /// The buffer.
- /// The length.
- /// The offset.
- /// The number of intersections found.
- public abstract int ScanX(int x, float[] buffer, int length, int offset);
-
- ///
- /// Scans the Y axis for intersections.
- ///
- /// The position along the y axis to find intersections.
- /// The buffer.
- /// The length.
- /// The offset.
- /// The number of intersections found.
- public abstract int ScanY(int y, float[] buffer, int length, int offset);
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Paths/DrawPath.cs b/src/ImageSharp.Drawing/Paths/DrawPath.cs
index 176539663..eb12a2606 100644
--- a/src/ImageSharp.Drawing/Paths/DrawPath.cs
+++ b/src/ImageSharp.Drawing/Paths/DrawPath.cs
@@ -28,7 +28,7 @@ namespace ImageSharp
public static Image Draw(this Image source, IPen pen, IPath path, GraphicsOptions options)
where TPixel : struct, IPixel
{
- return source.Draw(pen, new ShapePath(path), options);
+ return source.Fill(pen.StokeFill, new ShapePath(path, pen), options);
}
///
diff --git a/src/ImageSharp.Drawing/Paths/ShapePath.cs b/src/ImageSharp.Drawing/Paths/ShapePath.cs
index d0376ccc1..63c814f2d 100644
--- a/src/ImageSharp.Drawing/Paths/ShapePath.cs
+++ b/src/ImageSharp.Drawing/Paths/ShapePath.cs
@@ -1,12 +1,12 @@
-//
+//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
namespace ImageSharp.Drawing
{
+ using System;
using System.Buffers;
- using System.Collections.Immutable;
using System.Numerics;
using SixLabors.Shapes;
@@ -14,91 +14,19 @@ namespace ImageSharp.Drawing
using Rectangle = ImageSharp.Rectangle;
///
- /// A drawable mapping between a and a drawable region.
+ /// A mapping between a and a region.
///
- internal class ShapePath : Drawable
+ internal class ShapePath : ShapeRegion
{
///
/// Initializes a new instance of the class.
///
- /// The path.
- public ShapePath(IPath path)
+ /// The shape.
+ /// The pen to apply to the shape.
+ // SixLabors.shape willbe moving to a Span/ReadOnlySpan based API shortly use ToArray for now.
+ public ShapePath(IPath shape, Pens.IPen pen)
+ : base(shape.GenerateOutline(pen.StrokeWidth, pen.StrokePattern.ToArray()))
{
- this.Path = path;
- this.Bounds = path.Bounds.Convert();
- }
-
- ///
- /// Gets the fillable shape
- ///
- public IPath Path { get; }
-
- ///
- public override int MaxIntersections => this.Path.MaxIntersections;
-
- ///
- public override Rectangle Bounds { get; }
-
- ///
- public override int ScanX(int x, float[] buffer, int length, int offset)
- {
- Vector2 start = new Vector2(x, this.Bounds.Top - 1);
- Vector2 end = new Vector2(x, this.Bounds.Bottom + 1);
- Vector2[] innerbuffer = ArrayPool.Shared.Rent(length);
- try
- {
- int count = this.Path.FindIntersections(start, end, innerbuffer, length, 0);
-
- for (int i = 0; i < count; i++)
- {
- buffer[i + offset] = innerbuffer[i].Y;
- }
-
- return count;
- }
- finally
- {
- ArrayPool.Shared.Return(innerbuffer);
- }
- }
-
- ///
- public override int ScanY(int y, float[] buffer, int length, int offset)
- {
- Vector2 start = new Vector2(this.Bounds.Left - 1, y);
- Vector2 end = new Vector2(this.Bounds.Right + 1, y);
- Vector2[] innerbuffer = ArrayPool.Shared.Rent(length);
- try
- {
- int count = this.Path.FindIntersections(start, end, innerbuffer, length, 0);
-
- for (int i = 0; i < count; i++)
- {
- buffer[i + offset] = innerbuffer[i].X;
- }
-
- return count;
- }
- finally
- {
- ArrayPool.Shared.Return(innerbuffer);
- }
- }
-
- ///
- public override PointInfo GetPointInfo(int x, int y)
- {
- Vector2 point = new Vector2(x, y);
- SixLabors.Shapes.PointInfo dist = this.Path.Distance(point);
-
- return new PointInfo
- {
- DistanceAlongPath = dist.DistanceAlongPath,
- DistanceFromPath =
- dist.DistanceFromPath < 0
- ? -dist.DistanceFromPath
- : dist.DistanceFromPath
- };
}
}
}
diff --git a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
index 086894531..9dbf52285 100644
--- a/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
+++ b/src/ImageSharp.Drawing/Paths/ShapeRegion.cs
@@ -40,18 +40,18 @@ namespace ImageSharp.Drawing
public override Rectangle Bounds { get; }
///
- public override int Scan(float y, float[] buffer, int length, int offset)
+ public override int Scan(float y, Span buffer)
{
Vector2 start = new Vector2(this.Bounds.Left - 1, y);
Vector2 end = new Vector2(this.Bounds.Right + 1, y);
- Vector2[] innerbuffer = ArrayPool.Shared.Rent(length);
+ Vector2[] innerbuffer = ArrayPool.Shared.Rent(buffer.Length);
try
{
- int count = this.Shape.FindIntersections(start, end, innerbuffer, length, 0);
+ int count = this.Shape.FindIntersections(start, end, innerbuffer, buffer.Length, 0);
for (int i = 0; i < count; i++)
{
- buffer[i + offset] = innerbuffer[i].X;
+ buffer[i] = innerbuffer[i].X;
}
return count;
diff --git a/src/ImageSharp.Drawing/Pens/IPen.cs b/src/ImageSharp.Drawing/Pens/IPen.cs
index 81d273091..affcb9d1f 100644
--- a/src/ImageSharp.Drawing/Pens/IPen.cs
+++ b/src/ImageSharp.Drawing/Pens/IPen.cs
@@ -12,21 +12,28 @@ namespace ImageSharp.Drawing.Pens
/// Interface representing a Pen
///
/// The type of the color.
- public interface IPen
+ public interface IPen : IPen
where TPixel : struct, IPixel
{
///
- /// Creates the applicator for applying this pen to an Image
+ /// Gets the stoke fill.
///
- /// The source image.
- /// The region the pen will be applied to.
- /// The currently active graphic options.
- ///
- /// Returns a the applicator for the pen.
- ///
- ///
- /// The when being applied to things like shapes would usually be the bounding box of the shape not necessarily the shape of the whole image.
- ///
- PenApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options);
+ IBrush StokeFill { get; }
+ }
+
+ ///
+ /// Iterface represting the pattern and size of the stroke to apply with a Pen.
+ ///
+ public interface IPen
+ {
+ ///
+ /// Gets the width to apply to the stroke
+ ///
+ float StrokeWidth { get; }
+
+ ///
+ /// Gets the stoke pattern.
+ ///
+ System.ReadOnlySpan StrokePattern { get; }
}
}
diff --git a/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs b/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs
index a5639e49a..0a0c81f9c 100644
--- a/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs
+++ b/src/ImageSharp.Drawing/Pens/Pen{TPixel}.cs
@@ -5,6 +5,7 @@
namespace ImageSharp.Drawing.Pens
{
+ using System;
using System.Numerics;
using ImageSharp.Drawing.Brushes;
@@ -48,8 +49,8 @@ namespace ImageSharp.Drawing.Pens
/// The pattern.
public Pen(IBrush brush, float width, float[] pattern)
{
- this.Brush = brush;
- this.Width = width;
+ this.StokeFill = brush;
+ this.StrokeWidth = width;
this.pattern = pattern;
}
@@ -78,190 +79,17 @@ namespace ImageSharp.Drawing.Pens
///
/// The pen.
internal Pen(Pen pen)
- : this(pen.Brush, pen.Width, pen.pattern)
+ : this(pen.StokeFill, pen.StrokeWidth, pen.pattern)
{
}
- ///
- /// Gets the brush.
- ///
- ///
- /// The brush.
- ///
- public IBrush Brush { get; }
-
- ///
- /// Gets the width.
- ///
- ///
- /// The width.
- ///
- public float Width { get; }
-
- ///
- /// Creates the applicator for applying this pen to an Image
- ///
- /// The source image.
- /// The region the pen will be applied to.
- /// The Graphics options
- ///
- /// 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
- ///
- public PenApplicator CreateApplicator(ImageBase source, RectangleF region, GraphicsOptions options)
- {
- if (this.pattern == null || this.pattern.Length < 2)
- {
- // if there is only one item in the pattern then 100% of it will
- // be solid so use the quicker applicator
- return new SolidPenApplicator(source, this.Brush, region, this.Width, options);
- }
-
- return new PatternPenApplicator(source, this.Brush, region, this.Width, this.pattern, options);
- }
-
- private class SolidPenApplicator : PenApplicator
- {
- private readonly BrushApplicator brush;
- private readonly float halfWidth;
-
- public SolidPenApplicator(ImageBase sourcePixels, IBrush brush, RectangleF region, float width, GraphicsOptions options)
- {
- this.brush = brush.CreateApplicator(sourcePixels, region, options);
- this.halfWidth = width / 2;
- this.RequiredRegion = RectangleF.Inflate(region, width, width);
- }
-
- public override RectangleF RequiredRegion
- {
- get;
- }
-
- public override void Dispose()
- {
- this.brush.Dispose();
- }
-
- public override ColoredPointInfo GetColor(int x, int y, PointInfo info)
- {
- var result = default(ColoredPointInfo);
- result.Color = this.brush[x, y];
-
- if (info.DistanceFromPath < this.halfWidth)
- {
- // inside strip
- result.DistanceFromElement = 0;
- }
- else
- {
- result.DistanceFromElement = info.DistanceFromPath - this.halfWidth;
- }
-
- return result;
- }
- }
-
- private class PatternPenApplicator : PenApplicator
- {
- private readonly BrushApplicator brush;
- private readonly float halfWidth;
- private readonly float[] pattern;
- private readonly float totalLength;
-
- public PatternPenApplicator(ImageBase source, IBrush brush, RectangleF region, float width, float[] pattern, GraphicsOptions options)
- {
- this.brush = brush.CreateApplicator(source, region, options);
- this.halfWidth = width / 2;
- this.totalLength = 0;
-
- this.pattern = new float[pattern.Length + 1];
- this.pattern[0] = 0;
- for (int i = 0; i < pattern.Length; i++)
- {
- this.totalLength += pattern[i] * width;
- this.pattern[i + 1] = this.totalLength;
- }
-
- this.RequiredRegion = RectangleF.Inflate(region, width, width);
- }
-
- public override RectangleF RequiredRegion
- {
- get;
- }
-
- public override void Dispose()
- {
- this.brush.Dispose();
- }
-
- public override ColoredPointInfo GetColor(int x, int y, PointInfo info)
- {
- var infoResult = default(ColoredPointInfo);
- infoResult.DistanceFromElement = float.MaxValue; // is really outside the element
-
- float length = info.DistanceAlongPath % this.totalLength;
+ ///
+ public IBrush StokeFill { get; }
- // we can treat the DistanceAlongPath and DistanceFromPath as x,y coords for the pattern
- // we need to calcualte the distance from the outside edge of the pattern
- // and set them on the ColoredPointInfo along with the color.
- infoResult.Color = this.brush[x, y];
+ ///
+ public float StrokeWidth { get; }
- float distanceWAway = 0;
-
- if (info.DistanceFromPath < this.halfWidth)
- {
- // inside strip
- distanceWAway = 0;
- }
- else
- {
- distanceWAway = info.DistanceFromPath - this.halfWidth;
- }
-
- for (int i = 0; i < this.pattern.Length - 1; i++)
- {
- float start = this.pattern[i];
- float end = this.pattern[i + 1];
-
- if (length >= start && length < end)
- {
- // in section
- if (i % 2 == 0)
- {
- // solid part return the maxDistance
- infoResult.DistanceFromElement = distanceWAway;
- return infoResult;
- }
- else
- {
- // this is a none solid part
- float distanceFromStart = length - start;
- float distanceFromEnd = end - length;
-
- float closestEdge = MathF.Min(distanceFromStart, distanceFromEnd);
-
- float distanceAcross = closestEdge;
-
- if (distanceWAway > 0)
- {
- infoResult.DistanceFromElement = new Vector2(distanceAcross, distanceWAway).Length();
- }
- else
- {
- infoResult.DistanceFromElement = closestEdge;
- }
-
- return infoResult;
- }
- }
- }
-
- return infoResult;
- }
- }
+ ///
+ public ReadOnlySpan StrokePattern => this.pattern;
}
}
diff --git a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs b/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
deleted file mode 100644
index d40c71f7e..000000000
--- a/src/ImageSharp.Drawing/Processors/DrawPathProcessor.cs
+++ /dev/null
@@ -1,140 +0,0 @@
-//
-// Copyright (c) James Jackson-South and contributors.
-// Licensed under the Apache License, Version 2.0.
-//
-
-namespace ImageSharp.Drawing.Processors
-{
- using System;
- using System.Threading.Tasks;
-
- using ImageSharp.Memory;
- using ImageSharp.PixelFormats;
- using ImageSharp.Processing;
- using Pens;
-
- ///
- /// Draws a path using the processor pipeline
- ///
- /// The type of the color.
- ///
- internal class DrawPathProcessor : ImageProcessor
- where TPixel : struct, IPixel
- {
- private const float AntialiasFactor = 1f;
- private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor
-
- ///
- /// Initializes a new instance of the class.
- ///
- /// The details how to draw the outline/path.
- /// The details of the paths and outlines to draw.
- /// The drawing configuration options.
- public DrawPathProcessor(IPen pen, Drawable drawable, GraphicsOptions options)
- {
- this.Path = drawable;
- this.Pen = pen;
- this.Options = options;
- }
-
- ///
- /// Gets the graphics options.
- ///
- public GraphicsOptions Options { get; }
-
- ///
- /// Gets the pen.
- ///
- public IPen Pen { get; }
-
- ///
- /// Gets the path.
- ///
- public Drawable Path { get; }
-
- ///
- protected override void OnApply(ImageBase source, Rectangle sourceRectangle)
- {
- using (PenApplicator applicator = this.Pen.CreateApplicator(source, this.Path.Bounds, this.Options))
- {
- var rect = Rectangle.Ceiling(applicator.RequiredRegion);
-
- int polyStartY = rect.Y - PaddingFactor;
- int polyEndY = rect.Bottom + PaddingFactor;
- int startX = rect.X - PaddingFactor;
- int endX = rect.Right + PaddingFactor;
-
- int minX = Math.Max(sourceRectangle.Left, startX);
- int maxX = Math.Min(sourceRectangle.Right, endX);
- int minY = Math.Max(sourceRectangle.Top, polyStartY);
- int maxY = Math.Min(sourceRectangle.Bottom, polyEndY);
-
- // Align start/end positions.
- minX = Math.Max(0, minX);
- maxX = Math.Min(source.Width, maxX);
- minY = Math.Max(0, minY);
- maxY = Math.Min(source.Height, maxY);
-
- // Reset offset if necessary.
- if (minX > 0)
- {
- startX = 0;
- }
-
- if (minY > 0)
- {
- polyStartY = 0;
- }
-
- int width = maxX - minX;
- PixelBlender blender = PixelOperations.Instance.GetPixelBlender(this.Options.BlenderMode);
-
- Parallel.For(
- minY,
- maxY,
- this.ParallelOptions,
- y =>
- {
- int offsetY = y - polyStartY;
-
- using (var amount = new Buffer(width))
- using (var colors = new Buffer(width))
- {
- for (int i = 0; i < width; i++)
- {
- int x = i + minX;
- int offsetX = x - startX;
- PointInfo info = this.Path.GetPointInfo(offsetX, offsetY);
- ColoredPointInfo color = applicator.GetColor(offsetX, offsetY, info);
- amount[i] = (this.Opacity(color.DistanceFromElement) * this.Options.BlendPercentage).Clamp(0, 1);
- colors[i] = color.Color;
- }
-
- Span destination = source.GetRowSpan(offsetY).Slice(minX - startX, width);
- blender.Blend(destination, destination, colors, amount);
- }
- });
- }
- }
-
- ///
- /// Returns the correct opacity for the given distance.
- ///
- /// Thw distance from the central point.
- /// The
- private float Opacity(float distance)
- {
- if (distance <= 0)
- {
- return 1;
- }
-
- if (this.Options.Antialias && distance < AntialiasFactor)
- {
- return 1 - (distance / AntialiasFactor);
- }
-
- return 0;
- }
- }
-}
\ No newline at end of file
diff --git a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
index ae828e112..8224b234d 100644
--- a/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
+++ b/src/ImageSharp.Drawing/Processors/FillRegionProcessor.cs
@@ -93,6 +93,7 @@ namespace ImageSharp.Drawing.Processors
using (BrushApplicator applicator = this.Brush.CreateApplicator(source, rect, this.Options))
{
float[] buffer = arrayPool.Rent(maxIntersections);
+ Span bufferSpan = buffer.AsSpan().Slice(0, maxIntersections);
int scanlineWidth = maxX - minX;
using (var scanline = new Buffer(scanlineWidth))
{
@@ -116,14 +117,14 @@ namespace ImageSharp.Drawing.Processors
float subpixelFractionPoint = subpixelFraction / subpixelCount;
for (float subPixel = (float)y; subPixel < y + 1; subPixel += subpixelFraction)
{
- int pointsFound = region.Scan(subPixel, buffer, maxIntersections, 0);
+ int pointsFound = region.Scan(subPixel, bufferSpan);
if (pointsFound == 0)
{
// nothing on this line skip
continue;
}
- QuickSort(buffer, pointsFound);
+ QuickSort(bufferSpan.Slice(0, pointsFound));
for (int point = 0; point < pointsFound; point += 2)
{
@@ -194,20 +195,20 @@ namespace ImageSharp.Drawing.Processors
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private static void Swap(float[] data, int left, int right)
+ private static void Swap(Span data, int left, int right)
{
float tmp = data[left];
data[left] = data[right];
data[right] = tmp;
}
- private static void QuickSort(float[] data, int size)
+ private static void QuickSort(Span data)
{
- int hi = Math.Min(data.Length - 1, size - 1);
+ int hi = Math.Min(data.Length - 1, data.Length - 1);
QuickSort(data, 0, hi);
}
- private static void QuickSort(float[] data, int lo, int hi)
+ private static void QuickSort(Span data, int lo, int hi)
{
if (lo < hi)
{
@@ -217,7 +218,7 @@ namespace ImageSharp.Drawing.Processors
}
}
- private static int Partition(float[] data, int lo, int hi)
+ private static int Partition(Span data, int lo, int hi)
{
float pivot = data[lo];
int i = lo - 1;
diff --git a/src/ImageSharp.Drawing/Region.cs b/src/ImageSharp.Drawing/Region.cs
index 8cab88502..687ee23fd 100644
--- a/src/ImageSharp.Drawing/Region.cs
+++ b/src/ImageSharp.Drawing/Region.cs
@@ -5,6 +5,8 @@
namespace ImageSharp.Drawing
{
+ using System;
+
///
/// Represents a region of an image.
///
@@ -19,7 +21,7 @@ namespace ImageSharp.Drawing
/// Gets the bounding box that entirely surrounds this region.
///
///
- /// This should always contains all possible points returned from .
+ /// This should always contains all possible points returned from .
///
public abstract Rectangle Bounds { get; }
@@ -28,9 +30,7 @@ namespace ImageSharp.Drawing
///
/// The position along the y axis to find intersections.
/// The buffer.
- /// The length.
- /// The offset.
/// The number of intersections found.
- public abstract int Scan(float y, float[] buffer, int length, int offset);
+ public abstract int Scan(float y, Span buffer);
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs
index c7b789da0..58e55c124 100644
--- a/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs
+++ b/tests/ImageSharp.Tests/Drawing/FillRegionProcessorTests.cs
@@ -8,6 +8,9 @@ namespace ImageSharp.Tests.Drawing
using Moq;
using ImageSharp.PixelFormats;
+ using System;
+ using ImageSharp.Drawing.Pens;
+ using System.Numerics;
public class FillRegionProcessorTests
{
@@ -26,14 +29,61 @@ namespace ImageSharp.Tests.Drawing
Mock region = new Mock();
region.Setup(x => x.Bounds).Returns(bounds);
- GraphicsOptions options = new GraphicsOptions(antialias) {
+ GraphicsOptions options = new GraphicsOptions(antialias)
+ {
AntialiasSubpixelDepth = 1
};
FillRegionProcessor processor = new FillRegionProcessor(brush.Object, region.Object, options);
Image img = new Image(1, 1);
processor.Apply(img, bounds);
- region.Verify(x => x.Scan(It.IsAny(), It.IsAny(), It.IsAny(), It.IsAny()), Times.Exactly(4));
+ region.Verify(x => x.Scan(It.IsAny(), It.IsAny>()), Times.Exactly(4));
+ }
+
+ [Fact]
+ public void FillOffCanvas()
+ {
+
+ ImageSharp.Rectangle bounds = new ImageSharp.Rectangle(-100, -10, 10, 10);
+
+ Mock> brush = new Mock>();
+ Mock region = new Mock();
+ region.Setup(x => x.Bounds).Returns(bounds);
+
+ region.Setup(x => x.MaxIntersections).Returns(10);
+ region.Setup(x => x.Scan(It.IsAny(), It.IsAny>()))
+ .Returns>((y, span) =>
+ {
+ if (y < 5)
+ {
+ span[0] = -10f;
+ span[1] = 100f;
+ return 2;
+ }
+ return 0;
+ });
+
+ GraphicsOptions options = new GraphicsOptions(true)
+ {
+ };
+ FillRegionProcessor processor = new FillRegionProcessor(brush.Object, region.Object, options);
+ Image img = new Image(10, 10);
+ processor.Apply(img, bounds);
+ }
+
+
+
+ [Fact]
+ public void DrawOffCanvas()
+ {
+
+ using (var img = new Image(10, 10))
+ {
+ img.DrawLines(new Pen(Rgba32.Black, 10), new Vector2[] {
+ new Vector2(-10, 5),
+ new Vector2(20, 5),
+ });
+ }
}
}
}
diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs
deleted file mode 100644
index a9b2284e8..000000000
--- a/tests/ImageSharp.Tests/Drawing/Paths/DrawBeziersTests.cs
+++ /dev/null
@@ -1,163 +0,0 @@
-
-namespace ImageSharp.Tests.Drawing.Paths
-{
- using System;
-
- using ImageSharp.Drawing.Brushes;
-
- using Xunit;
- using ImageSharp.Drawing;
- using System.Numerics;
- using SixLabors.Shapes;
- using ImageSharp.Drawing.Processors;
- using ImageSharp.Drawing.Pens;
- using ImageSharp.PixelFormats;
-
- public class DrawBeziersTests : IDisposable
- {
- float thickness = 7.2f;
- GraphicsOptions noneDefault = new GraphicsOptions();
- Rgba32 color = Rgba32.HotPink;
- SolidBrush brush = Brushes.Solid(Rgba32.HotPink);
- Pen pen = new Pen(Rgba32.Firebrick, 99.9f);
- Vector2[] points = new Vector2[] {
- new Vector2(10,10),
- new Vector2(20,10),
- new Vector2(20,10),
- new Vector2(30,10),
- };
- private ProcessorWatchingImage img;
-
- public DrawBeziersTests()
- {
- this.img = new Paths.ProcessorWatchingImage(10, 10);
- }
-
- public void Dispose()
- {
- img.Dispose();
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessAndPoints()
- {
- img.DrawBeziers(brush, thickness, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
- Assert.NotNull(path.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
-
- BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessPointsAndOptions()
- {
- img.DrawBeziers(brush, thickness, points, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsColorThicknessAndPoints()
- {
- img.DrawBeziers(color, thickness, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(thickness, pen.Width);
-
- SolidBrush brush = Assert.IsType>(pen.Brush);
- Assert.Equal(color, brush.Color);
- }
-
- [Fact]
- public void CorrectlySetsColorThicknessPointsAndOptions()
- {
- img.DrawBeziers(color, thickness, points, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(thickness, pen.Width);
-
- SolidBrush brush = Assert.IsType>(pen.Brush);
- Assert.Equal(color, brush.Color);
- }
-
- [Fact]
- public void CorrectlySetsPenAndPoints()
- {
- img.DrawBeziers(pen, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Assert.Equal(pen, processor.Pen);
- }
-
- [Fact]
- public void CorrectlySetsPenPointsAndOptions()
- {
- img.DrawBeziers(pen, points, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- BezierLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Assert.Equal(pen, processor.Pen);
- }
- }
-}
diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs
deleted file mode 100644
index 3b7ba303d..000000000
--- a/tests/ImageSharp.Tests/Drawing/Paths/DrawLinesTests.cs
+++ /dev/null
@@ -1,160 +0,0 @@
-
-namespace ImageSharp.Tests.Drawing.Paths
-{
- using System;
-
- using ImageSharp.Drawing.Brushes;
- using Xunit;
- using ImageSharp.Drawing;
- using System.Numerics;
- using SixLabors.Shapes;
- using ImageSharp.Drawing.Processors;
- using ImageSharp.Drawing.Pens;
- using ImageSharp.PixelFormats;
-
- public class DrawLinesTests : IDisposable
- {
- float thickness = 7.2f;
- GraphicsOptions noneDefault = new GraphicsOptions();
- Rgba32 color = Rgba32.HotPink;
- SolidBrush brush = Brushes.Solid(Rgba32.HotPink);
- Pen pen = new Pen(Rgba32.Gray, 99.9f);
- Vector2[] points = new Vector2[] {
- new Vector2(10,10),
- new Vector2(20,10),
- new Vector2(20,10),
- new Vector2(30,10),
- };
- private ProcessorWatchingImage img;
-
- public DrawLinesTests()
- {
- this.img = new Paths.ProcessorWatchingImage(10, 10);
- }
-
- public void Dispose()
- {
- img.Dispose();
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessAndPoints()
- {
- img.DrawLines(brush, thickness, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessPointsAndOptions()
- {
- img.DrawLines(brush, thickness, points, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsColorThicknessAndPoints()
- {
- img.DrawLines(color, thickness, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(thickness, pen.Width);
-
- SolidBrush brush = Assert.IsType>(pen.Brush);
- Assert.Equal(color, brush.Color);
- }
-
- [Fact]
- public void CorrectlySetsColorThicknessPointsAndOptions()
- {
- img.DrawLines(color, thickness, points, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(thickness, pen.Width);
-
- SolidBrush brush = Assert.IsType>(pen.Brush);
- Assert.Equal(color, brush.Color);
- }
-
- [Fact]
- public void CorrectlySetsPenAndPoints()
- {
- img.DrawLines(pen, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Assert.Equal(pen, processor.Pen);
- }
-
- [Fact]
- public void CorrectlySetsPenPointsAndOptions()
- {
- img.DrawLines(pen, points, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- SixLabors.Shapes.Path vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Assert.Equal(pen, processor.Pen);
- }
- }
-}
diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs
deleted file mode 100644
index 0bdcbdc08..000000000
--- a/tests/ImageSharp.Tests/Drawing/Paths/DrawPath.cs
+++ /dev/null
@@ -1,149 +0,0 @@
-
-namespace ImageSharp.Tests.Drawing.Paths
-{
- using System;
-
- using ImageSharp.Drawing.Brushes;
-
- using Xunit;
- using ImageSharp.Drawing;
- using System.Numerics;
- using SixLabors.Shapes;
- using ImageSharp.Drawing.Processors;
- using ImageSharp.Drawing.Pens;
- using ImageSharp.PixelFormats;
-
- public class DrawPath : IDisposable
- {
- float thickness = 7.2f;
- GraphicsOptions noneDefault = new GraphicsOptions();
- Rgba32 color = Rgba32.HotPink;
- SolidBrush brush = Brushes.Solid(Rgba32.HotPink);
- Pen pen = new Pen(Rgba32.Gray, 99.9f);
- IPath path = new SixLabors.Shapes.Path(new LinearLineSegment(new Vector2[] {
- new Vector2(10,10),
- new Vector2(20,10),
- new Vector2(20,10),
- new Vector2(30,10),
- }));
- private ProcessorWatchingImage img;
-
- public DrawPath()
- {
- this.img = new Paths.ProcessorWatchingImage(10, 10);
- }
-
- public void Dispose()
- {
- img.Dispose();
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessAndPath()
- {
- img.Draw(brush, thickness, path);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath shapepath = Assert.IsType(processor.Path);
- Assert.Equal(path, shapepath.Path);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessPathAndOptions()
- {
- img.Draw(brush, thickness, path, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath shapepath = Assert.IsType(processor.Path);
- Assert.Equal(path, shapepath.Path);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsColorThicknessAndPath()
- {
- img.Draw(color, thickness, path);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath shapepath = Assert.IsType(processor.Path);
- Assert.Equal(path, shapepath.Path);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(thickness, pen.Width);
-
- SolidBrush brush = Assert.IsType>(pen.Brush);
- Assert.Equal(color, brush.Color);
- }
-
- [Fact]
- public void CorrectlySetsColorThicknessPathAndOptions()
- {
- img.Draw(color, thickness, path, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath shapepath = Assert.IsType(processor.Path);
- Assert.Equal(path, shapepath.Path);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(thickness, pen.Width);
-
- SolidBrush brush = Assert.IsType>(pen.Brush);
- Assert.Equal(color, brush.Color);
- }
-
- [Fact]
- public void CorrectlySetsPenAndPath()
- {
- img.Draw(pen, path);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath shapepath = Assert.IsType(processor.Path);
- Assert.Equal(path, shapepath.Path);
-
- Assert.Equal(pen, processor.Pen);
- }
-
- [Fact]
- public void CorrectlySetsPenPathAndOptions()
- {
- img.Draw(pen, path, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath shapepath = Assert.IsType(processor.Path);
- Assert.Equal(path, shapepath.Path);
-
- Assert.Equal(pen, processor.Pen);
- }
- }
-}
diff --git a/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs b/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs
deleted file mode 100644
index 3474e6f62..000000000
--- a/tests/ImageSharp.Tests/Drawing/Paths/DrawPolygon.cs
+++ /dev/null
@@ -1,161 +0,0 @@
-
-namespace ImageSharp.Tests.Drawing.Paths
-{
- using System;
-
- using ImageSharp.Drawing.Brushes;
-
- using Xunit;
- using ImageSharp.Drawing;
- using System.Numerics;
- using SixLabors.Shapes;
- using ImageSharp.Drawing.Processors;
- using ImageSharp.Drawing.Pens;
- using ImageSharp.PixelFormats;
-
- public class DrawPolygon : IDisposable
- {
- float thickness = 7.2f;
- GraphicsOptions noneDefault = new GraphicsOptions();
- Rgba32 color = Rgba32.HotPink;
- SolidBrush brush = Brushes.Solid(Rgba32.HotPink);
- Pen pen = new Pen(Rgba32.Gray, 99.9f);
- Vector2[] points = new Vector2[] {
- new Vector2(10,10),
- new Vector2(20,10),
- new Vector2(20,10),
- new Vector2(30,10),
- };
- private ProcessorWatchingImage img;
-
- public DrawPolygon()
- {
- this.img = new Paths.ProcessorWatchingImage(10, 10);
- }
-
- public void Dispose()
- {
- img.Dispose();
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessAndPoints()
- {
- img.DrawPolygon(brush, thickness, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- Polygon vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsBrushThicknessPointsAndOptions()
- {
- img.DrawPolygon(brush, thickness, points, noneDefault);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(noneDefault, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- Polygon vector = Assert.IsType(path.Path);
- LinearLineSegment segment = Assert.IsType(vector.LineSegments[0]);
-
- Pen pen = Assert.IsType>(processor.Pen);
- Assert.Equal(brush, pen.Brush);
- Assert.Equal(thickness, pen.Width);
- }
-
- [Fact]
- public void CorrectlySetsColorThicknessAndPoints()
- {
- img.DrawPolygon(color, thickness, points);
-
- Assert.NotEmpty(img.ProcessorApplications);
- DrawPathProcessor processor = Assert.IsType>(img.ProcessorApplications[0].processor);
-
- Assert.Equal(GraphicsOptions.Default, processor.Options);
-
- ShapePath path = Assert.IsType(processor.Path);
-
- Polygon vector = Assert.IsType