diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs index b8a61e5a32..8a7c424815 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs @@ -64,10 +64,6 @@ internal class Convolution2DProcessor : ImageProcessor var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - // We use a rectangle 3x the interest width to allocate a buffer big enough - // for source and target bulk pixel conversion. - var operationBounds = new Rectangle(interest.X, interest.Y, interest.Width * 3, interest.Height); - using (var map = new KernelSamplingMap(allocator)) { // Since the kernel sizes are identical we can use a single map. @@ -85,7 +81,7 @@ internal class Convolution2DProcessor : ImageProcessor ParallelRowIterator.IterateRows, Vector4>( this.Configuration, - operationBounds, + interest, in operation); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs index c04581444f..e5963bd390 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DRowOperation{TPixel}.cs @@ -49,7 +49,7 @@ internal readonly struct Convolution2DRowOperation : IRowOperation [MethodImpl(InliningOptions.ShortMethod)] public int GetRequiredBufferLength(Rectangle bounds) - => bounds.Width; + => 3 * bounds.Width; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs index fa05a98fd1..094a96f787 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs @@ -70,10 +70,6 @@ internal class Convolution2PassProcessor : ImageProcessor var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - // We use a rectangle 2x the interest width to allocate a buffer big enough - // for source and target bulk pixel conversion. - var operationBounds = new Rectangle(interest.X, interest.Y, interest.Width * 2, interest.Height); - // We can create a single sampling map with the size as if we were using the non separated 2D kernel // the two 1D kernels represent, and reuse it across both convolution steps, like in the bokeh blur. using var mapXY = new KernelSamplingMap(this.Configuration.MemoryAllocator); @@ -92,7 +88,7 @@ internal class Convolution2PassProcessor : ImageProcessor ParallelRowIterator.IterateRows( this.Configuration, - operationBounds, + interest, in horizontalOperation); // Vertical convolution @@ -107,7 +103,7 @@ internal class Convolution2PassProcessor : ImageProcessor ParallelRowIterator.IterateRows( this.Configuration, - operationBounds, + interest, in verticalOperation); } @@ -146,7 +142,7 @@ internal class Convolution2PassProcessor : ImageProcessor /// [MethodImpl(InliningOptions.ShortMethod)] public int GetRequiredBufferLength(Rectangle bounds) - => bounds.Width; + => 2 * bounds.Width; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -312,7 +308,7 @@ internal class Convolution2PassProcessor : ImageProcessor /// [MethodImpl(InliningOptions.ShortMethod)] public int GetRequiredBufferLength(Rectangle bounds) - => bounds.Width; + => 2 * bounds.Width; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs index f20cca3f71..54dad64a6b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs @@ -57,9 +57,6 @@ internal class ConvolutionProcessor : ImageProcessor var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - // We use a rectangle 2x the interest width to allocate a buffer big enough - // for source and target bulk pixel conversion. - var operationBounds = new Rectangle(interest.X, interest.Y, interest.Width * 2, interest.Height); using (var map = new KernelSamplingMap(allocator)) { map.BuildSamplingOffsetMap(this.KernelXY, interest); @@ -67,7 +64,7 @@ internal class ConvolutionProcessor : ImageProcessor var operation = new RowOperation(interest, targetPixels, source.PixelBuffer, map, this.KernelXY, this.Configuration, this.PreserveAlpha); ParallelRowIterator.IterateRows( this.Configuration, - operationBounds, + interest, in operation); } @@ -109,7 +106,7 @@ internal class ConvolutionProcessor : ImageProcessor /// [MethodImpl(InliningOptions.ShortMethod)] public int GetRequiredBufferLength(Rectangle bounds) - => bounds.Width; + => 2 * bounds.Width; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs index 4f0c2a36c9..fe3a29d437 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs @@ -31,11 +31,6 @@ internal sealed class MedianBlurProcessor : ImageProcessor Rectangle interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); - // We use a rectangle with width set wider, to allocate a buffer big enough - // for kernel source, channel buffers, source rows and target bulk pixel conversion. - int operationWidth = (2 * kernelSize * kernelSize) + interest.Width + (kernelSize * interest.Width); - Rectangle operationBounds = new(interest.X, interest.Y, operationWidth, interest.Height); - using KernelSamplingMap map = new(this.Configuration.MemoryAllocator); map.BuildSamplingOffsetMap(kernelSize, kernelSize, interest, this.definition.BorderWrapModeX, this.definition.BorderWrapModeY); @@ -50,7 +45,7 @@ internal sealed class MedianBlurProcessor : ImageProcessor ParallelRowIterator.IterateRows, Vector4>( this.Configuration, - operationBounds, + interest, in operation); Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); diff --git a/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs index 17df7b9be4..8caf33440d 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs @@ -46,11 +46,11 @@ internal readonly struct MedianRowOperation : IRowOperation /// [MethodImpl(InliningOptions.ShortMethod)] public int GetRequiredBufferLength(Rectangle bounds) - => bounds.Width; + => (2 * this.kernelSize * this.kernelSize) + bounds.Width + (kernelSize * bounds.Width); public void Invoke(int y, Span span) { - // Span has kernelSize^2 followed by bound width. + // Span has kernelSize^2 twice, then bound width followed by kernelsize * bounds width. int boundsX = this.bounds.X; int boundsWidth = this.bounds.Width; int kernelCount = this.kernelSize * this.kernelSize;