diff --git a/src/ImageSharp/Advanced/IRowAction.cs b/src/ImageSharp/Advanced/IRowAction.cs
deleted file mode 100644
index 74498eb0b1..0000000000
--- a/src/ImageSharp/Advanced/IRowAction.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Runtime.CompilerServices;
-
-namespace SixLabors.ImageSharp.Advanced
-{
- ///
- /// Defines the contract for an action that operates on a row.
- ///
- public interface IRowAction
- {
- ///
- /// Invokes the method passing the row y coordinate.
- ///
- /// The row y coordinate.
- void Invoke(int y);
- }
-
- ///
- /// A that wraps a value delegate of a specified type, and info on the memory areas to process
- ///
- /// The type of value delegate to invoke
- internal readonly struct WrappingRowAction
- where T : struct, IRowAction
- {
- public readonly int MinY;
- public readonly int MaxY;
- public readonly int StepY;
- public readonly int MaxX;
-
- private readonly T action;
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public WrappingRowAction(int minY, int maxY, int stepY, in T action)
- : this(minY, maxY, stepY, 0, action)
- {
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public WrappingRowAction(int minY, int maxY, int stepY, int maxX, in T action)
- {
- this.MinY = minY;
- this.MaxY = maxY;
- this.StepY = stepY;
- this.MaxX = maxX;
- this.action = action;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int i)
- {
- int yMin = this.MinY + (i * this.StepY);
-
- if (yMin >= this.MaxY)
- {
- return;
- }
-
- int yMax = Math.Min(yMin + this.StepY, this.MaxY);
-
- for (int y = yMin; y < yMax; y++)
- {
- // Skip the safety copy when invoking a potentially impure method on a readonly field
- Unsafe.AsRef(this.action).Invoke(y);
- }
- }
- }
-}
diff --git a/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs b/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs
deleted file mode 100644
index 4bf0d1fe44..0000000000
--- a/src/ImageSharp/Advanced/IRowAction{TBuffer}.cs
+++ /dev/null
@@ -1,88 +0,0 @@
-// Copyright (c) Six Labors and contributors.
-// Licensed under the Apache License, Version 2.0.
-
-using System;
-using System.Buffers;
-using System.Runtime.CompilerServices;
-using SixLabors.ImageSharp.Memory;
-
-namespace SixLabors.ImageSharp.Advanced
-{
- ///
- /// Defines the contract for an action that operates on a row with a temporary buffer.
- ///
- /// The type of buffer elements.
- public interface IRowAction
- where TBuffer : unmanaged
- {
- ///
- /// Invokes the method passing the row and a buffer.
- ///
- /// The row y coordinate.
- /// The contiguous region of memory.
- void Invoke(int y, Span span);
- }
-
- internal readonly struct WrappingRowAction
- where T : struct, IRowAction
- where TBuffer : unmanaged
- {
- public readonly int MinY;
- public readonly int MaxY;
- public readonly int StepY;
- public readonly int MaxX;
-
- private readonly MemoryAllocator allocator;
- private readonly T action;
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public WrappingRowAction(
- int minY,
- int maxY,
- int stepY,
- MemoryAllocator allocator,
- in T action)
- : this(minY, maxY, stepY, 0, allocator, action)
- {
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public WrappingRowAction(
- int minY,
- int maxY,
- int stepY,
- int maxX,
- MemoryAllocator allocator,
- in T action)
- {
- this.MinY = minY;
- this.MaxY = maxY;
- this.StepY = stepY;
- this.MaxX = maxX;
- this.allocator = allocator;
- this.action = action;
- }
-
- [MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int i)
- {
- int yMin = this.MinY + (i * this.StepY);
-
- if (yMin >= this.MaxY)
- {
- return;
- }
-
- int yMax = Math.Min(yMin + this.StepY, this.MaxY);
-
- using IMemoryOwner buffer = this.allocator.Allocate(this.MaxX);
-
- Span span = buffer.Memory.Span;
-
- for (int y = yMin; y < yMax; y++)
- {
- Unsafe.AsRef(this.action).Invoke(y, span);
- }
- }
- }
-}
diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs
index d57e673c0e..5c8a30f68b 100644
--- a/src/ImageSharp/Advanced/ParallelRowIterator.cs
+++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs
@@ -19,32 +19,32 @@ namespace SixLabors.ImageSharp.Advanced
public static class ParallelRowIterator
{
///
- /// Iterate through the rows of a rectangle in optimized batches.
+ /// Iterate through the rows of a rectangle in optimized batches defined by -s.
///
/// The type of row action to perform.
/// The .
/// The to get the parallel settings from.
- /// The method body defining the iteration logic on a single row.
+ /// The method body defining the iteration logic on a single .
[MethodImpl(InliningOptions.ShortMethod)]
public static void IterateRows(Rectangle rectangle, Configuration configuration, in T body)
- where T : struct, IRowAction
+ where T : struct, IRowIntervalAction
{
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows(rectangle, in parallelSettings, in body);
}
///
- /// Iterate through the rows of a rectangle in optimized batches.
+ /// Iterate through the rows of a rectangle in optimized batches defined by -s.
///
/// The type of row action to perform.
/// The .
/// The .
- /// The method body defining the iteration logic on a single row.
+ /// The method body defining the iteration logic on a single .
public static void IterateRows(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
in T body)
- where T : struct, IRowAction
+ where T : struct, IRowIntervalAction
{
ValidateRectangle(rectangle);
@@ -59,17 +59,15 @@ namespace SixLabors.ImageSharp.Advanced
// Avoid TPL overhead in this trivial case:
if (numOfSteps == 1)
{
- for (int y = top; y < bottom; y++)
- {
- Unsafe.AsRef(body).Invoke(y);
- }
-
+ var rows = new RowInterval(top, bottom);
+ Unsafe.AsRef(body).Invoke(in rows);
return;
}
int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
- var rowAction = new WrappingRowAction(top, bottom, verticalStep, in body);
+ var rowInfo = new WrappingRowIntervalInfo(top, bottom, verticalStep);
+ var rowAction = new WrappingRowIntervalAction(in rowInfo, in body);
Parallel.For(
0,
@@ -88,7 +86,7 @@ namespace SixLabors.ImageSharp.Advanced
/// The to get the parallel settings from.
/// The method body defining the iteration logic on a single .
public static void IterateRows(Rectangle rectangle, Configuration configuration, in T body)
- where T : struct, IRowAction
+ where T : struct, IRowIntervalAction
where TBuffer : unmanaged
{
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
@@ -103,7 +101,7 @@ namespace SixLabors.ImageSharp.Advanced
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
in T body)
- where T : struct, IRowAction
+ where T : struct, IRowIntervalAction
where TBuffer : unmanaged
{
ValidateRectangle(rectangle);
@@ -120,14 +118,10 @@ namespace SixLabors.ImageSharp.Advanced
// Avoid TPL overhead in this trivial case:
if (numOfSteps == 1)
{
+ var rows = new RowInterval(top, bottom);
using (IMemoryOwner buffer = allocator.Allocate(width))
{
- Span span = buffer.Memory.Span;
-
- for (int y = top; y < bottom; y++)
- {
- Unsafe.AsRef(body).Invoke(y, span);
- }
+ Unsafe.AsRef(body).Invoke(rows, buffer.Memory);
}
return;
@@ -135,7 +129,8 @@ namespace SixLabors.ImageSharp.Advanced
int verticalStep = DivideCeil(height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
- var rowAction = new WrappingRowAction(top, bottom, verticalStep, width, allocator, in body);
+ var rowInfo = new WrappingRowIntervalInfo(top, bottom, verticalStep, width);
+ var rowAction = new WrappingRowIntervalBufferAction(in rowInfo, allocator, in body);
Parallel.For(
0,
diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs
index 57b8a953a0..c3bab8e658 100644
--- a/src/ImageSharp/ImageFrame{TPixel}.cs
+++ b/src/ImageSharp/ImageFrame{TPixel}.cs
@@ -263,7 +263,7 @@ namespace SixLabors.ImageSharp
ParallelRowIterator.IterateRows(
this.Bounds(),
configuration,
- new RowAction(this, target, configuration));
+ new RowIntervalAction(this, target, configuration));
return target;
}
@@ -289,7 +289,7 @@ namespace SixLabors.ImageSharp
///
/// A implementing the clone logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
where TPixel2 : struct, IPixel
{
private readonly ImageFrame source;
@@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp
private readonly Configuration configuration;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
ImageFrame source,
ImageFrame target,
Configuration configuration)
@@ -309,11 +309,14 @@ namespace SixLabors.ImageSharp
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- Span sourceRow = this.source.GetPixelRowSpan(y);
- Span targetRow = this.target.GetPixelRowSpan(y);
- PixelOperations.Instance.To(this.configuration, sourceRow, targetRow);
+ 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);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
index 4db2b938ff..9e9dccc464 100644
--- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
@@ -4,6 +4,7 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization
@@ -53,13 +54,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
ParallelRowIterator.IterateRows(
workingRect,
configuration,
- new RowAction(source, upper, lower, threshold, startX, endX, isAlphaOnly));
+ new RowIntervalAction(source, upper, lower, threshold, startX, endX, isAlphaOnly));
}
///
/// A implementing the clone logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly ImageFrame source;
private readonly TPixel upper;
@@ -70,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
private readonly bool isAlphaOnly;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
ImageFrame source,
TPixel upper,
TPixel lower,
@@ -90,20 +91,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
Rgba32 rgba = default;
-
- Span row = this.source.GetPixelRowSpan(y);
-
- for (int x = this.startX; x < this.endX; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- 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 05508c90fb..834120f84a 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
@@ -268,10 +268,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
protected override void OnFrameApply(ImageFrame source)
{
// Preliminary gamma highlight pass
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
this.SourceRectangle,
this.Configuration,
- new ApplyGammaExposureRowAction(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma));
+ new ApplyGammaExposureRowIntervalAction(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma));
// Create a 0-filled buffer to use to store the result of the component convolutions
using Buffer2D processingBuffer = this.Configuration.MemoryAllocator.Allocate2D(source.Size(), AllocationOptions.Clean);
@@ -285,7 +285,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ParallelRowIterator.IterateRows(
this.SourceRectangle,
this.Configuration,
- new ApplyInverseGammaExposureRowAction(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma));
+ new ApplyInverseGammaExposureRowIntervalAction(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma));
}
///
@@ -317,20 +317,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ParallelRowIterator.IterateRows(
sourceRectangle,
configuration,
- new ApplyVerticalConvolutionRowAction(ref sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel));
+ new ApplyVerticalConvolutionRowIntervalAction(ref sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel));
// Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer
ParallelRowIterator.IterateRows(
sourceRectangle,
configuration,
- new ApplyHorizontalConvolutionRowAction(ref sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W));
+ new ApplyHorizontalConvolutionRowIntervalAction(ref sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W));
}
}
///
/// A implementing the vertical convolution logic for .
///
- private readonly struct ApplyVerticalConvolutionRowAction : IRowAction
+ private readonly struct ApplyVerticalConvolutionRowIntervalAction : IRowIntervalAction
{
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 ApplyVerticalConvolutionRowAction(
+ public ApplyVerticalConvolutionRowIntervalAction(
ref Rectangle bounds,
Buffer2D targetValues,
Buffer2D sourcePixels,
@@ -356,13 +356,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X);
-
- for (int x = 0; x < this.bounds.Width; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- Buffer2DUtils.Convolve4(this.kernel, this.sourcePixels, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX);
+ 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);
+ }
}
}
}
@@ -370,7 +373,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// A implementing the horizontal convolution logic for .
///
- private readonly struct ApplyHorizontalConvolutionRowAction : IRowAction
+ private readonly struct ApplyHorizontalConvolutionRowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly Buffer2D targetValues;
@@ -382,7 +385,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly int maxX;
[MethodImpl(InliningOptions.ShortMethod)]
- public ApplyHorizontalConvolutionRowAction(
+ public ApplyHorizontalConvolutionRowIntervalAction(
ref Rectangle bounds,
Buffer2D targetValues,
Buffer2D sourceValues,
@@ -402,13 +405,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- Span targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X);
-
- for (int x = 0; x < this.bounds.Width; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- Buffer2DUtils.Convolve4AndAccumulatePartials(this.kernel, this.sourceValues, targetRowSpan, y, x, this.bounds.Y, this.maxY, this.bounds.X, this.maxX, this.z, this.w);
+ 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);
+ }
}
}
}
@@ -416,7 +422,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// A implementing the gamma exposure logic for .
///
- private readonly struct ApplyGammaExposureRowAction : IRowAction
+ private readonly struct ApplyGammaExposureRowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly Buffer2D targetPixels;
@@ -424,7 +430,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly float gamma;
[MethodImpl(InliningOptions.ShortMethod)]
- public ApplyGammaExposureRowAction(
+ public ApplyGammaExposureRowIntervalAction(
Rectangle bounds,
Buffer2D targetPixels,
Configuration configuration,
@@ -438,30 +444,34 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
- int length = span.Length;
+ Span vectorSpan = memory.Span;
+ int length = vectorSpan.Length;
- Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
- PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span, PixelConversionModifiers.Premultiply);
- ref Vector4 baseRef = ref MemoryMarshal.GetReference(span);
-
- for (int x = 0; x < this.bounds.Width; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- ref Vector4 v = ref Unsafe.Add(ref baseRef, x);
- v.X = MathF.Pow(v.X, this.gamma);
- v.Y = MathF.Pow(v.Y, this.gamma);
- v.Z = MathF.Pow(v.Z, this.gamma);
- }
+ Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan, PixelConversionModifiers.Premultiply);
+ ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectorSpan);
- PixelOperations.Instance.FromVector4Destructive(this.configuration, span.Slice(0, length), targetRowSpan);
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ ref Vector4 v = ref Unsafe.Add(ref baseRef, x);
+ v.X = MathF.Pow(v.X, this.gamma);
+ v.Y = MathF.Pow(v.Y, this.gamma);
+ v.Z = MathF.Pow(v.Z, this.gamma);
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan.Slice(0, length), targetRowSpan);
+ }
}
}
///
/// A implementing the inverse gamma exposure logic for .
///
- private readonly struct ApplyInverseGammaExposureRowAction : IRowAction
+ private readonly struct ApplyInverseGammaExposureRowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly Buffer2D targetPixels;
@@ -470,7 +480,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly float inverseGamma;
[MethodImpl(InliningOptions.ShortMethod)]
- public ApplyInverseGammaExposureRowAction(
+ public ApplyInverseGammaExposureRowIntervalAction(
Rectangle bounds,
Buffer2D targetPixels,
Buffer2D sourceValues,
@@ -486,25 +496,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
Vector4 low = Vector4.Zero;
var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
- 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++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- 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/Convolution2DProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
index a6d47fa587..cd550a3355 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
@@ -66,10 +66,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
this.Configuration,
- new RowAction(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha));
+ new RowIntervalAction(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha));
Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
@@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// A implementing the convolution logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly int maxY;
@@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
Rectangle bounds,
Buffer2D targetPixels,
Buffer2D sourcePixels,
@@ -112,50 +112,54 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
- int length = span.Length;
- ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(span);
+ Span vectorSpan = memory.Span;
+ int length = vectorSpan.Length;
+ ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
- Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
- PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span);
-
- if (this.preserveAlpha)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- for (int x = 0; x < this.bounds.Width; x++)
+ Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan);
+
+ if (this.preserveAlpha)
{
- DenseMatrixUtils.Convolve2D3(
- in this.kernelY,
- in this.kernelX,
- this.sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- this.bounds.Y,
- this.maxY,
- this.bounds.X,
- this.maxX);
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve2D3(
+ in this.kernelY,
+ in this.kernelX,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
}
- }
- else
- {
- for (int x = 0; x < this.bounds.Width; x++)
+ else
{
- DenseMatrixUtils.Convolve2D4(
- in this.kernelY,
- in this.kernelX,
- this.sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- this.bounds.Y,
- this.maxY,
- this.bounds.X,
- this.maxX);
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve2D4(
+ in this.kernelY,
+ in this.kernelX,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
}
- }
- PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
index 1c6ca8b921..1be97a4f83 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
@@ -64,22 +64,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// Horizontal convolution
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
this.Configuration,
- new RowAction(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha));
+ new RowIntervalAction(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha));
// Vertical convolution
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
this.Configuration,
- new RowAction(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha));
+ new RowIntervalAction(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha));
}
///
/// A implementing the convolution logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly Buffer2D targetPixels;
@@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
Rectangle bounds,
Buffer2D targetPixels,
Buffer2D sourcePixels,
@@ -107,51 +107,55 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
- int length = span.Length;
- ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(span);
+ Span vectorSpan = memory.Span;
+ int length = vectorSpan.Length;
+ ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
int maxY = this.bounds.Bottom - 1;
int maxX = this.bounds.Right - 1;
- Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
- PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span);
-
- if (this.preserveAlpha)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- for (int x = 0; x < this.bounds.Width; x++)
+ Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan);
+
+ if (this.preserveAlpha)
{
- DenseMatrixUtils.Convolve3(
- in this.kernel,
- this.sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- this.bounds.Y,
- maxY,
- this.bounds.X,
- maxX);
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve3(
+ in this.kernel,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ maxY,
+ this.bounds.X,
+ maxX);
+ }
}
- }
- else
- {
- for (int x = 0; x < this.bounds.Width; x++)
+ else
{
- DenseMatrixUtils.Convolve4(
- in this.kernel,
- this.sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- this.bounds.Y,
- maxY,
- this.bounds.X,
- maxX);
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve4(
+ in this.kernel,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ maxY,
+ this.bounds.X,
+ maxX);
+ }
}
- }
- PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
index 6a2acf7707..b68dc56e05 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
@@ -57,10 +57,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
this.Configuration,
- new RowAction(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha));
+ new RowIntervalAction(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha));
Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels);
}
@@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// A implementing the convolution logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly int maxY;
@@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
Rectangle bounds,
Buffer2D targetPixels,
Buffer2D sourcePixels,
@@ -100,48 +100,52 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
- int length = span.Length;
- ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(span);
+ Span vectorSpan = memory.Span;
+ int length = vectorSpan.Length;
+ ref Vector4 vectorSpanRef = ref MemoryMarshal.GetReference(vectorSpan);
- Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
- PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), span);
-
- if (this.preserveAlpha)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- for (int x = 0; x < this.bounds.Width; x++)
+ Span targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, length), vectorSpan);
+
+ if (this.preserveAlpha)
{
- DenseMatrixUtils.Convolve3(
- in this.kernel,
- this.sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- this.bounds.Y,
- this.maxY,
- this.bounds.X,
- this.maxX);
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve3(
+ in this.kernel,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
}
- }
- else
- {
- for (int x = 0; x < this.bounds.Width; x++)
+ else
{
- DenseMatrixUtils.Convolve4(
- in this.kernel,
- this.sourcePixels,
- ref vectorSpanRef,
- y,
- x,
- this.bounds.Y,
- this.maxY,
- this.bounds.X,
- this.maxX);
+ for (int x = 0; x < this.bounds.Width; x++)
+ {
+ DenseMatrixUtils.Convolve4(
+ in this.kernel,
+ this.sourcePixels,
+ ref vectorSpanRef,
+ y,
+ x,
+ this.bounds.Y,
+ this.maxY,
+ this.bounds.X,
+ this.maxX);
+ }
}
- }
- PixelOperations.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, targetRowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
index 85736cbd9a..e2480957ea 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
@@ -105,14 +105,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ParallelRowIterator.IterateRows(
Rectangle.FromLTRB(minX, minY, maxX, maxY),
this.Configuration,
- new RowAction(source.PixelBuffer, pass.PixelBuffer, minX, maxX, shiftY, shiftX));
+ new RowIntervalAction(source.PixelBuffer, pass.PixelBuffer, minX, maxX, shiftY, shiftX));
}
}
///
/// A implementing the convolution logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
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 RowAction(
+ public RowIntervalAction(
Buffer2D targetPixels,
Buffer2D passPixels,
int minX,
@@ -140,26 +140,29 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- int offsetY = y - this.shiftY;
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ 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 a12bcb1fdc..2a181174c7 100644
--- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
+++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
@@ -4,6 +4,7 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Drawing
@@ -101,13 +102,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
ParallelRowIterator.IterateRows(
workingRect,
configuration,
- new RowAction(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity));
+ new RowIntervalAction(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity));
}
///
/// A implementing the draw logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly ImageFrame sourceFrame;
private readonly Image targetImage;
@@ -120,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
private readonly float opacity;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
ImageFrame sourceFrame,
Image targetImage,
PixelBlender blender,
@@ -144,11 +145,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- 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);
+ 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);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
index 45f221c937..4abaf7ac42 100644
--- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
@@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
ParallelRowIterator.IterateRows(
this.SourceRectangle,
this.Configuration,
- new RowAction(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels));
+ new RowIntervalAction(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 RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
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 RowAction(
+ public RowIntervalAction(
Rectangle bounds,
Buffer2D targetPixels,
ImageFrame source,
@@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
int maxY = this.bounds.Bottom - 1;
int maxX = this.bounds.Right - 1;
@@ -117,66 +117,69 @@ 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);
- Span sourceRowPixelSpan = this.source.GetPixelRowSpan(y);
- Span sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(this.bounds.X, this.bounds.Width);
-
- PixelOperations.Instance.ToVector4(this.configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span);
-
- for (int x = this.bounds.X; x < this.bounds.Right; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- int maxIntensity = 0;
- int maxIndex = 0;
+ Span sourceRowPixelSpan = this.source.GetPixelRowSpan(y);
+ Span sourceRowAreaPixelSpan = sourceRowPixelSpan.Slice(this.bounds.X, this.bounds.Width);
- // Clear the current shared buffer before processing each target pixel
- bins.Memory.Span.Clear();
+ PixelOperations.Instance.ToVector4(this.configuration, sourceRowAreaPixelSpan, sourceRowAreaVector4Span);
- for (int fy = 0; fy <= this.radius; fy++)
+ for (int x = this.bounds.X; x < this.bounds.Right; x++)
{
- int fyr = fy - this.radius;
- int offsetY = y + fyr;
-
- offsetY = offsetY.Clamp(0, maxY);
+ int maxIntensity = 0;
+ int maxIndex = 0;
- Span sourceOffsetRow = this.source.GetPixelRowSpan(offsetY);
+ // Clear the current shared buffer before processing each target pixel
+ bins.Memory.Span.Clear();
- for (int fx = 0; fx <= this.radius; fx++)
+ for (int fy = 0; fy <= this.radius; fy++)
{
- int fxr = fx - this.radius;
- int offsetX = x + fxr;
- offsetX = offsetX.Clamp(0, maxX);
+ int fyr = fy - this.radius;
+ int offsetY = y + fyr;
- var vector = sourceOffsetRow[offsetX].ToVector4();
+ offsetY = offsetY.Clamp(0, maxY);
- float sourceRed = vector.X;
- float sourceBlue = vector.Z;
- float sourceGreen = vector.Y;
+ Span sourceOffsetRow = this.source.GetPixelRowSpan(offsetY);
- int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (this.levels - 1));
+ for (int fx = 0; fx <= this.radius; fx++)
+ {
+ int fxr = fx - this.radius;
+ int offsetX = x + fxr;
+ offsetX = offsetX.Clamp(0, maxX);
- Unsafe.Add(ref intensityBinRef, currentIntensity)++;
- Unsafe.Add(ref redBinRef, currentIntensity) += sourceRed;
- Unsafe.Add(ref blueBinRef, currentIntensity) += sourceBlue;
- Unsafe.Add(ref greenBinRef, currentIntensity) += sourceGreen;
+ var vector = sourceOffsetRow[offsetX].ToVector4();
- if (Unsafe.Add(ref intensityBinRef, currentIntensity) > maxIntensity)
- {
- maxIntensity = Unsafe.Add(ref intensityBinRef, currentIntensity);
- maxIndex = currentIntensity;
+ float sourceRed = vector.X;
+ float sourceBlue = vector.Z;
+ float sourceGreen = vector.Y;
+
+ 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;
+
+ 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/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs
index c0f4797560..fd725d3ba0 100644
--- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs
+++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs
@@ -5,6 +5,7 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Effects
@@ -50,16 +51,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
{
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
this.Configuration,
- new RowAction(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate));
+ new RowIntervalAction(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate));
}
///
/// A implementing the convolution logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly int startX;
private readonly ImageFrame source;
@@ -68,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
private readonly TDelegate rowProcessor;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
int startX,
ImageFrame source,
Configuration configuration,
@@ -84,16 +85,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
- int length = span.Length;
- Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
- PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers);
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span vectorSpan = memory.Span;
+ int length = vectorSpan.Length;
+ Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
+ PixelOperations.Instance.ToVector4(this.configuration, rowSpan, vectorSpan, this.modifiers);
- // Run the user defined pixel shader to the current row of pixels
- Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y));
+ // Run the user defined pixel shader to the current row of pixels
+ Unsafe.AsRef(this.rowProcessor).Invoke(vectorSpan, new Point(this.startX, y));
- PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers);
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, rowSpan, this.modifiers);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
index c797c13587..cdb67e48b2 100644
--- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
@@ -5,6 +5,7 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Filters
@@ -36,16 +37,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
{
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
this.Configuration,
- new RowAction(interest.X, source, this.definition.Matrix, this.Configuration));
+ new RowIntervalAction(interest.X, source, this.definition.Matrix, this.Configuration));
}
///
/// A implementing the convolution logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly int startX;
private readonly ImageFrame source;
@@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
private readonly Configuration configuration;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
int startX,
ImageFrame source,
ColorMatrix matrix,
@@ -67,15 +68,19 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
- int length = span.Length;
- Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
- PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span);
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span vectorSpan = memory.Span;
+ int length = vectorSpan.Length;
+ Span rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, length);
+ PixelOperations.Instance.ToVector4(this.configuration, rowSpan, vectorSpan);
- Vector4Utils.Transform(span, ref Unsafe.AsRef(this.matrix));
+ Vector4Utils.Transform(vectorSpan, ref Unsafe.AsRef(this.matrix));
- PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan);
+ PixelOperations.Instance.FromVector4Destructive(this.configuration, vectorSpan, rowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
index a4a643425f..5d25bae821 100644
--- a/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
@@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
ParallelRowIterator.IterateRows(
workingRect,
this.Configuration,
- new GrayscaleLevelsRowAction(workingRect, histogramBuffer, source, this.LuminanceLevels));
+ new GrayscaleLevelsRowIntervalAction(workingRect, histogramBuffer, source, this.LuminanceLevels));
Span histogram = histogramBuffer.GetSpan();
if (this.ClipHistogramEnabled)
@@ -77,13 +77,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
ParallelRowIterator.IterateRows(
workingRect,
this.Configuration,
- new CdfApplicationRowAction(workingRect, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin));
+ new CdfApplicationRowIntervalAction(workingRect, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin));
}
///
/// A implementing the grayscale levels logic for .
///
- private readonly struct GrayscaleLevelsRowAction : IRowAction
+ private readonly struct GrayscaleLevelsRowIntervalAction : IRowIntervalAction
{
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 GrayscaleLevelsRowAction(
+ public GrayscaleLevelsRowIntervalAction(
in Rectangle bounds,
IMemoryOwner histogramBuffer,
ImageFrame source,
@@ -105,15 +105,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
ref int histogramBase = ref MemoryMarshal.GetReference(this.histogramBuffer.GetSpan());
- ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y));
-
- for (int x = 0; x < this.bounds.Width; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- int luminance = GetLuminance(Unsafe.Add(ref pixelBase, x), this.luminanceLevels);
- Unsafe.Add(ref histogramBase, luminance)++;
+ 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)++;
+ }
}
}
}
@@ -121,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
///
/// A implementing the cdf application levels logic for .
///
- private readonly struct CdfApplicationRowAction : IRowAction
+ private readonly struct CdfApplicationRowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly IMemoryOwner cdfBuffer;
@@ -130,7 +133,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly float numberOfPixelsMinusCdfMin;
[MethodImpl(InliningOptions.ShortMethod)]
- public CdfApplicationRowAction(
+ public CdfApplicationRowIntervalAction(
in Rectangle bounds,
IMemoryOwner cdfBuffer,
ImageFrame source,
@@ -146,17 +149,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
ref int cdfBase = ref MemoryMarshal.GetReference(this.cdfBuffer.GetSpan());
- ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y));
-
- for (int x = 0; x < this.bounds.Width; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- 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 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));
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
index 2c17d71c6c..a9b91e837f 100644
--- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
@@ -52,10 +52,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
ParallelRowIterator.IterateRows(
interest,
configuration,
- new RowAction(configuration, interest, blender, amount, colors, source));
+ new RowIntervalAction(configuration, interest, blender, amount, colors, source));
}
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
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 RowAction(
+ public RowIntervalAction(
Configuration configuration,
Rectangle bounds,
PixelBlender blender,
@@ -82,18 +82,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
}
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ 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/Overlays/GlowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
index 6777e32345..65a87fbf01 100644
--- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
@@ -55,13 +55,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner rowColors = allocator.Allocate(interest.Width);
rowColors.GetSpan().Fill(glowColor);
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
configuration,
- new RowAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source));
+ new RowIntervalAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source));
}
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly Configuration configuration;
private readonly Rectangle bounds;
@@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly ImageFrame source;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
Configuration configuration,
Rectangle bounds,
IMemoryOwner colors,
@@ -94,24 +94,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
}
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
+ Span amountsSpan = memory.Span;
Span colorSpan = this.colors.GetSpan();
- for (int i = 0; i < this.bounds.Width; i++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
- span[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1);
- }
+ for (int i = 0; i < this.bounds.Width; i++)
+ {
+ float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
+ amountsSpan[i] = (this.blendPercent * (1 - (.95F * (distance / this.maxDistance)))).Clamp(0, 1);
+ }
- 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);
- this.blender.Blend(
- this.configuration,
- destination,
- destination,
- colorSpan,
- span);
+ this.blender.Blend(
+ this.configuration,
+ destination,
+ destination,
+ colorSpan,
+ amountsSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
index 6e2c3c4427..11887433c0 100644
--- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
@@ -63,13 +63,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner rowColors = allocator.Allocate(interest.Width);
rowColors.GetSpan().Fill(vignetteColor);
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
interest,
configuration,
- new RowAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source));
+ new RowIntervalAction(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source));
}
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly Configuration configuration;
private readonly Rectangle bounds;
@@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly ImageFrame source;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
Configuration configuration,
Rectangle bounds,
IMemoryOwner colors,
@@ -102,24 +102,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
}
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
+ Span amountsSpan = memory.Span;
Span colorSpan = this.colors.GetSpan();
- for (int i = 0; i < this.bounds.Width; i++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
- span[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1);
+ for (int i = 0; i < this.bounds.Width; i++)
+ {
+ float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
+ amountsSpan[i] = (this.blendPercent * (.9F * (distance / this.maxDistance))).Clamp(0, 1);
+ }
+
+ Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
+
+ this.blender.Blend(
+ this.configuration,
+ destination,
+ destination,
+ colorSpan,
+ amountsSpan);
}
-
- Span destination = this.source.GetPixelRowSpan(y).Slice(this.bounds.X, this.bounds.Width);
-
- this.blender.Blend(
- this.configuration,
- destination,
- destination,
- colorSpan,
- span);
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs
index 447a99eeca..402a052496 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor{TPixel}.cs
@@ -5,6 +5,7 @@ using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@@ -60,23 +61,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ParallelRowIterator.IterateRows(
targetBounds,
configuration,
- new NearestNeighborRowAction(this.SourceRectangle, ref matrix, width, source, destination));
+ new NearestNeighborRowIntervalAction(this.SourceRectangle, ref matrix, width, source, destination));
return;
}
using var kernelMap = new TransformKernelMap(configuration, source.Size(), destination.Size(), this.resampler);
- ParallelRowIterator.IterateRows(
+ ParallelRowIterator.IterateRows(
targetBounds,
configuration,
- new RowAction(configuration, kernelMap, ref matrix, width, source, destination));
+ new RowIntervalAction(configuration, kernelMap, ref matrix, width, source, destination));
}
///
/// A implementing the nearest neighbor resampler logic for .
///
- private readonly struct NearestNeighborRowAction : IRowAction
+ private readonly struct NearestNeighborRowIntervalAction : IRowIntervalAction
{
private readonly Rectangle bounds;
private readonly Matrix3x2 matrix;
@@ -85,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame destination;
[MethodImpl(InliningOptions.ShortMethod)]
- public NearestNeighborRowAction(
+ public NearestNeighborRowIntervalAction(
Rectangle bounds,
ref Matrix3x2 matrix,
int maxX,
@@ -100,17 +101,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
}
///
+ ///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- Span destRow = this.destination.GetPixelRowSpan(y);
-
- for (int x = 0; x < this.maxX; x++)
+ for (int y = rows.Min; y < rows.Max; y++)
{
- var point = Point.Transform(new Point(x, y), this.matrix);
- if (this.bounds.Contains(point.X, point.Y))
+ Span destRow = this.destination.GetPixelRowSpan(y);
+
+ for (int x = 0; x < this.maxX; x++)
{
- destRow[x] = this.source[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];
+ }
}
}
}
@@ -119,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
///
/// A implementing the transformation logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
private readonly Configuration configuration;
private readonly TransformKernelMap kernelMap;
@@ -129,7 +134,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame destination;
[MethodImpl(InliningOptions.ShortMethod)]
- public RowAction(
+ public RowIntervalAction(
Configuration configuration,
TransformKernelMap kernelMap,
ref Matrix3x2 matrix,
@@ -147,31 +152,35 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y, Span span)
+ public void Invoke(in RowInterval rows, Memory memory)
{
- Span targetRowSpan = this.destination.GetPixelRowSpan(y);
- PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan, span);
- ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
- ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
-
- for (int x = 0; x < this.maxX; x++)
+ Span vectorSpan = memory.Span;
+ for (int y = rows.Min; y < rows.Max; y++)
{
- // Use the single precision position to calculate correct bounding pixels
- // otherwise we get rogue pixels outside of the bounds.
- var point = Vector2.Transform(new Vector2(x, y), this.matrix);
- this.kernelMap.Convolve(
- point,
- x,
- ref ySpanRef,
- ref xSpanRef,
- this.source.PixelBuffer,
- span);
- }
+ Span targetRowSpan = this.destination.GetPixelRowSpan(y);
+ PixelOperations.Instance.ToVector4(this.configuration, targetRowSpan, vectorSpan);
+ ref float ySpanRef = ref this.kernelMap.GetYStartReference(y);
+ ref float xSpanRef = ref this.kernelMap.GetXStartReference(y);
- PixelOperations.Instance.FromVector4Destructive(
- this.configuration,
- span,
- targetRowSpan);
+ for (int x = 0; x < this.maxX; x++)
+ {
+ // Use the single precision position to calculate correct bounding pixels
+ // otherwise we get rogue pixels outside of the bounds.
+ var point = Vector2.Transform(new Vector2(x, y), this.matrix);
+ this.kernelMap.Convolve(
+ point,
+ x,
+ ref ySpanRef,
+ ref xSpanRef,
+ this.source.PixelBuffer,
+ vectorSpan);
+ }
+
+ PixelOperations.Instance.FromVector4Destructive(
+ this.configuration,
+ vectorSpan,
+ targetRowSpan);
+ }
}
}
}
diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs
index b294ef465b..103c5d3ffc 100644
--- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs
@@ -4,6 +4,7 @@
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
+using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@@ -47,25 +48,34 @@ 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(
bounds,
in parallelSettings,
- new RowAction(ref bounds, source, destination));
+ in rowAction);
}
///
/// A implementing the processor logic for .
///
- private readonly struct RowAction : IRowAction
+ private readonly struct RowIntervalAction : IRowIntervalAction
{
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 RowAction(ref Rectangle bounds, ImageFrame source, ImageFrame destination)
+ public RowIntervalAction(ref Rectangle bounds, ImageFrame source, ImageFrame destination)
{
this.bounds = bounds;
this.source = source;
@@ -74,11 +84,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
///
[MethodImpl(InliningOptions.ShortMethod)]
- public void Invoke(int y)
+ public void Invoke(in RowInterval rows)
{
- 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);
+ for (int y = rows.Min; y < rows.Max; y++)
+ {
+ Span sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left);
+ Span