|
|
|
@ -1,7 +1,10 @@ |
|
|
|
// Copyright (c) Six Labors and contributors.
|
|
|
|
// Licensed under the Apache License, Version 2.0.
|
|
|
|
|
|
|
|
using System; |
|
|
|
using System.Globalization; |
|
|
|
using System.Linq; |
|
|
|
using System.Text; |
|
|
|
|
|
|
|
using SixLabors.ImageSharp.PixelFormats; |
|
|
|
using SixLabors.ImageSharp.Processing; |
|
|
|
@ -12,305 +15,364 @@ using Xunit; |
|
|
|
|
|
|
|
namespace SixLabors.ImageSharp.Tests.Drawing |
|
|
|
{ |
|
|
|
[GroupOutput("Drawing/GradientBrushes")] |
|
|
|
public class FillLinearGradientBrushTests : FileTestBase |
|
|
|
{ |
|
|
|
[Fact] |
|
|
|
public void LinearGradientBrushWithEqualColorsReturnsUnicolorImage() |
|
|
|
[Theory] |
|
|
|
[WithBlankImages(10, 10, PixelTypes.Rgba32)] |
|
|
|
public void WithEqualColorsReturnsUnicolorImage<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush"); |
|
|
|
using (var image = new Image<Rgba32>(10, 10)) |
|
|
|
TPixel red = NamedColors<TPixel>.Red; |
|
|
|
using (var image = provider.GetImage()) |
|
|
|
{ |
|
|
|
LinearGradientBrush<Rgba32> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<Rgba32>( |
|
|
|
LinearGradientBrush<TPixel> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<TPixel>( |
|
|
|
new SixLabors.Primitives.Point(0, 0), |
|
|
|
new SixLabors.Primitives.Point(10, 0), |
|
|
|
GradientRepetitionMode.None, |
|
|
|
new ColorStop<Rgba32>(0, Rgba32.Red), |
|
|
|
new ColorStop<Rgba32>(1, Rgba32.Red)); |
|
|
|
new ColorStop<TPixel>(0, red), |
|
|
|
new ColorStop<TPixel>(1, red)); |
|
|
|
|
|
|
|
image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); |
|
|
|
image.Save($"{path}/UnicolorGradient.png"); |
|
|
|
|
|
|
|
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|
|
|
{ |
|
|
|
Assert.Equal(Rgba32.Red, sourcePixels[0, 0]); |
|
|
|
Assert.Equal(Rgba32.Red, sourcePixels[9, 9]); |
|
|
|
Assert.Equal(Rgba32.Red, sourcePixels[5, 5]); |
|
|
|
Assert.Equal(Rgba32.Red, sourcePixels[3, 8]); |
|
|
|
} |
|
|
|
image.DebugSave(provider); |
|
|
|
image.CompareToReferenceOutput(provider); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void HorizontalLinearGradientBrushReturnsUnicolorColumns() |
|
|
|
[Theory] |
|
|
|
[WithBlankImages(500, 10, PixelTypes.Rgba32)] |
|
|
|
public void HorizontalReturnsUnicolorColumns<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
int width = 500; |
|
|
|
int height = 10; |
|
|
|
int lastColumnIndex = width - 1; |
|
|
|
|
|
|
|
string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush"); |
|
|
|
using (var image = new Image<Rgba32>(width, height)) |
|
|
|
using (var image = provider.GetImage()) |
|
|
|
{ |
|
|
|
LinearGradientBrush<Rgba32> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<Rgba32>( |
|
|
|
int lastColumnIndex = image.Width - 1; |
|
|
|
TPixel red = NamedColors<TPixel>.Red; |
|
|
|
TPixel yellow = NamedColors<TPixel>.Yellow; |
|
|
|
|
|
|
|
LinearGradientBrush<TPixel> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<TPixel>( |
|
|
|
new SixLabors.Primitives.Point(0, 0), |
|
|
|
new SixLabors.Primitives.Point(500, 0), |
|
|
|
new SixLabors.Primitives.Point(image.Width, 0), |
|
|
|
GradientRepetitionMode.None, |
|
|
|
new ColorStop<Rgba32>(0, Rgba32.Red), |
|
|
|
new ColorStop<Rgba32>(1, Rgba32.Yellow)); |
|
|
|
new ColorStop<TPixel>(0, red), |
|
|
|
new ColorStop<TPixel>(1, yellow)); |
|
|
|
|
|
|
|
image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); |
|
|
|
image.Save($"{path}/horizontalRedToYellow.png"); |
|
|
|
image.DebugSave(provider); |
|
|
|
|
|
|
|
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|
|
|
using (PixelAccessor<TPixel> sourcePixels = image.Lock()) |
|
|
|
{ |
|
|
|
Rgba32 columnColor0 = sourcePixels[0, 0]; |
|
|
|
Rgba32 columnColor23 = sourcePixels[23, 0]; |
|
|
|
Rgba32 columnColor42 = sourcePixels[42, 0]; |
|
|
|
Rgba32 columnColor333 = sourcePixels[333, 0]; |
|
|
|
TPixel columnColor0 = sourcePixels[0, 0]; |
|
|
|
TPixel columnColor23 = sourcePixels[23, 0]; |
|
|
|
TPixel columnColor42 = sourcePixels[42, 0]; |
|
|
|
TPixel columnColor333 = sourcePixels[333, 0]; |
|
|
|
|
|
|
|
Rgba32 lastColumnColor = sourcePixels[lastColumnIndex, 0]; |
|
|
|
TPixel lastColumnColor = sourcePixels[lastColumnIndex, 0]; |
|
|
|
|
|
|
|
for (int i = 0; i < height; i++) |
|
|
|
for (int i = 0; i < image.Height; i++) |
|
|
|
{ |
|
|
|
// check first and last column:
|
|
|
|
Assert.Equal(columnColor0, sourcePixels[0, i]); |
|
|
|
Assert.Equal(lastColumnColor, sourcePixels[lastColumnIndex, i]); |
|
|
|
|
|
|
|
// check the random colors:
|
|
|
|
Assert.True(columnColor23 == sourcePixels[23, i], $"at {i}"); |
|
|
|
Assert.True(columnColor23.Equals(sourcePixels[23, i]), $"at {i}"); |
|
|
|
Assert.Equal(columnColor42, sourcePixels[42, i]); |
|
|
|
Assert.Equal(columnColor333, sourcePixels[333, i]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
image.CompareToReferenceOutput(provider); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(GradientRepetitionMode.DontFill)] |
|
|
|
[InlineData(GradientRepetitionMode.None)] |
|
|
|
[InlineData(GradientRepetitionMode.Repeat)] |
|
|
|
[InlineData(GradientRepetitionMode.Reflect)] |
|
|
|
public void HorizontalLinearGradientBrushWithDifferentRepetitionModesCreatesCorrectImages( |
|
|
|
[WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.DontFill)] |
|
|
|
[WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.None)] |
|
|
|
[WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.Repeat)] |
|
|
|
[WithBlankImages(500, 10, PixelTypes.Rgba32, GradientRepetitionMode.Reflect)] |
|
|
|
public void HorizontalGradientWithRepMode<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider, |
|
|
|
GradientRepetitionMode repetitionMode) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
int width = 500; |
|
|
|
int height = 10; |
|
|
|
int lastColumnIndex = width - 1; |
|
|
|
|
|
|
|
string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush"); |
|
|
|
using (var image = new Image<Rgba32>(width, height)) |
|
|
|
using (var image = provider.GetImage()) |
|
|
|
{ |
|
|
|
LinearGradientBrush<Rgba32> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<Rgba32>( |
|
|
|
int lastColumnIndex = image.Width - 1; |
|
|
|
|
|
|
|
TPixel red = NamedColors<TPixel>.Red; |
|
|
|
TPixel yellow = NamedColors<TPixel>.Yellow; |
|
|
|
|
|
|
|
LinearGradientBrush<TPixel> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<TPixel>( |
|
|
|
new SixLabors.Primitives.Point(0, 0), |
|
|
|
new SixLabors.Primitives.Point(50, 0), |
|
|
|
new SixLabors.Primitives.Point(image.Width / 10, 0), |
|
|
|
repetitionMode, |
|
|
|
new ColorStop<Rgba32>(0, Rgba32.Red), |
|
|
|
new ColorStop<Rgba32>(1, Rgba32.Yellow)); |
|
|
|
new ColorStop<TPixel>(0, red), |
|
|
|
new ColorStop<TPixel>(1, yellow)); |
|
|
|
|
|
|
|
image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); |
|
|
|
image.Save($"{path}/horizontalRedToYellow_{repetitionMode}.png"); |
|
|
|
image.DebugSave(provider, repetitionMode); |
|
|
|
|
|
|
|
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|
|
|
using (PixelAccessor<TPixel> sourcePixels = image.Lock()) |
|
|
|
{ |
|
|
|
Rgba32 columnColor0 = sourcePixels[0, 0]; |
|
|
|
Rgba32 columnColor23 = sourcePixels[23, 0]; |
|
|
|
Rgba32 columnColor42 = sourcePixels[42, 0]; |
|
|
|
Rgba32 columnColor333 = sourcePixels[333, 0]; |
|
|
|
TPixel columnColor0 = sourcePixels[0, 0]; |
|
|
|
TPixel columnColor23 = sourcePixels[23, 0]; |
|
|
|
TPixel columnColor42 = sourcePixels[42, 0]; |
|
|
|
TPixel columnColor333 = sourcePixels[333, 0]; |
|
|
|
|
|
|
|
Rgba32 lastColumnColor = sourcePixels[lastColumnIndex, 0]; |
|
|
|
TPixel lastColumnColor = sourcePixels[lastColumnIndex, 0]; |
|
|
|
|
|
|
|
for (int i = 0; i < height; i++) |
|
|
|
for (int i = 0; i < image.Height; i++) |
|
|
|
{ |
|
|
|
// check first and last column:
|
|
|
|
Assert.Equal(columnColor0, sourcePixels[0, i]); |
|
|
|
Assert.Equal(lastColumnColor, sourcePixels[lastColumnIndex, i]); |
|
|
|
|
|
|
|
// check the random colors:
|
|
|
|
Assert.True(columnColor23 == sourcePixels[23, i], $"at {i}"); |
|
|
|
Assert.True(columnColor23.Equals(sourcePixels[23, i]), $"at {i}"); |
|
|
|
Assert.Equal(columnColor42, sourcePixels[42, i]); |
|
|
|
Assert.Equal(columnColor333, sourcePixels[333, i]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
image.CompareToReferenceOutput(provider, repetitionMode); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData(new[] { 0.5f })] |
|
|
|
[InlineData(new[] { 0.2f, 0.4f, 0.6f, 0.8f })] |
|
|
|
[InlineData(new[] { 0.1f, 0.3f, 0.6f })] |
|
|
|
public void LinearGradientsWithDoubledStopsProduceDashedPatterns( |
|
|
|
[WithBlankImages(200, 100, PixelTypes.Rgba32, new[] { 0.5f })] |
|
|
|
[WithBlankImages(200, 100, PixelTypes.Rgba32, new[] { 0.2f, 0.4f, 0.6f, 0.8f })] |
|
|
|
[WithBlankImages(200, 100, PixelTypes.Rgba32, new[] { 0.1f, 0.3f, 0.6f })] |
|
|
|
public void WithDoubledStopsProduceDashedPatterns<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider, |
|
|
|
float[] pattern) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
int width = 200; |
|
|
|
int height = 10; |
|
|
|
string variant = string.Join(",", pattern.Select(i => i.ToString(CultureInfo.InvariantCulture))); |
|
|
|
|
|
|
|
// ensure the input data is valid
|
|
|
|
Assert.True(pattern.Length > 0); |
|
|
|
|
|
|
|
TPixel black = NamedColors<TPixel>.Black; |
|
|
|
TPixel white = NamedColors<TPixel>.White; |
|
|
|
|
|
|
|
// create the input pattern: 0, followed by each of the arguments twice, followed by 1.0 - toggling black and white.
|
|
|
|
ColorStop<Rgba32>[] colorStops = |
|
|
|
Enumerable.Repeat(new ColorStop<Rgba32>(0, Rgba32.Black), 1) |
|
|
|
ColorStop<TPixel>[] colorStops = |
|
|
|
Enumerable.Repeat(new ColorStop<TPixel>(0, black), 1) |
|
|
|
.Concat( |
|
|
|
pattern |
|
|
|
.SelectMany((f, index) => new[] |
|
|
|
{ |
|
|
|
new ColorStop<Rgba32>(f, index % 2 == 0 ? Rgba32.Black : Rgba32.White), |
|
|
|
new ColorStop<Rgba32>(f, index % 2 == 0 ? Rgba32.White : Rgba32.Black) |
|
|
|
new ColorStop<TPixel>(f, index % 2 == 0 ? black : white), |
|
|
|
new ColorStop<TPixel>(f, index % 2 == 0 ? white : black) |
|
|
|
})) |
|
|
|
.Concat(Enumerable.Repeat(new ColorStop<Rgba32>(1, pattern.Length % 2 == 0 ? Rgba32.Black : Rgba32.White), 1)) |
|
|
|
.Concat(Enumerable.Repeat(new ColorStop<TPixel>(1, pattern.Length % 2 == 0 ? black : white), 1)) |
|
|
|
.ToArray(); |
|
|
|
|
|
|
|
string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush"); |
|
|
|
using (var image = new Image<Rgba32>(width, height)) |
|
|
|
using (Image<TPixel> image = provider.GetImage()) |
|
|
|
{ |
|
|
|
LinearGradientBrush<Rgba32> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<Rgba32>( |
|
|
|
LinearGradientBrush<TPixel> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<TPixel>( |
|
|
|
new SixLabors.Primitives.Point(0, 0), |
|
|
|
new SixLabors.Primitives.Point(width, 0), |
|
|
|
new SixLabors.Primitives.Point(image.Width, 0), |
|
|
|
GradientRepetitionMode.None, |
|
|
|
colorStops); |
|
|
|
|
|
|
|
image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); |
|
|
|
image.Save($"{path}/blackAndWhite{pattern[0]}.png"); |
|
|
|
image.DebugSave(provider, variant); |
|
|
|
|
|
|
|
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|
|
|
using (PixelAccessor<TPixel> sourcePixels = image.Lock()) |
|
|
|
{ |
|
|
|
// the result must be a black and white pattern, no other color should occur:
|
|
|
|
Assert.All( |
|
|
|
Enumerable.Range(0, width).Select(i => sourcePixels[i, 0]), |
|
|
|
color => Assert.True(color == Rgba32.Black || color == Rgba32.White)); |
|
|
|
Enumerable.Range(0, image.Width).Select(i => sourcePixels[i, 0]), |
|
|
|
color => Assert.True(color.Equals(black) || color.Equals(white))); |
|
|
|
} |
|
|
|
|
|
|
|
image.CompareToReferenceOutput(provider, variant); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Fact] |
|
|
|
public void VerticalLinearGradientBrushReturnsUnicolorColumns() |
|
|
|
[Theory] |
|
|
|
[WithBlankImages(10, 500, PixelTypes.Rgba32)] |
|
|
|
public void VerticalReturnsUnicolorColumns<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
int width = 10; |
|
|
|
int height = 500; |
|
|
|
int lastRowIndex = height - 1; |
|
|
|
|
|
|
|
string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush"); |
|
|
|
using (var image = new Image<Rgba32>(width, height)) |
|
|
|
using (var image = provider.GetImage()) |
|
|
|
{ |
|
|
|
LinearGradientBrush<Rgba32> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<Rgba32>( |
|
|
|
int lastRowIndex = image.Height - 1; |
|
|
|
|
|
|
|
TPixel red = NamedColors<TPixel>.Red; |
|
|
|
TPixel yellow = NamedColors<TPixel>.Yellow; |
|
|
|
|
|
|
|
LinearGradientBrush<TPixel> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<TPixel>( |
|
|
|
new SixLabors.Primitives.Point(0, 0), |
|
|
|
new SixLabors.Primitives.Point(0, 500), |
|
|
|
new SixLabors.Primitives.Point(0, image.Height), |
|
|
|
GradientRepetitionMode.None, |
|
|
|
new ColorStop<Rgba32>(0, Rgba32.Red), |
|
|
|
new ColorStop<Rgba32>(1, Rgba32.Yellow)); |
|
|
|
new ColorStop<TPixel>(0, red), |
|
|
|
new ColorStop<TPixel>(1, yellow)); |
|
|
|
|
|
|
|
image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); |
|
|
|
image.Save($"{path}/verticalRedToYellow.png"); |
|
|
|
image.DebugSave(provider); |
|
|
|
|
|
|
|
Random random = new Random(); |
|
|
|
|
|
|
|
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|
|
|
using (PixelAccessor<TPixel> sourcePixels = image.Lock()) |
|
|
|
{ |
|
|
|
Rgba32 firstRowColor = sourcePixels[0, 0]; |
|
|
|
TPixel firstRowColor = sourcePixels[0, 0]; |
|
|
|
|
|
|
|
Rgba32 columnColor23 = sourcePixels[0, 23]; |
|
|
|
Rgba32 columnColor42 = sourcePixels[0, 42]; |
|
|
|
Rgba32 columnColor333 = sourcePixels[0, 333]; |
|
|
|
int columnA = random.Next(0, image.Height); |
|
|
|
int columnB = random.Next(0, image.Height); |
|
|
|
int columnC = random.Next(0, image.Height); |
|
|
|
TPixel columnColorA = sourcePixels[0, columnA]; |
|
|
|
TPixel columnColorB = sourcePixels[0, columnB]; |
|
|
|
TPixel columnColorC = sourcePixels[0, columnC]; |
|
|
|
|
|
|
|
Rgba32 lastRowColor = sourcePixels[0, lastRowIndex]; |
|
|
|
TPixel lastRowColor = sourcePixels[0, lastRowIndex]; |
|
|
|
|
|
|
|
for (int i = 0; i < width; i++) |
|
|
|
for (int i = 0; i < image.Width; i++) |
|
|
|
{ |
|
|
|
// check first and last column, these are known:
|
|
|
|
Assert.Equal(firstRowColor, sourcePixels[i, 0]); |
|
|
|
Assert.Equal(lastRowColor, sourcePixels[i, lastRowIndex]); |
|
|
|
|
|
|
|
// check the random colors:
|
|
|
|
Assert.Equal(columnColor23, sourcePixels[i, 23]); |
|
|
|
Assert.Equal(columnColor42, sourcePixels[i, 42]); |
|
|
|
Assert.Equal(columnColor333, sourcePixels[i, 333]); |
|
|
|
Assert.Equal(columnColorA, sourcePixels[i, columnA]); |
|
|
|
Assert.Equal(columnColorB, sourcePixels[i, columnB]); |
|
|
|
Assert.Equal(columnColorC, sourcePixels[i, columnC]); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
image.CompareToReferenceOutput(provider); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[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) |
|
|
|
public enum ImageCorner |
|
|
|
{ |
|
|
|
int size = 500; |
|
|
|
TopLeft = 0, |
|
|
|
TopRight = 1, |
|
|
|
BottomLeft = 2, |
|
|
|
BottomRight = 3 |
|
|
|
} |
|
|
|
|
|
|
|
string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush"); |
|
|
|
using (var image = new Image<Rgba32>(size, size)) |
|
|
|
[Theory] |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, ImageCorner.TopLeft)] |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, ImageCorner.TopRight)] |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, ImageCorner.BottomLeft)] |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, ImageCorner.BottomRight)] |
|
|
|
public void DiagonalReturnsCorrectImages<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider, |
|
|
|
ImageCorner startCorner) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
using (var image = provider.GetImage()) |
|
|
|
{ |
|
|
|
LinearGradientBrush<Rgba32> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<Rgba32>( |
|
|
|
Assert.True(image.Height == image.Width, "For the math check block at the end the image must be squared, but it is not."); |
|
|
|
|
|
|
|
int startX = (int)startCorner % 2 == 0 ? 0 : image.Width - 1; |
|
|
|
int startY = startCorner > ImageCorner.TopRight ? 0 : image.Height - 1; |
|
|
|
int endX = image.Height - startX - 1; |
|
|
|
int endY = image.Width - startY - 1; |
|
|
|
|
|
|
|
TPixel red = NamedColors<TPixel>.Red; |
|
|
|
TPixel yellow = NamedColors<TPixel>.Yellow; |
|
|
|
|
|
|
|
LinearGradientBrush<TPixel> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<TPixel>( |
|
|
|
new SixLabors.Primitives.Point(startX, startY), |
|
|
|
new SixLabors.Primitives.Point(endX, endY), |
|
|
|
GradientRepetitionMode.None, |
|
|
|
new ColorStop<Rgba32>(0, Rgba32.Red), |
|
|
|
new ColorStop<Rgba32>(1, Rgba32.Yellow)); |
|
|
|
new ColorStop<TPixel>(0, red), |
|
|
|
new ColorStop<TPixel>(1, yellow)); |
|
|
|
|
|
|
|
image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); |
|
|
|
image.Save($"{path}/diagonalRedToYellowFrom{startX}_{startY}.png"); |
|
|
|
image.DebugSave(provider, startCorner); |
|
|
|
|
|
|
|
int verticalSign = startY == 0 ? 1 : -1; |
|
|
|
int horizontalSign = startX == 0 ? 1 : -1; |
|
|
|
|
|
|
|
using (PixelAccessor<Rgba32> sourcePixels = image.Lock()) |
|
|
|
using (PixelAccessor<TPixel> 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]); |
|
|
|
Assert.Equal(red, sourcePixels[startX, startY]); |
|
|
|
Assert.Equal(yellow, sourcePixels[endX, endY]); |
|
|
|
|
|
|
|
for (int i = 0; i < size; i++) |
|
|
|
for (int i = 0; i < image.Height; i++) |
|
|
|
{ |
|
|
|
// it's diagonal, so for any (a, a) on the gradient line, for all (a-x, b+x) - +/- depending on the diagonal direction - must be the same color)
|
|
|
|
TPixel colorOnDiagonal = sourcePixels[i, i]; |
|
|
|
int orthoCount = 0; |
|
|
|
for (int offset = -orthoCount; offset < orthoCount; offset++) |
|
|
|
{ |
|
|
|
Assert.Equal(colorOnDiagonal, sourcePixels[i + horizontalSign * offset, i + verticalSign * offset]); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
image.CompareToReferenceOutput(provider, startCorner); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
[Theory] |
|
|
|
[InlineData("a", 0, 0, 499, 499, new[] { 0f, .2f, .5f, .9f }, new[] { 0, 0, 1, 1 })] |
|
|
|
[InlineData("b", 0, 499, 499, 0, new[] { 0f, 0.2f, 0.5f, 0.9f }, new[] { 0, 1, 2, 3 })] |
|
|
|
[InlineData("c", 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f}, new[] { 0, 1, 2, 0 })] |
|
|
|
[InlineData("d", 0, 0, 499, 499, new[] { 0f, .5f, 1f}, new[]{0, 1, 3})] |
|
|
|
public void ArbitraryLinearGradientsProduceImagesVisualCheckOnly( |
|
|
|
string filenameSuffix, |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .2f, .5f, .9f }, new[] { 0, 0, 1, 1 })] |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 499, 499, 0, new[] { 0f, 0.2f, 0.5f, 0.9f }, new[] { 0, 1, 2, 3 })] |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, 499, 499, 0, 0, new[] { 0f, 0.7f, 0.8f, 0.9f}, new[] { 0, 1, 2, 0 })] |
|
|
|
[WithBlankImages(500, 500, PixelTypes.Rgba32, 0, 0, 499, 499, new[] { 0f, .5f, 1f}, new[]{0, 1, 3})] |
|
|
|
// TODO: add some more tests with arbitrary gradient orders!
|
|
|
|
public void ArbitraryGradients<TPixel>( |
|
|
|
TestImageProvider<TPixel> provider, |
|
|
|
int startX, int startY, |
|
|
|
int endX, int endY, |
|
|
|
float[] stopPositions, |
|
|
|
int[] stopColorCodes) |
|
|
|
where TPixel : struct, IPixel<TPixel> |
|
|
|
{ |
|
|
|
var colors = new Rgba32[] |
|
|
|
var colors = new [] |
|
|
|
{ |
|
|
|
Rgba32.Navy, |
|
|
|
Rgba32.LightGreen, |
|
|
|
Rgba32.Yellow, |
|
|
|
Rgba32.Red |
|
|
|
NamedColors<TPixel>.Navy, |
|
|
|
NamedColors<TPixel>.LightGreen, |
|
|
|
NamedColors<TPixel>.Yellow, |
|
|
|
NamedColors<TPixel>.Red |
|
|
|
}; |
|
|
|
|
|
|
|
var colorStops = new ColorStop<Rgba32>[stopPositions.Length]; |
|
|
|
StringBuilder coloringVariant = new StringBuilder(); |
|
|
|
var colorStops = new ColorStop<TPixel>[stopPositions.Length]; |
|
|
|
for (int i = 0; i < stopPositions.Length; i++) |
|
|
|
{ |
|
|
|
colorStops[i] = new ColorStop<Rgba32>( |
|
|
|
stopPositions[i], |
|
|
|
colors[stopColorCodes[i]]); |
|
|
|
TPixel color = colors[stopColorCodes[i % colors.Length]]; |
|
|
|
float position = stopPositions[i]; |
|
|
|
|
|
|
|
colorStops[i] = new ColorStop<TPixel>( |
|
|
|
position, |
|
|
|
color); |
|
|
|
coloringVariant.AppendFormat( |
|
|
|
CultureInfo.InvariantCulture, |
|
|
|
"{0}@{1};", |
|
|
|
color, |
|
|
|
position); |
|
|
|
} |
|
|
|
|
|
|
|
int size = 500; |
|
|
|
string variant = $"{startX},{startY}to{endX},{endY};[{coloringVariant}]"; |
|
|
|
|
|
|
|
string path = TestEnvironment.CreateOutputDirectory("Fill", "LinearGradientBrush"); |
|
|
|
using (var image = new Image<Rgba32>(size, size)) |
|
|
|
using (var image = provider.GetImage()) |
|
|
|
{ |
|
|
|
LinearGradientBrush<Rgba32> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<Rgba32>( |
|
|
|
LinearGradientBrush<TPixel> unicolorLinearGradientBrush = |
|
|
|
new LinearGradientBrush<TPixel>( |
|
|
|
new SixLabors.Primitives.Point(startX, startY), |
|
|
|
new SixLabors.Primitives.Point(endX, endY), |
|
|
|
GradientRepetitionMode.None, |
|
|
|
colorStops); |
|
|
|
|
|
|
|
image.Mutate(x => x.Fill(unicolorLinearGradientBrush)); |
|
|
|
image.Save($"{path}/arbitraryGradient_{filenameSuffix}.png"); |
|
|
|
image.DebugSave(provider, variant); |
|
|
|
image.CompareToReferenceOutput(provider, variant); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|