Browse Source

Accept points instead of line segments as constructor argument

Note that this is a breaking change.
af/merge-core
Xavier Cho 7 years ago
parent
commit
7e06b63420
  1. 43
      src/ImageSharp.Drawing/Processing/PathGradientBrush.cs
  2. 86
      tests/ImageSharp.Tests/Drawing/FillPathGradientBrushTests.cs

43
src/ImageSharp.Drawing/Processing/PathGradientBrush.cs

@ -18,8 +18,6 @@ namespace SixLabors.ImageSharp.Processing
/// </summary> /// </summary>
public sealed class PathGradientBrush : IBrush public sealed class PathGradientBrush : IBrush
{ {
private readonly Polygon path;
private readonly IList<Edge> edges; private readonly IList<Edge> edges;
private readonly Color centerColor; private readonly Color centerColor;
@ -27,20 +25,20 @@ namespace SixLabors.ImageSharp.Processing
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PathGradientBrush"/> class. /// Initializes a new instance of the <see cref="PathGradientBrush"/> class.
/// </summary> /// </summary>
/// <param name="lines">Line segments of a polygon that represents the gradient area.</param> /// <param name="points">Points that constitute a polygon that represents the gradient area.</param>
/// <param name="colors">Array of colors that correspond to each point in the polygon.</param> /// <param name="colors">Array of colors that correspond to each point in the polygon.</param>
/// <param name="centerColor">Color at the center of the gradient area to which the other colors converge.</param> /// <param name="centerColor">Color at the center of the gradient area to which the other colors converge.</param>
public PathGradientBrush(ILineSegment[] lines, Color[] colors, Color centerColor) public PathGradientBrush(PointF[] points, Color[] colors, Color centerColor)
{ {
if (lines == null) if (points == null)
{ {
throw new ArgumentNullException(nameof(lines)); throw new ArgumentNullException(nameof(points));
} }
if (lines.Length < 3) if (points.Length < 3)
{ {
throw new ArgumentOutOfRangeException( throw new ArgumentOutOfRangeException(
nameof(lines), nameof(points),
"There must be at least 3 lines to construct a path gradient brush."); "There must be at least 3 lines to construct a path gradient brush.");
} }
@ -56,22 +54,30 @@ namespace SixLabors.ImageSharp.Processing
"One or more color is needed to construct a path gradient brush."); "One or more color is needed to construct a path gradient brush.");
} }
this.path = new Polygon(lines); int size = points.Length;
var lines = new ILineSegment[size];
for (int i = 0; i < size; i++)
{
lines[i] = new LinearLineSegment(points[i % size], points[(i + 1) % size]);
}
this.centerColor = centerColor; this.centerColor = centerColor;
Color ColorAt(int index) => colors[index % colors.Length]; Color ColorAt(int index) => colors[index % colors.Length];
this.edges = this.path.LineSegments.Select(s => new Path(s)) this.edges = lines.Select(s => new Path(s))
.Select((path, i) => new Edge(path, ColorAt(i), ColorAt(i + 1))).ToList(); .Select((path, i) => new Edge(path, ColorAt(i), ColorAt(i + 1))).ToList();
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PathGradientBrush"/> class. /// Initializes a new instance of the <see cref="PathGradientBrush"/> class.
/// </summary> /// </summary>
/// <param name="lines">Line segments of a polygon that represents the gradient area.</param> /// <param name="points">Points that constitute a polygon that represents the gradient area.</param>
/// <param name="colors">Array of colors that correspond to each point in the polygon.</param> /// <param name="colors">Array of colors that correspond to each point in the polygon.</param>
public PathGradientBrush(ILineSegment[] lines, Color[] colors) public PathGradientBrush(PointF[] points, Color[] colors)
: this(lines, colors, CalculateCenterColor(colors)) : this(points, colors, CalculateCenterColor(colors))
{ {
} }
@ -82,7 +88,7 @@ namespace SixLabors.ImageSharp.Processing
GraphicsOptions options) GraphicsOptions options)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
return new PathGradientBrushApplicator<TPixel>(source, this.path, this.edges, this.centerColor, options); return new PathGradientBrushApplicator<TPixel>(source, this.edges, this.centerColor, options);
} }
private static Color CalculateCenterColor(Color[] colors) private static Color CalculateCenterColor(Color[] colors)
@ -182,8 +188,6 @@ namespace SixLabors.ImageSharp.Processing
private class PathGradientBrushApplicator<TPixel> : BrushApplicator<TPixel> private class PathGradientBrushApplicator<TPixel> : BrushApplicator<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
private readonly Path path;
private readonly PointF center; private readonly PointF center;
private readonly Vector4 centerColor; private readonly Vector4 centerColor;
@ -196,24 +200,21 @@ namespace SixLabors.ImageSharp.Processing
/// Initializes a new instance of the <see cref="PathGradientBrushApplicator{TPixel}"/> class. /// Initializes a new instance of the <see cref="PathGradientBrushApplicator{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="source">The source image.</param> /// <param name="source">The source image.</param>
/// <param name="path">A polygon that represents the gradient area.</param>
/// <param name="edges">Edges of the polygon.</param> /// <param name="edges">Edges of the polygon.</param>
/// <param name="centerColor">Color at the center of the gradient area to which the other colors converge.</param> /// <param name="centerColor">Color at the center of the gradient area to which the other colors converge.</param>
/// <param name="options">The options.</param> /// <param name="options">The options.</param>
public PathGradientBrushApplicator( public PathGradientBrushApplicator(
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
Path path,
IList<Edge> edges, IList<Edge> edges,
Color centerColor, Color centerColor,
GraphicsOptions options) GraphicsOptions options)
: base(source, options) : base(source, options)
{ {
this.path = path;
this.edges = edges; this.edges = edges;
PointF[] points = path.LineSegments.Select(s => s.EndPoint).ToArray(); PointF[] points = edges.Select(s => s.Start).ToArray();
this.center = points.Aggregate((p1, p2) => p1 + p2) / points.Length; this.center = points.Aggregate((p1, p2) => p1 + p2) / edges.Count;
this.centerColor = centerColor.ToVector4(); this.centerColor = centerColor.ToVector4();
this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Select(d => d.Length()).Max(); this.maxDistance = points.Select(p => (Vector2)(p - this.center)).Select(d => d.Length()).Max();

86
tests/ImageSharp.Tests/Drawing/FillPathGradientBrushTests.cs

@ -7,7 +7,6 @@ using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison;
using SixLabors.Primitives; using SixLabors.Primitives;
using SixLabors.Shapes;
using Xunit; using Xunit;
@ -27,17 +26,10 @@ namespace SixLabors.ImageSharp.Tests.Drawing
TolerantComparer, TolerantComparer,
image => image =>
{ {
ILineSegment[] path = PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(10, 10), new PointF(0, 10) };
{
new LinearLineSegment(new PointF(0, 0), new PointF(10, 0)),
new LinearLineSegment(new PointF(10, 0), new PointF(10, 10)),
new LinearLineSegment(new PointF(10, 10), new PointF(0, 10)),
new LinearLineSegment(new PointF(0, 10), new PointF(0, 0))
};
Color[] colors = { Color.Black, Color.Red, Color.Yellow, Color.Green }; Color[] colors = { Color.Black, Color.Red, Color.Yellow, Color.Green };
var brush = new PathGradientBrush(path, colors); var brush = new PathGradientBrush(points, colors);
image.Mutate(x => x.Fill(brush)); image.Mutate(x => x.Fill(brush));
image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
@ -53,16 +45,10 @@ namespace SixLabors.ImageSharp.Tests.Drawing
TolerantComparer, TolerantComparer,
image => image =>
{ {
ILineSegment[] path = PointF[] points = { new PointF(5, 0), new PointF(10, 10), new PointF(0, 10) };
{
new LinearLineSegment(new PointF(5, 0), new PointF(10, 10)),
new LinearLineSegment(new PointF(10, 10), new PointF(0, 10)),
new LinearLineSegment(new PointF(0, 10), new PointF(5, 0))
};
Color[] colors = { Color.Red, Color.Green, Color.Blue }; Color[] colors = { Color.Red, Color.Green, Color.Blue };
var brush = new PathGradientBrush(path, colors); var brush = new PathGradientBrush(points, colors);
image.Mutate(x => x.Fill(brush)); image.Mutate(x => x.Fill(brush));
image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
@ -76,17 +62,10 @@ namespace SixLabors.ImageSharp.Tests.Drawing
{ {
using (Image<TPixel> image = provider.GetImage()) using (Image<TPixel> image = provider.GetImage())
{ {
ILineSegment[] path = PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(10, 10), new PointF(0, 10) };
{
new LinearLineSegment(new PointF(0, 0), new PointF(10, 0)),
new LinearLineSegment(new PointF(10, 0), new PointF(10, 10)),
new LinearLineSegment(new PointF(10, 10), new PointF(0, 10)),
new LinearLineSegment(new PointF(0, 10), new PointF(0, 0))
};
Color[] colors = { Color.Red }; Color[] colors = { Color.Red };
var brush = new PathGradientBrush(path, colors); var brush = new PathGradientBrush(points, colors);
image.Mutate(x => x.Fill(brush)); image.Mutate(x => x.Fill(brush));
@ -103,17 +82,10 @@ namespace SixLabors.ImageSharp.Tests.Drawing
TolerantComparer, TolerantComparer,
image => image =>
{ {
ILineSegment[] path = PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(10, 10), new PointF(0, 10) };
{
new LinearLineSegment(new PointF(0, 0), new PointF(10, 0)),
new LinearLineSegment(new PointF(10, 0), new PointF(10, 10)),
new LinearLineSegment(new PointF(10, 10), new PointF(0, 10)),
new LinearLineSegment(new PointF(0, 10), new PointF(0, 0))
};
Color[] colors = { Color.Red, Color.Yellow }; Color[] colors = { Color.Red, Color.Yellow };
var brush = new PathGradientBrush(path, colors); var brush = new PathGradientBrush(points, colors);
image.Mutate(x => x.Fill(brush)); image.Mutate(x => x.Fill(brush));
image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
@ -129,17 +101,10 @@ namespace SixLabors.ImageSharp.Tests.Drawing
TolerantComparer, TolerantComparer,
image => image =>
{ {
ILineSegment[] path = PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(10, 10), new PointF(0, 10) };
{
new LinearLineSegment(new PointF(0, 0), new PointF(10, 0)),
new LinearLineSegment(new PointF(10, 0), new PointF(10, 10)),
new LinearLineSegment(new PointF(10, 10), new PointF(0, 10)),
new LinearLineSegment(new PointF(0, 10), new PointF(0, 0))
};
Color[] colors = { Color.Black, Color.Red, Color.Yellow, Color.Green }; Color[] colors = { Color.Black, Color.Red, Color.Yellow, Color.Green };
var brush = new PathGradientBrush(path, colors, Color.White); var brush = new PathGradientBrush(points, colors, Color.White);
image.Mutate(x => x.Fill(brush)); image.Mutate(x => x.Fill(brush));
image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); image.DebugSave(provider, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
@ -157,17 +122,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing
} }
[Fact] [Fact]
public void ShouldThrowArgumentOutOfRangeExceptionWhenLessThan3LinesAreGiven() public void ShouldThrowArgumentOutOfRangeExceptionWhenLessThan3PointsAreGiven()
{ {
ILineSegment[] path = PointF[] points = { new PointF(0, 0), new PointF(10, 0) };
{
new LinearLineSegment(new PointF(0, 0), new PointF(10, 0)),
new LinearLineSegment(new PointF(10, 0), new PointF(10, 10))
};
Color[] colors = { Color.Black, Color.Red, Color.Yellow, Color.Green }; Color[] colors = { Color.Black, Color.Red, Color.Yellow, Color.Green };
PathGradientBrush Create() => new PathGradientBrush(path, colors, Color.White); PathGradientBrush Create() => new PathGradientBrush(points, colors, Color.White);
Assert.Throws<ArgumentOutOfRangeException>(Create); Assert.Throws<ArgumentOutOfRangeException>(Create);
} }
@ -175,15 +135,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing
[Fact] [Fact]
public void ShouldThrowArgumentNullExceptionWhenColorsAreNull() public void ShouldThrowArgumentNullExceptionWhenColorsAreNull()
{ {
ILineSegment[] path = PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(10, 10), new PointF(0, 10) };
{
new LinearLineSegment(new PointF(0, 0), new PointF(10, 0)),
new LinearLineSegment(new PointF(10, 0), new PointF(10, 10)),
new LinearLineSegment(new PointF(10, 10), new PointF(0, 10)),
new LinearLineSegment(new PointF(0, 10), new PointF(0, 0))
};
PathGradientBrush Create() => new PathGradientBrush(path, null, Color.White); PathGradientBrush Create() => new PathGradientBrush(points, null, Color.White);
Assert.Throws<ArgumentNullException>(Create); Assert.Throws<ArgumentNullException>(Create);
} }
@ -191,17 +145,11 @@ namespace SixLabors.ImageSharp.Tests.Drawing
[Fact] [Fact]
public void ShouldThrowArgumentOutOfRangeExceptionWhenEmptyColorArrayIsGiven() public void ShouldThrowArgumentOutOfRangeExceptionWhenEmptyColorArrayIsGiven()
{ {
ILineSegment[] path = PointF[] points = { new PointF(0, 0), new PointF(10, 0), new PointF(10, 10), new PointF(0, 10) };
{
new LinearLineSegment(new PointF(0, 0), new PointF(10, 0)),
new LinearLineSegment(new PointF(10, 0), new PointF(10, 10)),
new LinearLineSegment(new PointF(10, 10), new PointF(0, 10)),
new LinearLineSegment(new PointF(0, 10), new PointF(0, 0))
};
var colors = new Color[0]; var colors = new Color[0];
PathGradientBrush Create() => new PathGradientBrush(path, colors, Color.White); PathGradientBrush Create() => new PathGradientBrush(points, colors, Color.White);
Assert.Throws<ArgumentOutOfRangeException>(Create); Assert.Throws<ArgumentOutOfRangeException>(Create);
} }

Loading…
Cancel
Save