From 3d8e0f3da0fd46480f07d0f2a8e6be8d1f3099c5 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Mon, 20 Aug 2018 17:41:58 +0200 Subject: [PATCH 1/9] Split PixelBlendMode enumeration into PixelColorBlendingMode and PixelAlphaCompositionMode --- .../Processing/BrushApplicator.cs | 2 +- .../Processing/DrawImageExtensions.cs | 4 +- .../Processors/Drawing/DrawImageProcessor.cs | 40 +++++++++-- .../Processors/Drawing/FillProcessor.cs | 37 +++++++--- .../Processing/TextGraphicsOptions.cs | 10 +-- .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 28 ++++---- .../Drawing/FillSolidBrushTests.cs | 68 +++++++++---------- .../Drawing/SolidFillBlendedShapesTests.cs | 24 +++---- 8 files changed, 132 insertions(+), 81 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs index 41b47a822e..770d440656 100644 --- a/src/ImageSharp.Drawing/Processing/BrushApplicator.cs +++ b/src/ImageSharp.Drawing/Processing/BrushApplicator.cs @@ -28,7 +28,7 @@ internal BrushApplicator(ImageFrame target, GraphicsOptions options) { this.Target = target; this.Options = options; - this.Blender = PixelOperations.Instance.GetPixelBlender(options.BlenderMode); + this.Blender = PixelOperations.Instance.GetPixelBlender(options); } /// diff --git a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs index 7c9d7c280a..df6080162f 100644 --- a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs @@ -33,7 +33,7 @@ public static IImageProcessingContext DrawImage(this IImageProce /// The blending mode. /// The opacity of the image to blend. Must be between 0 and 1. /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelBlenderMode blender, float opacity) + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode blender, float opacity) where TPixel : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, opacity, blender)); @@ -72,7 +72,7 @@ public static IImageProcessingContext DrawImage(this IImageProce /// The opacity of the image to blend. Must be between 0 and 1. /// The location to draw the blended image. /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelBlenderMode blender, float opacity, Point location) + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode blender, float opacity, Point location) where TPixel : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, location, opacity, blender)); diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index faf3fe7115..a114daa848 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -49,7 +49,7 @@ public DrawImageProcessor(Image image, GraphicsOptions options) /// The location to draw the blended image. /// The opacity of the image to blend. Must be between 0 and 1. public DrawImageProcessor(Image image, Point location, float opacity) - : this(image, location, opacity, GraphicsOptions.Default.BlenderMode) + : this(image, location, opacity, GraphicsOptions.Default.ColorBlendingMode) { } @@ -63,7 +63,7 @@ public DrawImageProcessor(Image image, Point location, float opacity) /// Opacity must be between 0 and 1. /// public DrawImageProcessor(Image image, Point location, GraphicsOptions options) - : this(image, location, options.BlendPercentage, options.BlenderMode) + : this(image, location, options.BlendPercentage, options.ColorBlendingMode, options.AlphaCompositionMode) { } @@ -73,9 +73,21 @@ public DrawImageProcessor(Image image, Point location, GraphicsOptions o /// The image to blend with the currently processing image. /// The opacity of the image to blend. Must be between 0 and 1. /// The blending mode to use when drawing the image. - public DrawImageProcessor(Image image, float opacity, PixelBlenderMode blenderMode) + public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode blenderMode) : this(image, Point.Empty, opacity, blenderMode) { + } + + /// + /// Initializes a new instance of the class. + /// + /// The image to blend with the currently processing image. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The Color blending mode to use when drawing the image. + /// The Alpha blending mode to use when drawing the image. + public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode blenderMode, PixelAlphaCompositionMode alphaMode) + : this(image, Point.Empty, opacity, blenderMode, alphaMode) + { } /// @@ -85,13 +97,31 @@ public DrawImageProcessor(Image image, float opacity, PixelBlenderMode b /// The location to draw the blended image. /// The opacity of the image to blend. Must be between 0 and 1. /// The blending mode to use when drawing the image. - public DrawImageProcessor(Image image, Point location, float opacity, PixelBlenderMode blenderMode) + public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode blenderMode) + { + Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + + this.Image = image; + this.Opacity = opacity; + this.Blender = PixelOperations.Instance.GetPixelBlender(blenderMode, PixelAlphaCompositionMode.SrcOver); + this.Location = location; + } + + /// + /// Initializes a new instance of the class. + /// + /// The image to blend with the currently processing image. + /// The location to draw the blended image. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The blending mode to use when drawing the image. + /// The Alpha blending mode to use when drawing the image. + public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode blenderMode, PixelAlphaCompositionMode alphaMode) { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); this.Image = image; this.Opacity = opacity; - this.Blender = PixelOperations.Instance.GetPixelBlender(blenderMode); + this.Blender = PixelOperations.Instance.GetPixelBlender(blenderMode, alphaMode); this.Location = location; } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index c9d6777ce6..7311a53da7 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -102,14 +102,35 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) { - solidBrush = this.brush as SolidBrush; - - return solidBrush != null - && ((this.options.BlenderMode == PixelBlenderMode.Normal && this.options.BlendPercentage == 1f - && solidBrush.Color.ToVector4().W == 1f) - || (this.options.BlenderMode == PixelBlenderMode.Over && this.options.BlendPercentage == 1f - && solidBrush.Color.ToVector4().W == 1f) - || (this.options.BlenderMode == PixelBlenderMode.Src)); + solidBrush = this.brush as SolidBrush; + + if (solidBrush == null) + { + return false; + } + + if (this.options.ColorBlendingMode != PixelColorBlendingMode.Normal) + { + return false; + } + + if (this.options.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver && + this.options.AlphaCompositionMode != PixelAlphaCompositionMode.Src) + { + return false; + } + + if (this.options.BlendPercentage != 1f) + { + return false; + } + + if (solidBrush.Color.ToVector4().W != 1f) + { + return false; + } + + return true; } } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs index dfad06768e..fa53706a3c 100644 --- a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs @@ -32,7 +32,7 @@ public struct TextGraphicsOptions private float? dpiY; - private PixelBlenderMode blenderMode; + private PixelColorBlendingMode blenderMode; private float wrapTextWidth; @@ -53,7 +53,7 @@ public TextGraphicsOptions(bool enableAntialiasing) this.verticalAlignment = VerticalAlignment.Top; this.antialiasSubpixelDepth = 16; - this.blenderMode = PixelBlenderMode.Normal; + this.blenderMode = PixelColorBlendingMode.Normal; this.blendPercentage = 1; this.antialias = enableAntialiasing; this.dpiX = DefaultTextDpi; @@ -82,7 +82,7 @@ public TextGraphicsOptions(bool enableAntialiasing) /// /// Gets or sets a value indicating the blending percentage to apply to the drawing operation /// - public PixelBlenderMode BlenderMode { get => this.blenderMode; set => this.blenderMode = value; } + public PixelColorBlendingMode BlenderMode { get => this.blenderMode; set => this.blenderMode = value; } /// /// Gets or sets a value indicating whether the text should be drawing with kerning enabled. @@ -135,7 +135,7 @@ public static implicit operator TextGraphicsOptions(GraphicsOptions options) { AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, blendPercentage = options.BlendPercentage, - blenderMode = options.BlenderMode + blenderMode = options.ColorBlendingMode }; } @@ -151,7 +151,7 @@ public static explicit operator GraphicsOptions(TextGraphicsOptions options) return new GraphicsOptions(options.Antialias) { AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, - BlenderMode = options.BlenderMode, + ColorBlendingMode = options.BlenderMode, BlendPercentage = options.BlendPercentage }; } diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index 40ad92adc2..f50df3b347 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -25,16 +25,16 @@ public class DrawImageTest : FileTestBase }; [Theory] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Normal)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Multiply)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Add)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Subtract)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Screen)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Darken)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Lighten)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Overlay)] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.HardLight)] - public void ImageShouldApplyDrawImage(TestImageProvider provider, PixelBlenderMode mode) + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Normal)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Multiply)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Add)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Subtract)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Screen)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Darken)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Lighten)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Overlay)] + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.HardLight)] + public void ImageShouldApplyDrawImage(TestImageProvider provider, PixelColorBlendingMode mode) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -47,8 +47,8 @@ public void ImageShouldApplyDrawImage(TestImageProvider provider } [Theory] - [WithFileCollection(nameof(TestFiles), PixelTypes, PixelBlenderMode.Normal)] - public void ImageShouldDrawTransformedImage(TestImageProvider provider, PixelBlenderMode mode) + [WithFileCollection(nameof(TestFiles), PixelTypes, PixelColorBlendingMode.Normal)] + public void ImageShouldDrawTransformedImage(TestImageProvider provider, PixelColorBlendingMode mode) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -88,7 +88,7 @@ public void ImageShouldHandleNegativeLocation(TestImageProvider provider Rgba32 backgroundPixel = background[0, 0]; Rgba32 overlayPixel = overlay[Math.Abs(xy) + 1, Math.Abs(xy) + 1]; - background.Mutate(x => x.DrawImage(overlay, PixelBlenderMode.Normal, 1F, new Point(xy, xy))); + background.Mutate(x => x.DrawImage(overlay, PixelColorBlendingMode.Normal, 1F, new Point(xy, xy))); Assert.Equal(Rgba32.White, backgroundPixel); Assert.Equal(overlayPixel, background[0, 0]); @@ -110,7 +110,7 @@ public void ImageShouldHandlePositiveLocation(TestImageProvider provider Rgba32 backgroundPixel = background[xy - 1, xy - 1]; Rgba32 overlayPixel = overlay[0, 0]; - background.Mutate(x => x.DrawImage(overlay, PixelBlenderMode.Normal, 1F, new Point(xy, xy))); + background.Mutate(x => x.DrawImage(overlay, PixelColorBlendingMode.Normal, 1F, new Point(xy, xy))); Assert.Equal(Rgba32.White, backgroundPixel); Assert.Equal(overlayPixel, background[xy, xy]); diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index 45f1340be9..e86d41f574 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -98,38 +98,38 @@ public void FillRegion_WorksOnWrappedMemoryImage(TestImageProvider BlendData = - new TheoryData() + 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 }, + { false, "Blue", 0.5f, PixelColorBlendingMode.Normal, 1.0f }, + { false, "Blue", 1.0f, PixelColorBlendingMode.Normal, 0.5f }, + { false, "Green", 0.5f, PixelColorBlendingMode.Normal, 0.3f }, + { false, "HotPink", 0.8f, PixelColorBlendingMode.Normal, 0.8f }, + + { false, "Blue", 0.5f, PixelColorBlendingMode.Multiply, 1.0f }, + { false, "Blue", 1.0f, PixelColorBlendingMode.Multiply, 0.5f }, + { false, "Green", 0.5f, PixelColorBlendingMode.Multiply, 0.3f }, + { false, "HotPink", 0.8f, PixelColorBlendingMode.Multiply, 0.8f }, + + { false, "Blue", 0.5f, PixelColorBlendingMode.Add, 1.0f }, + { false, "Blue", 1.0f, PixelColorBlendingMode.Add, 0.5f }, + { false, "Green", 0.5f, PixelColorBlendingMode.Add, 0.3f }, + { false, "HotPink", 0.8f, PixelColorBlendingMode.Add, 0.8f }, + + { true, "Blue", 0.5f, PixelColorBlendingMode.Normal, 1.0f }, + { true, "Blue", 1.0f, PixelColorBlendingMode.Normal, 0.5f }, + { true, "Green", 0.5f, PixelColorBlendingMode.Normal, 0.3f }, + { true, "HotPink", 0.8f, PixelColorBlendingMode.Normal, 0.8f }, + + { true, "Blue", 0.5f, PixelColorBlendingMode.Multiply, 1.0f }, + { true, "Blue", 1.0f, PixelColorBlendingMode.Multiply, 0.5f }, + { true, "Green", 0.5f, PixelColorBlendingMode.Multiply, 0.3f }, + { true, "HotPink", 0.8f, PixelColorBlendingMode.Multiply, 0.8f }, + + { true, "Blue", 0.5f, PixelColorBlendingMode.Add, 1.0f }, + { true, "Blue", 1.0f, PixelColorBlendingMode.Add, 0.5f }, + { true, "Green", 0.5f, PixelColorBlendingMode.Add, 0.3f }, + { true, "HotPink", 0.8f, PixelColorBlendingMode.Add, 0.8f }, }; [Theory] @@ -139,7 +139,7 @@ public void BlendFillColorOverBackround( bool triggerFillRegion, string newColorName, float alpha, - PixelBlenderMode blenderMode, + PixelColorBlendingMode blenderMode, float blendPercentage) where TPixel : struct, IPixel { @@ -155,7 +155,7 @@ public void BlendFillColorOverBackround( var options = new GraphicsOptions(false) { - BlenderMode = blenderMode, + ColorBlendingMode = blenderMode, BlendPercentage = blendPercentage }; @@ -185,7 +185,7 @@ public void BlendFillColorOverBackround( appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(blenderMode); + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(blenderMode, PixelAlphaCompositionMode.SrcOver); TPixel expectedPixel = blender.Blend(bgColor, fillColor, blendPercentage); image.ComparePixelBufferTo(expectedPixel); diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index b31a18ac45..f6a5b5cdd2 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -16,13 +16,13 @@ namespace SixLabors.ImageSharp.Tests.Drawing public class SolidFillBlendedShapesTests { public static IEnumerable modes = - ((PixelBlenderMode[])Enum.GetValues(typeof(PixelBlenderMode))).Select(x => new object[] { x }); + ((PixelColorBlendingMode[])Enum.GetValues(typeof(PixelColorBlendingMode))).Select(x => new object[] { x }); [Theory] [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void _1DarkBlueRect_2BlendHotPinkRect( TestImageProvider provider, - PixelBlenderMode mode) + PixelColorBlendingMode mode) where TPixel : struct, IPixel { using (Image img = provider.GetImage()) @@ -34,7 +34,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect( NamedColors.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) ) - .Fill(new GraphicsOptions(true) { BlenderMode = mode }, + .Fill(new GraphicsOptions(true) { ColorBlendingMode = mode }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) ); @@ -47,7 +47,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect( [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( TestImageProvider provider, - PixelBlenderMode mode) + PixelColorBlendingMode mode) where TPixel : struct, IPixel { using (Image img = provider.GetImage()) @@ -60,12 +60,12 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = mode }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = mode }, NamedColors.Transparent, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); @@ -78,7 +78,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse( TestImageProvider provider, - PixelBlenderMode mode) + PixelColorBlendingMode mode) where TPixel : struct, IPixel { using (Image img = provider.GetImage()) @@ -91,7 +91,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = mode }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); var c = NamedColors.Red.ToVector4(); @@ -101,7 +101,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { BlenderMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = mode }, pixel, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); @@ -112,7 +112,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse(TestImageProvider provider, PixelBlenderMode mode) + public void _1DarkBlueRect_2BlendBlackEllipse(TestImageProvider provider, PixelColorBlendingMode mode) where TPixel : struct, IPixel { using(Image dstImg = provider.GetImage(), srcImg = provider.GetImage()) @@ -131,14 +131,14 @@ public void _1DarkBlueRect_2BlendBlackEllipse(TestImageProvider new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); dstImg.Mutate( - x => x.DrawImage(new GraphicsOptions(true) { BlenderMode = mode }, srcImg) + x => x.DrawImage(new GraphicsOptions(true) { ColorBlendingMode = mode }, srcImg) ); VerifyImage(provider, mode, dstImg); } } - private static void VerifyImage(TestImageProvider provider, PixelBlenderMode mode, Image img) + private static void VerifyImage(TestImageProvider provider, PixelColorBlendingMode mode, Image img) where TPixel : struct, IPixel { img.DebugSave( From bfc2208d44e221bed6eefa2bd7c07454d21f45c0 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Tue, 21 Aug 2018 12:35:35 +0200 Subject: [PATCH 2/9] Fixed missing Alpha Composition property in TextGraphicsOptions --- .../Processing/TextGraphicsOptions.cs | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs index fa53706a3c..3c682a761b 100644 --- a/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs +++ b/src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs @@ -32,7 +32,9 @@ public struct TextGraphicsOptions private float? dpiY; - private PixelColorBlendingMode blenderMode; + private PixelColorBlendingMode colorBlendingMode; + + private PixelAlphaCompositionMode alphaCompositionMode; private float wrapTextWidth; @@ -53,7 +55,8 @@ public TextGraphicsOptions(bool enableAntialiasing) this.verticalAlignment = VerticalAlignment.Top; this.antialiasSubpixelDepth = 16; - this.blenderMode = PixelColorBlendingMode.Normal; + this.colorBlendingMode = PixelColorBlendingMode.Normal; + this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver; this.blendPercentage = 1; this.antialias = enableAntialiasing; this.dpiX = DefaultTextDpi; @@ -80,9 +83,14 @@ public TextGraphicsOptions(bool enableAntialiasing) // some API thought post V1. /// - /// Gets or sets a value indicating the blending percentage to apply to the drawing operation + /// Gets or sets a value indicating the color blending percentage to apply to the drawing operation + /// + public PixelColorBlendingMode ColorBlendingMode { get => this.colorBlendingMode; set => this.colorBlendingMode = value; } + + /// + /// Gets or sets a value indicating the color blending percentage to apply to the drawing operation /// - public PixelColorBlendingMode BlenderMode { get => this.blenderMode; set => this.blenderMode = value; } + public PixelAlphaCompositionMode AlphaCompositionMode { get => this.alphaCompositionMode; set => this.alphaCompositionMode = value; } /// /// Gets or sets a value indicating whether the text should be drawing with kerning enabled. @@ -135,7 +143,8 @@ public static implicit operator TextGraphicsOptions(GraphicsOptions options) { AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, blendPercentage = options.BlendPercentage, - blenderMode = options.ColorBlendingMode + colorBlendingMode = options.ColorBlendingMode, + alphaCompositionMode = options.AlphaCompositionMode }; } @@ -151,7 +160,8 @@ public static explicit operator GraphicsOptions(TextGraphicsOptions options) return new GraphicsOptions(options.Antialias) { AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, - ColorBlendingMode = options.BlenderMode, + ColorBlendingMode = options.ColorBlendingMode, + AlphaCompositionMode = options.AlphaCompositionMode, BlendPercentage = options.BlendPercentage }; } From 753cbbcb060f7406f5691717888afde9d05cb4ea Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Tue, 21 Aug 2018 15:56:49 +0200 Subject: [PATCH 3/9] refactored DrawImageProcessor methods --- .../Processors/Drawing/DrawImageProcessor.cs | 67 +++++++++---------- 1 file changed, 31 insertions(+), 36 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index a114daa848..760086183e 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -40,6 +40,29 @@ public DrawImageProcessor(Image image, float opacity) public DrawImageProcessor(Image image, GraphicsOptions options) : this(image, Point.Empty, options) { + } + + /// + /// Initializes a new instance of the class. + /// + /// The image to blend with the currently processing image. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The blending mode to use when drawing the image. + public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode colorBlendingMode) + : this(image, Point.Empty, opacity, colorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The image to blend with the currently processing image. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The Color blending mode to use when drawing the image. + /// The Alpha blending mode to use when drawing the image. + public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode) + : this(image, Point.Empty, opacity, colorBlendingMode, alphaCompositionMode) + { } /// @@ -49,7 +72,7 @@ public DrawImageProcessor(Image image, GraphicsOptions options) /// The location to draw the blended image. /// The opacity of the image to blend. Must be between 0 and 1. public DrawImageProcessor(Image image, Point location, float opacity) - : this(image, location, opacity, GraphicsOptions.Default.ColorBlendingMode) + : this(image, location, opacity, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode) { } @@ -65,46 +88,18 @@ public DrawImageProcessor(Image image, Point location, float opacity) public DrawImageProcessor(Image image, Point location, GraphicsOptions options) : this(image, location, options.BlendPercentage, options.ColorBlendingMode, options.AlphaCompositionMode) { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The blending mode to use when drawing the image. - public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode blenderMode) - : this(image, Point.Empty, opacity, blenderMode) - { } - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The Color blending mode to use when drawing the image. - /// The Alpha blending mode to use when drawing the image. - public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode blenderMode, PixelAlphaCompositionMode alphaMode) - : this(image, Point.Empty, opacity, blenderMode, alphaMode) - { - } - /// /// Initializes a new instance of the class. /// /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The opacity of the image to blend. Must be between 0 and 1. - /// The blending mode to use when drawing the image. - public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode blenderMode) + /// The blending mode to use when drawing the image. + public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode colorBlendingMode) + : this(image, location, opacity, colorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode) { - Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - this.Image = image; - this.Opacity = opacity; - this.Blender = PixelOperations.Instance.GetPixelBlender(blenderMode, PixelAlphaCompositionMode.SrcOver); - this.Location = location; } /// @@ -113,15 +108,15 @@ public DrawImageProcessor(Image image, Point location, float opacity, Pi /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The opacity of the image to blend. Must be between 0 and 1. - /// The blending mode to use when drawing the image. - /// The Alpha blending mode to use when drawing the image. - public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode blenderMode, PixelAlphaCompositionMode alphaMode) + /// The blending mode to use when drawing the image. + /// The Alpha blending mode to use when drawing the image. + public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode) { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); this.Image = image; this.Opacity = opacity; - this.Blender = PixelOperations.Instance.GetPixelBlender(blenderMode, alphaMode); + this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); this.Location = location; } From 44287aba0dcd78d0f3ac1f01e5ce7147ed000238 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Wed, 22 Aug 2018 09:37:09 +0200 Subject: [PATCH 4/9] rearranged DrawImage method arguments. Fixed tests accordingly --- .../Processing/DrawImageExtensions.cs | 85 +++++++++++------ .../Processors/Drawing/DrawImageProcessor.cs | 93 +------------------ .../ImageSharp.Tests/Drawing/DrawImageTest.cs | 8 +- .../Drawing/SolidFillBlendedShapesTests.cs | 2 +- 4 files changed, 67 insertions(+), 121 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs index df6080162f..8ccbe22acb 100644 --- a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs @@ -22,7 +22,7 @@ public static class DrawImageExtensions /// The . public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float opacity) where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, opacity)); + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); /// /// Draws the given image together with the current one by blending their pixels. @@ -30,63 +30,92 @@ public static IImageProcessingContext DrawImage(this IImageProce /// The pixel format. /// The image this method extends. /// The image to blend with the currently processing image. - /// The blending mode. + /// The blending mode. /// The opacity of the image to blend. Must be between 0 and 1. /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode blender, float opacity) + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, float opacity) where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, opacity, blender)); - + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + /// /// Draws the given image together with the current one by blending their pixels. /// /// The pixel format. /// The image this method extends. - /// The options, including the blending type and blending amount. /// The image to blend with the currently processing image. + /// The color blending mode. + /// The alpha composition mode. + /// The opacity of the image to blend. Must be between 0 and 1. /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, GraphicsOptions options, Image image) + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, options)); - + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, alphaComposition, opacity)); + /// /// Draws the given image together with the current one by blending their pixels. /// - /// The image this method extends. + /// The pixel format. + /// The image this method extends. /// The image to blend with the currently processing image. + /// The options, including the blending type and blending amount. + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, GraphicsOptions options) + where TPixel : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); + + /// + /// Draws the given image together with the current one by blending their pixels. + /// /// The pixel format. - /// The opacity of the image to blend. Must be between 0 and 1. + /// The image this method extends. + /// The image to blend with the currently processing image. /// The location to draw the blended image. + /// The opacity of the image to blend. Must be between 0 and 1. /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float opacity, Point location) + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, float opacity) where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, opacity)); - + => source.ApplyProcessor(new DrawImageProcessor(image, location, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + /// /// Draws the given image together with the current one by blending their pixels. - /// - /// The image this method extends. - /// The image to blend with the currently processing image. + /// /// The pixel format. - /// The type of bending to apply. - /// The opacity of the image to blend. Must be between 0 and 1. + /// The image this method extends. + /// The image to blend with the currently processing image. /// The location to draw the blended image. + /// The color blending to apply. + /// The opacity of the image to blend. Must be between 0 and 1. /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode blender, float opacity, Point location) + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, float opacity) where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, opacity, blender)); - + => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + /// /// Draws the given image together with the current one by blending their pixels. - /// - /// The image this method extends. - /// The options containing the blend mode and opacity. - /// The image to blend with the currently processing image. + /// /// The pixel format. + /// The image this method extends. + /// The image to blend with the currently processing image. /// The location to draw the blended image. + /// The color blending to apply. + /// The alpha composition mode. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) + where TPixel : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, alphaComposition, opacity)); + + /// + /// Draws the given image together with the current one by blending their pixels. + /// + /// The pixel format. + /// The image this method extends. + /// The image to blend with the currently processing image. + /// The location to draw the blended image. + /// The options containing the blend mode and opacity. /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, GraphicsOptions options, Image image, Point location) + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, GraphicsOptions options) where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, options)); + => source.ApplyProcessor(new DrawImageProcessor(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index 760086183e..324d25e097 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -18,99 +18,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// The pixel format. internal class DrawImageProcessor : ImageProcessor where TPixel : struct, IPixel - { + { /// /// Initializes a new instance of the class. /// /// The image to blend with the currently processing image. - /// The opacity of the image to blend. Must be between 0 and 1. - public DrawImageProcessor(Image image, float opacity) - : this(image, Point.Empty, opacity) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// - /// The options containing the opacity of the image to blend and blending mode. - /// Opacity must be between 0 and 1. - /// - public DrawImageProcessor(Image image, GraphicsOptions options) - : this(image, Point.Empty, options) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The blending mode to use when drawing the image. - public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode colorBlendingMode) - : this(image, Point.Empty, opacity, colorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The Color blending mode to use when drawing the image. - /// The Alpha blending mode to use when drawing the image. - public DrawImageProcessor(Image image, float opacity, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode) - : this(image, Point.Empty, opacity, colorBlendingMode, alphaCompositionMode) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The location to draw the blended image. - /// The opacity of the image to blend. Must be between 0 and 1. - public DrawImageProcessor(Image image, Point location, float opacity) - : this(image, location, opacity, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The location to draw the blended image. - /// - /// The options containing the opacity of the image to blend and blending mode. - /// Opacity must be between 0 and 1. - /// - public DrawImageProcessor(Image image, Point location, GraphicsOptions options) - : this(image, location, options.BlendPercentage, options.ColorBlendingMode, options.AlphaCompositionMode) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The location to draw the blended image. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The blending mode to use when drawing the image. - public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode colorBlendingMode) - : this(image, location, opacity, colorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode) - { - } - - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. - /// The location to draw the blended image. - /// The opacity of the image to blend. Must be between 0 and 1. + /// The location to draw the blended image. /// The blending mode to use when drawing the image. - /// The Alpha blending mode to use when drawing the image. - public DrawImageProcessor(Image image, Point location, float opacity, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode) + /// The Alpha blending mode to use when drawing the image. + /// The opacity of the image to blend. Must be between 0 and 1. + public DrawImageProcessor(Image image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs index f50df3b347..740b30a8c3 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTest.cs @@ -41,7 +41,7 @@ public void ImageShouldApplyDrawImage(TestImageProvider provider using (var blend = Image.Load(TestFile.Create(TestImages.Bmp.Car).Bytes)) { blend.Mutate(x => x.Resize(image.Width / 2, image.Height / 2)); - image.Mutate(x => x.DrawImage(blend, mode, .75f, new Point(image.Width / 4, image.Height / 4))); + image.Mutate(x => x.DrawImage(blend, new Point(image.Width / 4, image.Height / 4), mode, .75f) ); image.DebugSave(provider, new { mode }); } } @@ -70,7 +70,7 @@ public void ImageShouldDrawTransformedImage(TestImageProvider pr new Rectangle(0, 0, destBounds.Width, destBounds.Height))); var position = new Point((image.Width - blend.Width) / 2, (image.Height - blend.Height) / 2); - image.Mutate(x => x.DrawImage(blend, mode, .75F, position)); + image.Mutate(x => x.DrawImage(blend, position, mode, .75F)); image.DebugSave(provider, new[] { "Transformed" }); } } @@ -88,7 +88,7 @@ public void ImageShouldHandleNegativeLocation(TestImageProvider provider Rgba32 backgroundPixel = background[0, 0]; Rgba32 overlayPixel = overlay[Math.Abs(xy) + 1, Math.Abs(xy) + 1]; - background.Mutate(x => x.DrawImage(overlay, PixelColorBlendingMode.Normal, 1F, new Point(xy, xy))); + background.Mutate(x => x.DrawImage(overlay, new Point(xy, xy), PixelColorBlendingMode.Normal, 1F)); Assert.Equal(Rgba32.White, backgroundPixel); Assert.Equal(overlayPixel, background[0, 0]); @@ -110,7 +110,7 @@ public void ImageShouldHandlePositiveLocation(TestImageProvider provider Rgba32 backgroundPixel = background[xy - 1, xy - 1]; Rgba32 overlayPixel = overlay[0, 0]; - background.Mutate(x => x.DrawImage(overlay, PixelColorBlendingMode.Normal, 1F, new Point(xy, xy))); + background.Mutate(x => x.DrawImage(overlay, new Point(xy, xy), PixelColorBlendingMode.Normal, 1F)); Assert.Equal(Rgba32.White, backgroundPixel); Assert.Equal(overlayPixel, background[xy, xy]); diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index f6a5b5cdd2..6c0efce7a1 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -131,7 +131,7 @@ public void _1DarkBlueRect_2BlendBlackEllipse(TestImageProvider new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); dstImg.Mutate( - x => x.DrawImage(new GraphicsOptions(true) { ColorBlendingMode = mode }, srcImg) + x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = mode }) ); VerifyImage(provider, mode, dstImg); From afdc5322e5c2f14a0dc4c481d5d5644f5eb934d1 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Wed, 22 Aug 2018 12:18:38 +0200 Subject: [PATCH 5/9] Updated SolidFill tests to cover all possible Blending-Composition combinations, reference images not in place yet --- .../Drawing/SolidFillBlendedShapesTests.cs | 72 ++++++++++++------- 1 file changed, 48 insertions(+), 24 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index 6c0efce7a1..3686cceb6c 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -15,14 +15,26 @@ namespace SixLabors.ImageSharp.Tests.Drawing [GroupOutput("Drawing")] public class SolidFillBlendedShapesTests { - public static IEnumerable modes = - ((PixelColorBlendingMode[])Enum.GetValues(typeof(PixelColorBlendingMode))).Select(x => new object[] { x }); + public static IEnumerable modes = GetAllModeCombinations(); + + private static IEnumerable GetAllModeCombinations() + { + foreach (var blending in Enum.GetValues(typeof(PixelColorBlendingMode))) + { + foreach (var composition in Enum.GetValues(typeof(PixelAlphaCompositionMode))) + { + yield return new object[] { blending, composition }; + } + } + } + [Theory] [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void _1DarkBlueRect_2BlendHotPinkRect( TestImageProvider provider, - PixelColorBlendingMode mode) + PixelColorBlendingMode blending, + PixelAlphaCompositionMode composition) where TPixel : struct, IPixel { using (Image img = provider.GetImage()) @@ -34,12 +46,12 @@ public void _1DarkBlueRect_2BlendHotPinkRect( NamedColors.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) ) - .Fill(new GraphicsOptions(true) { ColorBlendingMode = mode }, + .Fill(new GraphicsOptions(true) { ColorBlendingMode = blending }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) ); - VerifyImage(provider, mode, img); + VerifyImage(provider, blending, composition, img); } } @@ -47,7 +59,8 @@ public void _1DarkBlueRect_2BlendHotPinkRect( [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( TestImageProvider provider, - PixelColorBlendingMode mode) + PixelColorBlendingMode blending, + PixelAlphaCompositionMode composition) where TPixel : struct, IPixel { using (Image img = provider.GetImage()) @@ -60,17 +73,17 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = blending }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = blending }, NamedColors.Transparent, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); - VerifyImage(provider, mode, img); + VerifyImage(provider, blending, composition, img); } } @@ -78,7 +91,8 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse( TestImageProvider provider, - PixelColorBlendingMode mode) + PixelColorBlendingMode blending, + PixelAlphaCompositionMode composition) where TPixel : struct, IPixel { using (Image img = provider.GetImage()) @@ -91,7 +105,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = blending }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); var c = NamedColors.Red.ToVector4(); @@ -101,18 +115,21 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = mode }, + new GraphicsOptions(true) { ColorBlendingMode = blending }, pixel, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); - VerifyImage(provider, mode, img); ; + VerifyImage(provider, blending, composition, img); ; } } [Theory] [WithBlankImages(nameof(modes), 250, 250, PixelTypes.Rgba32)] - public void _1DarkBlueRect_2BlendBlackEllipse(TestImageProvider provider, PixelColorBlendingMode mode) + public void _1DarkBlueRect_2BlendBlackEllipse( + TestImageProvider provider, + PixelColorBlendingMode blending, + PixelAlphaCompositionMode composition) where TPixel : struct, IPixel { using(Image dstImg = provider.GetImage(), srcImg = provider.GetImage()) @@ -131,28 +148,35 @@ public void _1DarkBlueRect_2BlendBlackEllipse(TestImageProvider new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); dstImg.Mutate( - x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = mode }) + x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = blending }) ); - VerifyImage(provider, mode, dstImg); + VerifyImage(provider, blending, composition, dstImg); } } - private static void VerifyImage(TestImageProvider provider, PixelColorBlendingMode mode, Image img) + private static void VerifyImage(TestImageProvider provider, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, Image img) where TPixel : struct, IPixel { img.DebugSave( provider, - new { mode }, + new { blending }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); - var comparer = ImageComparer.TolerantPercentage(0.01f, 3); - img.CompareFirstFrameToReferenceOutput(comparer, - provider, - new { mode }, - appendPixelTypeToFileName: false, - appendSourceFileOrDescription: false); + try + { + var comparer = ImageComparer.TolerantPercentage(0.01f, 3); + img.CompareFirstFrameToReferenceOutput(comparer, + provider, + new { blending }, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + } + catch(System.IO.FileNotFoundException) + { + // temporary hack until reference images are in place. + } } } } \ No newline at end of file From 29b81eaa64697c8943e6ff79a17f05527e566552 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Wed, 22 Aug 2018 13:20:15 +0200 Subject: [PATCH 6/9] Fixing SolidFill tests again... --- .../Drawing/SolidFillBlendedShapesTests.cs | 45 ++++++++++--------- 1 file changed, 23 insertions(+), 22 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index 3686cceb6c..3a572e29dc 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -21,10 +21,14 @@ private static IEnumerable GetAllModeCombinations() { foreach (var blending in Enum.GetValues(typeof(PixelColorBlendingMode))) { + // until reference images are in place, we will only test SrcOver + yield return new object[] { blending, PixelAlphaCompositionMode.SrcOver }; + + /* foreach (var composition in Enum.GetValues(typeof(PixelAlphaCompositionMode))) { yield return new object[] { blending, composition }; - } + }*/ } } @@ -46,7 +50,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect( NamedColors.DarkBlue, new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY) ) - .Fill(new GraphicsOptions(true) { ColorBlendingMode = blending }, + .Fill(new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode=composition }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY)) ); @@ -73,12 +77,12 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendTransparentEllipse( new Rectangle(0 * scaleX, 40 * scaleY, 100 * scaleX, 20 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending }, + new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0 * scaleY, 30 * scaleX, 100 * scaleY))); img.Mutate( x => x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending }, + new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, NamedColors.Transparent, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); @@ -105,7 +109,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending }, + new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, NamedColors.HotPink, new Rectangle(20 * scaleX, 0, 30 * scaleX, 100 * scaleY))); var c = NamedColors.Red.ToVector4(); @@ -115,7 +119,7 @@ public void _1DarkBlueRect_2BlendHotPinkRect_3BlendSemiTransparentRedEllipse x.Fill( - new GraphicsOptions(true) { ColorBlendingMode = blending }, + new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }, pixel, new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY)) ); @@ -148,14 +152,18 @@ public void _1DarkBlueRect_2BlendBlackEllipse( new Shapes.EllipsePolygon(40 * scaleX, 50 * scaleY, 50 * scaleX, 50 * scaleY))); dstImg.Mutate( - x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = blending }) + x => x.DrawImage(srcImg, new GraphicsOptions(true) { ColorBlendingMode = blending, AlphaCompositionMode = composition }) ); VerifyImage(provider, blending, composition, dstImg); } } - private static void VerifyImage(TestImageProvider provider, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, Image img) + private static void VerifyImage( + TestImageProvider provider, + PixelColorBlendingMode blending, + PixelAlphaCompositionMode composition, + Image img) where TPixel : struct, IPixel { img.DebugSave( @@ -163,20 +171,13 @@ private static void VerifyImage(TestImageProvider provider, Pixe new { blending }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); - - try - { - var comparer = ImageComparer.TolerantPercentage(0.01f, 3); - img.CompareFirstFrameToReferenceOutput(comparer, - provider, - new { blending }, - appendPixelTypeToFileName: false, - appendSourceFileOrDescription: false); - } - catch(System.IO.FileNotFoundException) - { - // temporary hack until reference images are in place. - } + + var comparer = ImageComparer.TolerantPercentage(0.01f, 3); + img.CompareFirstFrameToReferenceOutput(comparer, + provider, + new { blending }, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); } } } \ No newline at end of file From e60c8f02797c36ee2f18bc783163463760993b7d Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Wed, 22 Aug 2018 14:57:45 +0200 Subject: [PATCH 7/9] fixed argument name to help reflection match the file names --- .../ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index 3a572e29dc..92cfc24343 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -161,21 +161,21 @@ public void _1DarkBlueRect_2BlendBlackEllipse( private static void VerifyImage( TestImageProvider provider, - PixelColorBlendingMode blending, + PixelColorBlendingMode mode, PixelAlphaCompositionMode composition, Image img) where TPixel : struct, IPixel { img.DebugSave( provider, - new { blending }, + new { mode }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); var comparer = ImageComparer.TolerantPercentage(0.01f, 3); img.CompareFirstFrameToReferenceOutput(comparer, provider, - new { blending }, + new { mode }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); } From f24c86549fb793ad13c0734c2340af2628e28e81 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Wed, 22 Aug 2018 16:26:52 +0200 Subject: [PATCH 8/9] Refactored IsSolidBrushWithoutBlending into GraphicsOptions so it can be called from more places, and also allows for specific tests. --- .../Processors/Drawing/FillProcessor.cs | 23 +------------------ 1 file changed, 1 insertion(+), 22 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index 7311a53da7..3285e75a7b 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -109,28 +109,7 @@ private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) return false; } - if (this.options.ColorBlendingMode != PixelColorBlendingMode.Normal) - { - return false; - } - - if (this.options.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver && - this.options.AlphaCompositionMode != PixelAlphaCompositionMode.Src) - { - return false; - } - - if (this.options.BlendPercentage != 1f) - { - return false; - } - - if (solidBrush.Color.ToVector4().W != 1f) - { - return false; - } - - return true; + return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color); } } } \ No newline at end of file From 036ef6e513a024286a31237b0f8b04e208009e3c Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Thu, 23 Aug 2018 12:26:24 +0200 Subject: [PATCH 9/9] SolidFillBlendedShapesTests now tests all composition/blending combinations. --- .../Drawing/SolidFillBlendedShapesTests.cs | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs index 92cfc24343..a8fb187ced 100644 --- a/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs +++ b/tests/ImageSharp.Tests/Drawing/SolidFillBlendedShapesTests.cs @@ -19,16 +19,12 @@ public class SolidFillBlendedShapesTests private static IEnumerable GetAllModeCombinations() { - foreach (var blending in Enum.GetValues(typeof(PixelColorBlendingMode))) + foreach (var composition in Enum.GetValues(typeof(PixelAlphaCompositionMode))) { - // until reference images are in place, we will only test SrcOver - yield return new object[] { blending, PixelAlphaCompositionMode.SrcOver }; - - /* - foreach (var composition in Enum.GetValues(typeof(PixelAlphaCompositionMode))) + foreach (var blending in Enum.GetValues(typeof(PixelColorBlendingMode))) { yield return new object[] { blending, composition }; - }*/ + } } } @@ -161,21 +157,21 @@ public void _1DarkBlueRect_2BlendBlackEllipse( private static void VerifyImage( TestImageProvider provider, - PixelColorBlendingMode mode, + PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, Image img) where TPixel : struct, IPixel { img.DebugSave( provider, - new { mode }, + new { composition, blending }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); var comparer = ImageComparer.TolerantPercentage(0.01f, 3); img.CompareFirstFrameToReferenceOutput(comparer, provider, - new { mode }, + new { composition, blending }, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); }