diff --git a/src/ImageSharp/Processing/Processors/Convolution/Kernel.cs b/src/ImageSharp/Processing/Processors/Convolution/Kernel.cs
index dbf345caf4..032a8ce445 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/Kernel.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/Kernel.cs
@@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
/// A stack only, readonly, kernel matrix that can be indexed without
/// bounds checks when compiled in release mode.
///
+ /// The type of each element in the kernel.
internal readonly ref struct Kernel
where T : struct, IEquatable
{
@@ -39,10 +40,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
public ReadOnlySpan Span
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- get
- {
- return this.values;
- }
+ get => this.values;
}
public T this[int row, int column]
@@ -54,26 +52,26 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref T vBase = ref MemoryMarshal.GetReference(this.values);
return Unsafe.Add(ref vBase, (row * this.Columns) + column);
}
- }
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void SetValue(int row, int column, T value)
- {
- this.SetValue((row * this.Columns) + column, value);
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ set
+ {
+ this.CheckCoordinates(row, column);
+ ref T vBase = ref MemoryMarshal.GetReference(this.values);
+ Unsafe.Add(ref vBase, (row * this.Columns) + column) = value;
+ }
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void SetValue(int index, T value)
{
+ this.CheckIndex(index);
ref T vBase = ref MemoryMarshal.GetReference(this.values);
Unsafe.Add(ref vBase, index) = value;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void Clear()
- {
- this.values.Clear();
- }
+ public void Clear() => this.values.Clear();
[Conditional("DEBUG")]
private void CheckCoordinates(int row, int column)
@@ -88,5 +86,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
throw new ArgumentOutOfRangeException(nameof(column), column, $"{column} is outside the matrix bounds.");
}
}
+
+ [Conditional("DEBUG")]
+ private void CheckIndex(int index)
+ {
+ if (index < 0 || index >= this.values.Length)
+ {
+ throw new ArgumentOutOfRangeException(nameof(index), index, $"{index} is outside the matrix bounds.");
+ }
+ }
}
}
diff --git a/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs
index bc09d3bd8b..8e2540faf8 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/MedianBlurProcessor{TPixel}.cs
@@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Applies an median filter.
///
+ /// The type of pixel format.
internal sealed class MedianBlurProcessor : ImageProcessor
where TPixel : unmanaged, IPixel
{
@@ -28,17 +29,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
source.CopyTo(targetPixels);
- var interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
+ Rectangle interest = Rectangle.Intersect(this.SourceRectangle, source.Bounds());
// We use a rectangle with width set wider, to allocate a buffer big enough
// for kernel source, channel buffers, source rows and target bulk pixel conversion.
int operationWidth = (2 * kernelSize * kernelSize) + interest.Width + (kernelSize * interest.Width);
- var operationBounds = new Rectangle(interest.X, interest.Y, operationWidth, interest.Height);
+ Rectangle operationBounds = new(interest.X, interest.Y, operationWidth, interest.Height);
- using var map = new KernelSamplingMap(this.Configuration.MemoryAllocator);
+ using KernelSamplingMap map = new(this.Configuration.MemoryAllocator);
map.BuildSamplingOffsetMap(kernelSize, kernelSize, interest, this.definition.BorderWrapModeX, this.definition.BorderWrapModeY);
- var operation = new MedianRowOperation(
+ MedianRowOperation operation = new(
interest,
targetPixels,
source.PixelBuffer,
diff --git a/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs
index 76987abf8d..90dce4dad9 100644
--- a/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs
+++ b/src/ImageSharp/Processing/Processors/Convolution/MedianRowOperation{TPixel}.cs
@@ -14,6 +14,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
///
/// Applies an median filter.
///
+ /// The type of pixel format.
internal readonly struct MedianRowOperation : IRowOperation
where TPixel : unmanaged, IPixel
{
@@ -49,21 +50,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
int boundsX = this.bounds.X;
int boundsWidth = this.bounds.Width;
int kernelCount = this.kernelSize * this.kernelSize;
- Span kernelBuffer = span.Slice(0, kernelCount);
+ Span kernelBuffer = span[..kernelCount];
Span channelVectorBuffer = span.Slice(kernelCount, kernelCount);
Span sourceVectorBuffer = span.Slice(kernelCount << 1, this.kernelSize * boundsWidth);
Span targetBuffer = span.Slice((kernelCount << 1) + sourceVectorBuffer.Length, boundsWidth);
// Stack 4 channels of floats in the space of Vector4's.
Span channelBuffer = MemoryMarshal.Cast(channelVectorBuffer);
- Span xChannel = channelBuffer.Slice(0, kernelCount);
+ Span xChannel = channelBuffer[..kernelCount];
Span yChannel = channelBuffer.Slice(this.yChannelStart, kernelCount);
Span zChannel = channelBuffer.Slice(this.zChannelStart, kernelCount);
- var kernel = new DenseMatrix(this.kernelSize, this.kernelSize, kernelBuffer);
+ DenseMatrix kernel = new(this.kernelSize, this.kernelSize, kernelBuffer);
int row = y - this.bounds.Y;
- var state = new MedianConvolutionState(in kernel, this.map);
+ MedianConvolutionState state = new(in kernel, this.map);
ref int sampleRowBase = ref state.GetSampleRow(row);
ref Vector4 targetBase = ref MemoryMarshal.GetReference(targetBuffer);
@@ -85,7 +86,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
for (int kY = 0; kY < state.Kernel.Rows; kY++)
{
- Span sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
+ Span sourceRow = sourceVectorBuffer[(kY * boundsWidth)..];
ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
{
@@ -96,7 +97,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
}
- target = this.FindMedian3(state.Kernel.Span, xChannel, yChannel, zChannel, kernelCount);
+ target = FindMedian3(state.Kernel.Span, xChannel, yChannel, zChannel);
}
}
else
@@ -109,7 +110,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
ref Vector4 target = ref Unsafe.Add(ref targetBase, x);
for (int kY = 0; kY < state.Kernel.Rows; kY++)
{
- Span sourceRow = sourceVectorBuffer.Slice(kY * boundsWidth);
+ Span sourceRow = sourceVectorBuffer[(kY * boundsWidth)..];
ref Vector4 sourceRowBase = ref MemoryMarshal.GetReference(sourceRow);
for (int kX = 0; kX < state.Kernel.Columns; kX++)
{
@@ -120,7 +121,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
}
- target = this.FindMedian4(state.Kernel.Span, xChannel, yChannel, zChannel, wChannel, kernelCount);
+ target = FindMedian4(state.Kernel.Span, xChannel, yChannel, zChannel, wChannel);
}
}
@@ -129,7 +130,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private Vector4 FindMedian3(ReadOnlySpan kernelSpan, Span xChannel, Span yChannel, Span zChannel, int stride)
+ private static Vector4 FindMedian3(ReadOnlySpan kernelSpan, Span xChannel, Span yChannel, Span zChannel)
{
int halfLength = (kernelSpan.Length + 1) >> 1;
@@ -152,7 +153,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private Vector4 FindMedian4(ReadOnlySpan kernelSpan, Span xChannel, Span yChannel, Span zChannel, Span wChannel, int stride)
+ private static Vector4 FindMedian4(ReadOnlySpan kernelSpan, Span xChannel, Span yChannel, Span zChannel, Span wChannel)
{
int halfLength = (kernelSpan.Length + 1) >> 1;