diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
index ec33f2b3ed..b33d1f3d48 100644
--- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs
+++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs
@@ -3,7 +3,6 @@
using System.Buffers;
using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
@@ -37,22 +36,22 @@ internal sealed class LzwDecoder : IDisposable
///
/// The prefix buffer.
///
- private readonly IMemoryOwner prefix;
+ private readonly IMemoryOwner prefixOwner;
///
/// The suffix buffer.
///
- private readonly IMemoryOwner suffix;
+ private readonly IMemoryOwner suffixOwner;
///
/// The scratch buffer for reading data blocks.
///
- private readonly IMemoryOwner scratchBuffer;
+ private readonly IMemoryOwner bufferOwner;
///
/// The pixel stack buffer.
///
- private readonly IMemoryOwner pixelStack;
+ private readonly IMemoryOwner pixelStackOwner;
private readonly int minCodeSize;
private readonly int clearCode;
private readonly int endCode;
@@ -79,11 +78,12 @@ internal sealed class LzwDecoder : IDisposable
public LzwDecoder(MemoryAllocator memoryAllocator, BufferedReadStream stream, int minCodeSize)
{
this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
+ Guard.IsTrue(IsValidMinCodeSize(minCodeSize), nameof(minCodeSize), "Invalid minimum code size.");
- this.prefix = memoryAllocator.Allocate(MaxStackSize, AllocationOptions.Clean);
- this.suffix = memoryAllocator.Allocate(MaxStackSize, AllocationOptions.Clean);
- this.pixelStack = memoryAllocator.Allocate(MaxStackSize + 1, AllocationOptions.Clean);
- this.scratchBuffer = memoryAllocator.Allocate(byte.MaxValue, AllocationOptions.None);
+ this.prefixOwner = memoryAllocator.Allocate(MaxStackSize, AllocationOptions.Clean);
+ this.suffixOwner = memoryAllocator.Allocate(MaxStackSize, AllocationOptions.Clean);
+ this.pixelStackOwner = memoryAllocator.Allocate(MaxStackSize + 1, AllocationOptions.Clean);
+ this.bufferOwner = memoryAllocator.Allocate(byte.MaxValue, AllocationOptions.None);
this.minCodeSize = minCodeSize;
// Calculate the clear code. The value of the clear code is 2 ^ minCodeSize
@@ -93,11 +93,15 @@ internal sealed class LzwDecoder : IDisposable
this.endCode = this.clearCode + 1;
this.availableCode = this.clearCode + 2;
- ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan());
- for (this.code = 0; this.code < this.clearCode; this.code++)
+ // Fill the suffix buffer with the initial values represented by the number of colors.
+ Span suffix = this.suffixOwner.GetSpan()[..this.clearCode];
+ int i;
+ for (i = 0; i < suffix.Length; i++)
{
- Unsafe.Add(ref suffixRef, (uint)this.code) = (byte)this.code;
+ suffix[i] = i;
}
+
+ this.code = i;
}
///
@@ -112,8 +116,7 @@ internal sealed class LzwDecoder : IDisposable
// It is possible to specify a larger LZW minimum code size than the palette length in bits
// which may leave a gap in the codes where no colors are assigned.
// http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression
- int clearCode = 1 << minCodeSize;
- if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || clearCode > MaxStackSize)
+ if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || 1 << minCodeSize > MaxStackSize)
{
// Don't attempt to decode the frame indices.
// Theoretically we could determine a min code size from the length of the provided
@@ -132,112 +135,139 @@ internal sealed class LzwDecoder : IDisposable
{
indices.Clear();
- ref byte pixelsRowRef = ref MemoryMarshal.GetReference(indices);
- ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan());
- ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan());
- ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan());
- Span buffer = this.scratchBuffer.GetSpan();
-
- int x = 0;
- int xyz = 0;
- while (xyz < indices.Length)
+ // Get span values from the owners.
+ Span prefix = this.prefixOwner.GetSpan();
+ Span suffix = this.suffixOwner.GetSpan();
+ Span pixelStack = this.pixelStackOwner.GetSpan();
+ Span buffer = this.bufferOwner.GetSpan();
+
+ // Cache frequently accessed instance fields into locals.
+ // This helps avoid repeated field loads inside the tight loop.
+ BufferedReadStream stream = this.stream;
+ int top = this.top;
+ int bits = this.bits;
+ int codeSize = this.codeSize;
+ int codeMask = this.codeMask;
+ int minCodeSize = this.minCodeSize;
+ int availableCode = this.availableCode;
+ int oldCode = this.oldCode;
+ int first = this.first;
+ int data = this.data;
+ int count = this.count;
+ int bufferIndex = this.bufferIndex;
+ int code = this.code;
+ int clearCode = this.clearCode;
+ int endCode = this.endCode;
+
+ int i = 0;
+ while (i < indices.Length)
{
- if (this.top == 0)
+ if (top == 0)
{
- if (this.bits < this.codeSize)
+ if (bits < codeSize)
{
// Load bytes until there are enough bits for a code.
- if (this.count == 0)
+ if (count == 0)
{
// Read a new data block.
- this.count = this.ReadBlock(buffer);
- if (this.count == 0)
+ count = ReadBlock(stream, buffer);
+ if (count == 0)
{
break;
}
- this.bufferIndex = 0;
+ bufferIndex = 0;
}
- this.data += buffer[this.bufferIndex] << this.bits;
-
- this.bits += 8;
- this.bufferIndex++;
- this.count--;
+ data += buffer[bufferIndex] << bits;
+ bits += 8;
+ bufferIndex++;
+ count--;
continue;
}
// Get the next code
- this.code = this.data & this.codeMask;
- this.data >>= this.codeSize;
- this.bits -= this.codeSize;
+ code = data & codeMask;
+ data >>= codeSize;
+ bits -= codeSize;
// Interpret the code
- if (this.code > this.availableCode || this.code == this.endCode)
+ if (code > availableCode || code == endCode)
{
break;
}
- if (this.code == this.clearCode)
+ if (code == clearCode)
{
// Reset the decoder
- this.codeSize = this.minCodeSize + 1;
- this.codeMask = (1 << this.codeSize) - 1;
- this.availableCode = this.clearCode + 2;
- this.oldCode = NullCode;
+ codeSize = minCodeSize + 1;
+ codeMask = (1 << codeSize) - 1;
+ availableCode = clearCode + 2;
+ oldCode = NullCode;
continue;
}
- if (this.oldCode == NullCode)
+ if (oldCode == NullCode)
{
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code);
- this.oldCode = this.code;
- this.first = this.code;
+ pixelStack[top++] = suffix[code];
+ oldCode = code;
+ first = code;
continue;
}
- int inCode = this.code;
- if (this.code == this.availableCode)
+ int inCode = code;
+ if (code == availableCode)
{
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = (byte)this.first;
-
- this.code = this.oldCode;
+ pixelStack[top++] = first;
+ code = oldCode;
}
- while (this.code > this.clearCode)
+ while (code > clearCode && top < MaxStackSize)
{
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code);
- this.code = Unsafe.Add(ref prefixRef, (uint)this.code);
+ pixelStack[top++] = suffix[code];
+ code = prefix[code];
}
- int suffixCode = Unsafe.Add(ref suffixRef, (uint)this.code);
- this.first = suffixCode;
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = suffixCode;
+ int suffixCode = suffix[code];
+ first = suffixCode;
+ pixelStack[top++] = suffixCode;
- // Fix for Gifs that have "deferred clear code" as per here :
+ // Fix for GIFs that have "deferred clear code" as per:
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
- if (this.availableCode < MaxStackSize)
+ if (availableCode < MaxStackSize)
{
- Unsafe.Add(ref prefixRef, (uint)this.availableCode) = this.oldCode;
- Unsafe.Add(ref suffixRef, (uint)this.availableCode) = this.first;
- this.availableCode++;
- if (this.availableCode == this.codeMask + 1 && this.availableCode < MaxStackSize)
+ prefix[availableCode] = oldCode;
+ suffix[availableCode] = first;
+ availableCode++;
+ if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{
- this.codeSize++;
- this.codeMask = (1 << this.codeSize) - 1;
+ codeSize++;
+ codeMask = (1 << codeSize) - 1;
}
}
- this.oldCode = inCode;
+ oldCode = inCode;
}
// Pop a pixel off the pixel stack.
- this.top--;
+ top--;
- // Clear missing pixels
- xyz++;
- Unsafe.Add(ref pixelsRowRef, (uint)x++) = (byte)Unsafe.Add(ref pixelStackRef, (uint)this.top);
+ // Clear missing pixels.
+ indices[i++] = (byte)pixelStack[top];
}
+
+ // Write back the local values to the instance fields.
+ this.top = top;
+ this.bits = bits;
+ this.codeSize = codeSize;
+ this.codeMask = codeMask;
+ this.availableCode = availableCode;
+ this.oldCode = oldCode;
+ this.first = first;
+ this.data = data;
+ this.count = count;
+ this.bufferIndex = bufferIndex;
+ this.code = code;
}
///
@@ -246,130 +276,161 @@ internal sealed class LzwDecoder : IDisposable
/// The resulting index table length.
public void SkipIndices(int length)
{
- ref int prefixRef = ref MemoryMarshal.GetReference(this.prefix.GetSpan());
- ref int suffixRef = ref MemoryMarshal.GetReference(this.suffix.GetSpan());
- ref int pixelStackRef = ref MemoryMarshal.GetReference(this.pixelStack.GetSpan());
- Span buffer = this.scratchBuffer.GetSpan();
-
- int xyz = 0;
- while (xyz < length)
+ // Get span values from the owners.
+ Span prefix = this.prefixOwner.GetSpan();
+ Span suffix = this.suffixOwner.GetSpan();
+ Span pixelStack = this.pixelStackOwner.GetSpan();
+ Span buffer = this.bufferOwner.GetSpan();
+
+ // Cache frequently accessed instance fields into locals.
+ // This helps avoid repeated field loads inside the tight loop.
+ BufferedReadStream stream = this.stream;
+ int top = this.top;
+ int bits = this.bits;
+ int codeSize = this.codeSize;
+ int codeMask = this.codeMask;
+ int minCodeSize = this.minCodeSize;
+ int availableCode = this.availableCode;
+ int oldCode = this.oldCode;
+ int first = this.first;
+ int data = this.data;
+ int count = this.count;
+ int bufferIndex = this.bufferIndex;
+ int code = this.code;
+ int clearCode = this.clearCode;
+ int endCode = this.endCode;
+
+ int i = 0;
+ while (i < length)
{
- if (this.top == 0)
+ if (top == 0)
{
- if (this.bits < this.codeSize)
+ if (bits < codeSize)
{
// Load bytes until there are enough bits for a code.
- if (this.count == 0)
+ if (count == 0)
{
// Read a new data block.
- this.count = this.ReadBlock(buffer);
- if (this.count == 0)
+ count = ReadBlock(stream, buffer);
+ if (count == 0)
{
break;
}
- this.bufferIndex = 0;
+ bufferIndex = 0;
}
- this.data += buffer[this.bufferIndex] << this.bits;
-
- this.bits += 8;
- this.bufferIndex++;
- this.count--;
+ data += buffer[bufferIndex] << bits;
+ bits += 8;
+ bufferIndex++;
+ count--;
continue;
}
// Get the next code
- this.code = this.data & this.codeMask;
- this.data >>= this.codeSize;
- this.bits -= this.codeSize;
+ code = data & codeMask;
+ data >>= codeSize;
+ bits -= codeSize;
// Interpret the code
- if (this.code > this.availableCode || this.code == this.endCode)
+ if (code > availableCode || code == endCode)
{
break;
}
- if (this.code == this.clearCode)
+ if (code == clearCode)
{
// Reset the decoder
- this.codeSize = this.minCodeSize + 1;
- this.codeMask = (1 << this.codeSize) - 1;
- this.availableCode = this.clearCode + 2;
- this.oldCode = NullCode;
+ codeSize = minCodeSize + 1;
+ codeMask = (1 << codeSize) - 1;
+ availableCode = clearCode + 2;
+ oldCode = NullCode;
continue;
}
- if (this.oldCode == NullCode)
+ if (oldCode == NullCode)
{
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code);
- this.oldCode = this.code;
- this.first = this.code;
+ pixelStack[top++] = suffix[code];
+ oldCode = code;
+ first = code;
continue;
}
- int inCode = this.code;
- if (this.code == this.availableCode)
+ int inCode = code;
+ if (code == availableCode)
{
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = (byte)this.first;
-
- this.code = this.oldCode;
+ pixelStack[top++] = first;
+ code = oldCode;
}
- while (this.code > this.clearCode)
+ while (code > clearCode && top < MaxStackSize)
{
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = Unsafe.Add(ref suffixRef, (uint)this.code);
- this.code = Unsafe.Add(ref prefixRef, (uint)this.code);
+ pixelStack[top++] = suffix[code];
+ code = prefix[code];
}
- int suffixCode = Unsafe.Add(ref suffixRef, (uint)this.code);
- this.first = suffixCode;
- Unsafe.Add(ref pixelStackRef, (uint)this.top++) = suffixCode;
+ int suffixCode = suffix[code];
+ first = suffixCode;
+ pixelStack[top++] = suffixCode;
- // Fix for Gifs that have "deferred clear code" as per here :
+ // Fix for GIFs that have "deferred clear code" as per:
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
- if (this.availableCode < MaxStackSize)
+ if (availableCode < MaxStackSize)
{
- Unsafe.Add(ref prefixRef, (uint)this.availableCode) = this.oldCode;
- Unsafe.Add(ref suffixRef, (uint)this.availableCode) = this.first;
- this.availableCode++;
- if (this.availableCode == this.codeMask + 1 && this.availableCode < MaxStackSize)
+ prefix[availableCode] = oldCode;
+ suffix[availableCode] = first;
+ availableCode++;
+ if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{
- this.codeSize++;
- this.codeMask = (1 << this.codeSize) - 1;
+ codeSize++;
+ codeMask = (1 << codeSize) - 1;
}
}
- this.oldCode = inCode;
+ oldCode = inCode;
}
// Pop a pixel off the pixel stack.
- this.top--;
+ top--;
- // Clear missing pixels
- xyz++;
+ // Skip missing pixels.
+ i++;
}
+
+ // Write back the local values to the instance fields.
+ this.top = top;
+ this.bits = bits;
+ this.codeSize = codeSize;
+ this.codeMask = codeMask;
+ this.availableCode = availableCode;
+ this.oldCode = oldCode;
+ this.first = first;
+ this.data = data;
+ this.count = count;
+ this.bufferIndex = bufferIndex;
+ this.code = code;
}
///
/// Reads the next data block from the stream. A data block begins with a byte,
/// which defines the size of the block, followed by the block itself.
///
+ /// The stream to read from.
/// The buffer to store the block in.
///
/// The .
///
[MethodImpl(MethodImplOptions.AggressiveInlining)]
- private int ReadBlock(Span buffer)
+ private static int ReadBlock(BufferedReadStream stream, Span buffer)
{
- int bufferSize = this.stream.ReadByte();
+ int bufferSize = stream.ReadByte();
if (bufferSize < 1)
{
return 0;
}
- int count = this.stream.Read(buffer, 0, bufferSize);
+ int count = stream.Read(buffer, 0, bufferSize);
return count != bufferSize ? 0 : bufferSize;
}
@@ -377,9 +438,9 @@ internal sealed class LzwDecoder : IDisposable
///
public void Dispose()
{
- this.prefix.Dispose();
- this.suffix.Dispose();
- this.pixelStack.Dispose();
- this.scratchBuffer.Dispose();
+ this.prefixOwner.Dispose();
+ this.suffixOwner.Dispose();
+ this.pixelStackOwner.Dispose();
+ this.bufferOwner.Dispose();
}
}
diff --git a/src/ImageSharp/Formats/Png/PngThrowHelper.cs b/src/ImageSharp/Formats/Png/PngThrowHelper.cs
index 0552e9a79e..8dc70e1d9a 100644
--- a/src/ImageSharp/Formats/Png/PngThrowHelper.cs
+++ b/src/ImageSharp/Formats/Png/PngThrowHelper.cs
@@ -44,7 +44,7 @@ internal static class PngThrowHelper
=> throw new NotSupportedException($"Invalid {name}. {message}. Was '{value}'.");
[DoesNotReturn]
- public static void ThrowInvalidParameter(object value1, object value2, string message, [CallerArgumentExpression(nameof(value1))] string name1 = "", [CallerArgumentExpression(nameof(value1))] string name2 = "")
+ public static void ThrowInvalidParameter(object value1, object value2, string message, [CallerArgumentExpression(nameof(value1))] string name1 = "", [CallerArgumentExpression(nameof(value2))] string name2 = "")
=> throw new NotSupportedException($"Invalid {name1} or {name2}. {message}. Was '{value1}' and '{value2}'.");
[DoesNotReturn]
diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
index d699a7b631..7336924602 100644
--- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
+++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
@@ -648,7 +648,7 @@ internal class TiffDecoderCore : ImageDecoderCore
}
///
- /// Decodes the image data for Tiff's which arrange the pixel data in tiles and the chunky configuration.
+ /// Decodes the image data for TIFFs which arrange the pixel data in tiles and the chunky configuration.
///
/// The pixel format.
/// The image frame to decode into.
@@ -674,14 +674,10 @@ internal class TiffDecoderCore : ImageDecoderCore
int width = pixels.Width;
int height = pixels.Height;
int bitsPerPixel = this.BitsPerPixel;
-
- int bytesPerRow = RoundUpToMultipleOfEight(width * bitsPerPixel);
int bytesPerTileRow = RoundUpToMultipleOfEight(tileWidth * bitsPerPixel);
- int uncompressedTilesSize = bytesPerTileRow * tileLength;
- using IMemoryOwner tileBuffer = this.memoryAllocator.Allocate(uncompressedTilesSize, AllocationOptions.Clean);
- using IMemoryOwner uncompressedPixelBuffer = this.memoryAllocator.Allocate(tilesDown * tileLength * bytesPerRow, AllocationOptions.Clean);
+
+ using IMemoryOwner tileBuffer = this.memoryAllocator.Allocate(bytesPerTileRow * tileLength, AllocationOptions.Clean);
Span tileBufferSpan = tileBuffer.GetSpan();
- Span uncompressedPixelBufferSpan = uncompressedPixelBuffer.GetSpan();
using TiffBaseDecompressor decompressor = this.CreateDecompressor(frame.Width, bitsPerPixel);
TiffBaseColorDecoder colorDecoder = this.CreateChunkyColorDecoder();
@@ -689,13 +685,15 @@ internal class TiffDecoderCore : ImageDecoderCore
int tileIndex = 0;
for (int tileY = 0; tileY < tilesDown; tileY++)
{
- int remainingPixelsInRow = width;
+ int rowStartY = tileY * tileLength;
+ int rowEndY = Math.Min(rowStartY + tileLength, height);
+
for (int tileX = 0; tileX < tilesAcross; tileX++)
{
cancellationToken.ThrowIfCancellationRequested();
- int uncompressedPixelBufferOffset = tileY * tileLength * bytesPerRow;
bool isLastHorizontalTile = tileX == tilesAcross - 1;
+ int remainingPixelsInRow = width - (tileX * tileWidth);
decompressor.Decompress(
this.inputStream,
@@ -706,22 +704,21 @@ internal class TiffDecoderCore : ImageDecoderCore
cancellationToken);
int tileBufferOffset = 0;
- uncompressedPixelBufferOffset += bytesPerTileRow * tileX;
int bytesToCopy = isLastHorizontalTile ? RoundUpToMultipleOfEight(bitsPerPixel * remainingPixelsInRow) : bytesPerTileRow;
- for (int y = 0; y < tileLength; y++)
+ int rowWidth = Math.Min(tileWidth, remainingPixelsInRow);
+ int left = tileX * tileWidth;
+
+ for (int y = rowStartY; y < rowEndY; y++)
{
- Span uncompressedPixelRow = uncompressedPixelBufferSpan.Slice(uncompressedPixelBufferOffset, bytesToCopy);
- tileBufferSpan.Slice(tileBufferOffset, bytesToCopy).CopyTo(uncompressedPixelRow);
+ // Decode the tile row directly into the pixel buffer.
+ ReadOnlySpan tileRowSpan = tileBufferSpan.Slice(tileBufferOffset, bytesToCopy);
+ colorDecoder.Decode(tileRowSpan, pixels, left, y, rowWidth, 1);
tileBufferOffset += bytesPerTileRow;
- uncompressedPixelBufferOffset += bytesPerRow;
}
- remainingPixelsInRow -= tileWidth;
tileIndex++;
}
}
-
- colorDecoder.Decode(uncompressedPixelBufferSpan, pixels, 0, 0, width, height);
}
private TiffBaseColorDecoder CreateChunkyColorDecoder()
diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs
index 6cae208538..92d5bcdbfe 100644
--- a/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs
+++ b/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs
@@ -62,9 +62,7 @@ public abstract class FromRgba32Bytes
=> PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
-public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes
-{
-}
+public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes;
public class FromRgba32Bytes_ToBgra32 : FromRgba32Bytes
{
diff --git a/tests/ImageSharp.Benchmarks/Bulk/Vector4Factory.cs b/tests/ImageSharp.Benchmarks/Bulk/Vector4Factory.cs
index aa555f5c41..0842a6845d 100644
--- a/tests/ImageSharp.Benchmarks/Bulk/Vector4Factory.cs
+++ b/tests/ImageSharp.Benchmarks/Bulk/Vector4Factory.cs
@@ -30,5 +30,5 @@ internal static class Vector4Factory
}
private static float GetRandomFloat(Random rnd, float minVal, float maxVal)
- => (float)rnd.NextDouble() * (maxVal - minVal) + minVal;
+ => ((float)rnd.NextDouble() * (maxVal - minVal)) + minVal;
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs
index eb5b3c49d9..eec926a23c 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs
@@ -19,12 +19,7 @@ public class DecodeBmp
[GlobalSetup]
public void ReadImages()
- {
- if (this.bmpBytes == null)
- {
- this.bmpBytes = File.ReadAllBytes(this.TestImageFullPath);
- }
- }
+ => this.bmpBytes ??= File.ReadAllBytes(this.TestImageFullPath);
[Params(TestImages.Bmp.Car)]
public string TestImage { get; set; }
@@ -32,16 +27,16 @@ public class DecodeBmp
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public SDSize BmpSystemDrawing()
{
- using var memoryStream = new MemoryStream(this.bmpBytes);
- using var image = SDImage.FromStream(memoryStream);
+ using MemoryStream memoryStream = new(this.bmpBytes);
+ using SDImage image = SDImage.FromStream(memoryStream);
return image.Size;
}
[Benchmark(Description = "ImageSharp Bmp")]
public Size BmpImageSharp()
{
- using var memoryStream = new MemoryStream(this.bmpBytes);
- using var image = Image.Load(memoryStream);
+ using MemoryStream memoryStream = new(this.bmpBytes);
+ using Image image = Image.Load(memoryStream);
return new Size(image.Width, image.Height);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs
index 3e6cfa51b0..4c0a6c47b3 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs
@@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.Short))]
public class EncodeBmp
{
- private Stream bmpStream;
+ private FileStream bmpStream;
private SDImage bmpDrawing;
private Image bmpCore;
@@ -40,14 +40,14 @@ public class EncodeBmp
[Benchmark(Baseline = true, Description = "System.Drawing Bmp")]
public void BmpSystemDrawing()
{
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.bmpDrawing.Save(memoryStream, ImageFormat.Bmp);
}
[Benchmark(Description = "ImageSharp Bmp")]
public void BmpImageSharp()
{
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.bmpCore.SaveAsBmp(memoryStream);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs
index ef5db2f1e1..117cdd25b3 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs
@@ -18,13 +18,7 @@ public class DecodeGif
=> Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);
[GlobalSetup]
- public void ReadImages()
- {
- if (this.gifBytes == null)
- {
- this.gifBytes = File.ReadAllBytes(this.TestImageFullPath);
- }
- }
+ public void ReadImages() => this.gifBytes ??= File.ReadAllBytes(this.TestImageFullPath);
[Params(TestImages.Gif.Cheers)]
public string TestImage { get; set; }
@@ -32,16 +26,16 @@ public class DecodeGif
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public SDSize GifSystemDrawing()
{
- using var memoryStream = new MemoryStream(this.gifBytes);
- using var image = SDImage.FromStream(memoryStream);
+ using MemoryStream memoryStream = new(this.gifBytes);
+ using SDImage image = SDImage.FromStream(memoryStream);
return image.Size;
}
[Benchmark(Description = "ImageSharp Gif")]
public Size GifImageSharp()
{
- using var memoryStream = new MemoryStream(this.gifBytes);
- using var image = Image.Load(memoryStream);
+ using MemoryStream memoryStream = new(this.gifBytes);
+ using Image image = Image.Load(memoryStream);
return new Size(image.Width, image.Height);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs
index c3644221e1..beedbbe07c 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs
@@ -16,12 +16,12 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public class EncodeGif
{
// System.Drawing needs this.
- private Stream bmpStream;
+ private FileStream bmpStream;
private SDImage bmpDrawing;
private Image bmpCore;
// Try to get as close to System.Drawing's output as possible
- private readonly GifEncoder encoder = new GifEncoder
+ private readonly GifEncoder encoder = new()
{
Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 })
};
@@ -53,14 +53,14 @@ public class EncodeGif
[Benchmark(Baseline = true, Description = "System.Drawing Gif")]
public void GifSystemDrawing()
{
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.bmpDrawing.Save(memoryStream, ImageFormat.Gif);
}
[Benchmark(Description = "ImageSharp Gif")]
public void GifImageSharp()
{
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.bmpCore.SaveAsGif(memoryStream, this.encoder);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs
index 9557f616ca..303272837b 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs
@@ -22,7 +22,7 @@ public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
=> this.ForEachImageSharpImage((img, ms) =>
{
// Try to get as close to System.Drawing's output as possible
- var options = new GifEncoder
+ GifEncoder options = new()
{
Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = KnownDitherings.Bayer4x4 })
};
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs
index 91255c9466..7a8502c2cf 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_LoadFromInt16.cs
@@ -12,8 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg.BlockOperations;
public class Block8x8F_LoadFromInt16
{
private Block8x8 source;
-
- private Block8x8F dest = default;
+ private Block8x8F destination;
[GlobalSetup]
public void Setup()
@@ -30,16 +29,10 @@ public class Block8x8F_LoadFromInt16
}
[Benchmark(Baseline = true)]
- public void Scalar()
- {
- this.dest.LoadFromInt16Scalar(ref this.source);
- }
+ public void Scalar() => this.destination.LoadFromInt16Scalar(ref this.source);
[Benchmark]
- public void ExtendedAvx2()
- {
- this.dest.LoadFromInt16ExtendedAvx2(ref this.source);
- }
+ public void ExtendedAvx2() => this.destination.LoadFromInt16ExtendedAvx2(ref this.source);
// RESULT:
// Method | Mean | Error | StdDev | Scaled |
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs
index b1718759ea..88b8877e52 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Quantize.cs
@@ -11,7 +11,7 @@ public class Block8x8F_Quantize
{
private Block8x8F block = CreateFromScalar(1);
private Block8x8F quant = CreateFromScalar(1);
- private Block8x8 result = default;
+ private Block8x8 result;
[Benchmark]
public short Quantize()
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs
index 8a520b22d3..1d83851686 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/BlockOperations/Block8x8F_Round.cs
@@ -36,7 +36,7 @@ public unsafe class Block8x8F_Round
if (ptr % 16 != 0)
{
- throw new Exception("ptr is unaligned");
+ throw new InvalidOperationException("ptr is unaligned");
}
this.alignedPtr = (float*)ptr;
@@ -67,21 +67,21 @@ public unsafe class Block8x8F_Round
ref Block8x8F b = ref this.block;
ref Vector row0 = ref Unsafe.As>(ref b.V0L);
- row0 = SimdUtils.FastRound(row0);
+ row0 = row0.FastRound();
ref Vector row1 = ref Unsafe.As>(ref b.V1L);
- row1 = SimdUtils.FastRound(row1);
+ row1 = row1.FastRound();
ref Vector row2 = ref Unsafe.As>(ref b.V2L);
- row2 = SimdUtils.FastRound(row2);
+ row2 = row2.FastRound();
ref Vector row3 = ref Unsafe.As>(ref b.V3L);
- row3 = SimdUtils.FastRound(row3);
+ row3 = row3.FastRound();
ref Vector row4 = ref Unsafe.As>(ref b.V4L);
- row4 = SimdUtils.FastRound(row4);
+ row4 = row4.FastRound();
ref Vector row5 = ref Unsafe.As>(ref b.V5L);
- row5 = SimdUtils.FastRound(row5);
+ row5 = row5.FastRound();
ref Vector row6 = ref Unsafe.As>(ref b.V6L);
- row6 = SimdUtils.FastRound(row6);
+ row6 = row6.FastRound();
ref Vector row7 = ref Unsafe.As>(ref b.V7L);
- row7 = SimdUtils.FastRound(row7);
+ row7 = row7.FastRound();
}
[Benchmark]
@@ -90,21 +90,21 @@ public unsafe class Block8x8F_Round
ref Block8x8F b = ref Unsafe.AsRef(this.alignedPtr);
ref Vector row0 = ref Unsafe.As>(ref b.V0L);
- row0 = SimdUtils.FastRound(row0);
+ row0 = row0.FastRound();
ref Vector row1 = ref Unsafe.As>(ref b.V1L);
- row1 = SimdUtils.FastRound(row1);
+ row1 = row1.FastRound();
ref Vector row2 = ref Unsafe.As>(ref b.V2L);
- row2 = SimdUtils.FastRound(row2);
+ row2 = row2.FastRound();
ref Vector row3 = ref Unsafe.As>(ref b.V3L);
- row3 = SimdUtils.FastRound(row3);
+ row3 = row3.FastRound();
ref Vector row4 = ref Unsafe.As>(ref b.V4L);
- row4 = SimdUtils.FastRound(row4);
+ row4 = row4.FastRound();
ref Vector row5 = ref Unsafe.As>(ref b.V5L);
- row5 = SimdUtils.FastRound(row5);
+ row5 = row5.FastRound();
ref Vector row6 = ref Unsafe.As>(ref b.V6L);
- row6 = SimdUtils.FastRound(row6);
+ row6 = row6.FastRound();
ref Vector row7 = ref Unsafe.As>(ref b.V7L);
- row7 = SimdUtils.FastRound(row7);
+ row7 = row7.FastRound();
}
[Benchmark]
@@ -117,20 +117,20 @@ public unsafe class Block8x8F_Round
ref Vector row2 = ref Unsafe.As>(ref b.V2L);
ref Vector row3 = ref Unsafe.As>(ref b.V3L);
- row0 = SimdUtils.FastRound(row0);
- row1 = SimdUtils.FastRound(row1);
- row2 = SimdUtils.FastRound(row2);
- row3 = SimdUtils.FastRound(row3);
+ row0 = row0.FastRound();
+ row1 = row1.FastRound();
+ row2 = row2.FastRound();
+ row3 = row3.FastRound();
row0 = ref Unsafe.As>(ref b.V4L);
row1 = ref Unsafe.As>(ref b.V5L);
row2 = ref Unsafe.As>(ref b.V6L);
row3 = ref Unsafe.As>(ref b.V7L);
- row0 = SimdUtils.FastRound(row0);
- row1 = SimdUtils.FastRound(row1);
- row2 = SimdUtils.FastRound(row2);
- row3 = SimdUtils.FastRound(row3);
+ row0 = row0.FastRound();
+ row1 = row1.FastRound();
+ row2 = row2.FastRound();
+ row3 = row3.FastRound();
}
[Benchmark]
@@ -174,7 +174,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
- public unsafe void Sse41_V2()
+ public void Sse41_V2()
{
ref Vector128 p = ref Unsafe.As>(ref this.block);
p = Sse41.RoundToNearestInteger(p);
@@ -214,7 +214,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
- public unsafe void Sse41_V3()
+ public void Sse41_V3()
{
ref Vector128 p = ref Unsafe.As>(ref this.block);
p = Sse41.RoundToNearestInteger(p);
@@ -228,7 +228,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
- public unsafe void Sse41_V4()
+ public void Sse41_V4()
{
ref Vector128 p = ref Unsafe.As>(ref this.block);
nuint offset = (uint)sizeof(Vector128);
@@ -271,7 +271,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
- public unsafe void Sse41_V5_Unaligned()
+ public void Sse41_V5_Unaligned()
{
float* p = this.alignedPtr + 1;
@@ -356,7 +356,7 @@ public unsafe class Block8x8F_Round
}
[Benchmark]
- public unsafe void Sse41_V5_Aligned()
+ public void Sse41_V5_Aligned()
{
float* p = this.alignedPtr;
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
index f5178390f6..5f6dbbdf72 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
@@ -27,20 +27,20 @@ public class DecodeJpegParseStreamOnly
[Benchmark(Baseline = true, Description = "System.Drawing FULL")]
public SDSize JpegSystemDrawing()
{
- using var memoryStream = new MemoryStream(this.jpegBytes);
- using var image = System.Drawing.Image.FromStream(memoryStream);
+ using MemoryStream memoryStream = new(this.jpegBytes);
+ using System.Drawing.Image image = System.Drawing.Image.FromStream(memoryStream);
return image.Size;
}
[Benchmark(Description = "JpegDecoderCore.ParseStream")]
public void ParseStream()
{
- using var memoryStream = new MemoryStream(this.jpegBytes);
- using var bufferedStream = new BufferedReadStream(Configuration.Default, memoryStream);
- var options = new JpegDecoderOptions() { GeneralOptions = new() { SkipMetadata = true } };
+ using MemoryStream memoryStream = new(this.jpegBytes);
+ using BufferedReadStream bufferedStream = new(Configuration.Default, memoryStream);
+ JpegDecoderOptions options = new() { GeneralOptions = new() { SkipMetadata = true } };
- using var decoder = new JpegDecoderCore(options);
- var spectralConverter = new NoopSpectralConverter();
+ using JpegDecoderCore decoder = new(options);
+ NoopSpectralConverter spectralConverter = new();
decoder.ParseStream(bufferedStream, spectralConverter, cancellationToken: default);
}
@@ -48,7 +48,7 @@ public class DecodeJpegParseStreamOnly
// Nor we need to allocate final pixel buffer
// Note: this still introduces virtual method call overhead for baseline interleaved images
// There's no way to eliminate it as spectral conversion is built into the scan decoding loop for memory footprint reduction
- private class NoopSpectralConverter : SpectralConverter
+ private sealed class NoopSpectralConverter : SpectralConverter
{
public override void ConvertStrideBaseline()
{
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs
index 389fec88be..9f69f613e8 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs
@@ -17,21 +17,21 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase
{
protected override IEnumerable InputImageSubfoldersOrFiles
- => new[]
- {
+ =>
+ [
TestImages.Jpeg.BenchmarkSuite.Jpeg400_SmallMonochrome,
TestImages.Jpeg.BenchmarkSuite.Jpeg420Exif_MidSizeYCbCr,
TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr,
TestImages.Jpeg.BenchmarkSuite.MissingFF00ProgressiveBedroom159_MidSize420YCbCr,
TestImages.Jpeg.BenchmarkSuite.ExifGetString750Transform_Huge420YCbCr,
- };
+ ];
[Params(InputImageCategory.AllImages)]
public override InputImageCategory InputCategory { get; set; }
[Benchmark]
public void ImageSharp()
- => this.ForEachStream(ms => Image.Load(ms));
+ => this.ForEachStream(Image.Load);
[Benchmark(Baseline = true)]
public void SystemDrawing()
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
index 08df2580db..257e44cc40 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
@@ -35,26 +35,21 @@ public class DecodeJpeg_ImageSpecific
[GlobalSetup]
public void ReadImages()
- {
- if (this.jpegBytes == null)
- {
- this.jpegBytes = File.ReadAllBytes(this.TestImageFullPath);
- }
- }
+ => this.jpegBytes ??= File.ReadAllBytes(this.TestImageFullPath);
[Benchmark(Baseline = true)]
public SDSize SystemDrawing()
{
- using var memoryStream = new MemoryStream(this.jpegBytes);
- using var image = SDImage.FromStream(memoryStream);
+ using MemoryStream memoryStream = new(this.jpegBytes);
+ using SDImage image = SDImage.FromStream(memoryStream);
return image.Size;
}
[Benchmark]
public Size ImageSharp()
{
- using var memoryStream = new MemoryStream(this.jpegBytes);
- using var image = Image.Load(new DecoderOptions() { SkipMetadata = true }, memoryStream);
+ using MemoryStream memoryStream = new(this.jpegBytes);
+ using Image image = Image.Load(new DecoderOptions() { SkipMetadata = true }, memoryStream);
return new Size(image.Width, image.Height);
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs
index deb3125b30..c7cecd1a52 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegComparison.cs
@@ -19,11 +19,6 @@ public class EncodeJpegComparison
{
// Big enough, 4:4:4 chroma sampling
private const string TestImage = TestImages.Jpeg.Baseline.Calliphora;
-
- // Change/add parameters for extra benchmarks
- [Params(75, 90, 100)]
- public int Quality;
-
private MemoryStream destinationStream;
// ImageSharp
@@ -33,6 +28,10 @@ public class EncodeJpegComparison
// SkiaSharp
private SKBitmap imageSkiaSharp;
+ // Change/add parameters for extra benchmarks
+ [Params(75, 90, 100)]
+ public int Quality { get; set; }
+
[GlobalSetup(Target = nameof(BenchmarkImageSharp))]
public void SetupImageSharp()
{
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs
index 0692c5a3b5..858917995a 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/EncodeJpegFeatures.cs
@@ -20,19 +20,19 @@ public class EncodeJpegFeatures
// No metadata
private const string TestImage = TestImages.Jpeg.Baseline.Calliphora;
- public static IEnumerable ColorSpaceValues => new[]
- {
+ public static IEnumerable ColorSpaceValues =>
+ [
JpegColorType.Luminance,
JpegColorType.Rgb,
JpegColorType.YCbCrRatio420,
JpegColorType.YCbCrRatio444,
- };
+ ];
[Params(75, 90, 100)]
- public int Quality;
+ public int Quality { get; set; }
[ParamsSource(nameof(ColorSpaceValues), Priority = -100)]
- public JpegColorType TargetColorSpace;
+ public JpegColorType TargetColorSpace { get; set; }
private Image bmpCore;
private JpegEncoder encoder;
diff --git a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs
index b75d012f97..0adc52441a 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/MultiImageBenchmarkBase.cs
@@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public abstract class MultiImageBenchmarkBase
{
- protected Dictionary FileNamesToBytes { get; set; } = new Dictionary();
+ protected Dictionary FileNamesToBytes { get; set; } = [];
- protected Dictionary> FileNamesToImageSharpImages { get; set; } = new Dictionary>();
+ protected Dictionary> FileNamesToImageSharpImages { get; set; } = [];
- protected Dictionary FileNamesToSystemDrawingImages { get; set; } = new Dictionary();
+ protected Dictionary FileNamesToSystemDrawingImages { get; set; } = [];
///
/// The values of this enum separate input files into categories.
@@ -43,12 +43,12 @@ public abstract class MultiImageBenchmarkBase
protected virtual string BaseFolder => TestEnvironment.InputImagesDirectoryFullPath;
- protected virtual IEnumerable SearchPatterns => new[] { "*.*" };
+ protected virtual IEnumerable SearchPatterns => ["*.*"];
///
/// Gets the file names containing these strings are substrings are not processed by the benchmark.
///
- protected virtual IEnumerable ExcludeSubstringsInFileNames => new[] { "badeof", "BadEof", "CriticalEOF" };
+ protected virtual IEnumerable ExcludeSubstringsInFileNames => ["badeof", "BadEof", "CriticalEOF"];
///
/// Gets folders containing files OR files to be processed by the benchmark.
@@ -70,7 +70,7 @@ public abstract class MultiImageBenchmarkBase
InputImageCategory.AllImages => input,
InputImageCategory.SmallImagesOnly => input.Where(kv => checkIfSmall(kv.Value)),
InputImageCategory.LargeImagesOnly => input.Where(kv => !checkIfSmall(kv.Value)),
- _ => throw new ArgumentOutOfRangeException(),
+ _ => throw new ArgumentOutOfRangeException(nameof(input), "Invalid input category")
};
protected IEnumerable> FileNames2Bytes
@@ -86,7 +86,7 @@ public abstract class MultiImageBenchmarkBase
{
if (!Vector.IsHardwareAccelerated)
{
- throw new Exception("Vector.IsHardwareAccelerated == false! Check your build settings!");
+ throw new InvalidOperationException("Vector.IsHardwareAccelerated == false! Check your build settings!");
}
// Console.WriteLine("Vector.IsHardwareAccelerated: " + Vector.IsHardwareAccelerated);
@@ -103,13 +103,13 @@ public abstract class MultiImageBenchmarkBase
continue;
}
- string[] excludeStrings = this.ExcludeSubstringsInFileNames.Select(s => s.ToLower()).ToArray();
+ string[] excludeStrings = this.ExcludeSubstringsInFileNames.ToArray();
string[] allFiles =
this.SearchPatterns.SelectMany(
f =>
Directory.EnumerateFiles(path, f, SearchOption.AllDirectories)
- .Where(fn => !excludeStrings.Any(excludeStr => fn.ToLower().Contains(excludeStr)))).ToArray();
+ .Where(fn => !excludeStrings.Any(excludeStr => fn.Contains(excludeStr, StringComparison.OrdinalIgnoreCase)))).ToArray();
foreach (string fn in allFiles)
{
@@ -126,7 +126,7 @@ public abstract class MultiImageBenchmarkBase
{
foreach (KeyValuePair kv in this.FileNames2Bytes)
{
- using var memoryStream = new MemoryStream(kv.Value);
+ using MemoryStream memoryStream = new(kv.Value);
try
{
object obj = operation(memoryStream);
@@ -150,7 +150,7 @@ public abstract class MultiImageBenchmarkBase
byte[] bytes = kv.Value;
string fn = kv.Key;
- using (var ms1 = new MemoryStream(bytes))
+ using (MemoryStream ms1 = new(bytes))
{
this.FileNamesToImageSharpImages[fn] = Image.Load(ms1);
}
@@ -191,7 +191,7 @@ public abstract class MultiImageBenchmarkBase
protected void ForEachImageSharpImage(Func, MemoryStream, object> operation)
{
- using var workStream = new MemoryStream();
+ using MemoryStream workStream = new();
this.ForEachImageSharpImage(
img =>
{
@@ -222,7 +222,7 @@ public abstract class MultiImageBenchmarkBase
protected void ForEachSystemDrawingImage(Func operation)
{
- using var workStream = new MemoryStream();
+ using MemoryStream workStream = new();
this.ForEachSystemDrawingImage(
img =>
{
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs
index a45e7aea9b..125b42680d 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs
@@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public class EncodeIndexedPng
{
// System.Drawing needs this.
- private Stream bmpStream;
+ private FileStream bmpStream;
private Image bmpCore;
[GlobalSetup]
@@ -43,48 +43,48 @@ public class EncodeIndexedPng
[Benchmark(Baseline = true, Description = "ImageSharp Octree Png")]
public void PngCoreOctree()
{
- using var memoryStream = new MemoryStream();
- var options = new PngEncoder { Quantizer = KnownQuantizers.Octree };
+ using MemoryStream memoryStream = new();
+ PngEncoder options = new() { Quantizer = KnownQuantizers.Octree };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Octree NoDither Png")]
public void PngCoreOctreeNoDither()
{
- using var memoryStream = new MemoryStream();
- var options = new PngEncoder { Quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }) };
+ using MemoryStream memoryStream = new();
+ PngEncoder options = new() { Quantizer = new OctreeQuantizer(new QuantizerOptions { Dither = null }) };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Palette Png")]
public void PngCorePalette()
{
- using var memoryStream = new MemoryStream();
- var options = new PngEncoder { Quantizer = KnownQuantizers.WebSafe };
+ using MemoryStream memoryStream = new();
+ PngEncoder options = new() { Quantizer = KnownQuantizers.WebSafe };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Palette NoDither Png")]
public void PngCorePaletteNoDither()
{
- using var memoryStream = new MemoryStream();
- var options = new PngEncoder { Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = null }) };
+ using MemoryStream memoryStream = new();
+ PngEncoder options = new() { Quantizer = new WebSafePaletteQuantizer(new QuantizerOptions { Dither = null }) };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Wu Png")]
public void PngCoreWu()
{
- using var memoryStream = new MemoryStream();
- var options = new PngEncoder { Quantizer = KnownQuantizers.Wu };
+ using MemoryStream memoryStream = new();
+ PngEncoder options = new() { Quantizer = KnownQuantizers.Wu };
this.bmpCore.SaveAsPng(memoryStream, options);
}
[Benchmark(Description = "ImageSharp Wu NoDither Png")]
public void PngCoreWuNoDither()
{
- using var memoryStream = new MemoryStream();
- var options = new PngEncoder { Quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }), ColorType = PngColorType.Palette };
+ using MemoryStream memoryStream = new();
+ PngEncoder options = new() { Quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }), ColorType = PngColorType.Palette };
this.bmpCore.SaveAsPng(memoryStream, options);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs
index 4287914783..30a10af096 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs
@@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
public class EncodePng
{
// System.Drawing needs this.
- private Stream bmpStream;
+ private FileStream bmpStream;
private SDImage bmpDrawing;
private Image bmpCore;
@@ -46,15 +46,15 @@ public class EncodePng
[Benchmark(Baseline = true, Description = "System.Drawing Png")]
public void PngSystemDrawing()
{
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.bmpDrawing.Save(memoryStream, ImageFormat.Png);
}
[Benchmark(Description = "ImageSharp Png")]
public void PngCore()
{
- using var memoryStream = new MemoryStream();
- var encoder = new PngEncoder { FilterMethod = PngFilterMethod.None };
+ using MemoryStream memoryStream = new();
+ PngEncoder encoder = new() { FilterMethod = PngFilterMethod.None };
this.bmpCore.SaveAsPng(memoryStream, encoder);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs
index 7a3fc0b395..d6a6cf1fb4 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs
@@ -31,7 +31,7 @@ public class DecodeTga
{
MagickReadSettings settings = new() { Format = MagickFormat.Tga };
using MagickImage image = new(new MemoryStream(this.data), settings);
- return (int)image.Width;
+ return image.Width;
}
[Benchmark(Description = "ImageSharp Tga")]
@@ -48,7 +48,7 @@ public class DecodeTga
return image.Width;
}
- private class PfimAllocator : IImageAllocator
+ private sealed class PfimAllocator : IImageAllocator
{
private int rented;
private readonly ArrayPool shared = ArrayPool.Shared;
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs
index a7f5e35893..169a44d91a 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs
@@ -41,14 +41,14 @@ public class EncodeTga
[Benchmark(Baseline = true, Description = "Magick Tga")]
public void MagickTga()
{
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.tgaMagick.Write(memoryStream, MagickFormat.Tga);
}
[Benchmark(Description = "ImageSharp Tga")]
public void ImageSharpTga()
{
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.tga.SaveAsTga(memoryStream);
}
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
index d3e3944051..6fa6a15ed4 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
@@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.Short))]
public class EncodeTiff
{
- private Stream stream;
+ private FileStream stream;
private SDImage drawing;
private Image core;
@@ -60,12 +60,12 @@ public class EncodeTiff
public void SystemDrawing()
{
ImageCodecInfo codec = FindCodecForType("image/tiff");
- using var parameters = new EncoderParameters(1)
+ using EncoderParameters parameters = new(1)
{
Param = { [0] = new EncoderParameter(Encoder.Compression, (long)Cast(this.Compression)) }
};
- using var memoryStream = new MemoryStream();
+ using MemoryStream memoryStream = new();
this.drawing.Save(memoryStream, codec, parameters);
}
@@ -77,8 +77,8 @@ public class EncodeTiff
TiffPhotometricInterpretation.WhiteIsZero :
TiffPhotometricInterpretation.Rgb;
- var encoder = new TiffEncoder() { Compression = this.Compression, PhotometricInterpretation = photometricInterpretation };
- using var memoryStream = new MemoryStream();
+ TiffEncoder encoder = new() { Compression = this.Compression, PhotometricInterpretation = photometricInterpretation };
+ using MemoryStream memoryStream = new();
this.core.SaveAsTiff(memoryStream, encoder);
}
@@ -98,33 +98,15 @@ public class EncodeTiff
}
private static EncoderValue Cast(TiffCompression compression)
- {
- switch (compression)
+ => compression switch
{
- case TiffCompression.None:
- return EncoderValue.CompressionNone;
-
- case TiffCompression.CcittGroup3Fax:
- return EncoderValue.CompressionCCITT3;
-
- case TiffCompression.Ccitt1D:
- return EncoderValue.CompressionRle;
-
- case TiffCompression.Lzw:
- return EncoderValue.CompressionLZW;
-
- default:
- throw new NotSupportedException(compression.ToString());
- }
- }
+ TiffCompression.None => EncoderValue.CompressionNone,
+ TiffCompression.CcittGroup3Fax => EncoderValue.CompressionCCITT3,
+ TiffCompression.Ccitt1D => EncoderValue.CompressionRle,
+ TiffCompression.Lzw => EncoderValue.CompressionLZW,
+ _ => throw new NotSupportedException(compression.ToString()),
+ };
public static bool IsOneBitCompression(TiffCompression compression)
- {
- if (compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or TiffCompression.CcittGroup4Fax)
- {
- return true;
- }
-
- return false;
- }
+ => compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or TiffCompression.CcittGroup4Fax;
}
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs
index 4d6252c2b6..bba1bc1871 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs
@@ -47,7 +47,7 @@ public class DecodeWebp
MagickReadSettings settings = new() { Format = MagickFormat.WebP };
using MemoryStream memoryStream = new(this.webpLossyBytes);
using MagickImage image = new(memoryStream, settings);
- return (int)image.Width;
+ return image.Width;
}
[Benchmark(Description = "ImageSharp Lossy Webp")]
@@ -65,7 +65,7 @@ public class DecodeWebp
{ Format = MagickFormat.WebP };
using MemoryStream memoryStream = new(this.webpLossyBytes);
using MagickImage image = new(memoryStream, settings);
- return (int)image.Width;
+ return image.Width;
}
[Benchmark(Description = "ImageSharp Lossless Webp")]
diff --git a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs
index 31b6cbdde2..3b90584988 100644
--- a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs
+++ b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs
@@ -14,9 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[MarkdownExporter]
[HtmlExporter]
[Config(typeof(Config.Short))]
-#pragma warning disable CA1001 // Types that own disposable fields should be disposable
public class EncodeWebp
-#pragma warning restore CA1001 // Types that own disposable fields should be disposable
{
private MagickImage webpMagick;
private Image webp;
diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs
index 06e857484d..190c245c94 100644
--- a/tests/ImageSharp.Benchmarks/Config.cs
+++ b/tests/ImageSharp.Benchmarks/Config.cs
@@ -32,7 +32,7 @@ public partial class Config : ManualConfig
public class Standard : Config
{
public Standard() => this.AddJob(
- Job.Default.WithRuntime(CoreRuntime.Core80).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
+ Job.Default.WithRuntime(CoreRuntime.Core80).WithArguments([new MsBuildArgument("/p:DebugType=portable")]));
}
public class Short : Config
@@ -42,12 +42,10 @@ public partial class Config : ManualConfig
.WithLaunchCount(1)
.WithWarmupCount(3)
.WithIterationCount(3)
- .WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
+ .WithArguments([new MsBuildArgument("/p:DebugType=portable")]));
}
#if OS_WINDOWS
-#pragma warning disable CA1416 // Validate platform compatibility
private bool IsElevated => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
-#pragma warning restore CA1416 // Validate platform compatibility
#endif
}
diff --git a/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs b/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs
index 5ba7809e13..41e6bdec27 100644
--- a/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs
+++ b/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs
@@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
+#if OS_WINDOWS
using System.Drawing;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
@@ -25,3 +26,4 @@ public class GetSetPixel
return image[200, 200];
}
}
+#endif
diff --git a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs
index 9560d6ee71..d32e1fdd0d 100644
--- a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs
+++ b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs
@@ -78,7 +78,7 @@ public class BufferedStreams
public int StandardStreamRead()
{
int r = 0;
- Stream stream = this.stream1;
+ MemoryStream stream = this.stream1;
byte[] b = this.chunk1;
for (int i = 0; i < stream.Length / 2; i++)
@@ -138,7 +138,7 @@ public class BufferedStreams
public int StandardStreamReadByte()
{
int r = 0;
- Stream stream = this.stream2;
+ MemoryStream stream = this.stream2;
for (int i = 0; i < stream.Length; i++)
{
@@ -205,8 +205,8 @@ public class BufferedStreams
private static byte[] CreateTestBytes()
{
- var buffer = new byte[Configuration.Default.StreamProcessingBufferSize * 3];
- var random = new Random();
+ byte[] buffer = new byte[Configuration.Default.StreamProcessingBufferSize * 3];
+ Random random = new();
random.NextBytes(buffer);
return buffer;
diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
index 1d83b94dc8..c864e26c61 100644
--- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
+++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
@@ -184,14 +184,16 @@ public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConver
}
}
- [Benchmark]
- public void PixelConverter_Rgba32_ToArgb32()
- {
- Span source = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Source);
- Span dest = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Destination);
-
- PixelConverter.FromRgba32.ToArgb32(source, dest);
- }
+ // Commenting this out because for some reason MSBuild is showing error CS0029: Cannot implicitly convert type 'System.ReadOnlySpan' to 'System.Span'
+ // when trying to build via BenchmarkDotnet. (╯‵□′)╯︵┻━┻
+ // [Benchmark]
+ // public void PixelConverter_Rgba32_ToArgb32()
+ // {
+ // ReadOnlySpan source = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Source);
+ // Span destination = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Destination);
+ //
+ // PixelConverter.FromRgba32.ToArgb32(source, destination);
+ // }
/*
BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3)
diff --git a/tests/ImageSharp.Benchmarks/General/StructCasting.cs b/tests/ImageSharp.Benchmarks/General/StructCasting.cs
index f8432112e3..3f3767d429 100644
--- a/tests/ImageSharp.Benchmarks/General/StructCasting.cs
+++ b/tests/ImageSharp.Benchmarks/General/StructCasting.cs
@@ -11,7 +11,7 @@ public class StructCasting
[Benchmark(Baseline = true)]
public short ExplicitCast()
{
- int x = 5 * 2;
+ const int x = 5 * 2;
return (short)x;
}
@@ -25,6 +25,7 @@ public class StructCasting
[Benchmark]
public short UnsafeCastRef()
{
- return Unsafe.As(ref Unsafe.AsRef(5 * 2));
+ int x = 5 * 2;
+ return Unsafe.As(ref Unsafe.AsRef(ref x));
}
}
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
index 9c95c22e0f..5277897bb2 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Divide.cs
@@ -15,10 +15,10 @@ public class DivFloat : SIMDBenchmarkBase.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
- float v = this.testValue;
- for (int i = 0; i < this.input.Length; i++)
+ float v = this.TestValue;
+ for (int i = 0; i < this.Input.Length; i++)
{
- this.result[i] = this.input[i] / v;
+ this.Result[i] = this.Input[i] / v;
}
}
}
@@ -30,10 +30,10 @@ public class Divide : SIMDBenchmarkBase.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
- uint v = this.testValue;
- for (int i = 0; i < this.input.Length; i++)
+ uint v = this.TestValue;
+ for (int i = 0; i < this.Input.Length; i++)
{
- this.result[i] = this.input[i] / v;
+ this.Result[i] = this.Input[i] / v;
}
}
}
@@ -45,10 +45,10 @@ public class DivInt32 : SIMDBenchmarkBase.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
- int v = this.testValue;
- for (int i = 0; i < this.input.Length; i++)
+ int v = this.TestValue;
+ for (int i = 0; i < this.Input.Length; i++)
{
- this.result[i] = this.input[i] / v;
+ this.Result[i] = this.Input[i] / v;
}
}
}
@@ -62,10 +62,10 @@ public class DivInt16 : SIMDBenchmarkBase.Divide
[Benchmark(Baseline = true)]
public void Standard()
{
- short v = this.testValue;
- for (int i = 0; i < this.input.Length; i++)
+ short v = this.TestValue;
+ for (int i = 0; i < this.Input.Length; i++)
{
- this.result[i] = (short)(this.input[i] / v);
+ this.Result[i] = (short)(this.Input[i] / v);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs
index fe48c3301b..7e890cb925 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Multiply.cs
@@ -15,10 +15,10 @@ public class MulUInt32 : SIMDBenchmarkBase.Multiply
[Benchmark(Baseline = true)]
public void Standard()
{
- uint v = this.testValue;
- for (int i = 0; i < this.input.Length; i++)
+ uint v = this.TestValue;
+ for (int i = 0; i < this.Input.Length; i++)
{
- this.result[i] = this.input[i] * v;
+ this.Result[i] = this.Input[i] * v;
}
}
}
@@ -28,10 +28,10 @@ public class MulInt32 : SIMDBenchmarkBase.Multiply
[Benchmark(Baseline = true)]
public void Standard()
{
- int v = this.testValue;
- for (int i = 0; i < this.input.Length; i++)
+ int v = this.TestValue;
+ for (int i = 0; i < this.Input.Length; i++)
{
- this.result[i] = this.input[i] * v;
+ this.Result[i] = this.Input[i] * v;
}
}
}
@@ -45,10 +45,10 @@ public class MulInt16 : SIMDBenchmarkBase.Multiply
[Benchmark(Baseline = true)]
public void Standard()
{
- short v = this.testValue;
- for (int i = 0; i < this.input.Length; i++)
+ short v = this.TestValue;
+ for (int i = 0; i < this.Input.Length; i++)
{
- this.result[i] = (short)(this.input[i] * v);
+ this.Result[i] = (short)(this.Input[i] * v);
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
index 90d81a0583..0d856df615 100644
--- a/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
+++ b/tests/ImageSharp.Benchmarks/General/Vectorization/SIMDBenchmarkBase.cs
@@ -10,28 +10,28 @@ namespace ImageSharp.Benchmarks.General.Vectorization;
public abstract class SIMDBenchmarkBase
where T : struct
{
- protected T[] input;
+ protected virtual T GetTestValue() => default;
- protected T[] result;
+ protected virtual Vector GetTestVector() => new(this.GetTestValue());
- protected T testValue;
+ [Params(32)]
+ public int InputSize { get; set; }
- protected Vector testVector;
+ protected T[] Input { get; set; }
- protected virtual T GetTestValue() => default;
+ protected T[] Result { get; set; }
- protected virtual Vector GetTestVector() => new Vector(this.GetTestValue());
+ protected T TestValue { get; set; }
- [Params(32)]
- public int InputSize { get; set; }
+ protected Vector TestVector { get; set; }
[GlobalSetup]
public virtual void Setup()
{
- this.input = new T[this.InputSize];
- this.result = new T[this.InputSize];
- this.testValue = this.GetTestValue();
- this.testVector = this.GetTestVector();
+ this.Input = new T[this.InputSize];
+ this.Result = new T[this.InputSize];
+ this.TestValue = this.GetTestValue();
+ this.TestVector = this.GetTestVector();
}
public abstract class Multiply : SIMDBenchmarkBase
@@ -39,13 +39,13 @@ public abstract class SIMDBenchmarkBase
[Benchmark]
public void Simd()
{
- Vector v = this.testVector;
+ Vector v = this.TestVector;
- for (int i = 0; i < this.input.Length; i += Vector.Count)
+ for (int i = 0; i < this.Input.Length; i += Vector.Count)
{
- Vector a = Unsafe.As>(ref this.input[i]);
- a = a * v;
- Unsafe.As>(ref this.result[i]) = a;
+ Vector a = Unsafe.As>(ref this.Input[i]);
+ a *= v;
+ Unsafe.As>(ref this.Result[i]) = a;
}
}
}
@@ -55,13 +55,13 @@ public abstract class SIMDBenchmarkBase
[Benchmark]
public void Simd()
{
- Vector v = this.testVector;
+ Vector v = this.TestVector;
- for (int i = 0; i < this.input.Length; i += Vector.Count)
+ for (int i = 0; i < this.Input.Length; i += Vector.Count)
{
- Vector a = Unsafe.As>(ref this.input[i]);
- a = a / v;
- Unsafe.As>(ref this.result[i]) = a;
+ Vector a = Unsafe.As>(ref this.Input[i]);
+ a /= v;
+ Unsafe.As>(ref this.Result[i]) = a;
}
}
}
diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
index 37a991248c..c92bb6a6bb 100644
--- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
+++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
@@ -15,9 +15,25 @@
-
+
+
- CA1822
+
+
+
+ CA1822;CA1416;CA1001;CS0029;CA1861;CA2201
+
+
+
+
+
+
+
+
+
diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
index e7d240acd3..44c248dc98 100644
--- a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
+++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
@@ -40,7 +40,7 @@ public class LoadResizeSaveStressRunner
public double TotalProcessedMegapixels { get; private set; }
- public Size LastProcessedImageSize { get; private set; }
+ public ImageSharpSize LastProcessedImageSize { get; private set; }
private string outputDirectory;
diff --git a/tests/ImageSharp.Benchmarks/Processing/Crop.cs b/tests/ImageSharp.Benchmarks/Processing/Crop.cs
index 0432b76249..e14366bfde 100644
--- a/tests/ImageSharp.Benchmarks/Processing/Crop.cs
+++ b/tests/ImageSharp.Benchmarks/Processing/Crop.cs
@@ -17,9 +17,9 @@ public class Crop
[Benchmark(Baseline = true, Description = "System.Drawing Crop")]
public SDSize CropSystemDrawing()
{
- using var source = new Bitmap(800, 800);
- using var destination = new Bitmap(100, 100);
- using var graphics = Graphics.FromImage(destination);
+ using Bitmap source = new(800, 800);
+ using Bitmap destination = new(100, 100);
+ using Graphics graphics = Graphics.FromImage(destination);
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
@@ -32,7 +32,7 @@ public class Crop
[Benchmark(Description = "ImageSharp Crop")]
public Size CropImageSharp()
{
- using var image = new Image(800, 800);
+ using Image image = new(800, 800);
image.Mutate(x => x.Crop(100, 100));
return new Size(image.Width, image.Height);
}
diff --git a/tests/ImageSharp.Benchmarks/Processing/Resize.cs b/tests/ImageSharp.Benchmarks/Processing/Resize.cs
index 05baceb6a0..09673cb96a 100644
--- a/tests/ImageSharp.Benchmarks/Processing/Resize.cs
+++ b/tests/ImageSharp.Benchmarks/Processing/Resize.cs
@@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Benchmarks;
public abstract class Resize
where TPixel : unmanaged, IPixel
{
- private byte[] bytes = null;
+ private byte[] bytes;
private Image sourceImage;
@@ -35,7 +35,7 @@ public abstract class Resize
this.sourceImage = Image.Load(this.bytes);
- var ms1 = new MemoryStream(this.bytes);
+ MemoryStream ms1 = new(this.bytes);
this.sourceBitmap = SDImage.FromStream(ms1);
this.DestSize = this.sourceBitmap.Width / 2;
}
@@ -52,21 +52,19 @@ public abstract class Resize
[Benchmark(Baseline = true)]
public int SystemDrawing()
{
- using (var destination = new Bitmap(this.DestSize, this.DestSize))
+ using Bitmap destination = new(this.DestSize, this.DestSize);
+ using (Graphics g = Graphics.FromImage(destination))
{
- using (var g = Graphics.FromImage(destination))
- {
- g.CompositingMode = CompositingMode.SourceCopy;
- g.InterpolationMode = InterpolationMode.HighQualityBicubic;
- g.PixelOffsetMode = PixelOffsetMode.HighQuality;
- g.CompositingQuality = CompositingQuality.HighQuality;
- g.SmoothingMode = SmoothingMode.HighQuality;
-
- g.DrawImage(this.sourceBitmap, 0, 0, this.DestSize, this.DestSize);
- }
-
- return destination.Width;
+ g.CompositingMode = CompositingMode.SourceCopy;
+ g.InterpolationMode = InterpolationMode.HighQualityBicubic;
+ g.PixelOffsetMode = PixelOffsetMode.HighQuality;
+ g.CompositingQuality = CompositingQuality.HighQuality;
+ g.SmoothingMode = SmoothingMode.HighQuality;
+
+ g.DrawImage(this.sourceBitmap, 0, 0, this.DestSize, this.DestSize);
}
+
+ return destination.Width;
}
[Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 1")]
@@ -87,10 +85,8 @@ public abstract class Resize
{
this.Configuration.MaxDegreeOfParallelism = maxDegreeOfParallelism;
- using (Image clone = this.sourceImage.Clone(this.ExecuteResizeOperation))
- {
- return clone.Width;
- }
+ using Image clone = this.sourceImage.Clone(this.ExecuteResizeOperation);
+ return clone.Width;
}
protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx);
diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
index f4e6487a57..bc6eeedcbe 100644
--- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
+++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs
@@ -334,4 +334,16 @@ public class GifDecoderTests
image.DebugSaveMultiFrame(provider);
image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact);
}
+
+ // https://github.com/SixLabors/ImageSharp/issues/2859
+ [Theory]
+ [WithFile(TestImages.Gif.Issues.Issue2859_A, PixelTypes.Rgba32)]
+ [WithFile(TestImages.Gif.Issues.Issue2859_B, PixelTypes.Rgba32)]
+ public void Issue2859_LZWPixelStackOverflow(TestImageProvider provider)
+ where TPixel : unmanaged, IPixel
+ {
+ using Image image = provider.GetImage();
+ image.DebugSaveMultiFrame(provider);
+ image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact);
+ }
}
diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs
index d928b82b3d..2284167c80 100644
--- a/tests/ImageSharp.Tests/TestImages.cs
+++ b/tests/ImageSharp.Tests/TestImages.cs
@@ -536,6 +536,8 @@ public static class TestImages
public const string Issue2450_B = "Gif/issues/issue_2450_2.gif";
public const string Issue2198 = "Gif/issues/issue_2198.gif";
public const string Issue2758 = "Gif/issues/issue_2758.gif";
+ public const string Issue2859_A = "Gif/issues/issue_2859_A.gif";
+ public const string Issue2859_B = "Gif/issues/issue_2859_B.gif";
}
public static readonly string[] Animated =
diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_A.gif/00.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_A.gif/00.png
new file mode 100644
index 0000000000..d8c8df1263
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_A.gif/00.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:daa78347749c6ff49891e2e379a373599cd35c98b453af9bf8eac52f615f935c
+size 12237
diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/00.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/00.png
new file mode 100644
index 0000000000..36c3683187
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/00.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:731299281f942f277ce6803e0adda3b5dd0395eb79cae26cabc9d56905fae0fd
+size 1833
diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/01.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/01.png
new file mode 100644
index 0000000000..c03e5817f0
--- /dev/null
+++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2859_LZWPixelStackOverflow_Rgba32_issue_2859_B.gif/01.png
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:50ccac7739142578d99a76b6d39ba377099d4a7ac30cbb0a5aee44ef1e7c9c8c
+size 1271
diff --git a/tests/Images/Input/Gif/issues/issue_2859_A.gif b/tests/Images/Input/Gif/issues/issue_2859_A.gif
new file mode 100644
index 0000000000..f19a047525
--- /dev/null
+++ b/tests/Images/Input/Gif/issues/issue_2859_A.gif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:50a1a4afc62a3a36ff83596f1eb55d91cdd184c64e0d1339bbea17205c23eee1
+size 3406142
diff --git a/tests/Images/Input/Gif/issues/issue_2859_B.gif b/tests/Images/Input/Gif/issues/issue_2859_B.gif
new file mode 100644
index 0000000000..109b0f8797
--- /dev/null
+++ b/tests/Images/Input/Gif/issues/issue_2859_B.gif
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:db9b2992be772a4f0ac495e994a17c7c50fb6de9794cfb9afc4a3dc26ffdfae0
+size 4543