Browse Source

better FillSolidBrushTests + bugfix in FillProcessor

pull/555/head
Anton Firszov 8 years ago
parent
commit
ef9b350b27
  1. 2
      src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs
  2. 173
      tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs
  3. 2
      tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs
  4. 19
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs
  5. 5
      tests/ImageSharp.Tests/TestUtilities/TestUtils.cs

2
src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs

@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Drawing.Processors
sourceRectangle,
this.options))
{
amount.Span.Fill(this.options.BlendPercentage);
amount.Span.Fill(1f);
Parallel.For(
minY,

173
tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs

@ -1,79 +1,164 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing;
using SixLabors.ImageSharp.Processing.Drawing;
using SixLabors.ImageSharp.Processing.Overlays;
using SixLabors.ImageSharp.Primitives;
using SixLabors.ImageSharp.Processing.Drawing.Brushes;
using SixLabors.Shapes;
using Xunit;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Tests.Drawing
{
public class FillSolidBrushTests : FileTestBase
[GroupOutput("Drawing")]
public class FillSolidBrushTests
{
[Fact]
public void ImageShouldBeFloodFilledWithColorOnDefaultBackground()
[Theory]
[WithBlankImages(1, 1, PixelTypes.Rgba32)]
[WithBlankImages(7, 4, PixelTypes.Rgba32)]
[WithBlankImages(16, 7, PixelTypes.Rgba32)]
[WithBlankImages(33, 32, PixelTypes.Rgba32)]
[WithBlankImages(400, 500, PixelTypes.Rgba32)]
public void DoesNotDependOnSize<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush");
using (var image = new Image<Rgba32>(500, 500))
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x.Fill(Rgba32.HotPink));
image.Save($"{path}/DefaultBack.png");
using (PixelAccessor<Rgba32> sourcePixels = image.Lock())
{
Assert.Equal(Rgba32.HotPink, sourcePixels[9, 9]);
TPixel color = NamedColors<TPixel>.HotPink;
image.Mutate(c => c.Fill(color));
Assert.Equal(Rgba32.HotPink, sourcePixels[199, 149]);
}
image.DebugSave(provider, appendPixelTypeToFileName: false);
image.ComparePixelBufferTo(color);
}
}
[Fact]
public void ImageShouldBeFloodFilledWithColor()
[Theory]
[WithBlankImages(16, 16, PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector)]
public void DoesNotDependOnSinglePixelType<TPixel>(TestImageProvider<TPixel> provider)
where TPixel : struct, IPixel<TPixel>
{
string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush");
using (var image = new Image<Rgba32>(500, 500))
using (Image<TPixel> image = provider.GetImage())
{
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.Fill(Rgba32.HotPink));
image.Save($"{path}/Simple.png");
TPixel color = NamedColors<TPixel>.HotPink;
image.Mutate(c => c.Fill(color));
using (PixelAccessor<Rgba32> sourcePixels = image.Lock())
{
Assert.Equal(Rgba32.HotPink, sourcePixels[9, 9]);
Assert.Equal(Rgba32.HotPink, sourcePixels[199, 149]);
}
image.DebugSave(provider, appendSourceFileOrDescription: false);
image.ComparePixelBufferTo(color);
}
}
[Fact]
public void ImageShouldBeFloodFilledWithColorOpacity()
[Theory]
[WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, "Blue")]
[WithSolidFilledImages(16, 16, "Yellow", PixelTypes.Rgba32, "Khaki")]
public void WhenColorIsOpaque_OverridePreviousColor<TPixel>(TestImageProvider<TPixel> provider, string newColorName)
where TPixel : struct, IPixel<TPixel>
{
string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush");
using (var image = new Image<Rgba32>(500, 500))
using (Image<TPixel> image = provider.GetImage())
{
var color = new Rgba32(Rgba32.HotPink.R, Rgba32.HotPink.G, Rgba32.HotPink.B, 150);
TPixel color = TestUtils.GetPixelOfNamedColor<TPixel>(newColorName);
image.Mutate(c => c.Fill(color));
image.DebugSave(provider, newColorName, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false);
image.ComparePixelBufferTo(color);
}
}
public static readonly TheoryData<bool, string, float, PixelBlenderMode, float> BlendData =
new TheoryData<bool, string, float, PixelBlenderMode, float>()
{
{ false, "Blue", 0.5f, PixelBlenderMode.Normal, 1.0f },
{ false, "Blue", 1.0f, PixelBlenderMode.Normal, 0.5f },
{ false, "Green", 0.5f, PixelBlenderMode.Normal, 0.3f },
{ false, "HotPink", 0.8f, PixelBlenderMode.Normal, 0.8f },
{ false, "Blue", 0.5f, PixelBlenderMode.Multiply, 1.0f },
{ false, "Blue", 1.0f, PixelBlenderMode.Multiply, 0.5f },
{ false, "Green", 0.5f, PixelBlenderMode.Multiply, 0.3f },
{ false, "HotPink", 0.8f, PixelBlenderMode.Multiply, 0.8f },
{ false, "Blue", 0.5f, PixelBlenderMode.Add, 1.0f },
{ false, "Blue", 1.0f, PixelBlenderMode.Add, 0.5f },
{ false, "Green", 0.5f, PixelBlenderMode.Add, 0.3f },
{ false, "HotPink", 0.8f, PixelBlenderMode.Add, 0.8f },
image.Mutate(x => x
.BackgroundColor(Rgba32.Blue)
.Fill(color));
image.Save($"{path}/Opacity.png");
{ true, "Blue", 0.5f, PixelBlenderMode.Normal, 1.0f },
{ true, "Blue", 1.0f, PixelBlenderMode.Normal, 0.5f },
{ true, "Green", 0.5f, PixelBlenderMode.Normal, 0.3f },
{ true, "HotPink", 0.8f, PixelBlenderMode.Normal, 0.8f },
//shift background color towards forground color by the opacity amount
var mergedColor = new Rgba32(Vector4.Lerp(Rgba32.Blue.ToVector4(), Rgba32.HotPink.ToVector4(), 150f / 255f));
{ true, "Blue", 0.5f, PixelBlenderMode.Multiply, 1.0f },
{ true, "Blue", 1.0f, PixelBlenderMode.Multiply, 0.5f },
{ true, "Green", 0.5f, PixelBlenderMode.Multiply, 0.3f },
{ true, "HotPink", 0.8f, PixelBlenderMode.Multiply, 0.8f },
{ true, "Blue", 0.5f, PixelBlenderMode.Add, 1.0f },
{ true, "Blue", 1.0f, PixelBlenderMode.Add, 0.5f },
{ true, "Green", 0.5f, PixelBlenderMode.Add, 0.3f },
{ true, "HotPink", 0.8f, PixelBlenderMode.Add, 0.8f },
};
using (PixelAccessor<Rgba32> sourcePixels = image.Lock())
[Theory]
[WithSolidFilledImages(nameof(BlendData), 16, 16, "Red", PixelTypes.Rgba32)]
public void BlendFillColorOverBackround<TPixel>(
TestImageProvider<TPixel> provider,
bool triggerFillRegion,
string newColorName,
float alpha,
PixelBlenderMode blenderMode,
float blendPercentage)
where TPixel : struct, IPixel<TPixel>
{
var vec = TestUtils.GetPixelOfNamedColor<RgbaVector>(newColorName).ToVector4();
vec.W = alpha;
TPixel fillColor = default;
fillColor.PackFromVector4(vec);
using (Image<TPixel> image = provider.GetImage())
{
TPixel bgColor = image[0, 0];
var options = new GraphicsOptions(false)
{
BlenderMode = blenderMode,
BlendPercentage = blendPercentage
};
if (triggerFillRegion)
{
var region = new ShapeRegion(new RectangularPolygon(0, 0, 16, 16));
image.Mutate(c => c.Fill(options, new SolidBrush<TPixel>(fillColor), region));
}
else
{
Assert.Equal(mergedColor, sourcePixels[9, 9]);
Assert.Equal(mergedColor, sourcePixels[199, 149]);
image.Mutate(c => c.Fill(options, new SolidBrush<TPixel>(fillColor)));
}
var testOutputDetails = new
{
triggerFillRegion = triggerFillRegion,
newColorName = newColorName,
alpha = alpha,
blenderMode = blenderMode,
blendPercentage = blendPercentage
};
image.DebugSave(
provider,
testOutputDetails,
appendPixelTypeToFileName: false,
appendSourceFileOrDescription: false);
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(blenderMode);
TPixel expectedPixel = blender.Blend(bgColor, fillColor, blendPercentage);
image.ComparePixelBufferTo(expectedPixel);
}
}
}
}

2
tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs

@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.Tests
{
Guard.NotNull(colorName, nameof(colorName));
var c = (Rgba32)typeof(Rgba32).GetTypeInfo().GetField(colorName).GetValue(null);
Rgba32 c = TestUtils.GetPixelOfNamedColor<Rgba32>(colorName);
this.R = c.R;
this.G = c.G;
this.B = c.B;

19
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -346,13 +346,26 @@ namespace SixLabors.ImageSharp.Tests
Span<TPixel> expectedPixels)
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> actual = image.GetPixelSpan();
Span<TPixel> actualPixels = image.GetPixelSpan();
Assert.True(expectedPixels.Length == actual.Length, "Buffer sizes are not equal!");
Assert.True(expectedPixels.Length == actualPixels.Length, "Buffer sizes are not equal!");
for (int i = 0; i < expectedPixels.Length; i++)
{
Assert.True(expectedPixels[i].Equals(actual[i]), $"Pixels are different on position {i}!");
Assert.True(expectedPixels[i].Equals(actualPixels[i]), $"Pixels are different on position {i}!");
}
return image;
}
public static Image<TPixel> ComparePixelBufferTo<TPixel>(this Image<TPixel> image, TPixel expectedPixel)
where TPixel : struct, IPixel<TPixel>
{
Span<TPixel> actualPixels = image.GetPixelSpan();
for (int i = 0; i < actualPixels.Length; i++)
{
Assert.True(expectedPixel.Equals(actualPixels[i]), $"Pixels are different on position {i}!");
}
return image;

5
tests/ImageSharp.Tests/TestUtilities/TestUtils.cs

@ -147,6 +147,11 @@ namespace SixLabors.ImageSharp.Tests
/// <returns>The pixel types</returns>
internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes));
internal static TPixel GetPixelOfNamedColor<TPixel>(string colorName)
where TPixel : struct, IPixel<TPixel>
{
return (TPixel)typeof(NamedColors<TPixel>).GetTypeInfo().GetField(colorName).GetValue(null);
}
/// <summary>
/// Utility for testing image processor extension methods:

Loading…
Cancel
Save