diff --git a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs index c72e8cfb7..e469af18b 100644 --- a/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/ProcessingExtensions.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing /// The pixel format. /// The image to mutate. /// The operation to perform on the source. - public static void Mutate(this Image source, Action> operation) + public static void Mutate(this Image source, Action operation) where TPixel : struct, IPixel { Guard.NotNull(operation, nameof(operation)); @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.Processing /// The pixel format. /// The image to mutate. /// The operations to perform on the source. - public static void Mutate(this Image source, params IImageProcessor[] operations) + public static void Mutate(this Image source, params IImageProcessor[] operations) where TPixel : struct, IPixel { Guard.NotNull(operations, nameof(operations)); @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing /// The image to clone. /// The operation to perform on the clone. /// The new - public static Image Clone(this Image source, Action> operation) + public static Image Clone(this Image source, Action operation) where TPixel : struct, IPixel { Guard.NotNull(operation, nameof(operation)); @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Processing /// The image to clone. /// The operations to perform on the clone. /// The new - public static Image Clone(this Image source, params IImageProcessor[] operations) + public static Image Clone(this Image source, params IImageProcessor[] operations) where TPixel : struct, IPixel { Guard.NotNull(operations, nameof(operations)); @@ -122,14 +122,12 @@ namespace SixLabors.ImageSharp.Processing /// /// Applies the given collection against the context /// - /// The pixel format. /// The image processing context. /// The operations to perform on the source. /// The to allow chaining of operations. - public static IImageProcessingContext ApplyProcessors(this IImageProcessingContext source, params IImageProcessor[] operations) - where TPixel : struct, IPixel + public static IImageProcessingContext ApplyProcessors(this IImageProcessingContext source, params IImageProcessor[] operations) { - foreach (IImageProcessor p in operations) + foreach (IImageProcessor p in operations) { source = source.ApplyProcessor(p); } diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs index 28f410e7d..0982db334 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawText.cs @@ -55,8 +55,14 @@ namespace SixLabors.ImageSharp.Benchmarks image.Mutate(x => DrawTextOldVersion(x, new TextGraphicsOptions(true) { WrapTextWidth = 780 }, TextToRender, font, Processing.Brushes.Solid(Rgba32.HotPink), null, new SixLabors.Primitives.PointF(10, 10))); } - IImageProcessingContext DrawTextOldVersion(IImageProcessingContext source, TextGraphicsOptions options, string text, SixLabors.Fonts.Font font, IBrush brush, IPen pen, SixLabors.Primitives.PointF location) - where TPixel : struct, IPixel + IImageProcessingContext DrawTextOldVersion( + IImageProcessingContext source, + TextGraphicsOptions options, + string text, + SixLabors.Fonts.Font font, + IBrush brush, + IPen pen, + SixLabors.Primitives.PointF location) { float dpiX = 72; float dpiY = 72; diff --git a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs index 658590e2d..c5c1ba5ac 100644 --- a/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs +++ b/tests/ImageSharp.Benchmarks/Drawing/DrawTextOutline.cs @@ -64,15 +64,14 @@ namespace SixLabors.ImageSharp.Benchmarks new SixLabors.Primitives.PointF(10, 10))); } - IImageProcessingContext DrawTextOldVersion( - IImageProcessingContext source, + IImageProcessingContext DrawTextOldVersion( + IImageProcessingContext source, TextGraphicsOptions options, string text, SixLabors.Fonts.Font font, IBrush brush, IPen pen, SixLabors.Primitives.PointF location) - where TPixel : struct, IPixel { var style = new SixLabors.Fonts.RendererOptions(font, options.DpiX, options.DpiY, location) { diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index cf47202cc..172e24372 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -91,12 +91,12 @@ namespace SixLabors.ImageSharp.Benchmarks } } - protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx); + protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx); } public class Resize_Bicubic_Rgba32 : ResizeBenchmarkBase { - protected override void ExecuteResizeOperation(IImageProcessingContext ctx) + protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Benchmarks public class Resize_Bicubic_Bgra32 : ResizeBenchmarkBase { - protected override void ExecuteResizeOperation(IImageProcessingContext ctx) + protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } @@ -171,7 +171,7 @@ namespace SixLabors.ImageSharp.Benchmarks public class Resize_Bicubic_Rgb24 : ResizeBenchmarkBase { - protected override void ExecuteResizeOperation(IImageProcessingContext ctx) + protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic); } @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.Benchmarks public class Resize_BicubicCompand_Rgba32 : ResizeBenchmarkBase { - protected override void ExecuteResizeOperation(IImageProcessingContext ctx) + protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { ctx.Resize(this.DestSize, this.DestSize, KnownResamplers.Bicubic, true); } diff --git a/tests/ImageSharp.Tests/ImageOperationTests.cs b/tests/ImageSharp.Tests/ImageOperationTests.cs index e694f0b64..b99ad64b2 100644 --- a/tests/ImageSharp.Tests/ImageOperationTests.cs +++ b/tests/ImageSharp.Tests/ImageOperationTests.cs @@ -21,14 +21,21 @@ namespace SixLabors.ImageSharp.Tests { private readonly Image image; private readonly FakeImageOperationsProvider provider; - private readonly IImageProcessor processor; + private readonly IImageProcessor processorImplementation; + + private readonly IImageProcessor processorDefinition; public Configuration Configuration { get; private set; } public ImageOperationTests() { this.provider = new FakeImageOperationsProvider(); - this.processor = new Mock>().Object; + this.processorImplementation = new Mock>().Object; + + Mock processorMock = new Mock(); + processorMock.Setup(p => p.CreatePixelSpecificProcessor()).Returns(this.processorImplementation); + this.processorDefinition = processorMock.Object; + this.image = new Image(new Configuration() { ImageOperationsProvider = this.provider @@ -38,61 +45,61 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void MutateCallsImageOperationsProvider_Func_OriginalImage() { - this.image.Mutate(x => x.ApplyProcessor(this.processor)); + this.image.Mutate(x => x.ApplyProcessor(this.processorDefinition)); Assert.True(this.provider.HasCreated(this.image)); - Assert.Contains(this.processor, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); + Assert.Contains(this.processorImplementation, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); } [Fact] public void MutateCallsImageOperationsProvider_ListOfProcessors_OriginalImage() { - this.image.Mutate(this.processor); + this.image.Mutate(this.processorDefinition); Assert.True(this.provider.HasCreated(this.image)); - Assert.Contains(this.processor, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); + Assert.Contains(this.processorImplementation, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); } [Fact] public void CloneCallsImageOperationsProvider_Func_WithDuplicateImage() { - Image returned = this.image.Clone(x => x.ApplyProcessor(this.processor)); + Image returned = this.image.Clone(x => x.ApplyProcessor(this.processorDefinition)); Assert.True(this.provider.HasCreated(returned)); - Assert.Contains(this.processor, this.provider.AppliedOperations(returned).Select(x => x.GenericProcessor)); + Assert.Contains(this.processorImplementation, this.provider.AppliedOperations(returned).Select(x => x.GenericProcessor)); } [Fact] public void CloneCallsImageOperationsProvider_ListOfProcessors_WithDuplicateImage() { - Image returned = this.image.Clone(this.processor); + Image returned = this.image.Clone(this.processorDefinition); Assert.True(this.provider.HasCreated(returned)); - Assert.Contains(this.processor, this.provider.AppliedOperations(returned).Select(x => x.GenericProcessor)); + Assert.Contains(this.processorImplementation, this.provider.AppliedOperations(returned).Select(x => x.GenericProcessor)); } [Fact] public void CloneCallsImageOperationsProvider_Func_NotOnOrigional() { - Image returned = this.image.Clone(x => x.ApplyProcessor(this.processor)); + Image returned = this.image.Clone(x => x.ApplyProcessor(this.processorDefinition)); Assert.False(this.provider.HasCreated(this.image)); - Assert.DoesNotContain(this.processor, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); + Assert.DoesNotContain(this.processorImplementation, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); } [Fact] public void CloneCallsImageOperationsProvider_ListOfProcessors_NotOnOrigional() { - Image returned = this.image.Clone(this.processor); + Image returned = this.image.Clone(this.processorDefinition); Assert.False(this.provider.HasCreated(this.image)); - Assert.DoesNotContain(this.processor, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); + Assert.DoesNotContain(this.processorImplementation, this.provider.AppliedOperations(this.image).Select(x => x.GenericProcessor)); } [Fact] public void ApplyProcessors_ListOfProcessors_AppliesAllProcessorsToOperation() { var operations = new FakeImageOperationsProvider.FakeImageOperations(null, false); - operations.ApplyProcessors(this.processor); - Assert.Contains(this.processor, operations.Applied.Select(x => x.GenericProcessor)); + operations.ApplyProcessors(this.processorDefinition); + Assert.Contains(this.processorImplementation, operations.Applied.Select(x => x.GenericProcessor)); } public void Dispose() => this.image.Dispose(); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs index 1f939a281..0a10d0755 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/Basic1ParameterConvolutionTests.cs @@ -47,10 +47,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution ValidatorComparer); } - protected abstract void Apply(IImageProcessingContext ctx, int value) - where TPixel : struct, IPixel; + protected abstract void Apply(IImageProcessingContext ctx, int value); - protected abstract void Apply(IImageProcessingContext ctx, int value, Rectangle bounds) - where TPixel : struct, IPixel; + protected abstract void Apply(IImageProcessingContext ctx, int value, Rectangle bounds); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs index 923f9d616..a7cf9360c 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BoxBlurTest.cs @@ -9,9 +9,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution [GroupOutput("Convolution")] public class BoxBlurTest : Basic1ParameterConvolutionTests { - protected override void Apply(IImageProcessingContext ctx, int value) => ctx.BoxBlur(value); + protected override void Apply(IImageProcessingContext ctx, int value) => ctx.BoxBlur(value); - protected override void Apply(IImageProcessingContext ctx, int value, Rectangle bounds) => + protected override void Apply(IImageProcessingContext ctx, int value, Rectangle bounds) => ctx.BoxBlur(value, bounds); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs index 6307a1c51..68eb8c4f6 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianBlurTest.cs @@ -13,9 +13,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution [GroupOutput("Convolution")] public class GaussianBlurTest : Basic1ParameterConvolutionTests { - protected override void Apply(IImageProcessingContext ctx, int value) => ctx.GaussianBlur(value); + protected override void Apply(IImageProcessingContext ctx, int value) => ctx.GaussianBlur(value); - protected override void Apply(IImageProcessingContext ctx, int value, Rectangle bounds) => + protected override void Apply(IImageProcessingContext ctx, int value, Rectangle bounds) => ctx.GaussianBlur(value, bounds); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs index 29a1643b0..4b497309e 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/GaussianSharpenTest.cs @@ -12,9 +12,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution [GroupOutput("Convolution")] public class GaussianSharpenTest : Basic1ParameterConvolutionTests { - protected override void Apply(IImageProcessingContext ctx, int value) => ctx.GaussianSharpen(value); + protected override void Apply(IImageProcessingContext ctx, int value) => ctx.GaussianSharpen(value); - protected override void Apply(IImageProcessingContext ctx, int value, Rectangle bounds) => + protected override void Apply(IImageProcessingContext ctx, int value, Rectangle bounds) => ctx.GaussianSharpen(value, bounds); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 9bf9079d4..8ae298c51 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -322,11 +322,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } FormattableString testOutputDetails = $"{samplerName}-{destSizeInfo}"; - ctx.Apply( - img => img.DebugSave( - provider, - $"{testOutputDetails}-ORIGINAL", - appendPixelTypeToFileName: false)); + ctx.Resize((Size)newSize, sampler, false); return testOutputDetails; }, diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs index 15fab9b2b..8d493c7d4 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Tests /// /// Returns an instance to the test case with the necessary traits. /// - public Image GetImage(Action> operationsToApply) + public Image GetImage(Action operationsToApply) { Image img = this.GetImage(); img.Mutate(operationsToApply); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index e77b1974d..8de3a347b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -9,10 +9,13 @@ using System.Numerics; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using SixLabors.Primitives; using Xunit; @@ -21,39 +24,11 @@ namespace SixLabors.ImageSharp.Tests public static class TestImageExtensions { /// - /// TODO: This should be a common processing method! The image.Opacity(val) multiplies the alpha channel! + /// TODO: Consider adding this private processor to the library /// - /// /// - public static void MakeOpaque(this IImageProcessingContext ctx) - where TPixel : struct, IPixel - { - MemoryAllocator memoryAllocator = ctx.MemoryAllocator; - - ctx.Apply( - img => - { - Configuration configuration = img.GetConfiguration(); - using (Buffer2D temp = memoryAllocator.Allocate2D(img.Width, img.Height)) - { - Span tempSpan = temp.GetSpan(); - foreach (ImageFrame frame in img.Frames) - { - Span pixelSpan = frame.GetPixelSpan(); - - PixelOperations.Instance.ToVector4(configuration, pixelSpan, tempSpan, PixelConversionModifiers.Scale); - - for (int i = 0; i < tempSpan.Length; i++) - { - ref Vector4 v = ref tempSpan[i]; - v.W = 1F; - } - - PixelOperations.Instance.FromVector4Destructive(configuration, tempSpan, pixelSpan, PixelConversionModifiers.Scale); - } - } - }); - } + public static void MakeOpaque(this IImageProcessingContext ctx) => + ctx.ApplyProcessor(new MakeOpaqueProcessor()); public static void DebugSave( this Image image, @@ -702,5 +677,37 @@ namespace SixLabors.ImageSharp.Tests return image; } + private class MakeOpaqueProcessor : IImageProcessor + { + public IImageProcessor CreatePixelSpecificProcessor() + where TPixel : struct, IPixel + { + return new MakeOpaqueProcessor(); + } + } + + private class MakeOpaqueProcessor : ImageProcessor + where TPixel : struct, IPixel + { + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + ParallelHelper.IterateRowsWithTempBuffer(sourceRectangle, configuration, + (rows, temp) => + { + Span tempSpan = temp.Span; + for (int y = rows.Min; y < rows.Max; y++) + { + var rowSpan = source.GetPixelRowSpan(y).Slice(sourceRectangle.Left, sourceRectangle.Width); + PixelOperations.Instance.ToVector4(configuration, rowSpan, tempSpan, PixelConversionModifiers.Scale); + for (int i = 0; i < tempSpan.Length; i++) + { + ref Vector4 v = ref tempSpan[i]; + v.W = 1F; + } + PixelOperations.Instance.FromVector4Destructive(configuration, tempSpan, rowSpan, PixelConversionModifiers.Scale); + } + }); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 5db0c0828..b56ce0517 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.Tests /// internal static void RunValidatingProcessorTest( this TestImageProvider provider, - Action> process, + Action process, object testOutputDetails = null, ImageComparer comparer = null, bool appendPixelTypeToFileName = true, @@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.Tests internal static void RunValidatingProcessorTest( this TestImageProvider provider, - Func, FormattableString> processAndGetTestOutputDetails, + Func processAndGetTestOutputDetails, ImageComparer comparer = null, bool appendPixelTypeToFileName = true, bool appendSourceFileOrDescription = true) @@ -241,7 +241,7 @@ namespace SixLabors.ImageSharp.Tests public static void RunValidatingProcessorTestOnWrappedMemoryImage( this TestImageProvider provider, - Action> process, + Action process, object testOutputDetails = null, ImageComparer comparer = null, string useReferenceOutputFrom = null, @@ -291,11 +291,11 @@ namespace SixLabors.ImageSharp.Tests } /// - /// Same as but with an additional parameter passed to 'process' + /// Same as 'RunValidatingProcessorTest{TPixel}' but with an additional parameter passed to 'process' /// internal static void RunRectangleConstrainedValidatingProcessorTest( this TestImageProvider provider, - Action, Rectangle> process, + Action process, object testOutputDetails = null, ImageComparer comparer = null) where TPixel : struct, IPixel @@ -315,11 +315,11 @@ namespace SixLabors.ImageSharp.Tests } /// - /// Same as but without the 'CompareToReferenceOutput()' step. + /// Same as 'RunValidatingProcessorTest{TPixel}' but without the 'CompareToReferenceOutput()' step. /// internal static void RunProcessorTest( this TestImageProvider provider, - Action> process, + Action process, object testOutputDetails = null) where TPixel : struct, IPixel {