diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/LinearGradientBrush.cs b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/LinearGradientBrush.cs
index b955cd7504..8ef2295483 100644
--- a/src/ImageSharp.Drawing/Processing/Drawing/Brushes/LinearGradientBrush.cs
+++ b/src/ImageSharp.Drawing/Processing/Drawing/Brushes/LinearGradientBrush.cs
@@ -105,19 +105,14 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
private readonly float acrossX;
///
- /// helper to speed up calculation as these dont't change
+ /// the result of ^2 + ^2
///
- private readonly float aYcX;
+ private readonly float alongsSquared;
///
- /// helper to speed up calculation as these dont't change
+ /// the length of the defined gradient (between source and end)
///
- private readonly float aXcY;
-
- ///
- /// helper to speed up calculation as these dont't change
- ///
- private readonly float aXcX;
+ private readonly float length;
///
/// Initializes a new instance of the class.
@@ -142,17 +137,16 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
this.colorStops = colorStops; // TODO: requires colorStops to be sorted by Item1!
// the along vector:
- this.alongX = this.start.X - this.end.X;
- this.alongY = this.start.Y - this.end.Y;
+ this.alongX = this.end.X - this.start.X;
+ this.alongY = this.end.Y - this.start.Y;
// the cross vector:
this.acrossX = this.alongY;
this.acrossY = -this.alongX;
// some helpers:
- this.aYcX = this.alongY * this.acrossX;
- this.aXcY = this.alongX * this.acrossY;
- this.aXcX = this.alongX * this.acrossX;
+ this.alongsSquared = (this.alongX * this.alongX) + (this.alongY * this.alongY);
+ this.length = (float)Math.Sqrt(this.alongsSquared);
}
///
@@ -210,8 +204,33 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Brushes
private float RatioOnGradient(int x, int y)
{
- return ((x / this.acrossX) - (this.alongX * y / this.aYcX))
- / (1 - (this.aXcY / this.aXcX));
+ if (this.acrossX == 0)
+ {
+ return (x - this.start.X) / (float)(this.end.X - this.start.X);
+ }
+ else if (this.acrossY == 0)
+ {
+ return (y - this.start.Y) / (float)(this.end.Y - this.start.Y);
+ }
+ else
+ {
+ float deltaX = x - this.start.X;
+ float deltaY = y - this.start.Y;
+ float k = ((this.alongY * deltaX) - (this.alongX * deltaY)) / this.alongsSquared;
+
+ // point on the line:
+ float x4 = x - (k * this.alongY);
+ float y4 = y + (k * this.alongX);
+
+ // get distance from (x4,y4) to start
+ float distance = (float)Math.Sqrt(
+ Math.Pow(x4 - this.start.X, 2)
+ + Math.Pow(y4 - this.start.Y, 2));
+
+ // get and return ratio
+ float ratio = distance / this.length;
+ return ratio;
+ }
}
internal override void Apply(Span scanline, int x, int y)
diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs
index d1b253680e..52979d792b 100644
--- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs
+++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs
@@ -123,5 +123,40 @@ namespace SixLabors.ImageSharp.Tests.Drawing
}
}
}
+
+ [Theory]
+ [InlineData(0, 0, 499, 499)]
+ [InlineData(0, 499, 499, 0)]
+ [InlineData(499, 499, 0, 0)]
+ [InlineData(499, 0, 0, 499)]
+ public void DiagonalLinearGradientBrushReturnsUnicolorColumns(
+ int startX, int startY, int endX, int endY)
+ {
+ int size = 500;
+ int lastIndex = size - 1;
+
+
+ string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush");
+ using (var image = new Image(size, size))
+ {
+ LinearGradientBrush unicolorLinearGradientBrush =
+ new LinearGradientBrush(
+ new SixLabors.Primitives.Point(startX, startY),
+ new SixLabors.Primitives.Point(endX, endY),
+ new LinearGradientBrush.ColorStop(0, Rgba32.Red),
+ new LinearGradientBrush.ColorStop(1, Rgba32.Yellow));
+
+ image.Mutate(x => x.Fill(unicolorLinearGradientBrush));
+ image.Save($"{path}/diagonalRedToYellowFrom{startX}_{startY}.png");
+
+ using (PixelAccessor sourcePixels = image.Lock())
+ {
+ // check first and last pixel, these are known:
+ Assert.Equal(Rgba32.Red, sourcePixels[startX, startY]);
+ Assert.Equal(Rgba32.Yellow, sourcePixels[endX, endY]);
+
+ }
+ }
+ }
}
}
\ No newline at end of file