// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Primitives; using SixLabors.Shapes; using Xunit; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Drawing { using System; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; [GroupOutput("Drawing")] public class FillSolidBrushTests { [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 { using (Image image = provider.GetImage()) { TPixel color = NamedColors.HotPink; image.Mutate(c => c.Fill(color)); image.DebugSave(provider, appendPixelTypeToFileName: false); image.ComparePixelBufferTo(color); } } [Theory] [WithBlankImages(16, 16, PixelTypes.Rgba32 | PixelTypes.Argb32 | PixelTypes.RgbaVector)] public void DoesNotDependOnSinglePixelType(TestImageProvider provider) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) { TPixel color = NamedColors.HotPink; image.Mutate(c => c.Fill(color)); image.DebugSave(provider, appendSourceFileOrDescription: false); image.ComparePixelBufferTo(color); } } [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 { using (Image image = provider.GetImage()) { TPixel color = TestUtils.GetPixelOfNamedColor(newColorName); image.Mutate(c => c.Fill(color)); image.DebugSave(provider, newColorName, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); image.ComparePixelBufferTo(color); } } [Theory] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 5, 7, 3, 8)] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 8, 5, 6, 4)] public void FillRegion(TestImageProvider provider, int x0, int y0, int w, int h) where TPixel : struct, IPixel { FormattableString testDetails = $"(x{x0},y{y0},w{w},h{h})"; var region = new RectangleF(x0, y0, w, h); TPixel color = TestUtils.GetPixelOfNamedColor("Blue"); provider.RunValidatingProcessorTest(c => c.Fill(color, region), testDetails, ImageComparer.Exact); } 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 }, { 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 }, { 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 }, }; [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 { 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); } } } }