mirror of https://github.com/SixLabors/ImageSharp
54 changed files with 2974 additions and 2022 deletions
@ -0,0 +1,21 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Advanced |
|||
{ |
|||
/// <summary>
|
|||
/// Defines the contract for an action that operates on a row interval.
|
|||
/// </summary>
|
|||
public interface IRowIntervalOperation |
|||
{ |
|||
/// <summary>
|
|||
/// Invokes the method passing the row interval.
|
|||
/// </summary>
|
|||
/// <param name="rows">The row interval.</param>
|
|||
void Invoke(in RowInterval rows); |
|||
} |
|||
} |
|||
@ -0,0 +1,25 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Advanced |
|||
{ |
|||
/// <summary>
|
|||
/// Defines the contract for an action that operates on a row interval with a temporary buffer.
|
|||
/// </summary>
|
|||
/// <typeparam name="TBuffer">The type of buffer elements.</typeparam>
|
|||
public interface IRowIntervalOperation<TBuffer> |
|||
where TBuffer : unmanaged |
|||
{ |
|||
/// <summary>
|
|||
/// Invokes the method passing the row interval and a buffer.
|
|||
/// </summary>
|
|||
/// <param name="rows">The row interval.</param>
|
|||
/// <param name="span">The contiguous region of memory.</param>
|
|||
void Invoke(in RowInterval rows, Span<TBuffer> span); |
|||
} |
|||
} |
|||
@ -0,0 +1,110 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Advanced |
|||
{ |
|||
/// <content>
|
|||
/// Utility methods for batched processing of pixel row intervals.
|
|||
/// Parallel execution is optimized for image processing based on values defined
|
|||
/// <see cref="ParallelExecutionSettings"/> or <see cref="Configuration"/>.
|
|||
/// Using this class is preferred over direct usage of <see cref="Parallel"/> utility methods.
|
|||
/// </content>
|
|||
public static partial class ParallelRowIterator |
|||
{ |
|||
private readonly struct IterationParameters |
|||
{ |
|||
public readonly int MinY; |
|||
public readonly int MaxY; |
|||
public readonly int StepY; |
|||
public readonly int Width; |
|||
|
|||
public IterationParameters(int minY, int maxY, int stepY) |
|||
: this(minY, maxY, stepY, 0) |
|||
{ |
|||
} |
|||
|
|||
public IterationParameters(int minY, int maxY, int stepY, int width) |
|||
{ |
|||
this.MinY = minY; |
|||
this.MaxY = maxY; |
|||
this.StepY = stepY; |
|||
this.Width = width; |
|||
} |
|||
} |
|||
|
|||
private readonly struct RowIntervalOperationWrapper<T> |
|||
where T : struct, IRowIntervalOperation |
|||
{ |
|||
private readonly IterationParameters info; |
|||
private readonly T operation; |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public RowIntervalOperationWrapper(in IterationParameters info, in T operation) |
|||
{ |
|||
this.info = info; |
|||
this.operation = operation; |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void Invoke(int i) |
|||
{ |
|||
int yMin = this.info.MinY + (i * this.info.StepY); |
|||
|
|||
if (yMin >= this.info.MaxY) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); |
|||
var rows = new RowInterval(yMin, yMax); |
|||
|
|||
// Skip the safety copy when invoking a potentially impure method on a readonly field
|
|||
Unsafe.AsRef(in this.operation).Invoke(in rows); |
|||
} |
|||
} |
|||
|
|||
private readonly struct RowIntervalOperationWrapper<T, TBuffer> |
|||
where T : struct, IRowIntervalOperation<TBuffer> |
|||
where TBuffer : unmanaged |
|||
{ |
|||
private readonly IterationParameters info; |
|||
private readonly MemoryAllocator allocator; |
|||
private readonly T operation; |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public RowIntervalOperationWrapper( |
|||
in IterationParameters info, |
|||
MemoryAllocator allocator, |
|||
in T operation) |
|||
{ |
|||
this.info = info; |
|||
this.allocator = allocator; |
|||
this.operation = operation; |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void Invoke(int i) |
|||
{ |
|||
int yMin = this.info.MinY + (i * this.info.StepY); |
|||
|
|||
if (yMin >= this.info.MaxY) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int yMax = Math.Min(yMin + this.info.StepY, this.info.MaxY); |
|||
var rows = new RowInterval(yMin, yMax); |
|||
|
|||
using IMemoryOwner<TBuffer> buffer = this.allocator.Allocate<TBuffer>(this.info.Width); |
|||
|
|||
Unsafe.AsRef(in this.operation).Invoke(in rows, buffer.Memory.Span); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,162 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Threading.Tasks; |
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Advanced |
|||
{ |
|||
/// <summary>
|
|||
/// Utility methods for batched processing of pixel row intervals.
|
|||
/// Parallel execution is optimized for image processing based on values defined
|
|||
/// <see cref="ParallelExecutionSettings"/> or <see cref="Configuration"/>.
|
|||
/// Using this class is preferred over direct usage of <see cref="Parallel"/> utility methods.
|
|||
/// </summary>
|
|||
public static partial class ParallelRowIterator |
|||
{ |
|||
/// <summary>
|
|||
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
|
|||
/// </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 <see cref="RowInterval"/>.</param>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public static void IterateRows<T>(Configuration configuration, Rectangle rectangle, in T operation) |
|||
where T : struct, IRowIntervalOperation |
|||
{ |
|||
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); |
|||
IterateRows(rectangle, in parallelSettings, in operation); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
|
|||
/// </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 <see cref="RowInterval"/>.</param>
|
|||
public static void IterateRows<T>( |
|||
Rectangle rectangle, |
|||
in ParallelExecutionSettings parallelSettings, |
|||
in T operation) |
|||
where T : struct, IRowIntervalOperation |
|||
{ |
|||
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) |
|||
{ |
|||
var rows = new RowInterval(top, bottom); |
|||
Unsafe.AsRef(in operation).Invoke(in rows); |
|||
return; |
|||
} |
|||
|
|||
int verticalStep = DivideCeil(rectangle.Height, numOfSteps); |
|||
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; |
|||
var info = new IterationParameters(top, bottom, verticalStep); |
|||
var wrappingOperation = new RowIntervalOperationWrapper<T>(in info, in operation); |
|||
|
|||
Parallel.For( |
|||
0, |
|||
numOfSteps, |
|||
parallelOptions, |
|||
wrappingOperation.Invoke); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
|
|||
/// 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 <see cref="RowInterval"/>.</param>
|
|||
public static void IterateRows<T, TBuffer>(Configuration configuration, Rectangle rectangle, in T operation) |
|||
where T : struct, IRowIntervalOperation<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 defined by <see cref="RowInterval"/>-s
|
|||
/// 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 <see cref="RowInterval"/>.</param>
|
|||
public static void IterateRows<T, TBuffer>( |
|||
Rectangle rectangle, |
|||
in ParallelExecutionSettings parallelSettings, |
|||
in T operation) |
|||
where T : struct, IRowIntervalOperation<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) |
|||
{ |
|||
var rows = new RowInterval(top, bottom); |
|||
using (IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(width)) |
|||
{ |
|||
Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
int verticalStep = DivideCeil(height, numOfSteps); |
|||
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; |
|||
var info = new IterationParameters(top, bottom, verticalStep, width); |
|||
var wrappingOperation = new RowIntervalOperationWrapper<T, TBuffer>(in info, allocator, in operation); |
|||
|
|||
Parallel.For( |
|||
0, |
|||
numOfSteps, |
|||
parallelOptions, |
|||
wrappingOperation.Invoke); |
|||
} |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
private static int DivideCeil(int dividend, int divisor) => 1 + ((dividend - 1) / divisor); |
|||
|
|||
private static void ValidateRectangle(Rectangle rectangle) |
|||
{ |
|||
Guard.MustBeGreaterThan( |
|||
rectangle.Width, |
|||
0, |
|||
$"{nameof(rectangle)}.{nameof(rectangle.Width)}"); |
|||
|
|||
Guard.MustBeGreaterThan( |
|||
rectangle.Height, |
|||
0, |
|||
$"{nameof(rectangle)}.{nameof(rectangle.Height)}"); |
|||
} |
|||
} |
|||
} |
|||
@ -1,178 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using System.Runtime.CompilerServices; |
|||
using System.Threading.Tasks; |
|||
|
|||
using SixLabors.ImageSharp.Memory; |
|||
|
|||
namespace SixLabors.ImageSharp.Advanced.ParallelUtils |
|||
{ |
|||
/// <summary>
|
|||
/// Utility methods for batched processing of pixel row intervals.
|
|||
/// Parallel execution is optimized for image processing based on values defined
|
|||
/// <see cref="ParallelExecutionSettings"/> or <see cref="Configuration"/>.
|
|||
/// Using this class is preferred over direct usage of <see cref="Parallel"/> utility methods.
|
|||
/// </summary>
|
|||
public static class ParallelHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
|
|||
/// <param name="configuration">The <see cref="Configuration"/> to get the parallel settings from.</param>
|
|||
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
|
|||
public static void IterateRows(Rectangle rectangle, Configuration configuration, Action<RowInterval> body) |
|||
{ |
|||
var parallelSettings = ParallelExecutionSettings.FromConfiguration(configuration); |
|||
|
|||
IterateRows(rectangle, parallelSettings, body); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s.
|
|||
/// </summary>
|
|||
/// <param name="rectangle">The <see cref="Rectangle"/>.</param>
|
|||
/// <param name="parallelSettings">The <see cref="ParallelExecutionSettings"/>.</param>
|
|||
/// <param name="body">The method body defining the iteration logic on a single <see cref="RowInterval"/>.</param>
|
|||
public static void IterateRows( |
|||
Rectangle rectangle, |
|||
in ParallelExecutionSettings parallelSettings, |
|||
Action<RowInterval> body) |
|||
{ |
|||
ValidateRectangle(rectangle); |
|||
|
|||
int maxSteps = DivideCeil( |
|||
rectangle.Width * rectangle.Height, |
|||
parallelSettings.MinimumPixelsProcessedPerTask); |
|||
|
|||
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); |
|||
|
|||
// Avoid TPL overhead in this trivial case:
|
|||
if (numOfSteps == 1) |
|||
{ |
|||
var rows = new RowInterval(rectangle.Top, rectangle.Bottom); |
|||
body(rows); |
|||
return; |
|||
} |
|||
|
|||
int verticalStep = DivideCeil(rectangle.Height, numOfSteps); |
|||
|
|||
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; |
|||
|
|||
int top = rectangle.Top; |
|||
int bottom = rectangle.Bottom; |
|||
|
|||
Parallel.For( |
|||
0, |
|||
numOfSteps, |
|||
parallelOptions, |
|||
i => |
|||
{ |
|||
int yMin = top + (i * verticalStep); |
|||
|
|||
if (yMin >= bottom) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int yMax = Math.Min(yMin + verticalStep, bottom); |
|||
|
|||
var rows = new RowInterval(yMin, yMax); |
|||
body(rows); |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
|
|||
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
|
|||
/// </summary>
|
|||
internal static void IterateRowsWithTempBuffer<T>( |
|||
Rectangle rectangle, |
|||
in ParallelExecutionSettings parallelSettings, |
|||
Action<RowInterval, Memory<T>> body) |
|||
where T : unmanaged |
|||
{ |
|||
ValidateRectangle(rectangle); |
|||
|
|||
int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask); |
|||
|
|||
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); |
|||
|
|||
MemoryAllocator memoryAllocator = parallelSettings.MemoryAllocator; |
|||
|
|||
// Avoid TPL overhead in this trivial case:
|
|||
if (numOfSteps == 1) |
|||
{ |
|||
var rows = new RowInterval(rectangle.Top, rectangle.Bottom); |
|||
using (IMemoryOwner<T> buffer = memoryAllocator.Allocate<T>(rectangle.Width)) |
|||
{ |
|||
body(rows, buffer.Memory); |
|||
} |
|||
|
|||
return; |
|||
} |
|||
|
|||
int verticalStep = DivideCeil(rectangle.Height, numOfSteps); |
|||
|
|||
var parallelOptions = new ParallelOptions { MaxDegreeOfParallelism = numOfSteps }; |
|||
|
|||
int top = rectangle.Top; |
|||
int bottom = rectangle.Bottom; |
|||
|
|||
Parallel.For( |
|||
0, |
|||
numOfSteps, |
|||
parallelOptions, |
|||
i => |
|||
{ |
|||
int yMin = top + (i * verticalStep); |
|||
|
|||
if (yMin >= bottom) |
|||
{ |
|||
return; |
|||
} |
|||
|
|||
int yMax = Math.Min(yMin + verticalStep, rectangle.Bottom); |
|||
|
|||
var rows = new RowInterval(yMin, yMax); |
|||
|
|||
using (IMemoryOwner<T> buffer = memoryAllocator.Allocate<T>(rectangle.Width)) |
|||
{ |
|||
body(rows, buffer.Memory); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Iterate through the rows of a rectangle in optimized batches defined by <see cref="RowInterval"/>-s
|
|||
/// instantiating a temporary buffer for each <paramref name="body"/> invocation.
|
|||
/// </summary>
|
|||
internal static void IterateRowsWithTempBuffer<T>( |
|||
Rectangle rectangle, |
|||
Configuration configuration, |
|||
Action<RowInterval, Memory<T>> body) |
|||
where T : unmanaged |
|||
{ |
|||
IterateRowsWithTempBuffer(rectangle, ParallelExecutionSettings.FromConfiguration(configuration), body); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int DivideCeil(int dividend, int divisor) => 1 + ((dividend - 1) / divisor); |
|||
|
|||
private static void ValidateRectangle(Rectangle rectangle) |
|||
{ |
|||
Guard.MustBeGreaterThan( |
|||
rectangle.Width, |
|||
0, |
|||
$"{nameof(rectangle)}.{nameof(rectangle.Width)}"); |
|||
|
|||
Guard.MustBeGreaterThan( |
|||
rectangle.Height, |
|||
0, |
|||
$"{nameof(rectangle)}.{nameof(rectangle.Height)}"); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,21 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|||
{ |
|||
/// <summary>
|
|||
/// An <see langword="interface"/> used by the row delegates for a given <see cref="PixelRowDelegateProcessor{TPixel,TDelegate}"/> instance
|
|||
/// </summary>
|
|||
public interface IPixelRowDelegate |
|||
{ |
|||
/// <summary>
|
|||
/// Applies the current pixel row delegate to a target row of preprocessed pixels.
|
|||
/// </summary>
|
|||
/// <param name="span">The target row of <see cref="Vector4"/> pixels to process.</param>
|
|||
/// <param name="offset">The initial horizontal and vertical offset for the input pixels to process.</param>
|
|||
void Invoke(Span<Vector4> span, Point offset); |
|||
} |
|||
} |
|||
@ -1,70 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Advanced.ParallelUtils; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|||
{ |
|||
/// <summary>
|
|||
/// The base class for all processors that accept a user defined row processing delegate.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal abstract class PixelRowDelegateProcessorBase<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.
|
|||
/// </summary>
|
|||
private readonly PixelConversionModifiers modifiers; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PixelRowDelegateProcessorBase{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
|
|||
/// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
|
|||
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
|
|||
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
|
|||
protected PixelRowDelegateProcessorBase(Configuration configuration, PixelConversionModifiers modifiers, Image<TPixel> source, Rectangle sourceRectangle) |
|||
: base(configuration, source, sourceRectangle) |
|||
=> this.modifiers = modifiers; |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply(ImageFrame<TPixel> source) |
|||
{ |
|||
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); |
|||
int startX = interest.X; |
|||
Configuration configuration = this.Configuration; |
|||
PixelConversionModifiers modifiers = this.modifiers; |
|||
|
|||
ParallelHelper.IterateRowsWithTempBuffer<Vector4>( |
|||
interest, |
|||
this.Configuration, |
|||
(rows, vectorBuffer) => |
|||
{ |
|||
for (int y = rows.Min; y < rows.Max; y++) |
|||
{ |
|||
Span<Vector4> vectorSpan = vectorBuffer.Span; |
|||
int length = vectorSpan.Length; |
|||
Span<TPixel> rowSpan = source.GetPixelRowSpan(y).Slice(startX, length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(configuration, rowSpan, vectorSpan, modifiers); |
|||
|
|||
// Run the user defined pixel shader to the current row of pixels
|
|||
this.ApplyPixelRowDelegate(vectorSpan, new Point(startX, y)); |
|||
|
|||
PixelOperations<TPixel>.Instance.FromVector4Destructive(configuration, vectorSpan, rowSpan, modifiers); |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies the current pixel row delegate to a target row of preprocessed pixels.
|
|||
/// </summary>
|
|||
/// <param name="span">The target row of <see cref="Vector4"/> pixels to process.</param>
|
|||
/// <param name="offset">The initial horizontal and vertical offset for the input pixels to process.</param>
|
|||
protected abstract void ApplyPixelRowDelegate(Span<Vector4> span, Point offset); |
|||
} |
|||
} |
|||
@ -0,0 +1,104 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.Advanced; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|||
{ |
|||
/// <summary>
|
|||
/// The base class for all processors that accept a user defined row processing delegate.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <typeparam name="TDelegate">The row processor type.</typeparam>
|
|||
internal sealed class PixelRowDelegateProcessor<TPixel, TDelegate> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
where TDelegate : struct, IPixelRowDelegate |
|||
{ |
|||
private readonly TDelegate rowDelegate; |
|||
|
|||
/// <summary>
|
|||
/// The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.
|
|||
/// </summary>
|
|||
private readonly PixelConversionModifiers modifiers; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PixelRowDelegateProcessor{TPixel,TDelegate}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="rowDelegate">The row processor to use to process each pixel row</param>
|
|||
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
|
|||
/// <param name="modifiers">The <see cref="PixelConversionModifiers"/> to apply during the pixel conversions.</param>
|
|||
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
|
|||
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
|
|||
public PixelRowDelegateProcessor( |
|||
in TDelegate rowDelegate, |
|||
Configuration configuration, |
|||
PixelConversionModifiers modifiers, |
|||
Image<TPixel> source, |
|||
Rectangle sourceRectangle) |
|||
: base(configuration, source, sourceRectangle) |
|||
{ |
|||
this.rowDelegate = rowDelegate; |
|||
this.modifiers = modifiers; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnFrameApply(ImageFrame<TPixel> source) |
|||
{ |
|||
var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds()); |
|||
var operation = new RowIntervalOperation(interest.X, source, this.Configuration, this.modifiers, this.rowDelegate); |
|||
|
|||
ParallelRowIterator.IterateRows<RowIntervalOperation, Vector4>( |
|||
this.Configuration, |
|||
interest, |
|||
in operation); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// A <see langword="struct"/> implementing the convolution logic for <see cref="PixelRowDelegateProcessor{TPixel,TDelegate}"/>.
|
|||
/// </summary>
|
|||
private readonly struct RowIntervalOperation : IRowIntervalOperation<Vector4> |
|||
{ |
|||
private readonly int startX; |
|||
private readonly ImageFrame<TPixel> source; |
|||
private readonly Configuration configuration; |
|||
private readonly PixelConversionModifiers modifiers; |
|||
private readonly TDelegate rowProcessor; |
|||
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public RowIntervalOperation( |
|||
int startX, |
|||
ImageFrame<TPixel> source, |
|||
Configuration configuration, |
|||
PixelConversionModifiers modifiers, |
|||
in TDelegate rowProcessor) |
|||
{ |
|||
this.startX = startX; |
|||
this.source = source; |
|||
this.configuration = configuration; |
|||
this.modifiers = modifiers; |
|||
this.rowProcessor = rowProcessor; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
[MethodImpl(InliningOptions.ShortMethod)] |
|||
public void Invoke(in RowInterval rows, Span<Vector4> span) |
|||
{ |
|||
for (int y = rows.Min; y < rows.Max; y++) |
|||
{ |
|||
Span<TPixel> rowSpan = this.source.GetPixelRowSpan(y).Slice(this.startX, span.Length); |
|||
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers); |
|||
|
|||
// Run the user defined pixel shader to the current row of pixels
|
|||
Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y)); |
|||
|
|||
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers); |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -1,39 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|||
{ |
|||
/// <summary>
|
|||
/// Applies a user defined row processing delegate to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal sealed class PixelRowDelegateProcessor<TPixel> : PixelRowDelegateProcessorBase<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// The user defined pixel row processing delegate.
|
|||
/// </summary>
|
|||
private readonly PixelRowOperation pixelRowOperation; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PixelRowDelegateProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
|
|||
/// <param name="definition">The <see cref="PixelRowDelegateProcessor"/> defining the processor parameters.</param>
|
|||
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
|
|||
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
|
|||
public PixelRowDelegateProcessor(Configuration configuration, PixelRowDelegateProcessor definition, Image<TPixel> source, Rectangle sourceRectangle) |
|||
: base(configuration, definition.Modifiers, source, sourceRectangle) |
|||
{ |
|||
this.pixelRowOperation = definition.PixelRowOperation; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void ApplyPixelRowDelegate(Span<Vector4> span, Point offset) => this.pixelRowOperation(span); |
|||
} |
|||
} |
|||
@ -1,36 +0,0 @@ |
|||
// Copyright (c) Six Labors and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
|
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Processing.Processors.Effects |
|||
{ |
|||
/// <summary>
|
|||
/// Applies a user defined, position aware, row processing delegate to the image.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal sealed class PositionAwarePixelRowDelegateProcessor<TPixel> : PixelRowDelegateProcessorBase<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
private readonly PixelRowOperation<Point> pixelRowOperation; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="PositionAwarePixelRowDelegateProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param>
|
|||
/// <param name="definition">The <see cref="PositionAwarePixelRowDelegateProcessor"/> defining the processor parameters.</param>
|
|||
/// <param name="source">The source <see cref="Image{TPixel}"/> for the current processor instance.</param>
|
|||
/// <param name="sourceRectangle">The source area to process for the current processor instance.</param>
|
|||
public PositionAwarePixelRowDelegateProcessor(Configuration configuration, PositionAwarePixelRowDelegateProcessor definition, Image<TPixel> source, Rectangle sourceRectangle) |
|||
: base(configuration, definition.Modifiers, source, sourceRectangle) |
|||
{ |
|||
this.pixelRowOperation = definition.PixelRowOperation; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void ApplyPixelRowDelegate(Span<Vector4> span, Point offset) => this.pixelRowOperation(span, offset); |
|||
} |
|||
} |
|||
Loading…
Reference in new issue