From ef9b350b2712be23c87f0ee7c519ab603864c2bd Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 1 May 2018 01:10:37 +0200 Subject: [PATCH] better FillSolidBrushTests + bugfix in FillProcessor --- .../Drawing/Processors/FillProcessor.cs | 2 +- .../Drawing/FillSolidBrushTests.cs | 173 +++++++++++++----- .../WithSolidFilledImagesAttribute.cs | 2 +- .../TestUtilities/TestImageExtensions.cs | 19 +- .../TestUtilities/TestUtils.cs | 5 + 5 files changed, 152 insertions(+), 49 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs index e4ef44564e..b9f9b46001 100644 --- a/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Drawing/Processors/FillProcessor.cs @@ -68,7 +68,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source sourceRectangle, this.options)) { - amount.Span.Fill(this.options.BlendPercentage); + amount.Span.Fill(1f); Parallel.For( minY, diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index 02e34092e7..83f4fbde6a 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/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(TestImageProvider provider) + where TPixel : struct, IPixel { - string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush"); - using (var image = new Image(500, 500)) + using (Image image = provider.GetImage()) { - image.Mutate(x => x.Fill(Rgba32.HotPink)); - image.Save($"{path}/DefaultBack.png"); - - using (PixelAccessor sourcePixels = image.Lock()) - { - Assert.Equal(Rgba32.HotPink, sourcePixels[9, 9]); + TPixel color = NamedColors.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(TestImageProvider provider) + where TPixel : struct, IPixel { - string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush"); - using (var image = new Image(500, 500)) + using (Image image = provider.GetImage()) { - image.Mutate(x => x - .BackgroundColor(Rgba32.Blue) - .Fill(Rgba32.HotPink)); - image.Save($"{path}/Simple.png"); + TPixel color = NamedColors.HotPink; + image.Mutate(c => c.Fill(color)); - using (PixelAccessor 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(TestImageProvider provider, string newColorName) + where TPixel : struct, IPixel { - string path = TestEnvironment.CreateOutputDirectory("Fill", "SolidBrush"); - using (var image = new Image(500, 500)) + using (Image image = provider.GetImage()) { - var color = new Rgba32(Rgba32.HotPink.R, Rgba32.HotPink.G, Rgba32.HotPink.B, 150); + TPixel color = TestUtils.GetPixelOfNamedColor(newColorName); + image.Mutate(c => c.Fill(color)); + + image.DebugSave(provider, newColorName, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); + image.ComparePixelBufferTo(color); + } + } + + public static readonly TheoryData BlendData = + new TheoryData() + { + { 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 sourcePixels = image.Lock()) + [Theory] + [WithSolidFilledImages(nameof(BlendData), 16, 16, "Red", PixelTypes.Rgba32)] + public void BlendFillColorOverBackround( + TestImageProvider provider, + bool triggerFillRegion, + string newColorName, + float alpha, + PixelBlenderMode blenderMode, + float blendPercentage) + where TPixel : struct, IPixel + { + var vec = TestUtils.GetPixelOfNamedColor(newColorName).ToVector4(); + vec.W = alpha; + + TPixel fillColor = default; + fillColor.PackFromVector4(vec); + + using (Image 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(fillColor), region)); + } + else { - Assert.Equal(mergedColor, sourcePixels[9, 9]); - Assert.Equal(mergedColor, sourcePixels[199, 149]); + image.Mutate(c => c.Fill(options, new SolidBrush(fillColor))); } + + var testOutputDetails = new + { + triggerFillRegion = triggerFillRegion, + newColorName = newColorName, + alpha = alpha, + blenderMode = blenderMode, + blendPercentage = blendPercentage + }; + + image.DebugSave( + provider, + testOutputDetails, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(blenderMode); + TPixel expectedPixel = blender.Blend(bgColor, fillColor, blendPercentage); + + image.ComparePixelBufferTo(expectedPixel); } } - } } diff --git a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs index 991f7108fe..f95db45f71 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Attributes/WithSolidFilledImagesAttribute.cs @@ -133,7 +133,7 @@ public WithSolidFilledImagesAttribute( { Guard.NotNull(colorName, nameof(colorName)); - var c = (Rgba32)typeof(Rgba32).GetTypeInfo().GetField(colorName).GetValue(null); + Rgba32 c = TestUtils.GetPixelOfNamedColor(colorName); this.R = c.R; this.G = c.G; this.B = c.B; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index c2c0eb4871..f37df48dce 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -346,13 +346,26 @@ public static Image ComparePixelBufferTo( Span expectedPixels) where TPixel : struct, IPixel { - Span actual = image.GetPixelSpan(); + Span 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 ComparePixelBufferTo(this Image image, TPixel expectedPixel) + where TPixel : struct, IPixel + { + Span 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; diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 4f9a558d47..85729acd39 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -147,6 +147,11 @@ internal static bool HasAll(this PixelTypes pixelTypes, PixelTypes flagsToCheck) /// The pixel types internal static PixelTypes[] GetAllPixelTypes() => (PixelTypes[])Enum.GetValues(typeof(PixelTypes)); + internal static TPixel GetPixelOfNamedColor(string colorName) + where TPixel : struct, IPixel + { + return (TPixel)typeof(NamedColors).GetTypeInfo().GetField(colorName).GetValue(null); + } /// /// Utility for testing image processor extension methods: