From 13989ac1263671dc7bcda2d47a95523500504522 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Sun, 25 Aug 2019 04:35:50 +0200 Subject: [PATCH] Processors refactoring (#983) * Added new properties to ImageProcessor * Fixed constructors for convolution processors * Fixed constructors for binarization processors * Fixed constructor for dithering processor * Fixed constructors for effects processors * Fixed constructor for filter processor * Fixed constructor for normalization processor * Fixed constructors for overlay processors * Fixed constructor for quantization processor * Fixed constructors for transforms processors * Updated CreatePixelSpecificProcessor definition * Fixed convolution processors creation * Fixed leftover dithering processor constructor * Fixed another leftover dithering processor constructor * Fixed dithering processors creation * Fixed effects processors creation * Fixed filters processor * Fixed normalization processors creation * Fixed overlays processors creation * Fixed quantizer processor creation * Fixed constructors for some remaining processors * Fixed transform processors creation * ImageProcessor class refactored * Renamed some parameters * Convolution processors refactored * Refactored filters and dithering processors * Refactored normalization processors * Overlays processors refactored * Renamed some parameters * CloningImageProcessor class refactored * Transforms processors refactored * Updated DefaultImageProcessingContext class * Src builds, tests still require updating. * Fix tests * Removed unnecessary local variable --- .../Processors/Drawing/DrawImageProcessor.cs | 16 +- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 22 ++- .../Processors/Drawing/FillProcessor.cs | 9 +- .../Drawing/FillProcessor{TPixel}.cs | 9 +- .../Processors/Drawing/FillRegionProcessor.cs | 9 +- .../Drawing/FillRegionProcessor{TPixel}.cs | 6 +- .../Processors/Text/DrawTextProcessor.cs | 8 +- .../Text/DrawTextProcessor{TPixel}.cs | 49 ++--- src/ImageSharp/Advanced/AotCompilerTools.cs | 5 +- .../DefaultImageProcessorContext.cs | 26 +-- .../Extensions/GrayscaleExtensions.cs | 6 +- .../BinaryErrorDiffusionProcessor.cs | 11 +- .../BinaryErrorDiffusionProcessor{TPixel}.cs | 15 +- .../BinaryOrderedDitherProcessor.cs | 11 +- .../BinaryOrderedDitherProcessor{TPixel}.cs | 15 +- .../Binarization/BinaryThresholdProcessor.cs | 11 +- .../BinaryThresholdProcessor{TPixel}.cs | 19 +- .../Processors/CloningImageProcessor.cs | 91 ++++----- .../Convolution/BokehBlurProcessor.cs | 5 +- .../Convolution/BokehBlurProcessor{TPixel}.cs | 23 ++- .../Convolution/BoxBlurProcessor.cs | 5 +- .../Convolution/BoxBlurProcessor{TPixel}.cs | 17 +- .../Convolution2DProcessor{TPixel}.cs | 27 +-- .../Convolution2PassProcessor{TPixel}.cs | 21 ++- .../ConvolutionProcessor{TPixel}.cs | 25 ++- .../EdgeDetector2DProcessor{TPixel}.cs | 26 ++- .../EdgeDetectorCompassProcessor{TPixel}.cs | 29 +-- .../Convolution/EdgeDetectorProcessor.cs | 7 +- .../EdgeDetectorProcessor{TPixel}.cs | 15 +- .../Convolution/GaussianBlurProcessor.cs | 9 +- .../GaussianBlurProcessor{TPixel}.cs | 17 +- .../Convolution/GaussianSharpenProcessor.cs | 9 +- .../GaussianSharpenProcessor{TPixel}.cs | 11 +- .../Convolution/KayyaliProcessor.cs | 12 +- .../Processors/Convolution/KirschProcessor.cs | 10 +- .../Convolution/Laplacian3x3Processor.cs | 8 +- .../Convolution/Laplacian5x5Processor.cs | 10 +- .../LaplacianOfGaussianProcessor.cs | 10 +- .../Convolution/PrewittProcessor.cs | 10 +- .../Convolution/RobertsCrossProcessor.cs | 15 +- .../Convolution/RobinsonProcessor.cs | 10 +- .../Processors/Convolution/ScharrProcessor.cs | 10 +- .../Processors/Convolution/SobelProcessor.cs | 10 +- .../ErrorDiffusionPaletteProcessor.cs | 9 +- .../ErrorDiffusionPaletteProcessor{TPixel}.cs | 16 +- .../OrderedDitherPaletteProcessor.cs | 9 +- .../OrderedDitherPaletteProcessor{TPixel}.cs | 16 +- .../Dithering/PaletteDitherProcessor.cs | 7 +- .../PaletteDitherProcessor{TPixel}.cs | 20 +- .../Effects/OilPaintingProcessor.cs | 9 +- .../Effects/OilPaintingProcessor{TPixel}.cs | 26 +-- .../Processors/Effects/PixelateProcessor.cs | 9 +- .../Effects/PixelateProcessor{TPixel}.cs | 19 +- .../Processors/Filters/FilterProcessor.cs | 9 +- .../Filters/FilterProcessor{TPixel}.cs | 23 ++- .../Processors/Filters/LomographProcessor.cs | 10 +- .../Filters/LomographProcessor{TPixel}.cs | 12 +- .../Processors/Filters/PolaroidProcessor.cs | 10 +- .../Filters/PolaroidProcessor{TPixel}.cs | 17 +- .../Processors/ICloningImageProcessor.cs | 14 +- .../Processing/Processors/IImageProcessor.cs | 11 +- .../Processors/IImageProcessor{TPixel}.cs | 12 +- .../Processing/Processors/ImageProcessor.cs | 76 +++++--- .../Processors/ImageProcessorExtensions.cs | 21 +-- .../AdaptiveHistogramEqualizationProcessor.cs | 12 +- ...eHistogramEqualizationProcessor{TPixel}.cs | 18 +- ...ogramEqualizationSlidingWindowProcessor.cs | 12 +- ...alizationSlidingWindowProcessor{TPixel}.cs | 30 +-- .../GlobalHistogramEqualizationProcessor.cs | 12 +- ...lHistogramEqualizationProcessor{TPixel}.cs | 19 +- .../HistogramEqualizationProcessor.cs | 7 +- .../HistogramEqualizationProcessor{TPixel}.cs | 13 +- .../Overlays/BackgroundColorProcessor.cs | 9 +- .../BackgroundColorProcessor{TPixel}.cs | 23 +-- .../Processors/Overlays/GlowProcessor.cs | 9 +- .../Overlays/GlowProcessor{TPixel}.cs | 32 ++-- .../Processors/Overlays/VignetteProcessor.cs | 9 +- .../Overlays/VignetteProcessor{TPixel}.cs | 36 ++-- .../Quantization/QuantizeProcessor.cs | 9 +- .../Quantization/QuantizeProcessor{TPixel}.cs | 10 +- .../Transforms/AffineTransformProcessor.cs | 8 +- .../AffineTransformProcessor{TPixel}.cs | 37 ++-- .../Transforms/AutoOrientProcessor.cs | 9 +- .../Transforms/AutoOrientProcessor{TPixel}.cs | 41 ++-- .../Processors/Transforms/CropProcessor.cs | 8 +- .../Transforms/CropProcessor{TPixel}.cs | 21 ++- .../Transforms/EntropyCropProcessor.cs | 7 +- .../EntropyCropProcessor{TPixel}.cs | 23 ++- .../Processors/Transforms/FlipProcessor.cs | 9 +- .../Transforms/FlipProcessor{TPixel}.cs | 17 +- .../ProjectiveTransformProcessor.cs | 8 +- .../ProjectiveTransformProcessor{TPixel}.cs | 35 ++-- .../Transforms/Resize/ResizeProcessor.cs | 8 +- .../Resize/ResizeProcessor{TPixel}.cs | 33 ++-- .../Processors/Transforms/RotateProcessor.cs | 8 +- .../Transforms/RotateProcessor{TPixel}.cs | 29 ++- .../Transforms/TransformProcessor.cs | 16 +- .../Samplers/GaussianBlur.cs | 2 +- tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 176 ------------------ .../Processors/Convolution/BokehBlurTest.cs | 23 ++- .../TestUtilities/TestImageExtensions.cs | 30 +-- 101 files changed, 961 insertions(+), 891 deletions(-) delete mode 100644 tests/ImageSharp.Benchmarks/Samplers/Glow.cs diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index 7ec359220e..dc55112c9c 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; @@ -59,10 +59,10 @@ public DrawImageProcessor( public float Opacity { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixelBg : struct, IPixel { - var visitor = new ProcessorFactoryVisitor(this); + var visitor = new ProcessorFactoryVisitor(this, source, sourceRectangle); this.Image.AcceptVisitor(visitor); return visitor.Result; } @@ -71,10 +71,14 @@ private class ProcessorFactoryVisitor : IImageVisitor where TPixelBg : struct, IPixel { private readonly DrawImageProcessor definition; + private readonly Image source; + private readonly Rectangle sourceRectangle; - public ProcessorFactoryVisitor(DrawImageProcessor definition) + public ProcessorFactoryVisitor(DrawImageProcessor definition, Image source, Rectangle sourceRectangle) { this.definition = definition; + this.source = source; + this.sourceRectangle = sourceRectangle; } public IImageProcessor Result { get; private set; } @@ -84,6 +88,8 @@ public void Visit(Image image) { this.Result = new DrawImageProcessor( image, + this.source, + this.sourceRectangle, this.definition.Location, this.definition.ColorBlendingMode, this.definition.AlphaCompositionMode, @@ -91,4 +97,4 @@ public void Visit(Image image) } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index 21599bf787..6cfa23cce6 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -20,19 +20,24 @@ internal class DrawImageProcessor : ImageProcessor where TPixelFg : struct, IPixel { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// - /// The image to blend with the currently processing image. + /// The foreground to blend with the currently processing image. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. /// 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, + Image source, + Rectangle sourceRectangle, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) + : base(source, sourceRectangle) { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); @@ -63,11 +68,11 @@ public DrawImageProcessor( public Point Location { get; } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { + Rectangle sourceRectangle = this.SourceRectangle; + Configuration configuration = this.Configuration; + Image targetImage = this.Image; PixelBlender blender = this.Blender; int locationY = this.Location.Y; @@ -101,11 +106,10 @@ protected override void OnFrameApply( 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); + Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); blender.Blend(configuration, 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 81880308cf..1d3cf35576 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Drawing { @@ -33,10 +34,10 @@ public FillProcessor(IBrush brush, GraphicsOptions options) public GraphicsOptions Options { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new FillProcessor(this); + return new FillProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs index 68aef82e2d..a7c22f6d7b 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor{TPixel}.cs @@ -21,14 +21,17 @@ internal class FillProcessor : ImageProcessor { private readonly FillProcessor definition; - public FillProcessor(FillProcessor definition) + public FillProcessor(FillProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { + Rectangle sourceRectangle = this.SourceRectangle; + Configuration configuration = this.Configuration; int startX = sourceRectangle.X; int endX = sourceRectangle.Right; int startY = sourceRectangle.Y; @@ -115,4 +118,4 @@ private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) return this.definition.Options.IsOpaqueColorWithoutBlending(solidBrush.Color); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 000fa260ab..2318f3168b 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Drawing { @@ -41,10 +42,10 @@ public FillRegionProcessor(IBrush brush, Region region, GraphicsOptions options) public GraphicsOptions Options { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new FillRegionProcessor(this); + return new FillRegionProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs index 347d243ae7..45d5015ae0 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor{TPixel}.cs @@ -23,14 +23,16 @@ internal class FillRegionProcessor : ImageProcessor { private readonly FillRegionProcessor definition; - public FillRegionProcessor(FillRegionProcessor definition) + public FillRegionProcessor(FillRegionProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { + Configuration configuration = this.Configuration; GraphicsOptions options = this.definition.Options; IBrush brush = this.definition.Brush; Region region = this.definition.Region; diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 40621ce997..775cf55abf 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -72,10 +72,10 @@ public DrawTextProcessor(TextGraphicsOptions options, string text, Font font, IB public PointF Location { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new DrawTextProcessor(this); + return new DrawTextProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs index b3c336c885..3809200d5f 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor{TPixel}.cs @@ -27,7 +27,8 @@ internal class DrawTextProcessor : ImageProcessor private readonly DrawTextProcessor definition; - public DrawTextProcessor(DrawTextProcessor definition) + public DrawTextProcessor(DrawTextProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } @@ -44,35 +45,35 @@ public DrawTextProcessor(DrawTextProcessor definition) private IBrush Brush => this.definition.Brush; - protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) + protected override void BeforeImageApply() { - base.BeforeImageApply(source, sourceRectangle); + base.BeforeImageApply(); // do everything at the image level as we are delegating the processing down to other processors var style = new RendererOptions(this.Font, this.Options.DpiX, this.Options.DpiY, this.Location) - { - ApplyKerning = this.Options.ApplyKerning, - TabWidth = this.Options.TabWidth, - WrappingWidth = this.Options.WrapTextWidth, - HorizontalAlignment = this.Options.HorizontalAlignment, - VerticalAlignment = this.Options.VerticalAlignment - }; - - this.textRenderer = new CachingGlyphRenderer(source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null); + { + ApplyKerning = this.Options.ApplyKerning, + TabWidth = this.Options.TabWidth, + WrappingWidth = this.Options.WrapTextWidth, + HorizontalAlignment = this.Options.HorizontalAlignment, + VerticalAlignment = this.Options.VerticalAlignment + }; + + this.textRenderer = new CachingGlyphRenderer(this.Source.GetMemoryAllocator(), this.Text.Length, this.Pen, this.Brush != null); this.textRenderer.Options = (GraphicsOptions)this.Options; var renderer = new TextRenderer(this.textRenderer); renderer.RenderText(this.Text, style); } - protected override void AfterImageApply(Image source, Rectangle sourceRectangle) + protected override void AfterImageApply() { - base.AfterImageApply(source, sourceRectangle); + base.AfterImageApply(); this.textRenderer?.Dispose(); this.textRenderer = null; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { // this is a no-op as we have processes all as an image, we should be able to pass out of before email apply a skip frames outcome Draw(this.textRenderer.FillOperations, this.Brush); @@ -82,7 +83,7 @@ void Draw(List operations, IBrush brush) { if (operations?.Count > 0) { - using (BrushApplicator app = brush.CreateApplicator(source, sourceRectangle, this.textRenderer.Options)) + using (BrushApplicator app = brush.CreateApplicator(source, this.SourceRectangle, this.textRenderer.Options)) { foreach (DrawingOperation operation in operations) { @@ -279,19 +280,19 @@ public void EndGlyph() if (this.renderFill) { this.FillOperations.Add(new DrawingOperation - { - Location = this.currentRenderPosition, - Map = renderData.FillMap - }); + { + Location = this.currentRenderPosition, + Map = renderData.FillMap + }); } if (this.renderOutline) { this.OutlineOperations.Add(new DrawingOperation - { - Location = this.currentRenderPosition, - Map = renderData.OutlineMap - }); + { + Location = this.currentRenderPosition, + Map = renderData.OutlineMap + }); } } diff --git a/src/ImageSharp/Advanced/AotCompilerTools.cs b/src/ImageSharp/Advanced/AotCompilerTools.cs index 439ea6de0c..8d3a074b5f 100644 --- a/src/ImageSharp/Advanced/AotCompilerTools.cs +++ b/src/ImageSharp/Advanced/AotCompilerTools.cs @@ -179,9 +179,8 @@ private static void AotCompilePixelOperations() private static void AotCompileResizeOperations() where TPixel : struct, IPixel { - var resizeProcessor = new ResizeProcessor(new ResizeOptions(), default); - var genericResizeProcessor = new ResizeProcessor((ResizeProcessor)resizeProcessor.CreatePixelSpecificProcessor()); - genericResizeProcessor.AotCreateDestination(new Image(0, 0), default); + var genericResizeProcessor = (ResizeProcessor)new ResizeProcessor(new ResizeOptions(), default).CreatePixelSpecificProcessor(new Image(0, 0), default); + genericResizeProcessor.AotCreateDestination(); } } } diff --git a/src/ImageSharp/Processing/DefaultImageProcessorContext.cs b/src/ImageSharp/Processing/DefaultImageProcessorContext.cs index d0c4c076f1..7b6fbebd12 100644 --- a/src/ImageSharp/Processing/DefaultImageProcessorContext.cs +++ b/src/ImageSharp/Processing/DefaultImageProcessorContext.cs @@ -53,43 +53,33 @@ public Image GetResultImage() /// public Size GetCurrentSize() => this.GetCurrentBounds().Size; - public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle) - { - var processorImplementation = processor.CreatePixelSpecificProcessor(); - return this.ApplyProcessor(processorImplementation, rectangle); - } - + /// public IImageProcessingContext ApplyProcessor(IImageProcessor processor) { - var processorImplementation = processor.CreatePixelSpecificProcessor(); - return this.ApplyProcessor(processorImplementation); + return this.ApplyProcessor(processor, this.GetCurrentBounds()); } - private IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle) + /// + public IImageProcessingContext ApplyProcessor(IImageProcessor processor, Rectangle rectangle) { if (!this.mutate && this.destination is null) { // This will only work if the first processor applied is the cloning one thus // realistically for this optimization to work the resize must the first processor // applied any only up processors will take the double data path. - if (processor is ICloningImageProcessor cloningImageProcessor) + if (processor.CreatePixelSpecificProcessor(this.source, rectangle) is ICloningImageProcessor cloningImageProcessor) { - this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle); + this.destination = cloningImageProcessor.CloneAndApply(); return this; } this.destination = this.source.Clone(); } - processor.Apply(this.destination, rectangle); + processor.CreatePixelSpecificProcessor(this.destination, rectangle).Apply(); return this; } - private IImageProcessingContext ApplyProcessor(IImageProcessor processor) - { - return this.ApplyProcessor(processor, this.GetCurrentBounds()); - } - private Rectangle GetCurrentBounds() => this.destination?.Bounds() ?? this.source.Bounds(); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs b/src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs index a4bfaa516c..d87c40226c 100644 --- a/src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs +++ b/src/ImageSharp/Processing/Extensions/GrayscaleExtensions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Processing.Processors; @@ -50,7 +50,7 @@ public static IImageProcessingContext Grayscale(this IImageProcessingContext sou { IImageProcessor processor = mode == GrayscaleMode.Bt709 ? (IImageProcessor)new GrayscaleBt709Processor(amount) - : new GrayscaleBt601Processor(1F); + : new GrayscaleBt601Processor(amount); source.ApplyProcessor(processor); return source; @@ -111,4 +111,4 @@ public static IImageProcessingContext Grayscale(this IImageProcessingContext sou return source; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs index 840d1c1f46..80164793b2 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Dithering; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Binarization { @@ -69,10 +70,8 @@ public BinaryErrorDiffusionProcessor(IErrorDiffuser diffuser, float threshold, C public Color LowerColor { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new BinaryErrorDiffusionProcessor(this); - } + => new BinaryErrorDiffusionProcessor(this, source, sourceRectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs index e3828aeb60..7e3458ae3e 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor{TPixel}.cs @@ -19,13 +19,20 @@ internal class BinaryErrorDiffusionProcessor : ImageProcessor { private readonly BinaryErrorDiffusionProcessor definition; - public BinaryErrorDiffusionProcessor(BinaryErrorDiffusionProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public BinaryErrorDiffusionProcessor(BinaryErrorDiffusionProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { TPixel upperColor = this.definition.UpperColor.ToPixel(); TPixel lowerColor = this.definition.LowerColor.ToPixel(); @@ -34,7 +41,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source byte threshold = (byte)MathF.Round(this.definition.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; @@ -74,4 +81,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs index 6cf1a95266..0a426c893a 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs @@ -1,10 +1,11 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Dithering; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Binarization { @@ -51,10 +52,8 @@ public BinaryOrderedDitherProcessor(IOrderedDither dither, Color upperColor, Col public Color LowerColor { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new BinaryOrderedDitherProcessor(this); - } + => new BinaryOrderedDitherProcessor(this, source, sourceRectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs index b3d174dfbe..e0aae0279f 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor{TPixel}.cs @@ -19,13 +19,20 @@ internal class BinaryOrderedDitherProcessor : ImageProcessor { private readonly BinaryOrderedDitherProcessor definition; - public BinaryOrderedDitherProcessor(BinaryOrderedDitherProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public BinaryOrderedDitherProcessor(BinaryOrderedDitherProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { IOrderedDither dither = this.definition.Dither; TPixel upperColor = this.definition.UpperColor.ToPixel(); @@ -33,7 +40,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; @@ -72,4 +79,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index 7f00d0219d..a33c464694 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Binarization { @@ -49,10 +50,8 @@ public BinaryThresholdProcessor(float threshold, Color upperColor, Color lowerCo public Color LowerColor { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new BinaryThresholdProcessor(this); - } + => new BinaryThresholdProcessor(this, source, sourceRectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs index 0d90d3647d..7234955edb 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs @@ -19,21 +19,28 @@ internal class BinaryThresholdProcessor : ImageProcessor { private readonly BinaryThresholdProcessor definition; - public BinaryThresholdProcessor(BinaryThresholdProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public BinaryThresholdProcessor(BinaryThresholdProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { byte threshold = (byte)MathF.Round(this.definition.Threshold * 255F); TPixel upper = this.definition.UpperColor.ToPixel(); TPixel lower = this.definition.LowerColor.ToPixel(); + Rectangle sourceRectangle = this.SourceRectangle; + Configuration configuration = this.Configuration; + var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; @@ -67,4 +74,4 @@ protected override void OnFrameApply( }); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs index 8150d59218..518fdf0cb1 100644 --- a/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/CloningImageProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -15,32 +15,58 @@ namespace SixLabors.ImageSharp.Processing.Processors internal abstract class CloningImageProcessor : ICloningImageProcessor where TPixel : struct, IPixel { + /// + /// Initializes a new instance of the class. + /// + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + protected CloningImageProcessor(Image source, Rectangle sourceRectangle) + { + this.Source = source; + this.SourceRectangle = sourceRectangle; + this.Configuration = this.Source.GetConfiguration(); + } + + /// + /// Gets The source for the current processor instance. + /// + protected Image Source { get; } + + /// + /// Gets The source area to process for the current processor instance. + /// + protected Rectangle SourceRectangle { get; } + + /// + /// Gets the instance to use when performing operations. + /// + protected Configuration Configuration { get; } + /// - public Image CloneAndApply(Image source, Rectangle sourceRectangle) + public Image CloneAndApply() { try { - Image clone = this.CreateDestination(source, sourceRectangle); + Image clone = this.CreateDestination(); - if (clone.Frames.Count != source.Frames.Count) + if (clone.Frames.Count != this.Source.Frames.Count) { throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames."); } - Configuration configuration = source.GetConfiguration(); - this.BeforeImageApply(source, clone, sourceRectangle); + this.BeforeImageApply(clone); - for (int i = 0; i < source.Frames.Count; i++) + for (int i = 0; i < this.Source.Frames.Count; i++) { - ImageFrame sourceFrame = source.Frames[i]; + ImageFrame sourceFrame = this.Source.Frames[i]; ImageFrame clonedFrame = clone.Frames[i]; - this.BeforeFrameApply(sourceFrame, clonedFrame, sourceRectangle, configuration); - this.OnFrameApply(sourceFrame, clonedFrame, sourceRectangle, configuration); - this.AfterFrameApply(sourceFrame, clonedFrame, sourceRectangle, configuration); + this.BeforeFrameApply(sourceFrame, clonedFrame); + this.OnFrameApply(sourceFrame, clonedFrame); + this.AfterFrameApply(sourceFrame, clonedFrame); } - this.AfterImageApply(source, clone, sourceRectangle); + this.AfterImageApply(clone); return clone; } @@ -57,40 +83,31 @@ public Image CloneAndApply(Image source, Rectangle sourceRectang } /// - public void Apply(Image source, Rectangle sourceRectangle) + public void Apply() { - using (Image cloned = this.CloneAndApply(source, sourceRectangle)) + using (Image cloned = this.CloneAndApply()) { // we now need to move the pixel data/size data from one image base to another - if (cloned.Frames.Count != source.Frames.Count) + if (cloned.Frames.Count != this.Source.Frames.Count) { throw new ImageProcessingException($"An error occurred when processing the image using {this.GetType().Name}. The processor changed the number of frames."); } - source.SwapOrCopyPixelsBuffersFrom(cloned); + this.Source.SwapOrCopyPixelsBuffersFrom(cloned); } } /// /// Generates a deep clone of the source image that operations should be applied to. /// - /// The source image. Cannot be null. - /// The source rectangle. /// The cloned image. - protected virtual Image CreateDestination(Image source, Rectangle sourceRectangle) - { - return source.Clone(); - } + protected virtual Image CreateDestination() => this.Source.Clone(); /// /// This method is called before the process is applied to prepare the processor. /// - /// The source image. Cannot be null. /// The cloned/destination image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void BeforeImageApply(Image source, Image destination, Rectangle sourceRectangle) + protected virtual void BeforeImageApply(Image destination) { } @@ -99,9 +116,7 @@ protected virtual void BeforeImageApply(Image source, Image dest /// /// The source image. Cannot be null. /// The cloned/destination image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - /// The configuration. - protected virtual void BeforeFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) + protected virtual void BeforeFrameApply(ImageFrame source, ImageFrame destination) { } @@ -111,31 +126,23 @@ protected virtual void BeforeFrameApply(ImageFrame source, ImageFrame /// The source image. Cannot be null. /// The cloned/destination image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - /// The configuration. - protected abstract void OnFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration); + protected abstract void OnFrameApply(ImageFrame source, ImageFrame destination); /// /// This method is called after the process is applied to prepare the processor. /// /// The source image. Cannot be null. /// The cloned/destination image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - /// The configuration. - protected virtual void AfterFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) + protected virtual void AfterFrameApply(ImageFrame source, ImageFrame destination) { } /// /// This method is called after the process is applied to prepare the processor. /// - /// The source image. Cannot be null. /// The cloned/destination image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// - protected virtual void AfterImageApply(Image source, Image destination, Rectangle sourceRectangle) + protected virtual void AfterImageApply(Image destination) { } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs index ede68e3191..b7e102deb5 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { @@ -112,10 +113,10 @@ public BokehBlurProcessor(int radius, int components, float gamma, BokehBlurExec public BokehBlurExecutionMode ExecutionMode { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new BokehBlurProcessor(this); + return new BokehBlurProcessor(this, source, sourceRectangle); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index a083026c37..9339c8fe43 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -75,7 +75,10 @@ internal class BokehBlurProcessor : ImageProcessor /// Initializes a new instance of the class. /// /// The defining the processor parameters. - public BokehBlurProcessor(BokehBlurProcessor definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public BokehBlurProcessor(BokehBlurProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.radius = definition.Radius; this.kernelSize = (this.radius * 2) + 1; @@ -271,36 +274,36 @@ private void NormalizeKernels() } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { // Preliminary gamma highlight pass - this.ApplyGammaExposure(source.PixelBuffer, sourceRectangle, configuration); + this.ApplyGammaExposure(source.PixelBuffer, this.SourceRectangle, this.Configuration); // Create a 0-filled buffer to use to store the result of the component convolutions - using (Buffer2D processing = configuration.MemoryAllocator.Allocate2D(source.Size(), AllocationOptions.Clean)) + using (Buffer2D processing = this.Configuration.MemoryAllocator.Allocate2D(source.Size(), AllocationOptions.Clean)) { if (this.executionMode == BokehBlurExecutionMode.PreferLowMemoryUsage) { // Memory usage priority: allocate a shared buffer and execute the second convolution in sequential mode - using (Buffer2D buffer = configuration.MemoryAllocator.Allocate2D(source.Width, source.Height + this.radius)) + using (Buffer2D buffer = this.Configuration.MemoryAllocator.Allocate2D(source.Width, source.Height + this.radius)) using (Buffer2D firstPassBuffer = buffer.Slice(this.radius, source.Height)) using (Buffer2D secondPassBuffer = buffer.Slice(0, source.Height)) { - this.OnFrameApplyCore(source, sourceRectangle, configuration, processing, firstPassBuffer, secondPassBuffer); + this.OnFrameApplyCore(source, this.SourceRectangle, this.Configuration, processing, firstPassBuffer, secondPassBuffer); } } else { // Performance priority: allocate two independent buffers and execute both convolutions in parallel mode - using (Buffer2D firstPassValues = configuration.MemoryAllocator.Allocate2D(source.Size())) - using (Buffer2D secondPassBuffer = configuration.MemoryAllocator.Allocate2D(source.Size())) + using (Buffer2D firstPassValues = this.Configuration.MemoryAllocator.Allocate2D(source.Size())) + using (Buffer2D secondPassBuffer = this.Configuration.MemoryAllocator.Allocate2D(source.Size())) { - this.OnFrameApplyCore(source, sourceRectangle, configuration, processing, firstPassValues, secondPassBuffer); + this.OnFrameApplyCore(source, this.SourceRectangle, this.Configuration, processing, firstPassValues, secondPassBuffer); } } // Apply the inverse gamma exposure pass, and write the final pixel data - this.ApplyInverseGammaExposure(source.PixelBuffer, processing, sourceRectangle, configuration); + this.ApplyInverseGammaExposure(source.PixelBuffer, processing, this.SourceRectangle, this.Configuration); } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs index 726947ac91..a5368c4639 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { @@ -40,10 +41,10 @@ public BoxBlurProcessor() public int Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new BoxBlurProcessor(this); + return new BoxBlurProcessor(this, source, sourceRectangle); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs index f4252e840d..b9ca2df0b5 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BoxBlurProcessor{TPixel}.cs @@ -20,7 +20,10 @@ internal class BoxBlurProcessor : ImageProcessor /// Initializes a new instance of the class. /// /// The defining the processor parameters. - public BoxBlurProcessor(BoxBlurProcessor definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public BoxBlurProcessor(BoxBlurProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; int kernelSize = (definition.Radius * 2) + 1; @@ -39,14 +42,8 @@ public BoxBlurProcessor(BoxBlurProcessor definition) public DenseMatrix KernelY { get; } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) => - new Convolution2PassProcessor(this.KernelX, this.KernelY, false).Apply( - source, - sourceRectangle, - configuration); + protected override void OnFrameApply(ImageFrame source) => + new Convolution2PassProcessor(this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle).Apply(source); /// /// Create a 1 dimensional Box kernel. @@ -60,4 +57,4 @@ private static DenseMatrix CreateBoxKernel(int kernelSize) return kernel; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index 299b1d41c1..b38d87cd4f 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -26,7 +26,15 @@ internal class Convolution2DProcessor : ImageProcessor /// The horizontal gradient operator. /// The vertical gradient operator. /// Whether the convolution filter is applied to alpha as well as the color channels. - public Convolution2DProcessor(in DenseMatrix kernelX, in DenseMatrix kernelY, bool preserveAlpha) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public Convolution2DProcessor( + in DenseMatrix kernelX, + in DenseMatrix kernelY, + bool preserveAlpha, + Image source, + Rectangle sourceRectangle) + : base(source, sourceRectangle) { Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same."); this.KernelX = kernelX; @@ -50,16 +58,13 @@ public Convolution2DProcessor(in DenseMatrix kernelX, in DenseMatrix - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { DenseMatrix matrixY = this.KernelY; DenseMatrix matrixX = this.KernelX; bool preserveAlpha = this.PreserveAlpha; - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; @@ -67,7 +72,7 @@ protected override void OnFrameApply( int maxY = endY - 1; int maxX = endX - 1; - using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) + using (Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) { source.CopyTo(targetPixels); @@ -76,7 +81,7 @@ protected override void OnFrameApply( ParallelHelper.IterateRowsWithTempBuffer( workingRectangle, - configuration, + this.Configuration, (rows, vectorBuffer) => { Span vectorSpan = vectorBuffer.Span; @@ -86,7 +91,7 @@ protected override void OnFrameApply( for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(this.Configuration, targetRowSpan.Slice(0, length), vectorSpan); if (preserveAlpha) { @@ -123,7 +128,7 @@ protected override void OnFrameApply( } } - PixelOperations.Instance.FromVector4Destructive(configuration, vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, targetRowSpan); } }); @@ -131,4 +136,4 @@ protected override void OnFrameApply( } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index 03268c9dda..a523f7c227 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -25,10 +25,15 @@ internal class Convolution2PassProcessor : ImageProcessor /// The horizontal gradient operator. /// The vertical gradient operator. /// Whether the convolution filter is applied to alpha as well as the color channels. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. public Convolution2PassProcessor( in DenseMatrix kernelX, in DenseMatrix kernelY, - bool preserveAlpha) + bool preserveAlpha, + Image source, + Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.KernelX = kernelX; this.KernelY = kernelY; @@ -51,13 +56,13 @@ public Convolution2PassProcessor( public bool PreserveAlpha { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { - using (Buffer2D firstPassPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) + using (Buffer2D firstPassPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size())) { - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); - this.ApplyConvolution(firstPassPixels, source.PixelBuffer, interest, this.KernelX, configuration); - this.ApplyConvolution(source.PixelBuffer, firstPassPixels, interest, this.KernelY, configuration); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); + this.ApplyConvolution(firstPassPixels, source.PixelBuffer, interest, this.KernelX, this.Configuration); + this.ApplyConvolution(source.PixelBuffer, firstPassPixels, interest, this.KernelY, this.Configuration); } } @@ -144,4 +149,4 @@ private void ApplyConvolution( }); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index 6c3b9a46f5..5bdec738d7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -24,7 +24,14 @@ internal class ConvolutionProcessor : ImageProcessor /// /// The 2d gradient operator. /// Whether the convolution filter is applied to alpha as well as the color channels. - public ConvolutionProcessor(in DenseMatrix kernelXY, bool preserveAlpha) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public ConvolutionProcessor( + in DenseMatrix kernelXY, + bool preserveAlpha, + Image source, + Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.KernelXY = kernelXY; this.PreserveAlpha = preserveAlpha; @@ -41,12 +48,12 @@ public ConvolutionProcessor(in DenseMatrix kernelXY, bool preserveAlpha) public bool PreserveAlpha { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { DenseMatrix matrix = this.KernelXY; bool preserveAlpha = this.PreserveAlpha; - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; @@ -54,7 +61,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source int maxY = endY - 1; int maxX = endX - 1; - using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) + using (Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size())) { source.CopyTo(targetPixels); @@ -63,7 +70,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source ParallelHelper.IterateRowsWithTempBuffer( workingRectangle, - configuration, + this.Configuration, (rows, vectorBuffer) => { Span vectorSpan = vectorBuffer.Span; @@ -73,7 +80,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); - PixelOperations.Instance.ToVector4(configuration, targetRowSpan.Slice(0, length), vectorSpan); + PixelOperations.Instance.ToVector4(this.Configuration, targetRowSpan.Slice(0, length), vectorSpan); if (preserveAlpha) { @@ -108,7 +115,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } - PixelOperations.Instance.FromVector4Destructive(configuration, vectorSpan, targetRowSpan); + PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, targetRowSpan); } }); @@ -116,4 +123,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs index f6771288fe..26a789cfc7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor{TPixel}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; @@ -21,7 +21,15 @@ internal class EdgeDetector2DProcessor : ImageProcessor /// The horizontal gradient operator. /// The vertical gradient operator. /// Whether to convert the image to grayscale before performing edge detection. - internal EdgeDetector2DProcessor(in DenseMatrix kernelX, in DenseMatrix kernelY, bool grayscale) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + internal EdgeDetector2DProcessor( + in DenseMatrix kernelX, + in DenseMatrix kernelY, + bool grayscale, + Image source, + Rectangle sourceRectangle) + : base(source, sourceRectangle) { Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same."); this.KernelX = kernelX; @@ -41,17 +49,17 @@ internal EdgeDetector2DProcessor(in DenseMatrix kernelX, in DenseMatrix - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - => new Convolution2DProcessor(this.KernelX, this.KernelY, true).Apply(source, sourceRectangle, configuration); - /// - protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void BeforeImageApply() { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration); + new GrayscaleBt709Processor(1F).Apply(this.Source, this.SourceRectangle); } } + + /// + protected override void OnFrameApply(ImageFrame source) + => new Convolution2DProcessor(this.KernelX, this.KernelY, true, this.Source, this.SourceRectangle).Apply(source); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index 5995ac844f..543014f6f1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -27,7 +27,10 @@ internal class EdgeDetectorCompassProcessor : ImageProcessor /// /// Gets the kernels to use. /// Whether to convert the image to grayscale before performing edge detection. - internal EdgeDetectorCompassProcessor(CompassKernels kernels, bool grayscale) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + internal EdgeDetectorCompassProcessor(CompassKernels kernels, bool grayscale, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.Grayscale = grayscale; this.Kernels = kernels; @@ -38,23 +41,23 @@ internal EdgeDetectorCompassProcessor(CompassKernels kernels, bool grayscale) private bool Grayscale { get; } /// - protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void BeforeImageApply() { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration); + new GrayscaleBt709Processor(1F).Apply(this.Source, this.SourceRectangle); } } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { DenseMatrix[] kernels = this.Kernels.Flatten(); - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + int startY = this.SourceRectangle.Y; + int endY = this.SourceRectangle.Bottom; + int startX = this.SourceRectangle.X; + int endX = this.SourceRectangle.Right; // Align start/end positions. int minX = Math.Max(0, startX); @@ -65,7 +68,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source // we need a clean copy for each pass to start from using (ImageFrame cleanCopy = source.Clone()) { - new ConvolutionProcessor(kernels[0], true).Apply(source, sourceRectangle, configuration); + new ConvolutionProcessor(kernels[0], true, this.Source, this.SourceRectangle).Apply(source); if (kernels.Length == 1) { @@ -94,14 +97,14 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source { using (ImageFrame pass = cleanCopy.Clone()) { - new ConvolutionProcessor(kernels[i], true).Apply(pass, sourceRectangle, configuration); + new ConvolutionProcessor(kernels[i], true, this.Source, this.SourceRectangle).Apply(pass); Buffer2D passPixels = pass.PixelBuffer; Buffer2D targetPixels = source.PixelBuffer; ParallelHelper.IterateRows( workingRect, - configuration, + this.Configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) @@ -132,4 +135,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs index 75be15bcc7..24b95da696 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { @@ -25,7 +26,7 @@ protected EdgeDetectorProcessor(bool grayscale) public bool Grayscale { get; } /// - public abstract IImageProcessor CreatePixelSpecificProcessor() + public abstract IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs index 041c548032..7ee9d68293 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorProcessor{TPixel}.cs @@ -20,7 +20,10 @@ internal class EdgeDetectorProcessor : ImageProcessor /// /// The 2d gradient operator. /// Whether to convert the image to grayscale before performing edge detection. - public EdgeDetectorProcessor(in DenseMatrix kernelXY, bool grayscale) + /// The source for the current processor instance. + /// The target area to process for the current processor instance. + public EdgeDetectorProcessor(in DenseMatrix kernelXY, bool grayscale, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.KernelXY = kernelXY; this.Grayscale = grayscale; @@ -34,16 +37,16 @@ public EdgeDetectorProcessor(in DenseMatrix kernelXY, bool grayscale) public DenseMatrix KernelXY { get; } /// - protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void BeforeImageApply() { if (this.Grayscale) { - new GrayscaleBt709Processor(1F).Apply(source, sourceRectangle, configuration); + new GrayscaleBt709Processor(1F).Apply(this.Source, this.SourceRectangle); } } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - => new ConvolutionProcessor(this.KernelXY, true).Apply(source, sourceRectangle, configuration); + protected override void OnFrameApply(ImageFrame source) + => new ConvolutionProcessor(this.KernelXY, true, this.Source, this.SourceRectangle).Apply(source); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs index 8504db1617..aabc8041d9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { @@ -70,10 +71,10 @@ public GaussianBlurProcessor(float sigma, int radius) public int Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new GaussianBlurProcessor(this); + return new GaussianBlurProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs index a129ff5473..da7924d031 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianBlurProcessor{TPixel}.cs @@ -18,7 +18,10 @@ internal class GaussianBlurProcessor : ImageProcessor /// Initializes a new instance of the class. /// /// The defining the processor parameters. - public GaussianBlurProcessor(GaussianBlurProcessor definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public GaussianBlurProcessor(GaussianBlurProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { int kernelSize = (definition.Radius * 2) + 1; this.KernelX = ConvolutionProcessorHelpers.CreateGaussianBlurKernel(kernelSize, definition.Sigma); @@ -36,13 +39,7 @@ public GaussianBlurProcessor(GaussianBlurProcessor definition) public DenseMatrix KernelY { get; } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) => - new Convolution2PassProcessor(this.KernelX, this.KernelY, false).Apply( - source, - sourceRectangle, - configuration); + protected override void OnFrameApply(ImageFrame source) => + new Convolution2PassProcessor(this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle).Apply(source); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs index 75acc90e0c..0262ec8e44 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution { @@ -70,10 +71,10 @@ public GaussianSharpenProcessor(float sigma, int radius) public int Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new GaussianSharpenProcessor(this); + return new GaussianSharpenProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs index edde9f9e7f..0d99ceb9c0 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/GaussianSharpenProcessor{TPixel}.cs @@ -18,7 +18,10 @@ internal class GaussianSharpenProcessor : ImageProcessor /// Initializes a new instance of the class. /// /// The defining the processor parameters. - public GaussianSharpenProcessor(GaussianSharpenProcessor definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public GaussianSharpenProcessor(GaussianSharpenProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { int kernelSize = (definition.Radius * 2) + 1; this.KernelX = ConvolutionProcessorHelpers.CreateGaussianSharpenKernel(kernelSize, definition.Sigma); @@ -36,7 +39,7 @@ public GaussianSharpenProcessor(GaussianSharpenProcessor definition) public DenseMatrix KernelY { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - => new Convolution2PassProcessor(this.KernelX, this.KernelY, false).Apply(source, sourceRectangle, configuration); + protected override void OnFrameApply(ImageFrame source) + => new Convolution2PassProcessor(this.KernelX, this.KernelY, false, this.Source, this.SourceRectangle).Apply(source); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs index 2d0f056b61..2026512617 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KayyaliProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,12 +21,14 @@ public KayyaliProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { return new EdgeDetector2DProcessor( KayyaliKernels.KayyaliX, KayyaliKernels.KayyaliY, - this.Grayscale); + this.Grayscale, + source, + sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs index 9e95344222..bbbfc64d92 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/KirschProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public KirschProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetectorCompassProcessor(new KirschKernels(), this.Grayscale); + return new EdgeDetectorCompassProcessor(new KirschKernels(), this.Grayscale, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs index ab6658f3b2..64f99ebe61 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Laplacian3x3Processor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public Laplacian3x3Processor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetectorProcessor(LaplacianKernels.Laplacian3x3, this.Grayscale); + return new EdgeDetectorProcessor(LaplacianKernels.Laplacian3x3, this.Grayscale, source, sourceRectangle); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs b/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs index fa0c8c5aa3..d1c909a941 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Laplacian5x5Processor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public Laplacian5x5Processor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetectorProcessor(LaplacianKernels.Laplacian5x5, this.Grayscale); + return new EdgeDetectorProcessor(LaplacianKernels.Laplacian5x5, this.Grayscale, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs index 2caff8201c..0eecaefe16 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/LaplacianOfGaussianProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public LaplacianOfGaussianProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetectorProcessor(LaplacianKernels.LaplacianOfGaussianXY, this.Grayscale); + return new EdgeDetectorProcessor(LaplacianKernels.LaplacianOfGaussianXY, this.Grayscale, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs index 29f6fc279c..242e3f7b97 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/PrewittProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public PrewittProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetector2DProcessor(PrewittKernels.PrewittX, PrewittKernels.PrewittY, this.Grayscale); + return new EdgeDetector2DProcessor(PrewittKernels.PrewittX, PrewittKernels.PrewittY, this.Grayscale, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs index ca7d8895a8..481a990ff9 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/RobertsCrossProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,14 @@ public RobertsCrossProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetector2DProcessor(RobertsCrossKernels.RobertsCrossX, RobertsCrossKernels.RobertsCrossY, this.Grayscale); + return new EdgeDetector2DProcessor( + RobertsCrossKernels.RobertsCrossX, + RobertsCrossKernels.RobertsCrossY, + this.Grayscale, + source, + sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs index 6f5373fae5..324ed31545 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/RobinsonProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public RobinsonProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetectorCompassProcessor(new RobinsonKernels(), this.Grayscale); + return new EdgeDetectorCompassProcessor(new RobinsonKernels(), this.Grayscale, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs index da76aa971c..6a4bf6afd5 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ScharrProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public ScharrProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetector2DProcessor(ScharrKernels.ScharrX, ScharrKernels.ScharrY, this.Grayscale); + return new EdgeDetector2DProcessor(ScharrKernels.ScharrX, ScharrKernels.ScharrY, this.Grayscale, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs index 5fb32f4e62..96ed3bcea5 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/SobelProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Convolution { /// @@ -19,9 +21,9 @@ public SobelProcessor(bool grayscale) } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new EdgeDetector2DProcessor(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale); + return new EdgeDetector2DProcessor(SobelKernels.SobelX, SobelKernels.SobelY, this.Grayscale, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs index e612b4bf03..4e45130cc3 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -57,9 +58,9 @@ public ErrorDiffusionPaletteProcessor(IErrorDiffuser diffuser, float threshold, public float Threshold { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new ErrorDiffusionPaletteProcessor(this); + return new ErrorDiffusionPaletteProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs index 7edf287e85..557a31c336 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor{TPixel}.cs @@ -16,20 +16,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering internal class ErrorDiffusionPaletteProcessor : PaletteDitherProcessor where TPixel : struct, IPixel { - public ErrorDiffusionPaletteProcessor(ErrorDiffusionPaletteProcessor definition) - : base(definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public ErrorDiffusionPaletteProcessor(ErrorDiffusionPaletteProcessor definition, Image source, Rectangle sourceRectangle) + : base(definition, source, sourceRectangle) { } private new ErrorDiffusionPaletteProcessor Definition => (ErrorDiffusionPaletteProcessor)base.Definition; /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { byte threshold = (byte)MathF.Round(this.Definition.Threshold * 255F); bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; @@ -78,4 +84,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs index ac6554d4c1..87bb3e5171 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -34,9 +35,9 @@ public OrderedDitherPaletteProcessor(IOrderedDither dither, ReadOnlyMemory - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new OrderedDitherPaletteProcessor(this); + return new OrderedDitherPaletteProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs index eefa6e5229..08eaec503d 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor{TPixel}.cs @@ -16,19 +16,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering internal class OrderedDitherPaletteProcessor : PaletteDitherProcessor where TPixel : struct, IPixel { - public OrderedDitherPaletteProcessor(OrderedDitherPaletteProcessor definition) - : base(definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public OrderedDitherPaletteProcessor(OrderedDitherPaletteProcessor definition, Image source, Rectangle sourceRectangle) + : base(definition, source, sourceRectangle) { } private new OrderedDitherPaletteProcessor Definition => (OrderedDitherPaletteProcessor)base.Definition; /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); int startY = interest.Y; int endY = interest.Bottom; int startX = interest.X; @@ -76,4 +82,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs index de798b64bc..0de964b526 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor.cs @@ -1,9 +1,10 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Dithering { @@ -27,7 +28,7 @@ protected PaletteDitherProcessor(ReadOnlyMemory palette) public ReadOnlyMemory Palette { get; } /// - public abstract IImageProcessor CreatePixelSpecificProcessor() + public abstract IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs index 205b589b1e..291e6ac0ec 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/PaletteDitherProcessor{TPixel}.cs @@ -30,26 +30,28 @@ internal abstract class PaletteDitherProcessor : ImageProcessor /// /// Initializes a new instance of the class. /// - protected PaletteDitherProcessor(PaletteDitherProcessor definition) + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + protected PaletteDitherProcessor(PaletteDitherProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.Definition = definition; } protected PaletteDitherProcessor Definition { get; } - protected override void BeforeFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + /// + protected override void BeforeFrameApply(ImageFrame source) { - base.BeforeFrameApply(source, sourceRectangle, configuration); + base.BeforeFrameApply(source); // Lazy init palette: if (this.palette is null) { ReadOnlySpan sourcePalette = this.Definition.Palette.Span; this.palette = new TPixel[sourcePalette.Length]; - Color.ToPixel(configuration, sourcePalette, this.palette); + Color.ToPixel(this.Configuration, sourcePalette, this.palette); } // Lazy init paletteVector: @@ -57,7 +59,7 @@ protected override void BeforeFrameApply( { this.paletteVector = new Vector4[this.palette.Length]; PixelOperations.Instance.ToVector4( - configuration, + this.Configuration, (ReadOnlySpan)this.palette, (Span)this.paletteVector, PixelConversionModifiers.Scale); @@ -116,4 +118,4 @@ private PixelPair GetClosestPixelPairSlow(ref TPixel pixel) return pair; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 741ba9eced..6f9e1869a3 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Effects { @@ -39,10 +40,10 @@ public OilPaintingProcessor(int levels, int brushSize) public int BrushSize { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new OilPaintingProcessor(this); + return new OilPaintingProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs index d31858ba15..ea7ba7409d 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs @@ -22,16 +22,20 @@ internal class OilPaintingProcessor : ImageProcessor { private readonly OilPaintingProcessor definition; - public OilPaintingProcessor(OilPaintingProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public OilPaintingProcessor(OilPaintingProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { int brushSize = this.definition.BrushSize; if (brushSize <= 0 || brushSize > source.Height || brushSize > source.Width) @@ -39,24 +43,24 @@ protected override void OnFrameApply( throw new ArgumentOutOfRangeException(nameof(brushSize)); } - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + int startY = this.SourceRectangle.Y; + int endY = this.SourceRectangle.Bottom; + int startX = this.SourceRectangle.X; + int endX = this.SourceRectangle.Right; int maxY = endY - 1; int maxX = endX - 1; int radius = brushSize >> 1; int levels = this.definition.Levels; - using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) + using (Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Size())) { source.CopyTo(targetPixels); var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); ParallelHelper.IterateRows( workingRect, - configuration, + this.Configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs index 1599c9dab8..2d7cef8fff 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Effects { @@ -29,10 +30,10 @@ public PixelateProcessor(int size) public int Size { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new PixelateProcessor(this); + return new PixelateProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs index 21f3bb774d..53acc351cf 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelateProcessor{TPixel}.cs @@ -25,7 +25,10 @@ internal class PixelateProcessor : ImageProcessor /// Initializes a new instance of the class. /// /// The . - public PixelateProcessor(PixelateProcessor definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public PixelateProcessor(PixelateProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } @@ -33,17 +36,17 @@ public PixelateProcessor(PixelateProcessor definition) private int Size => this.definition.Size; /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { if (this.Size <= 0 || this.Size > source.Height || this.Size > source.Width) { throw new ArgumentOutOfRangeException(nameof(this.Size)); } - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + int startY = this.SourceRectangle.Y; + int endY = this.SourceRectangle.Bottom; + int startX = this.SourceRectangle.X; + int endX = this.SourceRectangle.Right; int size = this.Size; int offset = this.Size / 2; @@ -69,7 +72,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source Parallel.ForEach( range, - configuration.GetParallelOptions(), + this.Configuration.GetParallelOptions(), y => { int offsetY = y - startY; @@ -108,4 +111,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source }); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index 36c43d8446..9cd4a9e460 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Filters { @@ -23,10 +24,10 @@ public class FilterProcessor : IImageProcessor public ColorMatrix Matrix { get; } /// - public virtual IImageProcessor CreatePixelSpecificProcessor() + public virtual IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new FilterProcessor(this); + return new FilterProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index ab60a42793..5fa233d180 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -20,22 +20,29 @@ internal class FilterProcessor : ImageProcessor { private readonly FilterProcessor definition; - public FilterProcessor(FilterProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public FilterProcessor(FilterProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { - var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); int startX = interest.X; ColorMatrix matrix = this.definition.Matrix; ParallelHelper.IterateRowsWithTempBuffer( interest, - configuration, + this.Configuration, (rows, vectorBuffer) => { for (int y = rows.Min; y < rows.Max; y++) @@ -43,13 +50,13 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source Span vectorSpan = vectorBuffer.Span; int length = vectorSpan.Length; Span rowSpan = source.GetPixelRowSpan(y).Slice(startX, length); - PixelOperations.Instance.ToVector4(configuration, rowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(this.Configuration, rowSpan, vectorSpan); Vector4Utils.Transform(vectorSpan, ref matrix); - PixelOperations.Instance.FromVector4Destructive(configuration, vectorSpan, rowSpan); + PixelOperations.Instance.FromVector4Destructive(this.Configuration, vectorSpan, rowSpan); } }); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs index f5a1befffb..fdfaa9cb07 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Filters { /// @@ -17,7 +19,7 @@ public LomographProcessor() } /// - public override IImageProcessor CreatePixelSpecificProcessor() => - new LomographProcessor(this); + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) => + new LomographProcessor(this, source, sourceRectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs index e0f85945aa..52f0b37678 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs @@ -19,15 +19,17 @@ internal class LomographProcessor : FilterProcessor /// Initializes a new instance of the class. /// /// The defining the parameters. - public LomographProcessor(LomographProcessor definition) - : base(definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public LomographProcessor(LomographProcessor definition, Image source, Rectangle sourceRectangle) + : base(definition, source, sourceRectangle) { } /// - protected override void AfterFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void AfterFrameApply(ImageFrame source) { - new VignetteProcessor(VeryDarkGreen).Apply(source, sourceRectangle, configuration); + new VignetteProcessor(VeryDarkGreen).CreatePixelSpecificProcessor(this.Source, this.SourceRectangle).Apply(); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs index 676bbc06bb..c8527a29cf 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Filters { /// @@ -17,7 +19,7 @@ public PolaroidProcessor() } /// - public override IImageProcessor CreatePixelSpecificProcessor() => - new PolaroidProcessor(this); + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) => + new PolaroidProcessor(this, source, sourceRectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs index 0f511ee296..5aad1005bb 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs @@ -21,19 +21,18 @@ internal class PolaroidProcessor : FilterProcessor /// Initializes a new instance of the class. /// /// The defining the parameters. - public PolaroidProcessor(PolaroidProcessor definition) - : base(definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public PolaroidProcessor(PolaroidProcessor definition, Image source, Rectangle sourceRectangle) + : base(definition, source, sourceRectangle) { } /// - protected override void AfterFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void AfterImageApply() { - new VignetteProcessor(VeryDarkOrange).Apply(source, sourceRectangle, configuration); - new GlowProcessor(LightOrange, source.Width / 4F).Apply(source, sourceRectangle, configuration); + new VignetteProcessor(VeryDarkOrange).Apply(this.Source, this.SourceRectangle); + new GlowProcessor(LightOrange, this.Source.Width / 4F).Apply(this.Source, this.SourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs b/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs index 024ccbced1..1a21be1f93 100644 --- a/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ICloningImageProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; @@ -16,17 +16,13 @@ internal interface ICloningImageProcessor : IImageProcessor /// /// Applies the process to the specified portion of the specified . /// - /// The source image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// /// - /// is null. + /// The target is null. /// /// - /// doesn't fit the dimension of the image. + /// The target doesn't fit the dimension of the image. /// /// Returns the cloned image after there processor has been applied to it. - Image CloneAndApply(Image source, Rectangle sourceRectangle); + Image CloneAndApply(); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/IImageProcessor.cs b/src/ImageSharp/Processing/Processors/IImageProcessor.cs index 9b030a6fea..4fff5273ac 100644 --- a/src/ImageSharp/Processing/Processors/IImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/IImageProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors { @@ -18,8 +19,12 @@ public interface IImageProcessor /// the processing algorithm on an . /// /// The pixel type. + /// The source image. Cannot be null. + /// + /// The structure that specifies the portion of the image object to draw. + /// /// The - IImageProcessor CreatePixelSpecificProcessor() + IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs index 90dfaf8db5..e2bc1b0ffb 100644 --- a/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/IImageProcessor{TPixel}.cs @@ -16,16 +16,12 @@ public interface IImageProcessor /// /// Applies the process to the specified portion of the specified . /// - /// The source image. Cannot be null. - /// - /// The structure that specifies the portion of the image object to draw. - /// /// - /// is null. + /// The target is null. /// /// - /// doesn't fit the dimension of the image. + /// The target doesn't fit the dimension of the image. /// - void Apply(Image source, Rectangle sourceRectangle); + void Apply(); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/ImageProcessor.cs b/src/ImageSharp/Processing/Processors/ImageProcessor.cs index 0d27a9e1e8..39f3dd6360 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessor.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System; @@ -15,20 +15,46 @@ namespace SixLabors.ImageSharp.Processing.Processors internal abstract class ImageProcessor : IImageProcessor where TPixel : struct, IPixel { + /// + /// Initializes a new instance of the class. + /// + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + protected ImageProcessor(Image source, Rectangle sourceRectangle) + { + this.Source = source; + this.SourceRectangle = sourceRectangle; + this.Configuration = this.Source.GetConfiguration(); + } + + /// + /// Gets The source for the current processor instance. + /// + protected Image Source { get; } + + /// + /// Gets The source area to process for the current processor instance. + /// + protected Rectangle SourceRectangle { get; } + + /// + /// Gets the instance to use when performing operations. + /// + protected Configuration Configuration { get; } + /// - public void Apply(Image source, Rectangle sourceRectangle) + public void Apply() { try { - Configuration config = source.GetConfiguration(); - this.BeforeImageApply(source, sourceRectangle); + this.BeforeImageApply(); - foreach (ImageFrame sourceFrame in source.Frames) + foreach (ImageFrame sourceFrame in this.Source.Frames) { - this.Apply(sourceFrame, sourceRectangle, config); + this.Apply(sourceFrame); } - this.AfterImageApply(source, sourceRectangle); + this.AfterImageApply(); } #if DEBUG catch (Exception) @@ -43,18 +69,16 @@ public void Apply(Image source, Rectangle sourceRectangle) } /// - /// Applies the processor to just a single ImageBase + /// Applies the processor to just a single ImageBase. /// - /// the source image - /// the target - /// The configuration. - public void Apply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + /// the source image. + public void Apply(ImageFrame source) { try { - this.BeforeFrameApply(source, sourceRectangle, configuration); - this.OnFrameApply(source, sourceRectangle, configuration); - this.AfterFrameApply(source, sourceRectangle, configuration); + this.BeforeFrameApply(source); + this.OnFrameApply(source); + this.AfterFrameApply(source); } #if DEBUG catch (Exception) @@ -71,9 +95,7 @@ public void Apply(ImageFrame source, Rectangle sourceRectangle, Configur /// /// This method is called before the process is applied to prepare the processor. /// - /// The source image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - protected virtual void BeforeImageApply(Image source, Rectangle sourceRectangle) + protected virtual void BeforeImageApply() { } @@ -81,9 +103,7 @@ protected virtual void BeforeImageApply(Image source, Rectangle sourceRe /// This method is called before the process is applied to prepare the processor. /// /// The source image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - /// The configuration. - protected virtual void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected virtual void BeforeFrameApply(ImageFrame source) { } @@ -92,27 +112,21 @@ protected virtual void BeforeFrameApply(ImageFrame source, Rectangle sou /// and with the specified size. /// /// The source image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - /// The configuration. - protected abstract void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration); + protected abstract void OnFrameApply(ImageFrame source); /// /// This method is called after the process is applied to prepare the processor. /// /// The source image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - /// The configuration. - protected virtual void AfterFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected virtual void AfterFrameApply(ImageFrame source) { } /// /// This method is called after the process is applied to prepare the processor. /// - /// The source image. Cannot be null. - /// The structure that specifies the portion of the image object to draw. - protected virtual void AfterImageApply(Image source, Rectangle sourceRectangle) + protected virtual void AfterImageApply() { } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs index 91b2b30d02..9eb10b6e43 100644 --- a/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs +++ b/src/ImageSharp/Processing/Processors/ImageProcessorExtensions.cs @@ -14,21 +14,6 @@ public static void Apply(this IImageProcessor processor, Image source, Rectangle source.AcceptVisitor(visitor); } - /// - /// Apply an to a frame. - /// Only works from processors implemented by an subclass. - /// - internal static void Apply( - this IImageProcessor processor, - ImageFrame frame, - Rectangle sourceRectangle, - Configuration configuration) - where TPixel : struct, IPixel - { - var processorImpl = (ImageProcessor)processor.CreatePixelSpecificProcessor(); - processorImpl.Apply(frame, sourceRectangle, configuration); - } - private class ApplyVisitor : IImageVisitor { private readonly IImageProcessor processor; @@ -44,9 +29,9 @@ public ApplyVisitor(IImageProcessor processor, Rectangle sourceRectangle) public void Visit(Image image) where TPixel : struct, IPixel { - var processorImpl = this.processor.CreatePixelSpecificProcessor(); - processorImpl.Apply(image, this.sourceRectangle); + IImageProcessor processorImpl = this.processor.CreatePixelSpecificProcessor(image, this.sourceRectangle); + processorImpl.Apply(); } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs index ad27ae020c..af3a336a4d 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Normalization { /// @@ -33,13 +35,15 @@ public AdaptiveHistogramEqualizationProcessor( public int NumberOfTiles { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { return new AdaptiveHistogramEqualizationProcessor( this.LuminanceLevels, this.ClipHistogram, this.ClipLimitPercentage, - this.NumberOfTiles); + this.NumberOfTiles, + source, + sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs index 537a3089ec..08222d4caf 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs @@ -32,8 +32,16 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz /// Indicating whether to clip the histogram bins at a specific value. /// Histogram clip limit in percent of the total pixels in the tile. Histogram bins which exceed this limit, will be capped at this value. /// The number of tiles the image is split into (horizontal and vertically). Minimum value is 2. Maximum value is 100. - public AdaptiveHistogramEqualizationProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage, int tiles) - : base(luminanceLevels, clipHistogram, clipLimitPercentage) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public AdaptiveHistogramEqualizationProcessor( + int luminanceLevels, + bool clipHistogram, + float clipLimitPercentage, + int tiles, + Image source, + Rectangle sourceRectangle) + : base(luminanceLevels, clipHistogram, clipLimitPercentage, source, sourceRectangle) { Guard.MustBeGreaterThanOrEqualTo(tiles, 2, nameof(tiles)); Guard.MustBeLessThanOrEqualTo(tiles, 100, nameof(tiles)); @@ -47,7 +55,7 @@ public AdaptiveHistogramEqualizationProcessor(int luminanceLevels, bool clipHist private int Tiles { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { int sourceWidth = source.Width; int sourceHeight = source.Height; @@ -59,7 +67,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source int luminanceLevels = this.LuminanceLevels; // The image is split up into tiles. For each tile the cumulative distribution function will be calculated. - using (var cdfData = new CdfTileData(configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels)) + using (var cdfData = new CdfTileData(this.Configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels)) { cdfData.CalculateLookupTables(source, this); @@ -74,7 +82,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source Parallel.For( 0, tileYStartPositions.Count, - new ParallelOptions { MaxDegreeOfParallelism = configuration.MaxDegreeOfParallelism }, + new ParallelOptions { MaxDegreeOfParallelism = this.Configuration.MaxDegreeOfParallelism }, index => { int y = tileYStartPositions[index].y; diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs index 36f798975a..3ff001c522 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Normalization { /// @@ -32,13 +34,15 @@ public AdaptiveHistogramEqualizationSlidingWindowProcessor( public int NumberOfTiles { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { return new AdaptiveHistogramEqualizationSlidingWindowProcessor( this.LuminanceLevels, this.ClipHistogram, this.ClipLimitPercentage, - this.NumberOfTiles); + this.NumberOfTiles, + source, + sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs index 377af51354..24ac5ccef2 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs @@ -31,8 +31,16 @@ internal class AdaptiveHistogramEqualizationSlidingWindowProcessor : His /// Indicating whether to clip the histogram bins at a specific value. /// Histogram clip limit in percent of the total pixels in the tile. Histogram bins which exceed this limit, will be capped at this value. /// The number of tiles the image is split into (horizontal and vertically). Minimum value is 2. Maximum value is 100. - public AdaptiveHistogramEqualizationSlidingWindowProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage, int tiles) - : base(luminanceLevels, clipHistogram, clipLimitPercentage) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public AdaptiveHistogramEqualizationSlidingWindowProcessor( + int luminanceLevels, + bool clipHistogram, + float clipLimitPercentage, + int tiles, + Image source, + Rectangle sourceRectangle) + : base(luminanceLevels, clipHistogram, clipLimitPercentage, source, sourceRectangle) { Guard.MustBeGreaterThanOrEqualTo(tiles, 2, nameof(tiles)); Guard.MustBeLessThanOrEqualTo(tiles, 100, nameof(tiles)); @@ -46,11 +54,11 @@ public AdaptiveHistogramEqualizationSlidingWindowProcessor(int luminanceLevels, private int Tiles { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; + MemoryAllocator memoryAllocator = this.Configuration.MemoryAllocator; - var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = configuration.MaxDegreeOfParallelism }; + var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = this.Configuration.MaxDegreeOfParallelism }; int tileWidth = source.Width / this.Tiles; int tileHeight = tileWidth; int pixelInTile = tileWidth * tileHeight; @@ -58,7 +66,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source int halfTileWidth = halfTileHeight; var slidingWindowInfos = new SlidingWindowInfos(tileWidth, tileHeight, halfTileWidth, halfTileHeight, pixelInTile); - using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) + using (Buffer2D targetPixels = this.Configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) { // Process the inner tiles, which do not require to check the borders. Parallel.For( @@ -73,7 +81,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source yStart: halfTileHeight, yEnd: source.Height - halfTileHeight, useFastPath: true, - configuration)); + this.Configuration)); // Process the left border of the image. Parallel.For( @@ -88,7 +96,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source yStart: 0, yEnd: source.Height, useFastPath: false, - configuration)); + this.Configuration)); // Process the right border of the image. Parallel.For( @@ -103,7 +111,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source yStart: 0, yEnd: source.Height, useFastPath: false, - configuration)); + this.Configuration)); // Process the top border of the image. Parallel.For( @@ -118,7 +126,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source yStart: 0, yEnd: halfTileHeight, useFastPath: false, - configuration)); + this.Configuration)); // Process the bottom border of the image. Parallel.For( @@ -133,7 +141,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source yStart: source.Height - halfTileHeight, yEnd: source.Height, useFastPath: false, - configuration)); + this.Configuration)); Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs index 9af2c8352b..dab101fcc2 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor.cs @@ -1,6 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.Primitives; + namespace SixLabors.ImageSharp.Processing.Processors.Normalization { /// @@ -20,12 +22,14 @@ public GlobalHistogramEqualizationProcessor(int luminanceLevels, bool clipHistog } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { return new GlobalHistogramEqualizationProcessor( this.LuminanceLevels, this.ClipHistogram, - this.ClipLimitPercentage); + this.ClipLimitPercentage, + source, + sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs index a790263fa1..6ae6882479 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs @@ -32,15 +32,22 @@ internal class GlobalHistogramEqualizationProcessor : HistogramEqualizat /// /// Indicating whether to clip the histogram bins at a specific value. /// Histogram clip limit in percent of the total pixels. Histogram bins which exceed this limit, will be capped at this value. - public GlobalHistogramEqualizationProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage) - : base(luminanceLevels, clipHistogram, clipLimitPercentage) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public GlobalHistogramEqualizationProcessor( + int luminanceLevels, + bool clipHistogram, + float clipLimitPercentage, + Image source, + Rectangle sourceRectangle) + : base(luminanceLevels, clipHistogram, clipLimitPercentage, source, sourceRectangle) { } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; + MemoryAllocator memoryAllocator = this.Configuration.MemoryAllocator; int numberOfPixels = source.Width * source.Height; var workingRect = new Rectangle(0, 0, source.Width, source.Height); @@ -50,7 +57,7 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source // Build the histogram of the grayscale levels. ParallelHelper.IterateRows( workingRect, - configuration, + this.Configuration, rows => { ref int histogramBase = ref MemoryMarshal.GetReference(histogramBuffer.GetSpan()); @@ -83,7 +90,7 @@ ref MemoryMarshal.GetReference(histogram), // Apply the cdf to each pixel of the image ParallelHelper.IterateRows( workingRect, - configuration, + this.Configuration, rows => { ref int cdfBase = ref MemoryMarshal.GetReference(cdfBuffer.GetSpan()); diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs index b1d12f8478..01a687ac5c 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Normalization { @@ -40,7 +41,7 @@ protected HistogramEqualizationProcessor(int luminanceLevels, bool clipHistogram public float ClipLimitPercentage { get; } /// - public abstract IImageProcessor CreatePixelSpecificProcessor() + public abstract IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel; /// @@ -89,4 +90,4 @@ public static HistogramEqualizationProcessor FromOptions(HistogramEqualizationOp return processor; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs index 8dbc903f29..f8515ece6f 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/HistogramEqualizationProcessor{TPixel}.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Normalization { @@ -26,7 +27,15 @@ internal abstract class HistogramEqualizationProcessor : ImageProcessor< /// or 65536 for 16-bit grayscale images. /// Indicates, if histogram bins should be clipped. /// Histogram clip limit in percent of the total pixels in the tile. Histogram bins which exceed this limit, will be capped at this value. - protected HistogramEqualizationProcessor(int luminanceLevels, bool clipHistogram, float clipLimitPercentage) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + protected HistogramEqualizationProcessor( + int luminanceLevels, + bool clipHistogram, + float clipLimitPercentage, + Image source, + Rectangle sourceRectangle) + : base(source, sourceRectangle) { Guard.MustBeGreaterThan(luminanceLevels, 0, nameof(luminanceLevels)); Guard.MustBeGreaterThan(clipLimitPercentage, 0F, nameof(clipLimitPercentage)); @@ -136,4 +145,4 @@ public static int GetLuminance(TPixel sourcePixel, int luminanceLevels) public static int GetLuminance(ref Vector4 vector, int luminanceLevels) => (int)MathF.Round(((.2126F * vector.X) + (.7152F * vector.Y) + (.0722F * vector.Y)) * (luminanceLevels - 1)); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index 62848172a1..4b4c537277 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Overlays { @@ -32,10 +33,10 @@ public BackgroundColorProcessor(Color color, GraphicsOptions options) public Color Color { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new BackgroundColorProcessor(this); + return new BackgroundColorProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs index c4af59fecb..2459b47069 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs @@ -24,24 +24,25 @@ internal class BackgroundColorProcessor : ImageProcessor /// /// Initializes a new instance of the class. /// - public BackgroundColorProcessor(BackgroundColorProcessor definition) + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public BackgroundColorProcessor(BackgroundColorProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { TPixel color = this.definition.Color.ToPixel(); GraphicsOptions graphicsOptions = this.definition.GraphicsOptions; - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + int startY = this.SourceRectangle.Y; + int endY = this.SourceRectangle.Bottom; + int startX = this.SourceRectangle.X; + int endX = this.SourceRectangle.Right; // Align start/end positions. int minX = Math.Max(0, startX); @@ -78,7 +79,7 @@ protected override void OnFrameApply( ParallelHelper.IterateRows( workingRect, - configuration, + this.Configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) @@ -98,4 +99,4 @@ protected override void OnFrameApply( } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index 255be5ed59..0958e3aa9e 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Overlays { @@ -69,10 +70,10 @@ internal GlowProcessor(Color color, ValueSize radius, GraphicsOptions options) internal ValueSize Radius { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new GlowProcessor(this); + return new GlowProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs index 3201fcbfee..756e8647ba 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs @@ -24,31 +24,35 @@ internal class GlowProcessor : ImageProcessor private readonly GlowProcessor definition; - public GlowProcessor(GlowProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public GlowProcessor(GlowProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; this.blender = PixelOperations.Instance.GetPixelBlender(definition.GraphicsOptions); } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { // TODO: can we simplify the rectangle calculation? - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + int startY = this.SourceRectangle.Y; + int endY = this.SourceRectangle.Bottom; + int startX = this.SourceRectangle.X; + int endX = this.SourceRectangle.Right; TPixel glowColor = this.definition.GlowColor.ToPixel(); - Vector2 center = Rectangle.Center(sourceRectangle); + Vector2 center = Rectangle.Center(this.SourceRectangle); float finalRadius = this.definition.Radius.Calculate(source.Size()); float maxDistance = finalRadius > 0 - ? MathF.Min(finalRadius, sourceRectangle.Width * .5F) - : sourceRectangle.Width * .5F; + ? MathF.Min(finalRadius, this.SourceRectangle.Width * .5F) + : this.SourceRectangle.Width * .5F; // Align start/end positions. int minX = Math.Max(0, startX); @@ -80,7 +84,7 @@ protected override void OnFrameApply( ParallelHelper.IterateRowsWithTempBuffer( workingRect, - configuration, + this.Configuration, (rows, amounts) => { Span amountsSpan = amounts.Span; @@ -109,4 +113,4 @@ protected override void OnFrameApply( } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 66bf9f1af7..2365318f3d 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -1,8 +1,9 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Overlays { @@ -67,10 +68,10 @@ internal VignetteProcessor(Color color, ValueSize radiusX, ValueSize radiusY, Gr internal ValueSize RadiusY { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new VignetteProcessor(this); + return new VignetteProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs index 78c3cec5e7..8569410d22 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs @@ -24,34 +24,38 @@ internal class VignetteProcessor : ImageProcessor private readonly VignetteProcessor definition; - public VignetteProcessor(VignetteProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public VignetteProcessor(VignetteProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; this.blender = PixelOperations.Instance.GetPixelBlender(definition.GraphicsOptions); } /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + int startY = this.SourceRectangle.Y; + int endY = this.SourceRectangle.Bottom; + int startX = this.SourceRectangle.X; + int endX = this.SourceRectangle.Right; TPixel vignetteColor = this.definition.VignetteColor.ToPixel(); - Vector2 centre = Rectangle.Center(sourceRectangle); + Vector2 centre = Rectangle.Center(this.SourceRectangle); Size sourceSize = source.Size(); float finalRadiusX = this.definition.RadiusX.Calculate(sourceSize); float finalRadiusY = this.definition.RadiusY.Calculate(sourceSize); float rX = finalRadiusX > 0 - ? MathF.Min(finalRadiusX, sourceRectangle.Width * .5F) - : sourceRectangle.Width * .5F; + ? MathF.Min(finalRadiusX, this.SourceRectangle.Width * .5F) + : this.SourceRectangle.Width * .5F; float rY = finalRadiusY > 0 - ? MathF.Min(finalRadiusY, sourceRectangle.Height * .5F) - : sourceRectangle.Height * .5F; + ? MathF.Min(finalRadiusY, this.SourceRectangle.Height * .5F) + : this.SourceRectangle.Height * .5F; float maxDistance = MathF.Sqrt((rX * rX) + (rY * rY)); // Align start/end positions. @@ -83,7 +87,7 @@ protected override void OnFrameApply( ParallelHelper.IterateRowsWithTempBuffer( workingRect, - configuration, + this.Configuration, (rows, amounts) => { Span amountsSpan = amounts.Span; @@ -111,4 +115,4 @@ protected override void OnFrameApply( } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs index 0aee0b4831..8cc14da675 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Quantization { @@ -25,10 +26,10 @@ public QuantizeProcessor(IQuantizer quantizer) public IQuantizer Quantizer { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new QuantizeProcessor(this.Quantizer); + return new QuantizeProcessor(this.Quantizer, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index 5cb45e8d70..9309467229 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -22,15 +22,19 @@ internal class QuantizeProcessor : ImageProcessor /// Initializes a new instance of the class. /// /// The quantizer used to reduce the color palette. - public QuantizeProcessor(IQuantizer quantizer) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public QuantizeProcessor(IQuantizer quantizer, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { Guard.NotNull(quantizer, nameof(quantizer)); this.quantizer = quantizer; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { + Configuration configuration = this.Configuration; using (IFrameQuantizer frameQuantizer = this.quantizer.CreateFrameQuantizer(configuration)) using (IQuantizedFrame quantized = frameQuantizer.QuantizeFrame(source)) { @@ -57,4 +61,4 @@ protected override void OnFrameApply(ImageFrame source, Rectangle source } } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 713f042653..6e669e7779 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; @@ -43,10 +43,10 @@ public AffineTransformProcessor(Matrix3x2 matrix, IResampler sampler, Size targe public Size TargetDimensions { get; } /// - public virtual IImageProcessor CreatePixelSpecificProcessor() + public virtual IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new AffineTransformProcessor(this); + return new AffineTransformProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs index a33352c73b..7c50c04f3a 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs @@ -20,7 +20,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal class AffineTransformProcessor : TransformProcessor where TPixel : struct, IPixel { - public AffineTransformProcessor(AffineTransformProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public AffineTransformProcessor(AffineTransformProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.Definition = definition; } @@ -32,22 +39,18 @@ public AffineTransformProcessor(AffineTransformProcessor definition) private Matrix3x2 TransformMatrix => this.Definition.TransformMatrix; /// - protected override Image CreateDestination(Image source, Rectangle sourceRectangle) + protected override Image CreateDestination() { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select, ImageFrame>( - x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.Metadata.DeepClone())); + IEnumerable> frames = this.Source.Frames.Select, ImageFrame>( + x => new ImageFrame(this.Configuration, this.TargetDimensions, x.Metadata.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.Metadata.DeepClone(), frames); + return new Image(this.Configuration, this.Source.Metadata.DeepClone(), frames); } /// - protected override void OnFrameApply( - ImageFrame source, - ImageFrame destination, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source, ImageFrame destination) { // Handle transforms that result in output identical to the original. if (this.TransformMatrix.Equals(default) || this.TransformMatrix.Equals(Matrix3x2.Identity)) @@ -63,13 +66,13 @@ protected override void OnFrameApply( // Convert from screen to world space. Matrix3x2.Invert(this.TransformMatrix, out Matrix3x2 matrix); - var sampler = this.Definition.Sampler; + IResampler sampler = this.Definition.Sampler; if (sampler is NearestNeighborResampler) { ParallelHelper.IterateRows( targetBounds, - configuration, + this.Configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) @@ -79,7 +82,7 @@ protected override void OnFrameApply( for (int x = 0; x < width; x++) { var point = Point.Transform(new Point(x, y), matrix); - if (sourceRectangle.Contains(point.X, point.Y)) + if (this.SourceRectangle.Contains(point.X, point.Y)) { destRow[x] = source[point.X, point.Y]; } @@ -90,19 +93,19 @@ protected override void OnFrameApply( return; } - var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), sampler); + var kernel = new TransformKernelMap(this.Configuration, source.Size(), destination.Size(), sampler); try { ParallelHelper.IterateRowsWithTempBuffer( targetBounds, - configuration, + this.Configuration, (rows, vectorBuffer) => { Span vectorSpan = vectorBuffer.Span; for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(this.Configuration, targetRowSpan, vectorSpan); ref float ySpanRef = ref kernel.GetYStartReference(y); ref float xSpanRef = ref kernel.GetXStartReference(y); @@ -121,7 +124,7 @@ protected override void OnFrameApply( } PixelOperations.Instance.FromVector4Destructive( - configuration, + this.Configuration, vectorSpan, targetRowSpan); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs index 3eb0d998a2..eef7643da3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { @@ -11,10 +12,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public sealed class AutoOrientProcessor : IImageProcessor { /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new AutoOrientProcessor(); + return new AutoOrientProcessor(source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs index 8b3ec8690e..e68a24b727 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor{TPixel}.cs @@ -16,41 +16,51 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal class AutoOrientProcessor : ImageProcessor where TPixel : struct, IPixel { + /// + /// Initializes a new instance of the class. + /// + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public AutoOrientProcessor(Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) + { + } + /// - protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) + protected override void BeforeImageApply() { - OrientationMode orientation = GetExifOrientation(source); - Size size = sourceRectangle.Size; + OrientationMode orientation = GetExifOrientation(this.Source); + Size size = this.SourceRectangle.Size; switch (orientation) { case OrientationMode.TopRight: - new FlipProcessor(FlipMode.Horizontal).Apply(source, sourceRectangle); + new FlipProcessor(FlipMode.Horizontal).Apply(this.Source, this.SourceRectangle); break; case OrientationMode.BottomRight: - new RotateProcessor((int)RotateMode.Rotate180, size).Apply(source, sourceRectangle); + new RotateProcessor((int)RotateMode.Rotate180, size).Apply(this.Source, this.SourceRectangle); break; case OrientationMode.BottomLeft: - new FlipProcessor(FlipMode.Vertical).Apply(source, sourceRectangle); + new FlipProcessor(FlipMode.Vertical).Apply(this.Source, this.SourceRectangle); break; case OrientationMode.LeftTop: - new RotateProcessor((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle); - new FlipProcessor(FlipMode.Horizontal).Apply(source, sourceRectangle); + new RotateProcessor((int)RotateMode.Rotate90, size).Apply(this.Source, this.SourceRectangle); + new FlipProcessor(FlipMode.Horizontal).Apply(this.Source, this.SourceRectangle); break; case OrientationMode.RightTop: - new RotateProcessor((int)RotateMode.Rotate90, size).Apply(source, sourceRectangle); + new RotateProcessor((int)RotateMode.Rotate90, size).Apply(this.Source, this.SourceRectangle); break; case OrientationMode.RightBottom: - new FlipProcessor(FlipMode.Vertical).Apply(source, sourceRectangle); - new RotateProcessor((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle); + new FlipProcessor(FlipMode.Vertical).Apply(this.Source, this.SourceRectangle); + new RotateProcessor((int)RotateMode.Rotate270, size).Apply(this.Source, this.SourceRectangle); break; case OrientationMode.LeftBottom: - new RotateProcessor((int)RotateMode.Rotate270, size).Apply(source, sourceRectangle); + new RotateProcessor((int)RotateMode.Rotate270, size).Apply(this.Source, this.SourceRectangle); break; case OrientationMode.Unknown: @@ -61,10 +71,7 @@ protected override void BeforeImageApply(Image source, Rectangle sourceR } /// - protected override void OnFrameApply( - ImageFrame sourceBase, - Rectangle sourceRectangle, - Configuration config) + protected override void OnFrameApply(ImageFrame sourceBase) { // All processing happens at the image level within BeforeImageApply(); } @@ -103,4 +110,4 @@ private static OrientationMode GetExifOrientation(Image source) return orientation; } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 76f223e038..6105330df3 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; @@ -32,10 +32,10 @@ public CropProcessor(Rectangle cropRectangle, Size sourceSize) public Rectangle CropRectangle { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new CropProcessor(this); + return new CropProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs index 25f8d78491..539a11f028 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs @@ -25,7 +25,10 @@ internal class CropProcessor : TransformProcessor /// Initializes a new instance of the class. /// /// The . - public CropProcessor(CropProcessor definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public CropProcessor(CropProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } @@ -33,25 +36,25 @@ public CropProcessor(CropProcessor definition) private Rectangle CropRectangle => this.definition.CropRectangle; /// - protected override Image CreateDestination(Image source, Rectangle sourceRectangle) + protected override Image CreateDestination() { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select, ImageFrame>( + IEnumerable> frames = this.Source.Frames.Select, ImageFrame>( x => new ImageFrame( - source.GetConfiguration(), + this.Source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.Metadata.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.Metadata.DeepClone(), frames); + return new Image(this.Source.GetConfiguration(), this.Source.Metadata.DeepClone(), frames); } /// - protected override void OnFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source, ImageFrame destination) { // Handle resize dimensions identical to the original - if (source.Width == destination.Width && source.Height == destination.Height && sourceRectangle == this.CropRectangle) + if (source.Width == destination.Width && source.Height == destination.Height && this.SourceRectangle == this.CropRectangle) { // the cloned will be blank here copy all the pixel data over source.GetPixelSpan().CopyTo(destination.GetPixelSpan()); @@ -61,7 +64,7 @@ protected override void OnFrameApply(ImageFrame source, ImageFrame source, ImageFrame - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new EntropyCropProcessor(this); + return new EntropyCropProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs index 4bfeb25198..6129e69ef4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor{TPixel}.cs @@ -22,38 +22,41 @@ internal class EntropyCropProcessor : ImageProcessor /// Initializes a new instance of the class. /// /// The . - public EntropyCropProcessor(EntropyCropProcessor definition) + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public EntropyCropProcessor(EntropyCropProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void BeforeImageApply(Image source, Rectangle sourceRectangle) + protected override void BeforeImageApply() { Rectangle rectangle; // All frames have be the same size so we only need to calculate the correct dimensions for the first frame - using (ImageFrame temp = source.Frames.RootFrame.Clone()) + using (var temp = new Image(this.Configuration, this.Source.Metadata.DeepClone(), new[] { this.Source.Frames.RootFrame.Clone() })) { - Configuration configuration = source.GetConfiguration(); + Configuration configuration = this.Source.GetConfiguration(); // Detect the edges. - new SobelProcessor(false).Apply(temp, sourceRectangle, configuration); + new SobelProcessor(false).Apply(temp, this.SourceRectangle); // Apply threshold binarization filter. - new BinaryThresholdProcessor(this.definition.Threshold).Apply(temp, sourceRectangle, configuration); + new BinaryThresholdProcessor(this.definition.Threshold).Apply(temp, this.SourceRectangle); // Search for the first white pixels - rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); + rectangle = ImageMaths.GetFilteredBoundingRectangle(temp.Frames.RootFrame, 0); } - new CropProcessor(rectangle, source.Size()).Apply(source, sourceRectangle); + new CropProcessor(rectangle, this.Source.Size()).Apply(this.Source, this.SourceRectangle); } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { // All processing happens at the image level within BeforeImageApply(); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index f604d8399f..e2364e180f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { @@ -25,10 +26,10 @@ public FlipProcessor(FlipMode flipMode) public FlipMode FlipMode { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new FlipProcessor(this); + return new FlipProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs index 0247862096..9374af476b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs @@ -20,22 +20,29 @@ internal class FlipProcessor : ImageProcessor { private readonly FlipProcessor definition; - public FlipProcessor(FlipProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The . + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public FlipProcessor(FlipProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source) { switch (this.definition.FlipMode) { // No default needed as we have already set the pixels. case FlipMode.Vertical: - this.FlipX(source, configuration); + this.FlipX(source, this.Configuration); break; case FlipMode.Horizontal: - this.FlipY(source, configuration); + this.FlipY(source, this.Configuration); break; } } @@ -84,4 +91,4 @@ private void FlipY(ImageFrame source, Configuration configuration) }); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 3a86b3fe4f..15a6e2d095 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; @@ -43,10 +43,10 @@ public ProjectiveTransformProcessor(Matrix4x4 matrix, IResampler sampler, Size t public Size TargetDimensions { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel { - return new ProjectiveTransformProcessor(this); + return new ProjectiveTransformProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs index f95040facd..29dc8a070d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs @@ -22,7 +22,14 @@ internal class ProjectiveTransformProcessor : TransformProcessor { private readonly ProjectiveTransformProcessor definition; - public ProjectiveTransformProcessor(ProjectiveTransformProcessor definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public ProjectiveTransformProcessor(ProjectiveTransformProcessor definition, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.definition = definition; } @@ -30,26 +37,22 @@ public ProjectiveTransformProcessor(ProjectiveTransformProcessor definition) private Size TargetDimensions => this.definition.TargetDimensions; /// - protected override Image CreateDestination(Image source, Rectangle sourceRectangle) + protected override Image CreateDestination() { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select, ImageFrame>( + IEnumerable> frames = this.Source.Frames.Select, ImageFrame>( x => new ImageFrame( - source.GetConfiguration(), + this.Source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.Metadata.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.Metadata.DeepClone(), frames); + return new Image(this.Source.GetConfiguration(), this.Source.Metadata.DeepClone(), frames); } /// - protected override void OnFrameApply( - ImageFrame source, - ImageFrame destination, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source, ImageFrame destination) { Matrix4x4 transformMatrix = this.definition.TransformMatrix; @@ -73,7 +76,7 @@ protected override void OnFrameApply( { ParallelHelper.IterateRows( targetBounds, - configuration, + this.Configuration, rows => { for (int y = rows.Min; y < rows.Max; y++) @@ -86,7 +89,7 @@ protected override void OnFrameApply( int px = (int)MathF.Round(point.X); int py = (int)MathF.Round(point.Y); - if (sourceRectangle.Contains(px, py)) + if (this.SourceRectangle.Contains(px, py)) { destRow[x] = source[px, py]; } @@ -97,19 +100,19 @@ protected override void OnFrameApply( return; } - var kernel = new TransformKernelMap(configuration, source.Size(), destination.Size(), sampler); + var kernel = new TransformKernelMap(this.Configuration, source.Size(), destination.Size(), sampler); try { ParallelHelper.IterateRowsWithTempBuffer( targetBounds, - configuration, + this.Configuration, (rows, vectorBuffer) => { Span vectorSpan = vectorBuffer.Span; for (int y = rows.Min; y < rows.Max; y++) { Span targetRowSpan = destination.GetPixelRowSpan(y); - PixelOperations.Instance.ToVector4(configuration, targetRowSpan, vectorSpan); + PixelOperations.Instance.ToVector4(this.Configuration, targetRowSpan, vectorSpan); ref float ySpanRef = ref kernel.GetYStartReference(y); ref float xSpanRef = ref kernel.GetXStartReference(y); @@ -128,7 +131,7 @@ protected override void OnFrameApply( } PixelOperations.Instance.FromVector4Destructive( - configuration, + this.Configuration, vectorSpan, targetRowSpan); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs index 8762d6b263..cf27de5eb1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor.cs @@ -130,10 +130,8 @@ public ResizeProcessor(IResampler sampler, int width, int height, Size sourceSiz public bool Compand { get; } /// - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new ResizeProcessor(this); - } + => new ResizeProcessor(this, source, sourceRectangle); } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index b68a7f93f7..2033fd38c0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -30,7 +30,8 @@ internal class ResizeProcessor : TransformProcessor private readonly ResizeProcessor parameterSource; - public ResizeProcessor(ResizeProcessor parameterSource) + public ResizeProcessor(ResizeProcessor parameterSource, Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) { this.parameterSource = parameterSource; } @@ -64,31 +65,36 @@ public ResizeProcessor(ResizeProcessor parameterSource) /// This is a shim for tagging the CreateDestination virtual generic method for the AoT iOS compiler. /// This method should never be referenced outside of the AotCompiler code. /// - /// Passed through as source to the CreateDestination method. - /// Passed through as sourceRectangle to the CreateDestination method. - /// The result returned from CreateDestination. - internal Image AotCreateDestination(Image source, Rectangle sourceRectangle) => this.CreateDestination(source, sourceRectangle); + /// The result returned from . + internal Image AotCreateDestination() + => this.CreateDestination(); /// - protected override Image CreateDestination(Image source, Rectangle sourceRectangle) + protected override Image CreateDestination() { + Image source = this.Source; + Configuration configuration = this.Configuration; + // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = source.Frames.Select, ImageFrame>( x => new ImageFrame( - source.GetConfiguration(), + configuration, this.Width, this.Height, x.Metadata.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.Metadata.DeepClone(), frames); + return new Image(configuration, source.Metadata.DeepClone(), frames); } /// - protected override void BeforeImageApply(Image source, Image destination, Rectangle sourceRectangle) + protected override void BeforeImageApply(Image destination) { if (!(this.Sampler is NearestNeighborResampler)) { + Image source = this.Source; + Rectangle sourceRectangle = this.SourceRectangle; + // Since all image frame dimensions have to be the same we can calculate this for all frames. MemoryAllocator memoryAllocator = source.GetMemoryAllocator(); this.horizontalKernelMap = ResizeKernelMap.Calculate( @@ -106,8 +112,11 @@ protected override void BeforeImageApply(Image source, Image des } /// - protected override void OnFrameApply(ImageFrame source, ImageFrame destination, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source, ImageFrame destination) { + Rectangle sourceRectangle = this.SourceRectangle; + Configuration configuration = this.Configuration; + // Handle resize dimensions identical to the original if (source.Width == destination.Width && source.Height == destination.Height && sourceRectangle == this.TargetRectangle) { @@ -180,9 +189,9 @@ protected override void OnFrameApply(ImageFrame source, ImageFrame source, Image destination, Rectangle sourceRectangle) + protected override void AfterImageApply(Image destination) { - base.AfterImageApply(source, destination, sourceRectangle); + base.AfterImageApply(destination); // TODO: An exception in the processing chain can leave these buffers undisposed. We should consider making image processors IDisposable! this.horizontalKernelMap?.Dispose(); diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index ef0671d20d..10d6cdc943 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using System.Numerics; @@ -47,9 +47,9 @@ private RotateProcessor(Matrix3x2 rotationMatrix, IResampler sampler, Size sourc public float Degrees { get; } /// - public override IImageProcessor CreatePixelSpecificProcessor() + public override IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) { - return new RotateProcessor(this); + return new RotateProcessor(this, source, sourceRectangle); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs index 252cb77aba..1ed4c362c5 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs @@ -18,8 +18,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal class RotateProcessor : AffineTransformProcessor where TPixel : struct, IPixel { - public RotateProcessor(RotateProcessor definition) - : base(definition) + /// + /// Initializes a new instance of the class. + /// + /// The defining the processor parameters. + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + public RotateProcessor(RotateProcessor definition, Image source, Rectangle sourceRectangle) + : base(definition, source, sourceRectangle) { this.Degrees = definition.Degrees; } @@ -27,10 +33,7 @@ public RotateProcessor(RotateProcessor definition) private float Degrees { get; } /// - protected override void AfterImageApply( - Image source, - Image destination, - Rectangle sourceRectangle) + protected override void AfterImageApply(Image destination) { ExifProfile profile = destination.Metadata.ExifProfile; if (profile is null) @@ -46,22 +49,18 @@ protected override void AfterImageApply( profile.RemoveValue(ExifTag.Orientation); - base.AfterImageApply(source, destination, sourceRectangle); + base.AfterImageApply(destination); } /// - protected override void OnFrameApply( - ImageFrame source, - ImageFrame destination, - Rectangle sourceRectangle, - Configuration configuration) + protected override void OnFrameApply(ImageFrame source, ImageFrame destination) { - if (this.OptimizedApply(source, destination, configuration)) + if (this.OptimizedApply(source, destination, this.Configuration)) { return; } - base.OnFrameApply(source, destination, sourceRectangle, configuration); + base.OnFrameApply(source, destination); } /// @@ -222,4 +221,4 @@ private void Rotate90(ImageFrame source, ImageFrame destination, }); } } -} \ No newline at end of file +} diff --git a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs index f6d3299fcd..ee501adf31 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/TransformProcessor.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.PixelFormats; @@ -13,8 +13,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms internal abstract class TransformProcessor : CloningImageProcessor where TPixel : struct, IPixel { + /// + /// Initializes a new instance of the class. + /// + /// The source for the current processor instance. + /// The source area to process for the current processor instance. + protected TransformProcessor(Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) + { + } + /// - protected override void AfterImageApply(Image source, Image destination, Rectangle sourceRectangle) + protected override void AfterImageApply(Image destination) => TransformProcessorHelpers.UpdateDimensionalMetadata(destination); } -} \ No newline at end of file +} diff --git a/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs b/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs index 47bd42a3c2..3a47d016a4 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/GaussianBlur.cs @@ -1,4 +1,4 @@ -using BenchmarkDotNet.Attributes; +using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs deleted file mode 100644 index 28cb047356..0000000000 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Numerics; - -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.ParallelUtils; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.ImageSharp.Processing.Processors.Overlays; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Benchmarks -{ - using CoreSize = SixLabors.Primitives.Size; - - public class Glow : BenchmarkBase - { - private GlowProcessor bulk; - - private GlowProcessorParallel parallel; - - [GlobalSetup] - public void Setup() - { - this.bulk = new GlowProcessor(Color.Beige, 800 * .5f, GraphicsOptions.Default); - this.parallel = new GlowProcessorParallel(Color.Beige) { Radius = 800 * .5f, }; - } - - [Benchmark(Description = "ImageSharp Glow - Bulk")] - public CoreSize GlowBulk() - { - using (var image = new Image(800, 800)) - { - this.bulk.Apply(image, image.Bounds()); - return new CoreSize(image.Width, image.Height); - } - } - - [Benchmark(Description = "ImageSharp Glow - Parallel")] - public CoreSize GLowSimple() - { - using (var image = new Image(800, 800)) - { - this.parallel.Apply(image, image.Bounds()); - return new CoreSize(image.Width, image.Height); - } - } - - internal class GlowProcessorParallel : ImageProcessor - where TPixel : struct, IPixel - { - /// - /// Initializes a new instance of the class. - /// - /// The color or the glow. - public GlowProcessorParallel(TPixel color) - { - this.GlowColor = color; - } - - /// - /// Gets or sets the glow color to apply. - /// - public TPixel GlowColor { get; set; } - - /// - /// Gets or sets the the radius. - /// - public float Radius { get; set; } - - /// - protected override void OnFrameApply( - ImageFrame source, - Rectangle sourceRectangle, - Configuration configuration) - { - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; - TPixel glowColor = this.GlowColor; - Vector2 centre = Rectangle.Center(sourceRectangle); - float maxDistance = this.Radius > 0 - ? Math.Min(this.Radius, sourceRectangle.Width * .5F) - : sourceRectangle.Width * .5F; - - // 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); - - // Reset offset if necessary. - if (minX > 0) - { - startX = 0; - } - - if (minY > 0) - { - startY = 0; - } - - int width = maxX - minX; - using (IMemoryOwner rowColors = Configuration.Default.MemoryAllocator.Allocate(width)) - { - Buffer2D sourcePixels = source.PixelBuffer; - rowColors.GetSpan().Fill(glowColor); - - var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); - ParallelHelper.IterateRows( - workingRect, - configuration, - rows => - { - for (int y = rows.Min; y < rows.Max; y++) - { - int offsetY = y - startY; - - for (int x = minX; x < maxX; x++) - { - int offsetX = x - startX; - float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); - Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); - TPixel packed = default; - packed.FromVector4( - PremultipliedLerp( - sourceColor, - glowColor.ToVector4(), - 1 - (.95F * (distance / maxDistance)))); - sourcePixels[offsetX, offsetY] = packed; - } - } - }); - } - } - - public static Vector4 PremultipliedLerp(Vector4 backdrop, Vector4 source, float amount) - { - amount = amount.Clamp(0, 1); - - // Sanitize on zero alpha - if (Math.Abs(backdrop.W) < Constants.Epsilon) - { - source.W *= amount; - return source; - } - - if (Math.Abs(source.W) < Constants.Epsilon) - { - return backdrop; - } - - // Premultiply the source vector. - // Oddly premultiplying the background vector creates dark outlines when pixels - // Have low alpha values. - source = new Vector4(source.X, source.Y, source.Z, 1) * (source.W * amount); - - // This should be implementing the following formula - // https://en.wikipedia.org/wiki/Alpha_compositing - // Vout = Vs + Vb (1 - Vsa) - // Aout = Vsa + Vsb (1 - Vsa) - var inverseW = new Vector3(1 - source.W); - var xyzB = new Vector3(backdrop.X, backdrop.Y, backdrop.Z); - var xyzS = new Vector3(source.X, source.Y, source.Z); - - return new Vector4(xyzS + (xyzB * inverseW), source.W + (backdrop.W * (1 - source.W))); - } - } - } -} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs index 3796c51a3b..a23de2b681 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/BokehBlurTest.cs @@ -56,17 +56,20 @@ public void VerifyComplexComponents() } // Make sure the kernel components are the same - var definition = new BokehBlurProcessor(10, BokehBlurProcessor.DefaultComponents, BokehBlurProcessor.DefaultGamma); - var processor = new BokehBlurProcessor(definition); - Assert.Equal(components.Count, processor.Kernels.Count); - foreach ((Complex64[] a, Complex64[] b) in components.Zip(processor.Kernels, (a, b) => (a, b))) + using (var image = new Image(1, 1)) { - Span spanA = a.AsSpan(), spanB = b.AsSpan(); - Assert.Equal(spanA.Length, spanB.Length); - for (int i = 0; i < spanA.Length; i++) + var definition = new BokehBlurProcessor(10, BokehBlurProcessor.DefaultComponents, BokehBlurProcessor.DefaultGamma); + var processor = (BokehBlurProcessor)definition.CreatePixelSpecificProcessor(image, image.Bounds()); + Assert.Equal(components.Count, processor.Kernels.Count); + foreach ((Complex64[] a, Complex64[] b) in components.Zip(processor.Kernels, (a, b) => (a, b))) { - Assert.True(Math.Abs(Math.Abs(spanA[i].Real) - Math.Abs(spanB[i].Real)) < 0.0001f); - Assert.True(Math.Abs(Math.Abs(spanA[i].Imaginary) - Math.Abs(spanB[i].Imaginary)) < 0.0001f); + Span spanA = a.AsSpan(), spanB = b.AsSpan(); + Assert.Equal(spanA.Length, spanB.Length); + for (int i = 0; i < spanA.Length; i++) + { + Assert.True(Math.Abs(Math.Abs(spanA[i].Real) - Math.Abs(spanB[i].Real)) < 0.0001f); + Assert.True(Math.Abs(Math.Abs(spanA[i].Imaginary) - Math.Abs(spanB[i].Imaginary)) < 0.0001f); + } } } } @@ -122,7 +125,7 @@ public void BokehBlurFilterProcessor(TestImageProvider provider, { provider.RunValidatingProcessorTest( x => x.BokehBlur(value.Radius, value.Components, value.Gamma), - testOutputDetails: value.ToString(), + testOutputDetails: value.ToString(), appendPixelTypeToFileName: false); } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 91943d9a6a..95f7f81fda 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -448,10 +448,10 @@ public static Image ComparePixelBufferTo(this Image imag { imageFrame.ComparePixelBufferTo(expectedPixel); } - + return image; } - + /// /// All pixels in all frames should be exactly equal to 'expectedPixelColor.ToPixel()'. /// @@ -462,7 +462,7 @@ public static Image ComparePixelBufferTo(this Image imag { imageFrame.ComparePixelBufferTo(expectedPixelColor.ToPixel()); } - + return image; } @@ -481,7 +481,7 @@ public static ImageFrame ComparePixelBufferTo(this ImageFrame ComparePixelBufferTo( this ImageFrame image, Span expectedPixels) @@ -524,7 +524,7 @@ public static Image CompareToOriginal( var testFile = TestFile.Create(path); referenceDecoder = referenceDecoder ?? TestEnvironment.GetReferenceDecoder(path); - + using (var original = Image.Load(testFile.Bytes, referenceDecoder)) { comparer.VerifySimilarity(original, image); @@ -558,7 +558,7 @@ internal static void VerifyOperation( appendPixelTypeToFileName: appendPixelTypeToFileName, appendSourceFileOrDescription: appendSourceFileOrDescription); - image.CompareToReferenceOutput(comparer, + image.CompareToReferenceOutput(comparer, provider, testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName, @@ -678,25 +678,31 @@ internal static Image ToGrayscaleImage(this Buffer2D buffer, floa private class MakeOpaqueProcessor : IImageProcessor { - public IImageProcessor CreatePixelSpecificProcessor() + public IImageProcessor CreatePixelSpecificProcessor(Image source, Rectangle sourceRectangle) where TPixel : struct, IPixel - { - return new MakeOpaqueProcessor(); - } + => new MakeOpaqueProcessor(source, sourceRectangle); } private class MakeOpaqueProcessor : ImageProcessor where TPixel : struct, IPixel { - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + public MakeOpaqueProcessor(Image source, Rectangle sourceRectangle) + : base(source, sourceRectangle) + { + + } + + protected override void OnFrameApply(ImageFrame source) { + Rectangle sourceRectangle = this.SourceRectangle; + Configuration configuration = this.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); + Span 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++) {