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;