From d6c53a02becad3a9230e34d1431e0c314d22aa0f Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Fri, 7 Feb 2020 17:20:21 +0100 Subject: [PATCH] Refactor processors to single row logic --- src/ImageSharp/ImageFrame{TPixel}.cs | 19 ++-- .../BinaryThresholdProcessor{TPixel}.cs | 31 +++--- .../Convolution/BokehBlurProcessor{TPixel}.cs | 79 +++++++-------- .../EdgeDetectorCompassProcessor{TPixel}.cs | 39 ++++---- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 20 ++-- .../Effects/OilPaintingProcessor{TPixel}.cs | 97 +++++++++---------- ...lHistogramEqualizationProcessor{TPixel}.cs | 50 +++++----- .../BackgroundColorProcessor{TPixel}.cs | 33 +++---- .../AffineTransformProcessor{TPixel}.cs | 25 +++-- .../Transforms/CropProcessor{TPixel}.cs | 31 ++---- .../Transforms/FlipProcessor{TPixel}.cs | 19 ++-- .../ProjectiveTransformProcessor{TPixel}.cs | 29 +++--- .../Resize/ResizeProcessor{TPixel}.cs | 27 +++--- .../Transforms/RotateProcessor{TPixel}.cs | 75 +++++++------- 14 files changed, 253 insertions(+), 321 deletions(-) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index c3bab8e658..0a345db7c8 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -260,10 +260,10 @@ namespace SixLabors.ImageSharp var target = new ImageFrame(configuration, this.Width, this.Height, this.Metadata.DeepClone()); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( this.Bounds(), configuration, - new RowIntervalAction(this, target, configuration)); + new RowAction(this, target, configuration)); return target; } @@ -289,7 +289,7 @@ namespace SixLabors.ImageSharp /// /// A implementing the clone logic for . /// - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction where TPixel2 : struct, IPixel { private readonly ImageFrame source; @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp private readonly Configuration configuration; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction( + public RowAction( ImageFrame source, ImageFrame target, Configuration configuration) @@ -309,14 +309,11 @@ namespace SixLabors.ImageSharp /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span sourceRow = this.source.GetPixelRowSpan(y); - Span targetRow = this.target.GetPixelRowSpan(y); - PixelOperations.Instance.To(this.configuration, sourceRow, targetRow); - } + Span sourceRow = this.source.GetPixelRowSpan(y); + Span targetRow = this.target.GetPixelRowSpan(y); + PixelOperations.Instance.To(this.configuration, sourceRow, targetRow); } } } diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs index 9e9dccc464..26685d75be 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Binarization @@ -51,16 +50,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( workingRect, configuration, - new RowIntervalAction(source, upper, lower, threshold, startX, endX, isAlphaOnly)); + new RowAction(source, upper, lower, threshold, startX, endX, isAlphaOnly)); } /// /// A implementing the clone logic for . /// - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction { private readonly ImageFrame source; private readonly TPixel upper; @@ -71,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization private readonly bool isAlphaOnly; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction( + public RowAction( ImageFrame source, TPixel upper, TPixel lower, @@ -91,22 +90,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { Rgba32 rgba = default; - for (int y = rows.Min; y < rows.Max; y++) - { - Span row = this.source.GetPixelRowSpan(y); - for (int x = this.startX; x < this.endX; x++) - { - ref TPixel color = ref row[x]; - color.ToRgba32(ref rgba); + Span row = this.source.GetPixelRowSpan(y); + + for (int x = this.startX; x < this.endX; x++) + { + ref TPixel color = ref row[x]; + color.ToRgba32(ref rgba); - // Convert to grayscale using ITU-R Recommendation BT.709 if required - byte luminance = this.isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); - color = luminance >= this.threshold ? this.upper : this.lower; - } + // Convert to grayscale using ITU-R Recommendation BT.709 if required + byte luminance = this.isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B); + color = luminance >= this.threshold ? this.upper : this.lower; } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs index 834120f84a..71647234b5 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs @@ -282,10 +282,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution float inverseGamma = 1 / this.gamma; // Apply the inverse gamma exposure pass, and write the final pixel data - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( this.SourceRectangle, this.Configuration, - new ApplyInverseGammaExposureRowIntervalAction(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma)); + new ApplyInverseGammaExposureRowAction(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma)); } /// @@ -314,23 +314,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Vector4 parameters = Unsafe.Add(ref paramsRef, i); // Compute the vertical 1D convolution - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( sourceRectangle, configuration, - new ApplyVerticalConvolutionRowIntervalAction(ref sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel)); + new ApplyVerticalConvolutionRowAction(ref sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel)); // Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( sourceRectangle, configuration, - new ApplyHorizontalConvolutionRowIntervalAction(ref sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W)); + new ApplyHorizontalConvolutionRowAction(ref sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W)); } } /// /// A implementing the vertical convolution logic for . /// - private readonly struct ApplyVerticalConvolutionRowIntervalAction : IRowIntervalAction + private readonly struct ApplyVerticalConvolutionRowAction : IRowAction { private readonly Rectangle bounds; private readonly Buffer2D targetValues; @@ -340,7 +340,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly int maxX; [MethodImpl(InliningOptions.ShortMethod)] - public ApplyVerticalConvolutionRowIntervalAction( + public ApplyVerticalConvolutionRowAction( ref Rectangle bounds, Buffer2D targetValues, Buffer2D sourcePixels, @@ -356,16 +356,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); - for (int x = 0; x < this.bounds.Width; x++) - { - Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX); - } + for (int x = 0; x < this.bounds.Width; x++) + { + Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX); } } } @@ -373,7 +370,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the horizontal convolution logic for . /// - private readonly struct ApplyHorizontalConvolutionRowIntervalAction : IRowIntervalAction + private readonly struct ApplyHorizontalConvolutionRowAction : IRowAction { private readonly Rectangle bounds; private readonly Buffer2D targetValues; @@ -385,7 +382,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly int maxX; [MethodImpl(InliningOptions.ShortMethod)] - public ApplyHorizontalConvolutionRowIntervalAction( + public ApplyHorizontalConvolutionRowAction( ref Rectangle bounds, Buffer2D targetValues, Buffer2D sourceValues, @@ -405,16 +402,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); + Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); - for (int x = 0; x < this.bounds.Width; x++) - { - Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w); - } + for (int x = 0; x < this.bounds.Width; x++) + { + Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w); } } } @@ -471,7 +465,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// /// A implementing the inverse gamma exposure logic for . /// - private readonly struct ApplyInverseGammaExposureRowIntervalAction : IRowIntervalAction + private readonly struct ApplyInverseGammaExposureRowAction : IRowAction { private readonly Rectangle bounds; private readonly Buffer2D targetPixels; @@ -480,7 +474,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly float inverseGamma; [MethodImpl(InliningOptions.ShortMethod)] - public ApplyInverseGammaExposureRowIntervalAction( + public ApplyInverseGammaExposureRowAction( Rectangle bounds, Buffer2D targetPixels, Buffer2D sourceValues, @@ -496,28 +490,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { Vector4 low = Vector4.Zero; var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); - for (int y = rows.Min; y < rows.Max; y++) - { - Span targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); - Span sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); - ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); - - for (int x = 0; x < this.bounds.Width; x++) - { - ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); - var clamp = Vector4.Clamp(v, low, high); - v.X = MathF.Pow(clamp.X, this.inverseGamma); - v.Y = MathF.Pow(clamp.Y, this.inverseGamma); - v.Z = MathF.Pow(clamp.Z, this.inverseGamma); - } + Span targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); + Span sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); + ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); - PixelOperations.Instance.FromVector4Destructive(this.configuration, sourceRowSpan.Slice(0, this.bounds.Width), targetPixelSpan, PixelConversionModifiers.Premultiply); + for (int x = 0; x < this.bounds.Width; x++) + { + ref Vector4 v = ref Unsafe.Add(ref sourceRef, x); + var clamp = Vector4.Clamp(v, low, high); + v.X = MathF.Pow(clamp.X, this.inverseGamma); + v.Y = MathF.Pow(clamp.Y, this.inverseGamma); + v.Z = MathF.Pow(clamp.Z, this.inverseGamma); } + + PixelOperations.Instance.FromVector4Destructive(this.configuration, sourceRowSpan.Slice(0, this.bounds.Width), targetPixelSpan, PixelConversionModifiers.Premultiply); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index e2480957ea..6ccd9914bb 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -102,17 +102,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution processor.Apply(pass); } - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( Rectangle.FromLTRB(minX, minY, maxX, maxY), this.Configuration, - new RowIntervalAction(source.PixelBuffer, pass.PixelBuffer, minX, maxX, shiftY, shiftX)); + new RowAction(source.PixelBuffer, pass.PixelBuffer, minX, maxX, shiftY, shiftX)); } } /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction { private readonly Buffer2D targetPixels; private readonly Buffer2D passPixels; @@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution private readonly int shiftX; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction( + public RowAction( Buffer2D targetPixels, Buffer2D passPixels, int minX, @@ -140,29 +140,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - int offsetY = y - this.shiftY; + int offsetY = y - this.shiftY; - ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(offsetY)); - ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(offsetY)); + ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(offsetY)); + ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(offsetY)); - for (int x = this.minX; x < this.maxX; x++) - { - int offsetX = x - this.shiftX; + for (int x = this.minX; x < this.maxX; x++) + { + int offsetX = x - this.shiftX; - // Grab the max components of the two pixels - ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX); - ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX); + // Grab the max components of the two pixels + ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX); + ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX); - var pixelValue = Vector4.Max( - currentPassPixel.ToVector4(), - currentTargetPixel.ToVector4()); + var pixelValue = Vector4.Max( + currentPassPixel.ToVector4(), + currentTargetPixel.ToVector4()); - currentTargetPixel.FromVector4(pixelValue); - } + currentTargetPixel.FromVector4(pixelValue); } } } diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index 2a181174c7..55399c5fde 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Drawing @@ -99,16 +98,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing "Cannot draw image because the source image does not overlap the target image."); } - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( workingRect, configuration, - new RowIntervalAction(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity)); + new RowAction(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity)); } /// /// A implementing the draw logic for . /// - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction { private readonly ImageFrame sourceFrame; private readonly Image targetImage; @@ -121,7 +120,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing private readonly float opacity; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction( + public RowAction( ImageFrame sourceFrame, Image targetImage, PixelBlender blender, @@ -145,14 +144,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width); - Span foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width); - this.blender.Blend(this.configuration, background, background, foreground, this.opacity); - } + Span background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width); + Span foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width); + this.blender.Blend(this.configuration, background, background, foreground, this.opacity); } } } diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs index 4abaf7ac42..728e4850d4 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs @@ -47,10 +47,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects source.CopyTo(targetPixels); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( this.SourceRectangle, this.Configuration, - new RowIntervalAction(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels)); + new RowAction(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels)); Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects /// /// A implementing the convolution logic for . /// - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction { private readonly Rectangle bounds; private readonly Buffer2D targetPixels; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects private readonly int levels; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction( + public RowAction( Rectangle bounds, Buffer2D targetPixels, ImageFrame source, @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { int maxY = this.bounds.Bottom - 1; int maxX = this.bounds.Right - 1; @@ -117,69 +117,66 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects ref float blueBinRef = ref Unsafe.Add(ref redBinRef, this.levels); ref float greenBinRef = ref Unsafe.Add(ref blueBinRef, this.levels); - for (int y = rows.Min; y < rows.Max; y++) - { - Span sourceRowPixelSpan = this.source.GetPixelRowSpan(y); - Span sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(this.bounds.X, this.bounds.Width); + Span sourceRowPixelSpan = this.source.GetPixelRowSpan(y); + Span sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(this.bounds.X, this.bounds.Width); - PixelOperations.Instance.ToVector4(this.configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span); + PixelOperations.Instance.ToVector4(this.configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span); - for (int x = this.bounds.X; x < this.bounds.Right; x++) - { - int maxIntensity = 0; - int maxIndex = 0; + for (int x = this.bounds.X; x < this.bounds.Right; x++) + { + int maxIntensity = 0; + int maxIndex = 0; - // Clear the current shared buffer before processing each target pixel - bins.Memory.Span.Clear(); + // Clear the current shared buffer before processing each target pixel + bins.Memory.Span.Clear(); - for (int fy = 0; fy <= this.radius; fy++) - { - int fyr = fy - this.radius; - int offsetY = y + fyr; + for (int fy = 0; fy <= this.radius; fy++) + { + int fyr = fy - this.radius; + int offsetY = y + fyr; - offsetY = offsetY.Clamp(0, maxY); + offsetY = offsetY.Clamp(0, maxY); - Span sourceOffsetRow = this.source.GetPixelRowSpan(offsetY); + Span sourceOffsetRow = this.source.GetPixelRowSpan(offsetY); - for (int fx = 0; fx <= this.radius; fx++) - { - int fxr = fx - this.radius; - int offsetX = x + fxr; - offsetX = offsetX.Clamp(0, maxX); + for (int fx = 0; fx <= this.radius; fx++) + { + int fxr = fx - this.radius; + int offsetX = x + fxr; + offsetX = offsetX.Clamp(0, maxX); - var vector = sourceOffsetRow[offsetX].ToVector4(); + var vector = sourceOffsetRow[offsetX].ToVector4(); - float sourceRed = vector.X; - float sourceBlue = vector.Z; - float sourceGreen = vector.Y; + float sourceRed = vector.X; + float sourceBlue = vector.Z; + float sourceGreen = vector.Y; - int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (this.levels - 1)); + int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (this.levels - 1)); - Unsafe.Add(ref intensityBinRef, currentIntensity)++; - Unsafe.Add(ref redBinRef, currentIntensity) += sourceRed; - Unsafe.Add(ref blueBinRef, currentIntensity) += sourceBlue; - Unsafe.Add(ref greenBinRef, currentIntensity) += sourceGreen; + Unsafe.Add(ref intensityBinRef, currentIntensity)++; + Unsafe.Add(ref redBinRef, currentIntensity) += sourceRed; + Unsafe.Add(ref blueBinRef, currentIntensity) += sourceBlue; + Unsafe.Add(ref greenBinRef, currentIntensity) += sourceGreen; - if (Unsafe.Add(ref intensityBinRef, currentIntensity) > maxIntensity) - { - maxIntensity = Unsafe.Add(ref intensityBinRef, currentIntensity); - maxIndex = currentIntensity; - } + if (Unsafe.Add(ref intensityBinRef, currentIntensity) > maxIntensity) + { + maxIntensity = Unsafe.Add(ref intensityBinRef, currentIntensity); + maxIndex = currentIntensity; } + } - float red = MathF.Abs(Unsafe.Add(ref redBinRef, maxIndex) / maxIntensity); - float blue = MathF.Abs(Unsafe.Add(ref blueBinRef, maxIndex) / maxIntensity); - float green = MathF.Abs(Unsafe.Add(ref greenBinRef, maxIndex) / maxIntensity); - float alpha = sourceRowVector4Span[x].W; + float red = MathF.Abs(Unsafe.Add(ref redBinRef, maxIndex) / maxIntensity); + float blue = MathF.Abs(Unsafe.Add(ref blueBinRef, maxIndex) / maxIntensity); + float green = MathF.Abs(Unsafe.Add(ref greenBinRef, maxIndex) / maxIntensity); + float alpha = sourceRowVector4Span[x].W; - targetRowVector4Span[x] = new Vector4(red, green, blue, alpha); - } + targetRowVector4Span[x] = new Vector4(red, green, blue, alpha); } + } - Span targetRowAreaPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X, this.bounds.Width); + Span targetRowAreaPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X, this.bounds.Width); - PixelOperations.Instance.FromVector4Destructive(this.configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan); - } + PixelOperations.Instance.FromVector4Destructive(this.configuration, targetRowAreaVector4Span, targetRowAreaPixelSpan); } } } diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs index 5d25bae821..b6ae981fc1 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs @@ -52,10 +52,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization using IMemoryOwner histogramBuffer = memoryAllocator.Allocate(this.LuminanceLevels, AllocationOptions.Clean); // Build the histogram of the grayscale levels - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( workingRect, this.Configuration, - new GrayscaleLevelsRowIntervalAction(workingRect, histogramBuffer, source, this.LuminanceLevels)); + new GrayscaleLevelsRowAction(workingRect, histogramBuffer, source, this.LuminanceLevels)); Span histogram = histogramBuffer.GetSpan(); if (this.ClipHistogramEnabled) @@ -74,16 +74,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization float numberOfPixelsMinusCdfMin = numberOfPixels - cdfMin; // Apply the cdf to each pixel of the image - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( workingRect, this.Configuration, - new CdfApplicationRowIntervalAction(workingRect, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin)); + new CdfApplicationRowAction(workingRect, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin)); } /// /// A implementing the grayscale levels logic for . /// - private readonly struct GrayscaleLevelsRowIntervalAction : IRowIntervalAction + private readonly struct GrayscaleLevelsRowAction : IRowAction { private readonly Rectangle bounds; private readonly IMemoryOwner histogramBuffer; @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization private readonly int luminanceLevels; [MethodImpl(InliningOptions.ShortMethod)] - public GrayscaleLevelsRowIntervalAction( + public GrayscaleLevelsRowAction( in Rectangle bounds, IMemoryOwner histogramBuffer, ImageFrame source, @@ -105,18 +105,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { ref int histogramBase = ref MemoryMarshal.GetReference(this.histogramBuffer.GetSpan()); - for (int y = rows.Min; y < rows.Max; y++) - { - ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); + ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); - for (int x = 0; x < this.bounds.Width; x++) - { - int luminance = GetLuminance(Unsafe.Add(ref pixelBase, x), this.luminanceLevels); - Unsafe.Add(ref histogramBase, luminance)++; - } + for (int x = 0; x < this.bounds.Width; x++) + { + int luminance = GetLuminance(Unsafe.Add(ref pixelBase, x), this.luminanceLevels); + Unsafe.Add(ref histogramBase, luminance)++; } } } @@ -124,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// /// A implementing the cdf application levels logic for . /// - private readonly struct CdfApplicationRowIntervalAction : IRowIntervalAction + private readonly struct CdfApplicationRowAction : IRowAction { private readonly Rectangle bounds; private readonly IMemoryOwner cdfBuffer; @@ -133,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization private readonly float numberOfPixelsMinusCdfMin; [MethodImpl(InliningOptions.ShortMethod)] - public CdfApplicationRowIntervalAction( + public CdfApplicationRowAction( in Rectangle bounds, IMemoryOwner cdfBuffer, ImageFrame source, @@ -149,20 +146,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { ref int cdfBase = ref MemoryMarshal.GetReference(this.cdfBuffer.GetSpan()); - for (int y = rows.Min; y < rows.Max; y++) + ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); + + for (int x = 0; x < this.bounds.Width; x++) { - ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y)); - - for (int x = 0; x < this.bounds.Width; x++) - { - ref TPixel pixel = ref Unsafe.Add(ref pixelBase, x); - int luminance = GetLuminance(pixel, this.luminanceLevels); - float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / this.numberOfPixelsMinusCdfMin; - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); - } + ref TPixel pixel = ref Unsafe.Add(ref pixelBase, x); + int luminance = GetLuminance(pixel, this.luminanceLevels); + float luminanceEqualized = Unsafe.Add(ref cdfBase, luminance) / this.numberOfPixelsMinusCdfMin; + pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); } } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs index a9b91e837f..cb19211c29 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs @@ -49,13 +49,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays PixelBlender blender = PixelOperations.Instance.GetPixelBlender(graphicsOptions); - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( interest, configuration, - new RowIntervalAction(configuration, interest, blender, amount, colors, source)); + new RowAction(configuration, interest, blender, amount, colors, source)); } - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction { private readonly Configuration configuration; private readonly Rectangle bounds; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays private readonly ImageFrame source; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction( + public RowAction( Configuration configuration, Rectangle bounds, PixelBlender blender, @@ -82,23 +82,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destination = - this.source.GetPixelRowSpan(y) - .Slice(this.bounds.X, this.bounds.Width); + Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width); - // Switch color & destination in the 2nd and 3rd places because we are - // applying the target color under the current one. - this.blender.Blend( - this.configuration, - destination, - this.colors.GetSpan(), - destination, - this.amount.GetSpan()); - } + // Switch color & destination in the 2nd and 3rd places because we are + // applying the target color under the current one. + this.blender.Blend( + this.configuration, + destination, + this.colors.GetSpan(), + destination, + this.amount.GetSpan()); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs index 402a052496..9bf9dc5076 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs @@ -58,10 +58,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (this.resampler is NearestNeighborResampler) { - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( targetBounds, configuration, - new NearestNeighborRowIntervalAction(this.SourceRectangle, ref matrix, width, source, destination)); + new NearestNeighborRowAction(this.SourceRectangle, ref matrix, width, source, destination)); return; } @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// A implementing the nearest neighbor resampler logic for . /// - private readonly struct NearestNeighborRowIntervalAction : IRowIntervalAction + private readonly struct NearestNeighborRowAction : IRowAction { private readonly Rectangle bounds; private readonly Matrix3x2 matrix; @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public NearestNeighborRowIntervalAction( + public NearestNeighborRowAction( Rectangle bounds, ref Matrix3x2 matrix, int maxX, @@ -103,19 +103,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span destRow = this.destination.GetPixelRowSpan(y); + Span destRow = this.destination.GetPixelRowSpan(y); - for (int x = 0; x < this.maxX; x++) + for (int x = 0; x < this.maxX; x++) + { + var point = Point.Transform(new Point(x, y), this.matrix); + if (this.bounds.Contains(point.X, point.Y)) { - var point = Point.Transform(new Point(x, y), this.matrix); - if (this.bounds.Contains(point.X, point.Y)) - { - destRow[x] = this.source[point.X, point.Y]; - } + destRow[x] = this.source[point.X, point.Y]; } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs index 103c5d3ffc..55b1534675 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -48,34 +47,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Rectangle bounds = this.cropRectangle; // Copying is cheap, we should process more pixels per task: - ParallelExecutionSettings parallelSettings = - ParallelExecutionSettings.FromConfiguration(this.Configuration).MultiplyMinimumPixelsPerTask(4); + ParallelExecutionSettings parallelSettings = ParallelExecutionSettings.FromConfiguration(this.Configuration).MultiplyMinimumPixelsPerTask(4); - var rowAction = new RowIntervalAction(ref bounds, source, destination); - - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( bounds, in parallelSettings, - in rowAction); + new RowAction(ref bounds, source, destination)); } /// /// A implementing the processor logic for . /// - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction { private readonly Rectangle bounds; private readonly ImageFrame source; private readonly ImageFrame destination; - /// - /// Initializes a new instance of the struct. - /// - /// The target processing bounds for the current instance. - /// The source for the current instance. - /// The destination for the current instance. [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction(ref Rectangle bounds, ImageFrame source, ImageFrame destination) + public RowAction(ref Rectangle bounds, ImageFrame source, ImageFrame destination) { this.bounds = bounds; this.source = source; @@ -84,14 +74,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left); - Span targetRow = this.destination.GetPixelRowSpan(y - this.bounds.Top); - sourceRow.Slice(0, this.bounds.Width).CopyTo(targetRow); - } + Span sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left); + Span targetRow = this.destination.GetPixelRowSpan(y - this.bounds.Top); + sourceRow.Slice(0, this.bounds.Width).CopyTo(targetRow); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs index 041f602a55..b88ead08fa 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor{TPixel}.cs @@ -5,7 +5,6 @@ using System; using System.Buffers; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Processing.Processors.Transforms @@ -76,26 +75,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void FlipY(ImageFrame source, Configuration configuration) { - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( source.Bounds(), configuration, - new RowIntervalAction(source)); + new RowAction(source)); } - private readonly struct RowIntervalAction : IRowIntervalAction + /// + /// A implementing the reverse logic for . + /// + private readonly struct RowAction : IRowAction { private readonly ImageFrame source; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction(ImageFrame source) => this.source = source; + public RowAction(ImageFrame source) => this.source = source; [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - this.source.GetPixelRowSpan(y).Reverse(); - } + this.source.GetPixelRowSpan(y).Reverse(); } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs index 5034b072f5..5a13619c55 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor{TPixel}.cs @@ -60,10 +60,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { Rectangle sourceBounds = this.SourceRectangle; - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( targetBounds, configuration, - new NearestNeighborRowIntervalAction(ref sourceBounds, ref matrix, width, source, destination)); + new NearestNeighborRowAction(ref sourceBounds, ref matrix, width, source, destination)); return; } @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms new RowIntervalAction(configuration, kernelMap, ref matrix, width, source, destination)); } - private readonly struct NearestNeighborRowIntervalAction : IRowIntervalAction + private readonly struct NearestNeighborRowAction : IRowAction { private readonly Rectangle bounds; private readonly Matrix4x4 matrix; @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public NearestNeighborRowIntervalAction( + public NearestNeighborRowAction( ref Rectangle bounds, ref Matrix4x4 matrix, int maxX, @@ -100,22 +100,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) + Span destRow = this.destination.GetPixelRowSpan(y); + + for (int x = 0; x < this.maxX; x++) { - Span destRow = this.destination.GetPixelRowSpan(y); + Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix); + int px = (int)MathF.Round(point.X); + int py = (int)MathF.Round(point.Y); - for (int x = 0; x < this.maxX; x++) + if (this.bounds.Contains(px, py)) { - Vector2 point = TransformUtils.ProjectiveTransform2D(x, y, this.matrix); - int px = (int)MathF.Round(point.X); - int py = (int)MathF.Round(point.Y); - - if (this.bounds.Contains(px, py)) - { - destRow[x] = this.source[px, py]; - } + destRow[x] = this.source[px, py]; } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 02622622d7..027846fc4e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -95,10 +95,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float widthFactor = sourceRectangle.Width / (float)this.targetRectangle.Width; float heightFactor = sourceRectangle.Height / (float)this.targetRectangle.Height; - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( interest, configuration, - new RowIntervalAction(sourceRectangle, this.targetRectangle, widthFactor, heightFactor, source, destination)); + new RowAction(sourceRectangle, this.targetRectangle, widthFactor, heightFactor, source, destination)); return; } @@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms base.Dispose(disposing); } - private readonly struct RowIntervalAction : IRowIntervalAction + private readonly struct RowAction : IRowAction { private readonly Rectangle sourceBounds; private readonly Rectangle destinationBounds; @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public RowIntervalAction( + public RowAction( Rectangle sourceBounds, Rectangle destinationBounds, float widthFactor, @@ -174,7 +174,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { int sourceX = this.sourceBounds.X; int sourceY = this.sourceBounds.Y; @@ -183,17 +183,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int destLeft = this.destinationBounds.Left; int destRight = this.destinationBounds.Right; - for (int y = rows.Min; y < rows.Max; y++) + // Y coordinates of source points + Span sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY)); + Span targetRow = this.destination.GetPixelRowSpan(y); + + for (int x = destLeft; x < destRight; x++) { - // Y coordinates of source points - Span sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY)); - Span targetRow = this.destination.GetPixelRowSpan(y); - - for (int x = destLeft; x < destRight; x++) - { - // X coordinates of source points - targetRow[x] = sourceRow[(int)(((x - destX) * this.widthFactor) + sourceX)]; - } + // X coordinates of source points + targetRow[x] = sourceRow[(int)(((x - destX) * this.widthFactor) + sourceX)]; } } } diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs index bf03ce319b..6107c8ef9c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor{TPixel}.cs @@ -131,10 +131,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void Rotate180(ImageFrame source, ImageFrame destination, Configuration configuration) { - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( source.Bounds(), configuration, - new Rotate180RowIntervalAction(source.Width, source.Height, source, destination)); + new Rotate180RowAction(source.Width, source.Height, source, destination)); } /// @@ -145,10 +145,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void Rotate270(ImageFrame source, ImageFrame destination, Configuration configuration) { - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( source.Bounds(), configuration, - new Rotate270RowIntervalAction(destination.Bounds(), source.Width, source.Height, source, destination)); + new Rotate270RowAction(destination.Bounds(), source.Width, source.Height, source, destination)); } /// @@ -159,13 +159,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void Rotate90(ImageFrame source, ImageFrame destination, Configuration configuration) { - ParallelRowIterator.IterateRows( + ParallelRowIterator.IterateRows2( source.Bounds(), configuration, - new Rotate90RowIntervalAction(destination.Bounds(), source.Width, source.Height, source, destination)); + new Rotate90RowAction(destination.Bounds(), source.Width, source.Height, source, destination)); } - private readonly struct Rotate180RowIntervalAction : IRowIntervalAction + private readonly struct Rotate180RowAction : IRowAction { private readonly int width; private readonly int height; @@ -173,7 +173,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public Rotate180RowIntervalAction( + public Rotate180RowAction( int width, int height, ImageFrame source, @@ -186,22 +186,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) - { - Span sourceRow = this.source.GetPixelRowSpan(y); - Span targetRow = this.destination.GetPixelRowSpan(this.height - y - 1); + Span sourceRow = this.source.GetPixelRowSpan(y); + Span targetRow = this.destination.GetPixelRowSpan(this.height - y - 1); - for (int x = 0; x < this.width; x++) - { - targetRow[this.width - x - 1] = sourceRow[x]; - } + for (int x = 0; x < this.width; x++) + { + targetRow[this.width - x - 1] = sourceRow[x]; } } } - private readonly struct Rotate270RowIntervalAction : IRowIntervalAction + private readonly struct Rotate270RowAction : IRowAction { private readonly Rectangle bounds; private readonly int width; @@ -210,7 +207,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public Rotate270RowIntervalAction( + public Rotate270RowAction( Rectangle bounds, int width, int height, @@ -225,27 +222,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) + Span sourceRow = this.source.GetPixelRowSpan(y); + for (int x = 0; x < this.width; x++) { - Span sourceRow = this.source.GetPixelRowSpan(y); - for (int x = 0; x < this.width; x++) + int newX = this.height - y - 1; + newX = this.height - newX - 1; + int newY = this.width - x - 1; + + if (this.bounds.Contains(newX, newY)) { - int newX = this.height - y - 1; - newX = this.height - newX - 1; - int newY = this.width - x - 1; - - if (this.bounds.Contains(newX, newY)) - { - this.destination[newX, newY] = sourceRow[x]; - } + this.destination[newX, newY] = sourceRow[x]; } } } } - private readonly struct Rotate90RowIntervalAction : IRowIntervalAction + private readonly struct Rotate90RowAction : IRowAction { private readonly Rectangle bounds; private readonly int width; @@ -254,7 +248,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly ImageFrame destination; [MethodImpl(InliningOptions.ShortMethod)] - public Rotate90RowIntervalAction( + public Rotate90RowAction( Rectangle bounds, int width, int height, @@ -269,18 +263,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } [MethodImpl(InliningOptions.ShortMethod)] - public void Invoke(in RowInterval rows) + public void Invoke(int y) { - for (int y = rows.Min; y < rows.Max; y++) + Span sourceRow = this.source.GetPixelRowSpan(y); + int newX = this.height - y - 1; + for (int x = 0; x < this.width; x++) { - Span sourceRow = this.source.GetPixelRowSpan(y); - int newX = this.height - y - 1; - for (int x = 0; x < this.width; x++) + if (this.bounds.Contains(newX, x)) { - if (this.bounds.Contains(newX, x)) - { - this.destination[newX, x] = sourceRow[x]; - } + this.destination[newX, x] = sourceRow[x]; } } }