Browse Source

Merge branch 'master' of https://github.com/SixLabors/ImageSharp

af/octree-no-pixelmap
Anton Firszov 7 years ago
parent
commit
6208cdba52
  1. 2
      src/ImageSharp/Advanced/IRowIntervalOperation.cs
  2. 2
      src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs
  3. 17
      src/ImageSharp/Advanced/IRowOperation.cs
  4. 22
      src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs
  5. 138
      src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
  6. 152
      src/ImageSharp/Advanced/ParallelRowIterator.cs
  7. 2
      src/ImageSharp/ImageFrame{TPixel}.cs
  8. 16
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs
  9. 46
      src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs
  10. 14
      src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs
  11. 17
      src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs
  12. 13
      src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs
  13. 11
      src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs
  14. 4
      src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs
  15. 11
      src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs
  16. 2
      src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs
  17. 13
      src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs
  18. 13
      src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
  19. 4
      src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs
  20. 22
      src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs
  21. 11
      src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs
  22. 13
      src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs
  23. 13
      src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs
  24. 2
      src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs
  25. 2
      src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs
  26. 13
      src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs
  27. 15
      src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs
  28. 15
      src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs
  29. 15
      src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs
  30. 24
      src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs
  31. 11
      src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs
  32. 18
      tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs
  33. 2
      tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

2
src/ImageSharp/Advanced/IRowIntervalOperation.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Advanced namespace SixLabors.ImageSharp.Advanced

2
src/ImageSharp/Advanced/IRowIntervalOperation{TBuffer}.cs

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Advanced namespace SixLabors.ImageSharp.Advanced

17
src/ImageSharp/Advanced/IRowOperation.cs

@ -0,0 +1,17 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Advanced
{
/// <summary>
/// Defines the contract for an action that operates on a row.
/// </summary>
public interface IRowOperation
{
/// <summary>
/// Invokes the method passing the row y coordinate.
/// </summary>
/// <param name="y">The row y coordinate.</param>
void Invoke(int y);
}
}

22
src/ImageSharp/Advanced/IRowOperation{TBuffer}.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
namespace SixLabors.ImageSharp.Advanced
{
/// <summary>
/// Defines the contract for an action that operates on a row with a temporary buffer.
/// </summary>
/// <typeparam name="TBuffer">The type of buffer elements.</typeparam>
public interface IRowOperation<TBuffer>
where TBuffer : unmanaged
{
/// <summary>
/// Invokes the method passing the row and a buffer.
/// </summary>
/// <param name="y">The row y coordinate.</param>
/// <param name="span">The contiguous region of memory.</param>
void Invoke(int y, Span<TBuffer> span);
}
}

138
src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs

@ -17,51 +17,130 @@ namespace SixLabors.ImageSharp.Advanced
/// </content> /// </content>
public static partial class ParallelRowIterator public static partial class ParallelRowIterator
{ {
private readonly struct IterationParameters private readonly struct RowOperationWrapper<T>
where T : struct, IRowOperation
{ {
public readonly int MinY; private readonly int minY;
public readonly int MaxY; private readonly int maxY;
public readonly int StepY; private readonly int stepY;
public readonly int Width; private readonly T action;
public IterationParameters(int minY, int maxY, int stepY) [MethodImpl(InliningOptions.ShortMethod)]
: this(minY, maxY, stepY, 0) public RowOperationWrapper(
int minY,
int maxY,
int stepY,
in T action)
{
this.minY = minY;
this.maxY = maxY;
this.stepY = stepY;
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);
}
}
}
private readonly struct RowOperationWrapper<T, TBuffer>
where T : struct, IRowOperation<TBuffer>
where TBuffer : unmanaged
{ {
private readonly int minY;
private readonly int maxY;
private readonly int stepY;
private readonly int width;
private readonly MemoryAllocator allocator;
private readonly T action;
[MethodImpl(InliningOptions.ShortMethod)]
public RowOperationWrapper(
int minY,
int maxY,
int stepY,
int width,
MemoryAllocator allocator,
in T action)
{
this.minY = minY;
this.maxY = maxY;
this.stepY = stepY;
this.width = width;
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;
} }
public IterationParameters(int minY, int maxY, int stepY, int width) int yMax = Math.Min(yMin + this.stepY, this.maxY);
using IMemoryOwner<TBuffer> buffer = this.allocator.Allocate<TBuffer>(this.width);
Span<TBuffer> span = buffer.Memory.Span;
for (int y = yMin; y < yMax; y++)
{ {
this.MinY = minY; Unsafe.AsRef(this.action).Invoke(y, span);
this.MaxY = maxY; }
this.StepY = stepY;
this.Width = width;
} }
} }
private readonly struct RowIntervalOperationWrapper<T> private readonly struct RowIntervalOperationWrapper<T>
where T : struct, IRowIntervalOperation where T : struct, IRowIntervalOperation
{ {
private readonly IterationParameters info; private readonly int minY;
private readonly int maxY;
private readonly int stepY;
private readonly T operation; private readonly T operation;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperationWrapper(in IterationParameters info, in T operation) public RowIntervalOperationWrapper(
int minY,
int maxY,
int stepY,
in T operation)
{ {
this.info = info; this.minY = minY;
this.maxY = maxY;
this.stepY = stepY;
this.operation = operation; this.operation = operation;
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int i) public void Invoke(int i)
{ {
int yMin = this.info.MinY + (i * this.info.StepY); int yMin = this.minY + (i * this.stepY);
if (yMin >= this.info.MaxY) if (yMin >= this.maxY)
{ {
return; return;
} }
int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); int yMax = Math.Min(yMin + this.stepY, this.maxY);
var rows = new RowInterval(yMin, yMax); var rows = new RowInterval(yMin, yMax);
// Skip the safety copy when invoking a potentially impure method on a readonly field // Skip the safety copy when invoking a potentially impure method on a readonly field
@ -73,17 +152,26 @@ namespace SixLabors.ImageSharp.Advanced
where T : struct, IRowIntervalOperation<TBuffer> where T : struct, IRowIntervalOperation<TBuffer>
where TBuffer : unmanaged where TBuffer : unmanaged
{ {
private readonly IterationParameters info; private readonly int minY;
private readonly int maxY;
private readonly int stepY;
private readonly int width;
private readonly MemoryAllocator allocator; private readonly MemoryAllocator allocator;
private readonly T operation; private readonly T operation;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperationWrapper( public RowIntervalOperationWrapper(
in IterationParameters info, int minY,
int maxY,
int stepY,
int width,
MemoryAllocator allocator, MemoryAllocator allocator,
in T operation) in T operation)
{ {
this.info = info; this.minY = minY;
this.maxY = maxY;
this.stepY = stepY;
this.width = width;
this.allocator = allocator; this.allocator = allocator;
this.operation = operation; this.operation = operation;
} }
@ -91,17 +179,17 @@ namespace SixLabors.ImageSharp.Advanced
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(int i) public void Invoke(int i)
{ {
int yMin = this.info.MinY + (i * this.info.StepY); int yMin = this.minY + (i * this.stepY);
if (yMin >= this.info.MaxY) if (yMin >= this.maxY)
{ {
return; return;
} }
int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); int yMax = Math.Min(yMin + this.stepY, this.maxY);
var rows = new RowInterval(yMin, yMax); var rows = new RowInterval(yMin, yMax);
using IMemoryOwner<TBuffer> buffer = this.allocator.Allocate<TBuffer>(this.info.Width); using IMemoryOwner<TBuffer> buffer = this.allocator.Allocate<TBuffer>(this.width);
Unsafe.AsRef(in this.operation).Invoke(in rows, buffer.Memory.Span); Unsafe.AsRef(in this.operation).Invoke(in rows, buffer.Memory.Span);
} }

152
src/ImageSharp/Advanced/ParallelRowIterator.cs

@ -17,6 +17,135 @@ namespace SixLabors.ImageSharp.Advanced
/// </summary> /// </summary>
public static partial class ParallelRowIterator public static partial class ParallelRowIterator
{ {
/// <summary>
/// Iterate through the rows of a rectangle in optimized batches.
/// </summary>
/// <typeparam name="T">The type of row operation to perform.</typeparam>
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single row.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void IterateRows<T>(Configuration configuration, Rectangle rectangle, in T operation)
where T : struct, IRowOperation
{
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows(rectangle, in parallelSettings, in operation);
}
/// <summary>
/// Iterate through the rows of a rectangle in optimized batches.
/// </summary>
/// <typeparam name="T">The type of row operation to perform.</typeparam>
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single row.</param>
public static void IterateRows<T>(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
in T operation)
where T : struct, IRowOperation
{
ValidateRectangle(rectangle);
int top = rectangle.Top;
int bottom = rectangle.Bottom;
int width = rectangle.Width;
int height = rectangle.Height;
int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
// Avoid TPL overhead in this trivial case:
if (numOfSteps == 1)
{
for (int y = top; y < bottom; y++)
{
Unsafe.AsRef(operation).Invoke(y);
}
return;
}
int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
var wrappingOperation = new RowOperationWrapper<T>(top, bottom, verticalStep, in operation);
Parallel.For(
0,
numOfSteps,
parallelOptions,
wrappingOperation.Invoke);
}
/// <summary>
/// Iterate through the rows of a rectangle in optimized batches.
/// instantiating a temporary buffer for each <paramref name="operation"/> invocation.
/// </summary>
/// <typeparam name="T">The type of row operation to perform.</typeparam>
/// <typeparam name="TBuffer">The type of buffer elements.</typeparam>
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single row.</param>
public static void IterateRows<T, TBuffer>(Configuration configuration, Rectangle rectangle, in T operation)
where T : struct, IRowOperation<TBuffer>
where TBuffer : unmanaged
{
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows<T, TBuffer>(rectangle, in parallelSettings, in operation);
}
/// <summary>
/// Iterate through the rows of a rectangle in optimized batches.
/// instantiating a temporary buffer for each <paramref name="operation"/> invocation.
/// </summary>
/// <typeparam name="T">The type of row operation to perform.</typeparam>
/// <typeparam name="TBuffer">The type of buffer elements.</typeparam>
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single row.</param>
public static void IterateRows<T, TBuffer>(
Rectangle rectangle,
in ParallelExecutionSettings parallelSettings,
in T operation)
where T : struct, IRowOperation<TBuffer>
where TBuffer : unmanaged
{
ValidateRectangle(rectangle);
int top = rectangle.Top;
int bottom = rectangle.Bottom;
int width = rectangle.Width;
int height = rectangle.Height;
int maxSteps = DivideCeil(width * height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
MemoryAllocator allocator = parallelSettings.MemoryAllocator;
// Avoid TPL overhead in this trivial case:
if (numOfSteps == 1)
{
using IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(width);
Span<TBuffer> span = buffer.Memory.Span;
for (int y = top; y < bottom; y++)
{
Unsafe.AsRef(operation).Invoke(y, span);
}
return;
}
int verticalStep = DivideCeil(height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
var wrappingOperation = new RowOperationWrapper<T, TBuffer>(top, bottom, verticalStep, width, allocator, in operation);
Parallel.For(
0,
numOfSteps,
parallelOptions,
wrappingOperation.Invoke);
}
/// <summary> /// <summary>
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s. /// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
/// </summary> /// </summary>
@ -25,11 +154,11 @@ namespace SixLabors.ImageSharp.Advanced
/// <param name="rectangle">The <see cref="Rectangle"/>.</param> /// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param> /// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static void IterateRows<T>(Configuration configuration, Rectangle rectangle, in T operation) public static void IterateRowIntervals<T>(Configuration configuration, Rectangle rectangle, in T operation)
where T : struct, IRowIntervalOperation where T : struct, IRowIntervalOperation
{ {
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows(rectangle, in parallelSettings, in operation); IterateRowIntervals(rectangle, in parallelSettings, in operation);
} }
/// <summary> /// <summary>
@ -39,7 +168,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <param name="rectangle">The <see cref="Rectangle"/>.</param> /// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param> /// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param> /// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param>
public static void IterateRows<T>( public static void IterateRowIntervals<T>(
Rectangle rectangle, Rectangle rectangle,
in ParallelExecutionSettings parallelSettings, in ParallelExecutionSettings parallelSettings,
in T operation) in T operation)
@ -65,8 +194,7 @@ namespace SixLabors.ImageSharp.Advanced
int verticalStep = DivideCeil(rectangle.Height, numOfSteps); int verticalStep = DivideCeil(rectangle.Height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
var info = new IterationParameters(top, bottom, verticalStep); var wrappingOperation = new RowIntervalOperationWrapper<T>(top, bottom, verticalStep, in operation);
var wrappingOperation = new RowIntervalOperationWrapper<T>(in info, in operation);
Parallel.For( Parallel.For(
0, 0,
@ -84,12 +212,12 @@ namespace SixLabors.ImageSharp.Advanced
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param> /// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
/// <param name="rectangle">The <see cref="Rectangle"/>.</param> /// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param> /// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param>
public static void IterateRows<T, TBuffer>(Configuration configuration, Rectangle rectangle, in T operation) public static void IterateRowIntervals<T, TBuffer>(Configuration configuration, Rectangle rectangle, in T operation)
where T : struct, IRowIntervalOperation<TBuffer> where T : struct, IRowIntervalOperation<TBuffer>
where TBuffer : unmanaged where TBuffer : unmanaged
{ {
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration);
IterateRows<T, TBuffer>(rectangle, in parallelSettings, in operation); IterateRowIntervals<T, TBuffer>(rectangle, in parallelSettings, in operation);
} }
/// <summary> /// <summary>
@ -101,7 +229,7 @@ namespace SixLabors.ImageSharp.Advanced
/// <param name="rectangle">The <see cref="Rectangle"/>.</param> /// <param name="rectangle">The <see cref="Rectangle"/>.</param>
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param> /// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
/// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param> /// <param name="operation">The operation defining the iteration logic on a single <see cref="RowInterval"/>.</param>
public static void IterateRows<T, TBuffer>( public static void IterateRowIntervals<T, TBuffer>(
Rectangle rectangle, Rectangle rectangle,
in ParallelExecutionSettings parallelSettings, in ParallelExecutionSettings parallelSettings,
in T operation) in T operation)
@ -123,18 +251,16 @@ namespace SixLabors.ImageSharp.Advanced
if (numOfSteps == 1) if (numOfSteps == 1)
{ {
var rows = new RowInterval(top, bottom); var rows = new RowInterval(top, bottom);
using (IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(width)) using IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(width);
{
Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span);
}
return; return;
} }
int verticalStep = DivideCeil(height, numOfSteps); int verticalStep = DivideCeil(height, numOfSteps);
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps };
var info = new IterationParameters(top, bottom, verticalStep, width); var wrappingOperation = new RowIntervalOperationWrapper<T, TBuffer>(top, bottom, verticalStep, width, allocator, in operation);
var wrappingOperation = new RowIntervalOperationWrapper<T, TBuffer>(in info, allocator, in operation);
Parallel.For( Parallel.For(
0, 0,

2
src/ImageSharp/ImageFrame{TPixel}.cs

@ -277,7 +277,7 @@ namespace SixLabors.ImageSharp
var target = new ImageFrame<TPixel2>(configuration, this.Width, this.Height, this.Metadata.DeepClone()); var target = new ImageFrame<TPixel2>(configuration, this.Width, this.Height, this.Metadata.DeepClone());
var operation = new RowIntervalOperation<TPixel2>(this, target, configuration); var operation = new RowIntervalOperation<TPixel2>(this, target, configuration);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
configuration, configuration,
this.Bounds(), this.Bounds(),
in operation); in operation);

16
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor{TPixel}.cs

@ -3,8 +3,8 @@
using System; using System;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Binarization namespace SixLabors.ImageSharp.Processing.Processors.Binarization
@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
bool isAlphaOnly = typeof(TPixel) == typeof(A8); bool isAlphaOnly = typeof(TPixel) == typeof(A8);
var operation = new RowIntervalOperation(interest, source, upper, lower, threshold, isAlphaOnly); var operation = new RowOperation(interest, source, upper, lower, threshold, isAlphaOnly);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
interest, interest,
@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the clone logic for <see cref="BinaryThresholdProcessor{TPixel}"/>. /// A <see langword="struct"/> implementing the clone logic for <see cref="BinaryThresholdProcessor{TPixel}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation private readonly struct RowOperation : IRowOperation
{ {
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
private readonly TPixel upper; private readonly TPixel upper;
@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
private readonly bool isAlphaOnly; private readonly bool isAlphaOnly;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Rectangle bounds, Rectangle bounds,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
TPixel upper, TPixel upper,
@ -84,16 +84,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{ {
Rgba32 rgba = default; Rgba32 rgba = default;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> row = this.source.GetPixelRowSpan(y); Span<TPixel> row = this.source.GetPixelRowSpan(y);
ref TPixel rowRef = ref MemoryMarshal.GetReference(row);
for (int x = this.minX; x < this.maxX; x++) for (int x = this.minX; x < this.maxX; x++)
{ {
ref TPixel color = ref row[x]; ref TPixel color = ref Unsafe.Add(ref rowRef, x);
color.ToRgba32(ref rgba); color.ToRgba32(ref rgba);
// Convert to grayscale using ITU-R Recommendation BT.709 if required // Convert to grayscale using ITU-R Recommendation BT.709 if required
@ -104,4 +103,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
} }
} }
} }
}

46
src/ImageSharp/Processing/Processors/Convolution/BokehBlurProcessor{TPixel}.cs

@ -72,8 +72,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
protected override void OnFrameApply(ImageFrame<TPixel> source) protected override void OnFrameApply(ImageFrame<TPixel> source)
{ {
// Preliminary gamma highlight pass // Preliminary gamma highlight pass
var gammaOperation = new ApplyGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma); var gammaOperation = new ApplyGammaExposureRowOperation(this.SourceRectangle, source.PixelBuffer, this.Configuration, this.gamma);
ParallelRowIterator.IterateRows<ApplyGammaExposureRowIntervalOperation, Vector4>( ParallelRowIterator.IterateRows<ApplyGammaExposureRowOperation, Vector4>(
this.Configuration, this.Configuration,
this.SourceRectangle, this.SourceRectangle,
in gammaOperation); in gammaOperation);
@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
float inverseGamma = 1 / this.gamma; float inverseGamma = 1 / this.gamma;
// Apply the inverse gamma exposure pass, and write the final pixel data // Apply the inverse gamma exposure pass, and write the final pixel data
var operation = new ApplyInverseGammaExposureRowIntervalOperation(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma); var operation = new ApplyInverseGammaExposureRowOperation(this.SourceRectangle, source.PixelBuffer, processingBuffer, this.Configuration, inverseGamma);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
this.Configuration, this.Configuration,
this.SourceRectangle, this.SourceRectangle,
@ -120,14 +120,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
Vector4 parameters = Unsafe.Add(ref paramsRef, i); Vector4 parameters = Unsafe.Add(ref paramsRef, i);
// Compute the vertical 1D convolution // Compute the vertical 1D convolution
var verticalOperation = new ApplyVerticalConvolutionRowIntervalOperation(sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel); var verticalOperation = new ApplyVerticalConvolutionRowOperation(sourceRectangle, firstPassBuffer, source.PixelBuffer, kernel);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
sourceRectangle, sourceRectangle,
in verticalOperation); in verticalOperation);
// Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer // Compute the horizontal 1D convolutions and accumulate the partial results on the target buffer
var horizontalOperation = new ApplyHorizontalConvolutionRowIntervalOperation(sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W); var horizontalOperation = new ApplyHorizontalConvolutionRowOperation(sourceRectangle, processingBuffer, firstPassBuffer, kernel, parameters.Z, parameters.W);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
sourceRectangle, sourceRectangle,
@ -138,7 +138,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the vertical convolution logic for <see cref="BokehBlurProcessor{T}"/>. /// A <see langword="struct"/> implementing the vertical convolution logic for <see cref="BokehBlurProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct ApplyVerticalConvolutionRowIntervalOperation : IRowIntervalOperation private readonly struct ApplyVerticalConvolutionRowOperation : IRowOperation
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly Buffer2D<ComplexVector4> targetValues; private readonly Buffer2D<ComplexVector4> targetValues;
@ -148,7 +148,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly int maxX; private readonly int maxX;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public ApplyVerticalConvolutionRowIntervalOperation( public ApplyVerticalConvolutionRowOperation(
Rectangle bounds, Rectangle bounds,
Buffer2D<ComplexVector4> targetValues, Buffer2D<ComplexVector4> targetValues,
Buffer2D<TPixel> sourcePixels, Buffer2D<TPixel> sourcePixels,
@ -164,9 +164,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<ComplexVector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); Span<ComplexVector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X);
@ -176,12 +174,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
} }
} }
} }
}
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the horizontal convolution logic for <see cref="BokehBlurProcessor{T}"/>. /// A <see langword="struct"/> implementing the horizontal convolution logic for <see cref="BokehBlurProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct ApplyHorizontalConvolutionRowIntervalOperation : IRowIntervalOperation private readonly struct ApplyHorizontalConvolutionRowOperation : IRowOperation
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly Buffer2D<Vector4> targetValues; private readonly Buffer2D<Vector4> targetValues;
@ -193,7 +190,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly int maxX; private readonly int maxX;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public ApplyHorizontalConvolutionRowIntervalOperation( public ApplyHorizontalConvolutionRowOperation(
Rectangle bounds, Rectangle bounds,
Buffer2D<Vector4> targetValues, Buffer2D<Vector4> targetValues,
Buffer2D<ComplexVector4> sourceValues, Buffer2D<ComplexVector4> sourceValues,
@ -213,9 +210,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<Vector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X); Span<Vector4> targetRowSpan = this.targetValues.GetRowSpan(y).Slice(this.bounds.X);
@ -225,12 +220,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
} }
} }
} }
}
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the gamma exposure logic for <see cref="BokehBlurProcessor{T}"/>. /// A <see langword="struct"/> implementing the gamma exposure logic for <see cref="BokehBlurProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct ApplyGammaExposureRowIntervalOperation : IRowIntervalOperation<Vector4> private readonly struct ApplyGammaExposureRowOperation : IRowOperation<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> targetPixels; private readonly Buffer2D<TPixel> targetPixels;
@ -238,7 +232,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly float gamma; private readonly float gamma;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public ApplyGammaExposureRowIntervalOperation( public ApplyGammaExposureRowOperation(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Configuration configuration, Configuration configuration,
@ -252,9 +246,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Premultiply); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span, PixelConversionModifiers.Premultiply);
@ -271,12 +263,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, targetRowSpan);
} }
} }
}
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the inverse gamma exposure logic for <see cref="BokehBlurProcessor{T}"/>. /// A <see langword="struct"/> implementing the inverse gamma exposure logic for <see cref="BokehBlurProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct ApplyInverseGammaExposureRowIntervalOperation : IRowIntervalOperation private readonly struct ApplyInverseGammaExposureRowOperation : IRowOperation
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> targetPixels; private readonly Buffer2D<TPixel> targetPixels;
@ -285,7 +276,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly float inverseGamma; private readonly float inverseGamma;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public ApplyInverseGammaExposureRowIntervalOperation( public ApplyInverseGammaExposureRowOperation(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<Vector4> sourceValues, Buffer2D<Vector4> sourceValues,
@ -301,13 +292,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{ {
Vector4 low = Vector4.Zero; Vector4 low = Vector4.Zero;
var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity); var high = new Vector4(float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity, float.PositiveInfinity);
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); Span<TPixel> targetPixelSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
Span<Vector4> sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X); Span<Vector4> sourceRowSpan = this.sourceValues.GetRowSpan(y).Slice(this.bounds.X);
ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan); ref Vector4 sourceRef = ref MemoryMarshal.GetReference(sourceRowSpan);
@ -326,4 +315,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
} }
} }
} }
}

14
src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor{TPixel}.cs

@ -65,9 +65,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
source.CopyTo(targetPixels); source.CopyTo(targetPixels);
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha); var operation = new RowOperation(interest, targetPixels, source.PixelBuffer, this.KernelY, this.KernelX, this.Configuration, this.PreserveAlpha);
ParallelRowIterator.IterateRows<RowIntervalOperation, Vector4>( ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration, this.Configuration,
interest, interest,
in operation); in operation);
@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2DProcessor{T}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2DProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation<Vector4> private readonly struct RowOperation : IRowOperation<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly int maxY; private readonly int maxY;
@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha; private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> sourcePixels, Buffer2D<TPixel> sourcePixels,
@ -113,12 +113,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{ {
ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); ref Vector4 spanRef = ref MemoryMarshal.GetReference(span);
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
@ -162,4 +159,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
} }
} }
} }
}

17
src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor{TPixel}.cs

@ -64,15 +64,15 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// Horizontal convolution // Horizontal convolution
var horizontalOperation = new RowIntervalOperation(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha); var horizontalOperation = new RowOperation(interest, firstPassPixels, source.PixelBuffer, this.KernelX, this.Configuration, this.PreserveAlpha);
ParallelRowIterator.IterateRows<RowIntervalOperation, Vector4>( ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration, this.Configuration,
interest, interest,
in horizontalOperation); in horizontalOperation);
// Vertical convolution // Vertical convolution
var verticalOperation = new RowIntervalOperation(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha); var verticalOperation = new RowOperation(interest, source.PixelBuffer, firstPassPixels, this.KernelY, this.Configuration, this.PreserveAlpha);
ParallelRowIterator.IterateRows<RowIntervalOperation, Vector4>( ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration, this.Configuration,
interest, interest,
in verticalOperation); in verticalOperation);
@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2PassProcessor{T}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="Convolution2PassProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation<Vector4> private readonly struct RowOperation : IRowOperation<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly Buffer2D<TPixel> targetPixels; private readonly Buffer2D<TPixel> targetPixels;
@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha; private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> sourcePixels, Buffer2D<TPixel> sourcePixels,
@ -109,15 +109,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{ {
ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); ref Vector4 spanRef = ref MemoryMarshal.GetReference(span);
int maxY = this.bounds.Bottom - 1; int maxY = this.bounds.Bottom - 1;
int maxX = this.bounds.Right - 1; int maxX = this.bounds.Right - 1;
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
@ -159,4 +157,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
} }
} }
} }
}

13
src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor{TPixel}.cs

@ -56,8 +56,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
source.CopyTo(targetPixels); source.CopyTo(targetPixels);
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new RowIntervalOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha); var operation = new RowOperation(interest, targetPixels, source.PixelBuffer, this.KernelXY, this.Configuration, this.PreserveAlpha);
ParallelRowIterator.IterateRows<RowIntervalOperation, Vector4>( ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration, this.Configuration,
interest, interest,
in operation); in operation);
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="ConvolutionProcessor{T}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="ConvolutionProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation<Vector4> private readonly struct RowOperation : IRowOperation<Vector4>
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly int maxY; private readonly int maxY;
@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly bool preserveAlpha; private readonly bool preserveAlpha;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Rectangle bounds, Rectangle bounds,
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> sourcePixels, Buffer2D<TPixel> sourcePixels,
@ -100,12 +100,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{ {
ref Vector4 spanRef = ref MemoryMarshal.GetReference(span); ref Vector4 spanRef = ref MemoryMarshal.GetReference(span);
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X); Span<TPixel> targetRowSpan = this.targetPixels.GetRowSpan(y).Slice(this.bounds.X);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, targetRowSpan.Slice(0, span.Length), span);
@ -147,4 +145,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
} }
} }
} }
}

11
src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs

@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
processor.Apply(pass); processor.Apply(pass);
} }
var operation = new RowIntervalOperation(source.PixelBuffer, pass.PixelBuffer, interest); var operation = new RowOperation(source.PixelBuffer, pass.PixelBuffer, interest);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
this.Configuration, this.Configuration,
interest, interest,
@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="EdgeDetectorCompassProcessor{T}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="EdgeDetectorCompassProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation private readonly struct RowOperation : IRowOperation
{ {
private readonly Buffer2D<TPixel> targetPixels; private readonly Buffer2D<TPixel> targetPixels;
private readonly Buffer2D<TPixel> passPixels; private readonly Buffer2D<TPixel> passPixels;
@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
private readonly int maxX; private readonly int maxX;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Buffer2D<TPixel> targetPixels, Buffer2D<TPixel> targetPixels,
Buffer2D<TPixel> passPixels, Buffer2D<TPixel> passPixels,
Rectangle bounds) Rectangle bounds)
@ -110,9 +110,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(y)); ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(this.passPixels.GetRowSpan(y));
ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(y)); ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(this.targetPixels.GetRowSpan(y));
@ -131,4 +129,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
} }
} }
} }
}

4
src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs

@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
palette, palette,
ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length)); ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length));
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
quantizer.Configuration, quantizer.Configuration,
bounds, bounds,
in ditherOperation); in ditherOperation);
@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
scale, scale,
ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length)); ImageMaths.GetBitsNeededForColorDepth(palette.Span.Length));
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
configuration, configuration,
bounds, bounds,
in ditherOperation); in ditherOperation);

11
src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs

@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
"Cannot draw image because the source image does not overlap the target image."); "Cannot draw image because the source image does not overlap the target image.");
} }
var operation = new RowIntervalOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity); var operation = new RowOperation(source, targetImage, blender, configuration, minX, width, locationY, targetX, this.Opacity);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
workingRect, workingRect,
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the draw logic for <see cref="DrawImageProcessor{TPixelBg,TPixelFg}"/>. /// A <see langword="struct"/> implementing the draw logic for <see cref="DrawImageProcessor{TPixelBg,TPixelFg}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation private readonly struct RowOperation : IRowOperation
{ {
private readonly ImageFrame<TPixelBg> sourceFrame; private readonly ImageFrame<TPixelBg> sourceFrame;
private readonly Image<TPixelFg> targetImage; private readonly Image<TPixelFg> targetImage;
@ -122,7 +122,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
private readonly float opacity; private readonly float opacity;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
ImageFrame<TPixelBg> sourceFrame, ImageFrame<TPixelBg> sourceFrame,
Image<TPixelFg> targetImage, Image<TPixelFg> targetImage,
PixelBlender<TPixelBg> blender, PixelBlender<TPixelBg> blender,
@ -146,9 +146,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixelBg> background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width); Span<TPixelBg> background = this.sourceFrame.GetPixelRowSpan(y).Slice(this.minX, this.width);
Span<TPixelFg> foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width); Span<TPixelFg> foreground = this.targetImage.GetPixelRowSpan(y - this.locationY).Slice(this.targetX, this.width);
@ -157,4 +155,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
} }
} }
} }
}

2
src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor{TPixel}.cs

@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
source.CopyTo(targetPixels); source.CopyTo(targetPixels);
var operation = new RowIntervalOperation(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels); var operation = new RowIntervalOperation(this.SourceRectangle, targetPixels, source, this.Configuration, brushSize >> 1, this.definition.Levels);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
this.Configuration, this.Configuration,
this.SourceRectangle, this.SourceRectangle,
in operation); in operation);

13
src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs

@ -50,9 +50,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
protected override void OnFrameApply(ImageFrame<TPixel> source) protected override void OnFrameApply(ImageFrame<TPixel> source)
{ {
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new RowIntervalOperation(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate); var operation = new RowOperation(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate);
ParallelRowIterator.IterateRows<RowIntervalOperation, Vector4>( ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration, this.Configuration,
interest, interest,
in operation); in operation);
@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="PixelRowDelegateProcessor{TPixel,TDelegate}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="PixelRowDelegateProcessor{TPixel,TDelegate}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation<Vector4> private readonly struct RowOperation : IRowOperation<Vector4>
{ {
private readonly int startX; private readonly int startX;
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
private readonly TDelegate rowProcessor; private readonly TDelegate rowProcessor;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
int startX, int startX,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
Configuration configuration, Configuration configuration,
@ -86,9 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers);
@ -101,4 +99,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects
} }
} }
} }
}

13
src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs

@ -36,9 +36,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
protected override void OnFrameApply(ImageFrame<TPixel> source) protected override void OnFrameApply(ImageFrame<TPixel> source)
{ {
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
var operation = new RowIntervalOperation(interest.X, source, this.definition.Matrix, this.Configuration); var operation = new RowOperation(interest.X, source, this.definition.Matrix, this.Configuration);
ParallelRowIterator.IterateRows<RowIntervalOperation, Vector4>( ParallelRowIterator.IterateRows<RowOperation, Vector4>(
this.Configuration, this.Configuration,
interest, interest,
in operation); in operation);
@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the convolution logic for <see cref="FilterProcessor{TPixel}"/>. /// A <see langword="struct"/> implementing the convolution logic for <see cref="FilterProcessor{TPixel}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation<Vector4> private readonly struct RowOperation : IRowOperation<Vector4>
{ {
private readonly int startX; private readonly int startX;
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
@ -55,7 +55,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
private readonly Configuration configuration; private readonly Configuration configuration;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
int startX, int startX,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
ColorMatrix matrix, ColorMatrix matrix,
@ -69,9 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span);
@ -83,4 +81,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters
} }
} }
} }
}

4
src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs

@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
} }
var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source); var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
this.Configuration, this.Configuration,
new Rectangle(0, 0, sourceWidth, tileYStartPositions.Count), new Rectangle(0, 0, sourceWidth, tileYStartPositions.Count),
in operation); in operation);
@ -522,7 +522,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
this.luminanceLevels, this.luminanceLevels,
source); source);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
this.configuration, this.configuration,
new Rectangle(0, 0, this.sourceWidth, this.tileYStartPositions.Count), new Rectangle(0, 0, this.sourceWidth, this.tileYStartPositions.Count),
in operation); in operation);

22
src/ImageSharp/Processing/Processors/Normalization/GlobalHistogramEqualizationProcessor{TPixel}.cs

@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
using IMemoryOwner<int> histogramBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean); using IMemoryOwner<int> histogramBuffer = memoryAllocator.Allocate<int>(this.LuminanceLevels, AllocationOptions.Clean);
// Build the histogram of the grayscale levels // Build the histogram of the grayscale levels
var grayscaleOperation = new GrayscaleLevelsRowIntervalOperation(interest, histogramBuffer, source, this.LuminanceLevels); var grayscaleOperation = new GrayscaleLevelsRowOperation(interest, histogramBuffer, source, this.LuminanceLevels);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
this.Configuration, this.Configuration,
interest, interest,
@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
float numberOfPixelsMinusCdfMin = numberOfPixels - cdfMin; float numberOfPixelsMinusCdfMin = numberOfPixels - cdfMin;
// Apply the cdf to each pixel of the image // Apply the cdf to each pixel of the image
var cdfOperation = new CdfApplicationRowIntervalOperation(interest, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin); var cdfOperation = new CdfApplicationRowOperation(interest, cdfBuffer, source, this.LuminanceLevels, numberOfPixelsMinusCdfMin);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
this.Configuration, this.Configuration,
interest, interest,
@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the grayscale levels logic for <see cref="GlobalHistogramEqualizationProcessor{TPixel}"/>. /// A <see langword="struct"/> implementing the grayscale levels logic for <see cref="GlobalHistogramEqualizationProcessor{TPixel}"/>.
/// </summary> /// </summary>
private readonly struct GrayscaleLevelsRowIntervalOperation : IRowIntervalOperation private readonly struct GrayscaleLevelsRowOperation : IRowOperation
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly IMemoryOwner<int> histogramBuffer; private readonly IMemoryOwner<int> histogramBuffer;
@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly int luminanceLevels; private readonly int luminanceLevels;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public GrayscaleLevelsRowIntervalOperation( public GrayscaleLevelsRowOperation(
Rectangle bounds, Rectangle bounds,
IMemoryOwner<int> histogramBuffer, IMemoryOwner<int> histogramBuffer,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
@ -107,11 +107,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{ {
ref int histogramBase = ref MemoryMarshal.GetReference(this.histogramBuffer.GetSpan()); 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++) for (int x = 0; x < this.bounds.Width; x++)
@ -121,12 +119,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
} }
} }
} }
}
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the cdf application levels logic for <see cref="GlobalHistogramEqualizationProcessor{TPixel}"/>. /// A <see langword="struct"/> implementing the cdf application levels logic for <see cref="GlobalHistogramEqualizationProcessor{TPixel}"/>.
/// </summary> /// </summary>
private readonly struct CdfApplicationRowIntervalOperation : IRowIntervalOperation private readonly struct CdfApplicationRowOperation : IRowOperation
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly IMemoryOwner<int> cdfBuffer; private readonly IMemoryOwner<int> cdfBuffer;
@ -135,7 +132,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
private readonly float numberOfPixelsMinusCdfMin; private readonly float numberOfPixelsMinusCdfMin;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public CdfApplicationRowIntervalOperation( public CdfApplicationRowOperation(
Rectangle bounds, Rectangle bounds,
IMemoryOwner<int> cdfBuffer, IMemoryOwner<int> cdfBuffer,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
@ -151,11 +148,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{ {
ref int cdfBase = ref MemoryMarshal.GetReference(this.cdfBuffer.GetSpan()); 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)); ref TPixel pixelBase = ref MemoryMarshal.GetReference(this.source.GetPixelRowSpan(y));
for (int x = 0; x < this.bounds.Width; x++) for (int x = 0; x < this.bounds.Width; x++)
@ -169,4 +164,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Normalization
} }
} }
} }
}

11
src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor{TPixel}.cs

@ -49,14 +49,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(graphicsOptions); PixelBlender<TPixel> blender = PixelOperations<TPixel>.Instance.GetPixelBlender(graphicsOptions);
var operation = new RowIntervalOperation(configuration, interest, blender, amount, colors, source); var operation = new RowOperation(configuration, interest, blender, amount, colors, source);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
interest, interest,
in operation); in operation);
} }
private readonly struct RowIntervalOperation : IRowIntervalOperation private readonly struct RowOperation : IRowOperation
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly Rectangle bounds; private readonly Rectangle bounds;
@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Configuration configuration, Configuration configuration,
Rectangle bounds, Rectangle bounds,
PixelBlender<TPixel> blender, PixelBlender<TPixel> blender,
@ -83,9 +83,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> destination = Span<TPixel> destination =
this.source.GetPixelRowSpan(y) this.source.GetPixelRowSpan(y)
@ -103,4 +101,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
} }
} }
}

13
src/ImageSharp/Processing/Processors/Overlays/GlowProcessor{TPixel}.cs

@ -55,14 +55,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width); using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width);
rowColors.GetSpan().Fill(glowColor); rowColors.GetSpan().Fill(glowColor);
var operation = new RowIntervalOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source);
ParallelRowIterator.IterateRows<RowIntervalOperation, float>( ParallelRowIterator.IterateRows<RowOperation, float>(
configuration, configuration,
interest, interest,
in operation); in operation);
} }
private readonly struct RowIntervalOperation : IRowIntervalOperation<float> private readonly struct RowOperation : IRowOperation<float>
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly Rectangle bounds; private readonly Rectangle bounds;
@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Configuration configuration, Configuration configuration,
Rectangle bounds, Rectangle bounds,
IMemoryOwner<TPixel> colors, IMemoryOwner<TPixel> colors,
@ -95,12 +95,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<float> span) public void Invoke(int y, Span<float> span)
{ {
Span<TPixel> colorSpan = this.colors.GetSpan(); Span<TPixel> colorSpan = this.colors.GetSpan();
for (int y = rows.Min; y < rows.Max; y++)
{
for (int i = 0; i < this.bounds.Width; i++) for (int i = 0; i < this.bounds.Width; i++)
{ {
float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
@ -119,4 +117,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
} }
} }
}

13
src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor{TPixel}.cs

@ -63,14 +63,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width); using IMemoryOwner<TPixel> rowColors = allocator.Allocate<TPixel>(interest.Width);
rowColors.GetSpan().Fill(vignetteColor); rowColors.GetSpan().Fill(vignetteColor);
var operation = new RowIntervalOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source); var operation = new RowOperation(configuration, interest, rowColors, this.blender, center, maxDistance, blendPercent, source);
ParallelRowIterator.IterateRows<RowIntervalOperation, float>( ParallelRowIterator.IterateRows<RowOperation, float>(
configuration, configuration,
interest, interest,
in operation); in operation);
} }
private readonly struct RowIntervalOperation : IRowIntervalOperation<float> private readonly struct RowOperation : IRowOperation<float>
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
private readonly Rectangle bounds; private readonly Rectangle bounds;
@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation( public RowOperation(
Configuration configuration, Configuration configuration,
Rectangle bounds, Rectangle bounds,
IMemoryOwner<TPixel> colors, IMemoryOwner<TPixel> colors,
@ -103,12 +103,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<float> span) public void Invoke(int y, Span<float> span)
{ {
Span<TPixel> colorSpan = this.colors.GetSpan(); Span<TPixel> colorSpan = this.colors.GetSpan();
for (int y = rows.Min; y < rows.Max; y++)
{
for (int i = 0; i < this.bounds.Width; i++) for (int i = 0; i < this.bounds.Width; i++)
{ {
float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y)); float distance = Vector2.Distance(this.center, new Vector2(i + this.bounds.X, y));
@ -127,4 +125,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays
} }
} }
} }
}

2
src/ImageSharp/Processing/Processors/Quantization/FrameQuantizerExtensions.cs

@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
if (dither is null) if (dither is null)
{ {
var operation = new RowIntervalOperation<TFrameQuantizer, TPixel>(quantizer, source, output, bounds, palette); var operation = new RowIntervalOperation<TFrameQuantizer, TPixel>(quantizer, source, output, bounds, palette);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
quantizer.Configuration, quantizer.Configuration,
bounds, bounds,
in operation); in operation);

2
src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs

@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
using QuantizedFrame<TPixel> quantized = frameQuantizer.QuantizeFrame(source, interest); using QuantizedFrame<TPixel> quantized = frameQuantizer.QuantizeFrame(source, interest);
var operation = new RowIntervalOperation(this.SourceRectangle, source, quantized); var operation = new RowIntervalOperation(this.SourceRectangle, source, quantized);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
configuration, configuration,
interest, interest,
in operation); in operation);

13
src/ImageSharp/Processing/Processors/Transforms/CropProcessor{TPixel}.cs

@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
ParallelExecutionSettings parallelSettings = ParallelExecutionSettings parallelSettings =
ParallelExecutionSettings.FromConfiguration(this.Configuration).MultiplyMinimumPixelsPerTask(4); ParallelExecutionSettings.FromConfiguration(this.Configuration).MultiplyMinimumPixelsPerTask(4);
var operation = new RowIntervalOperation(bounds, source, destination); var operation = new RowOperation(bounds, source, destination);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
bounds, bounds,
@ -62,20 +62,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <summary> /// <summary>
/// A <see langword="struct"/> implementing the processor logic for <see cref="CropProcessor{T}"/>. /// A <see langword="struct"/> implementing the processor logic for <see cref="CropProcessor{T}"/>.
/// </summary> /// </summary>
private readonly struct RowIntervalOperation : IRowIntervalOperation private readonly struct RowOperation : IRowOperation
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="RowIntervalOperation"/> struct. /// Initializes a new instance of the <see cref="RowOperation"/> struct.
/// </summary> /// </summary>
/// <param name="bounds">The target processing bounds for the current instance.</param> /// <param name="bounds">The target processing bounds for the current instance.</param>
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current instance.</param> /// <param name="source">The source <see cref="Image{TPixel}"/> for the current instance.</param>
/// <param name="destination">The destination <see cref="Image{TPixel}"/> for the current instance.</param> /// <param name="destination">The destination <see cref="Image{TPixel}"/> for the current instance.</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation(Rectangle bounds, ImageFrame<TPixel> source, ImageFrame<TPixel> destination) public RowOperation(Rectangle bounds, ImageFrame<TPixel> source, ImageFrame<TPixel> destination)
{ {
this.bounds = bounds; this.bounds = bounds;
this.source = source; this.source = source;
@ -84,9 +84,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left); Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y).Slice(this.bounds.Left);
Span<TPixel> targetRow = this.destination.GetPixelRowSpan(y - this.bounds.Top); Span<TPixel> targetRow = this.destination.GetPixelRowSpan(y - this.bounds.Top);
@ -95,4 +93,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}

15
src/ImageSharp/Processing/Processors/Transforms/Linear/AffineTransformProcessor{TPixel}.cs

@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
in operation); in operation);
} }
private readonly struct NNAffineOperation : IRowIntervalOperation private readonly struct NNAffineOperation : IRowOperation
{ {
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
@ -133,9 +133,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> destRow = this.destination.GetPixelRowSpan(y); Span<TPixel> destRow = this.destination.GetPixelRowSpan(y);
@ -152,9 +150,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}
private readonly struct AffineOperation<TResampler> : IRowIntervalOperation<Vector4> private readonly struct AffineOperation<TResampler> : IRowOperation<Vector4>
where TResampler : struct, IResampler where TResampler : struct, IResampler
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
@ -193,11 +190,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{ {
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer; Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
for (int y = rows.Min; y < rows.Max; y++)
{
PixelOperations<TPixel>.Instance.ToVector4( PixelOperations<TPixel>.Instance.ToVector4(
this.configuration, this.configuration,
this.destination.GetPixelRowSpan(y), this.destination.GetPixelRowSpan(y),
@ -231,4 +227,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}

15
src/ImageSharp/Processing/Processors/Transforms/Linear/FlipProcessor{TPixel}.cs

@ -5,7 +5,6 @@ using System;
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Processing.Processors.Transforms namespace SixLabors.ImageSharp.Processing.Processors.Transforms
@ -76,28 +75,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param> /// <param name="configuration">The configuration.</param>
private void FlipY(ImageFrame<TPixel> source, Configuration configuration) private void FlipY(ImageFrame<TPixel> source, Configuration configuration)
{ {
var operation = new RowIntervalOperation(source); var operation = new RowOperation(source);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
source.Bounds(), source.Bounds(),
in operation); in operation);
} }
private readonly struct RowIntervalOperation : IRowIntervalOperation private readonly struct RowOperation : IRowOperation
{ {
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public RowIntervalOperation(ImageFrame<TPixel> source) => this.source = source; public RowOperation(ImageFrame<TPixel> source) => this.source = source;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y) => this.source.GetPixelRowSpan(y).Reverse();
{
for (int y = rows.Min; y < rows.Max; y++)
{
this.source.GetPixelRowSpan(y).Reverse();
}
}
} }
} }
} }

15
src/ImageSharp/Processing/Processors/Transforms/Linear/ProjectiveTransformProcessor{TPixel}.cs

@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
in operation); in operation);
} }
private readonly struct NNProjectiveOperation : IRowIntervalOperation private readonly struct NNProjectiveOperation : IRowOperation
{ {
private readonly ImageFrame<TPixel> source; private readonly ImageFrame<TPixel> source;
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
@ -133,9 +133,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> destRow = this.destination.GetPixelRowSpan(y); Span<TPixel> destRow = this.destination.GetPixelRowSpan(y);
@ -152,9 +150,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}
private readonly struct ProjectiveOperation<TResampler> : IRowIntervalOperation<Vector4> private readonly struct ProjectiveOperation<TResampler> : IRowOperation<Vector4>
where TResampler : struct, IResampler where TResampler : struct, IResampler
{ {
private readonly Configuration configuration; private readonly Configuration configuration;
@ -193,11 +190,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows, Span<Vector4> span) public void Invoke(int y, Span<Vector4> span)
{ {
Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer; Buffer2D<TPixel> sourceBuffer = this.source.PixelBuffer;
for (int y = rows.Min; y < rows.Max; y++)
{
PixelOperations<TPixel>.Instance.ToVector4( PixelOperations<TPixel>.Instance.ToVector4(
this.configuration, this.configuration,
this.destination.GetPixelRowSpan(y), this.destination.GetPixelRowSpan(y),
@ -231,4 +227,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}

24
src/ImageSharp/Processing/Processors/Transforms/Linear/RotateProcessor{TPixel}.cs

@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param> /// <param name="configuration">The configuration.</param>
private void Rotate180(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration) private void Rotate180(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{ {
var operation = new Rotate180RowIntervalOperation(source.Width, source.Height, source, destination); var operation = new Rotate180RowOperation(source.Width, source.Height, source, destination);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
source.Bounds(), source.Bounds(),
@ -147,7 +147,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private void Rotate270(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration) private void Rotate270(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{ {
var operation = new Rotate270RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source, destination); var operation = new Rotate270RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source, destination);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
configuration, configuration,
source.Bounds(), source.Bounds(),
in operation); in operation);
@ -161,14 +161,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <param name="configuration">The configuration.</param> /// <param name="configuration">The configuration.</param>
private void Rotate90(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration) private void Rotate90(ImageFrame<TPixel> source, ImageFrame<TPixel> destination, Configuration configuration)
{ {
var operation = new Rotate90RowIntervalOperation(destination.Bounds(), source.Width, source.Height, source, destination); var operation = new Rotate90RowOperation(destination.Bounds(), source.Width, source.Height, source, destination);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRows(
configuration, configuration,
source.Bounds(), source.Bounds(),
in operation); in operation);
} }
private readonly struct Rotate180RowIntervalOperation : IRowIntervalOperation private readonly struct Rotate180RowOperation : IRowOperation
{ {
private readonly int width; private readonly int width;
private readonly int height; private readonly int height;
@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Rotate180RowIntervalOperation( public Rotate180RowOperation(
int width, int width,
int height, int height,
ImageFrame<TPixel> source, ImageFrame<TPixel> source,
@ -189,9 +189,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y); Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
Span<TPixel> targetRow = this.destination.GetPixelRowSpan(this.height - y - 1); Span<TPixel> targetRow = this.destination.GetPixelRowSpan(this.height - y - 1);
@ -202,7 +200,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}
private readonly struct Rotate270RowIntervalOperation : IRowIntervalOperation private readonly struct Rotate270RowIntervalOperation : IRowIntervalOperation
{ {
@ -248,7 +245,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
private readonly struct Rotate90RowIntervalOperation : IRowIntervalOperation private readonly struct Rotate90RowOperation : IRowOperation
{ {
private readonly Rectangle bounds; private readonly Rectangle bounds;
private readonly int width; private readonly int width;
@ -257,7 +254,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public Rotate90RowIntervalOperation( public Rotate90RowOperation(
Rectangle bounds, Rectangle bounds,
int width, int width,
int height, int height,
@ -272,9 +269,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{
for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y); Span<TPixel> sourceRow = this.source.GetPixelRowSpan(y);
int newX = this.height - y - 1; int newX = this.height - y - 1;
@ -289,4 +284,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}

11
src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs

@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
float widthFactor = sourceRectangle.Width / (float)destinationRectangle.Width; float widthFactor = sourceRectangle.Width / (float)destinationRectangle.Width;
float heightFactor = sourceRectangle.Height / (float)destinationRectangle.Height; float heightFactor = sourceRectangle.Height / (float)destinationRectangle.Height;
var operation = new NNRowIntervalOperation( var operation = new NNRowOperation(
sourceRectangle, sourceRectangle,
destinationRectangle, destinationRectangle,
widthFactor, widthFactor,
@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
private readonly struct NNRowIntervalOperation : IRowIntervalOperation private readonly struct NNRowOperation : IRowOperation
{ {
private readonly Rectangle sourceBounds; private readonly Rectangle sourceBounds;
private readonly Rectangle destinationBounds; private readonly Rectangle destinationBounds;
@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
private readonly ImageFrame<TPixel> destination; private readonly ImageFrame<TPixel> destination;
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public NNRowIntervalOperation( public NNRowOperation(
Rectangle sourceBounds, Rectangle sourceBounds,
Rectangle destinationBounds, Rectangle destinationBounds,
float widthFactor, float widthFactor,
@ -220,7 +220,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void Invoke(in RowInterval rows) public void Invoke(int y)
{ {
int sourceX = this.sourceBounds.X; int sourceX = this.sourceBounds.X;
int sourceY = this.sourceBounds.Y; int sourceY = this.sourceBounds.Y;
@ -229,8 +229,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
int destLeft = this.destinationBounds.Left; int destLeft = this.destinationBounds.Left;
int destRight = this.destinationBounds.Right; int destRight = this.destinationBounds.Right;
for (int y = rows.Min; y < rows.Max; y++)
{
// Y coordinates of source points // Y coordinates of source points
Span<TPixel> sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY)); Span<TPixel> sourceRow = this.source.GetPixelRowSpan((int)(((y - destY) * this.heightFactor) + sourceY));
Span<TPixel> targetRow = this.destination.GetPixelRowSpan(y); Span<TPixel> targetRow = this.destination.GetPixelRowSpan(y);
@ -244,4 +242,3 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
} }
} }
} }
}

18
tests/ImageSharp.Tests/Helpers/ParallelRowIteratorTests.cs

@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation(RowAction); var operation = new TestRowIntervalOperation(RowAction);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
rectangle, rectangle,
in parallelSettings, in parallelSettings,
in operation); in operation);
@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation(RowAction); var operation = new TestRowIntervalOperation(RowAction);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
rectangle, rectangle,
in parallelSettings, in parallelSettings,
in operation); in operation);
@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation<Vector4>(RowAction); var operation = new TestRowIntervalOperation<Vector4>(RowAction);
ParallelRowIterator.IterateRows<TestRowIntervalOperation<Vector4>, Vector4>( ParallelRowIterator.IterateRowIntervals<TestRowIntervalOperation<Vector4>, Vector4>(
rectangle, rectangle,
in parallelSettings, in parallelSettings,
in operation); in operation);
@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation<Vector4>(RowAction); var operation = new TestRowIntervalOperation<Vector4>(RowAction);
ParallelRowIterator.IterateRows<TestRowIntervalOperation<Vector4>, Vector4>( ParallelRowIterator.IterateRowIntervals<TestRowIntervalOperation<Vector4>, Vector4>(
rectangle, rectangle,
in parallelSettings, in parallelSettings,
in operation); in operation);
@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation(RowAction); var operation = new TestRowIntervalOperation(RowAction);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
rectangle, rectangle,
in parallelSettings, in parallelSettings,
in operation); in operation);
@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation<Vector4>(RowAction); var operation = new TestRowIntervalOperation<Vector4>(RowAction);
ParallelRowIterator.IterateRows<TestRowIntervalOperation<Vector4>, Vector4>( ParallelRowIterator.IterateRowIntervals<TestRowIntervalOperation<Vector4>, Vector4>(
rectangle, rectangle,
in parallelSettings, in parallelSettings,
in operation); in operation);
@ -355,7 +355,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation(RowAction); var operation = new TestRowIntervalOperation(RowAction);
ParallelRowIterator.IterateRows( ParallelRowIterator.IterateRowIntervals(
rect, rect,
settings, settings,
in operation); in operation);
@ -383,7 +383,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation(RowAction); var operation = new TestRowIntervalOperation(RowAction);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>( ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(
() => ParallelRowIterator.IterateRows(rect, in parallelSettings, in operation)); () => ParallelRowIterator.IterateRowIntervals(rect, in parallelSettings, in operation));
Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message); Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message);
} }
@ -406,7 +406,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers
var operation = new TestRowIntervalOperation<Rgba32>(RowAction); var operation = new TestRowIntervalOperation<Rgba32>(RowAction);
ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>( ArgumentOutOfRangeException ex = Assert.Throws<ArgumentOutOfRangeException>(
() => ParallelRowIterator.IterateRows<TestRowIntervalOperation<Rgba32>, Rgba32>(rect, in parallelSettings, in operation)); () => ParallelRowIterator.IterateRowIntervals<TestRowIntervalOperation<Rgba32>, Rgba32>(rect, in parallelSettings, in operation));
Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message); Assert.Contains(width <= 0 ? "Width" : "Height", ex.Message);
} }

2
tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs

@ -713,7 +713,7 @@ namespace SixLabors.ImageSharp.Tests
var operation = new RowOperation(configuration, sourceRectangle, source); var operation = new RowOperation(configuration, sourceRectangle, source);
ParallelRowIterator.IterateRows<RowOperation, Vector4>( ParallelRowIterator.IterateRowIntervals<RowOperation, Vector4>(
configuration, configuration,
sourceRectangle, sourceRectangle,
in operation); in operation);

Loading…
Cancel
Save