From 7277ca2a29115688b38ac541ea22711b05c7caec Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:30:22 +0200 Subject: [PATCH] DrawImageProcessor + formatting --- .../Processors/Drawing/DrawImageProcessor.cs | 178 ++++++------ .../Processors/Drawing/FillProcessor.cs | 214 +++++++-------- .../Drawing/FillPatternTests.cs | 255 +++++++++++------- .../Drawing/FillSolidBrushTests.cs | 44 +-- 4 files changed, 379 insertions(+), 312 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index 4e6018e07..add34ca36 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -1,95 +1,101 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Drawing -{ - /// - /// Combines two images together by blending the pixels. - /// +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Drawing +{ + /// + /// Combines two images together by blending the pixels. + /// /// The pixel format of destination image. - /// The pixel format os source image. - internal class DrawImageProcessor : ImageProcessor + /// The pixel format os source image. + internal class DrawImageProcessor : ImageProcessor where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel { - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. + /// + /// Initializes a new instance of the class. + /// + /// The image to blend with the currently processing image. /// 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. - /// 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)); - - this.Image = image; - this.Opacity = opacity; - this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); - this.Location = location; - } - - /// - /// Gets the image to blend - /// - public Image Image { get; } - - /// - /// Gets the opacity of the image to blend - /// - public float Opacity { get; } - - /// - /// Gets the pixel blender - /// - public PixelBlender Blender { get; } - - /// - /// Gets the location to draw the blended image - /// - public Point Location { get; } - - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - Image targetImage = this.Image; - PixelBlender blender = this.Blender; - int locationY = this.Location.Y; - - // Align start/end positions. - Rectangle bounds = targetImage.Bounds(); - - int minX = Math.Max(this.Location.X, sourceRectangle.X); - int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); - int targetX = minX - this.Location.X; - - int minY = Math.Max(this.Location.Y, sourceRectangle.Y); - int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); - - int width = maxX - minX; - + /// 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)); + + this.Image = image; + this.Opacity = opacity; + this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); + this.Location = location; + } + + /// + /// Gets the image to blend + /// + public Image Image { get; } + + /// + /// Gets the opacity of the image to blend + /// + public float Opacity { get; } + + /// + /// Gets the pixel blender + /// + public PixelBlender Blender { get; } + + /// + /// Gets the location to draw the blended image + /// + public Point Location { get; } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + Image targetImage = this.Image; + PixelBlender blender = this.Blender; + int locationY = this.Location.Y; + + // Align start/end positions. + Rectangle bounds = targetImage.Bounds(); + + int minX = Math.Max(this.Location.X, sourceRectangle.X); + int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); + int targetX = minX - this.Location.X; + + int minY = Math.Max(this.Location.Y, sourceRectangle.Y); + int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); + + int width = maxX - minX; + MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - Span background = source.GetPixelRowSpan(y).Slice(minX, width); - Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); - blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); - }); - } - } + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + + ParallelHelper.IterateRows( + workingRect, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span background = source.GetPixelRowSpan(y).Slice(minX, width); + Span foreground = + targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); + blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); + } + }); + } + } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index 3285e75a7..4f2be309b 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -1,107 +1,107 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Drawing -{ - /// - /// Using the brush as a source of pixels colors blends the brush color with source. - /// - /// The pixel format. - internal class FillProcessor : ImageProcessor - where TPixel : struct, IPixel - { - /// - /// The brush. - /// - private readonly IBrush brush; - private readonly GraphicsOptions options; - - /// - /// Initializes a new instance of the class. - /// - /// The brush to source pixel colors from. - /// The options - public FillProcessor(IBrush brush, GraphicsOptions options) - { - this.brush = brush; - this.options = options; - } - - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - - // Align start/end positions. - int minX = Math.Max(0, startX); - int maxX = Math.Min(source.Width, endX); - int minY = Math.Max(0, startY); - int maxY = Math.Min(source.Height, endY); - - int width = maxX - minX; - - // If there's no reason for blending, then avoid it. - if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) - { - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); - }); - } - else - { - // Reset offset if necessary. - if (minX > 0) - { - startX = 0; - } - - if (minY > 0) - { - startY = 0; - } - - using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) - using (BrushApplicator applicator = this.brush.CreateApplicator( - source, - sourceRectangle, - this.options)) - { - amount.GetSpan().Fill(1f); - - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - int offsetY = y - startY; - int offsetX = minX - startX; - - applicator.Apply(amount.GetSpan(), offsetX, offsetY); - }); - } - } - } - - private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) - { +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Drawing +{ + /// + /// Using the brush as a source of pixels colors blends the brush color with source. + /// + /// The pixel format. + internal class FillProcessor : ImageProcessor + where TPixel : struct, IPixel + { + /// + /// The brush. + /// + private readonly IBrush brush; + private readonly GraphicsOptions options; + + /// + /// Initializes a new instance of the class. + /// + /// The brush to source pixel colors from. + /// The options + public FillProcessor(IBrush brush, GraphicsOptions options) + { + this.brush = brush; + this.options = options; + } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + int startY = sourceRectangle.Y; + int endY = sourceRectangle.Bottom; + + // Align start/end positions. + int minX = Math.Max(0, startX); + int maxX = Math.Min(source.Width, endX); + int minY = Math.Max(0, startY); + int maxY = Math.Min(source.Height, endY); + + int width = maxX - minX; + + // If there's no reason for blending, then avoid it. + if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) + { + ParallelFor.WithConfiguration( + minY, + maxY, + configuration, + y => + { + source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); + }); + } + else + { + // Reset offset if necessary. + if (minX > 0) + { + startX = 0; + } + + if (minY > 0) + { + startY = 0; + } + + using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) + using (BrushApplicator applicator = this.brush.CreateApplicator( + source, + sourceRectangle, + this.options)) + { + amount.GetSpan().Fill(1f); + + ParallelFor.WithConfiguration( + minY, + maxY, + configuration, + y => + { + int offsetY = y - startY; + int offsetX = minX - startX; + + applicator.Apply(amount.GetSpan(), offsetX, offsetY); + }); + } + } + } + + private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) + { solidBrush = this.brush as SolidBrush; if (solidBrush == null) @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing return false; } - return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color); - } - } + return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color); + } + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs index 93715c586..b310c7afc 100644 --- a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs @@ -54,172 +54,225 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Fact] public void ImageShouldBeFloodFilledWithPercent10() { - this.Test("Percent10", Rgba32.Blue, Brushes.Percent10(Rgba32.HotPink, Rgba32.LimeGreen), + this.Test( + "Percent10", + Rgba32.Blue, + Brushes.Percent10(Rgba32.HotPink, Rgba32.LimeGreen), new[,] - { - { Rgba32.HotPink , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink , Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen} - }); + { + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithPercent10Transparent() { - Test("Percent10_Transparent", Rgba32.Blue, Brushes.Percent10(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.HotPink , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink , Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue} - }); + this.Test( + "Percent10_Transparent", + Rgba32.Blue, + Brushes.Percent10(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithPercent20() { - Test("Percent20", Rgba32.Blue, Brushes.Percent20(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.HotPink , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink , Rgba32.LimeGreen}, - { Rgba32.HotPink , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink , Rgba32.LimeGreen} - }); + this.Test( + "Percent20", + Rgba32.Blue, + Brushes.Percent20(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithPercent20_transparent() { - Test("Percent20_Transparent", Rgba32.Blue, Brushes.Percent20(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.HotPink , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink , Rgba32.Blue}, - { Rgba32.HotPink , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink , Rgba32.Blue} - }); + this.Test( + "Percent20_Transparent", + Rgba32.Blue, + Brushes.Percent20(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithHorizontal() { - Test("Horizontal", Rgba32.Blue, Brushes.Horizontal(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink}, - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen , Rgba32.LimeGreen} - }); + this.Test( + "Horizontal", + Rgba32.Blue, + Brushes.Horizontal(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithHorizontal_transparent() { - Test("Horizontal_Transparent", Rgba32.Blue, Brushes.Horizontal(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink}, - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue , Rgba32.Blue} - }); + this.Test( + "Horizontal_Transparent", + Rgba32.Blue, + Brushes.Horizontal(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue } + }); } - - [Fact] public void ImageShouldBeFloodFilledWithMin() { - Test("Min", Rgba32.Blue, Brushes.Min(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen , Rgba32.LimeGreen}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink} - }); + this.Test( + "Min", + Rgba32.Blue, + Brushes.Min(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink } + }); } [Fact] public void ImageShouldBeFloodFilledWithMin_transparent() { - Test("Min_Transparent", Rgba32.Blue, Brushes.Min(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue , Rgba32.Blue}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink}, - }); + this.Test( + "Min_Transparent", + Rgba32.Blue, + Brushes.Min(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink }, + }); } [Fact] public void ImageShouldBeFloodFilledWithVertical() { - Test("Vertical", Rgba32.Blue, Brushes.Vertical(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen} - }); + this.Test( + "Vertical", + Rgba32.Blue, + Brushes.Vertical(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithVertical_transparent() { - Test("Vertical_Transparent", Rgba32.Blue, Brushes.Vertical(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue} - }); + this.Test( + "Vertical_Transparent", + Rgba32.Blue, + Brushes.Vertical(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithForwardDiagonal() { - Test("ForwardDiagonal", Rgba32.Blue, Brushes.ForwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen} - }); + this.Test( + "ForwardDiagonal", + Rgba32.Blue, + Brushes.ForwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithForwardDiagonal_transparent() { - Test("ForwardDiagonal_Transparent", Rgba32.Blue, Brushes.ForwardDiagonal(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue} - }); + this.Test( + "ForwardDiagonal_Transparent", + Rgba32.Blue, + Brushes.ForwardDiagonal(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithBackwardDiagonal() { - Test("BackwardDiagonal", Rgba32.Blue, Brushes.BackwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink} - }); + this.Test( + "BackwardDiagonal", + Rgba32.Blue, + Brushes.BackwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink } + }); } [Fact] public void ImageShouldBeFloodFilledWithBackwardDiagonal_transparent() { - Test("BackwardDiagonal_Transparent", Rgba32.Blue, Brushes.BackwardDiagonal(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink} - }); + this.Test( + "BackwardDiagonal_Transparent", + Rgba32.Blue, + Brushes.BackwardDiagonal(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink } + }); } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index e86d41f57..32f723e72 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -1,20 +1,21 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using SixLabors.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 { @@ -55,7 +56,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Theory] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, "Blue")] [WithSolidFilledImages(16, 16, "Yellow", PixelTypes.Rgba32, "Khaki")] - public void WhenColorIsOpaque_OverridePreviousColor(TestImageProvider provider, string newColorName) + public void WhenColorIsOpaque_OverridePreviousColor( + TestImageProvider provider, + string newColorName) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -63,7 +66,11 @@ namespace SixLabors.ImageSharp.Tests.Drawing TPixel color = TestUtils.GetPixelOfNamedColor(newColorName); image.Mutate(c => c.Fill(color)); - image.DebugSave(provider, newColorName, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); + image.DebugSave( + provider, + newColorName, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); image.ComparePixelBufferTo(color); } } @@ -84,7 +91,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Theory] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 5, 7, 3, 8)] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 8, 5, 6, 4)] - public void FillRegion_WorksOnWrappedMemoryImage(TestImageProvider provider, int x0, int y0, int w, int h) + public void FillRegion_WorksOnWrappedMemoryImage( + TestImageProvider provider, + int x0, + int y0, + int w, + int h) where TPixel : struct, IPixel { FormattableString testDetails = $"(x{x0},y{y0},w{w},h{h})"; @@ -105,27 +117,22 @@ namespace SixLabors.ImageSharp.Tests.Drawing { 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 }, @@ -155,8 +162,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing var options = new GraphicsOptions(false) { - ColorBlendingMode = blenderMode, - BlendPercentage = blendPercentage + ColorBlendingMode = blenderMode, BlendPercentage = blendPercentage }; if (triggerFillRegion) @@ -185,11 +191,13 @@ namespace SixLabors.ImageSharp.Tests.Drawing appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(blenderMode, PixelAlphaCompositionMode.SrcOver); + PixelBlender blender = PixelOperations.Instance.GetPixelBlender( + blenderMode, + PixelAlphaCompositionMode.SrcOver); TPixel expectedPixel = blender.Blend(bgColor, fillColor, blendPercentage); image.ComparePixelBufferTo(expectedPixel); } } } -} +} \ No newline at end of file