Browse Source

Merge branch 'main' into js/fix-sse3-paeth

pull/2620/head
James Jackson-South 3 years ago
parent
commit
df5061397f
  1. 3
      .gitattributes
  2. 43
      .github/workflows/build-and-test.yml
  3. 6
      .github/workflows/code-coverage.yml
  4. 4
      README.md
  5. 2
      shared-infrastructure
  6. 2
      src/ImageSharp.ruleset
  7. 4
      src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs
  8. 10
      src/ImageSharp/Advanced/ParallelRowIterator.cs
  9. 2
      src/ImageSharp/Common/Helpers/DebugGuard.cs
  10. 19
      src/ImageSharp/Common/Helpers/Numerics.cs
  11. 5
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  12. 3
      src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
  13. 69
      src/ImageSharp/Compression/Zlib/Crc32.Lut.cs
  14. 308
      src/ImageSharp/Compression/Zlib/Crc32.cs
  15. BIN
      src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf
  16. 5
      src/ImageSharp/Configuration.cs
  17. 42
      src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs
  18. 1
      src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs
  19. 1
      src/ImageSharp/Formats/AnimatedImageMetadata.cs
  20. 5
      src/ImageSharp/Formats/ImageFormatManager.cs
  21. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs
  22. 5
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  23. 16
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  24. 20
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  25. 1
      src/ImageSharp/Formats/Qoi/QoiDecoder.cs
  26. 2
      src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs
  27. 13
      src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs
  28. 12
      src/ImageSharp/ImageSharp.csproj
  29. 8
      src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs
  30. 2
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  31. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs
  32. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
  33. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
  34. 2
      src/ImageSharp/PixelFormats/PixelImplementations/La16.cs
  35. 2
      src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
  36. 2
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
  37. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs
  38. 2
      src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs
  39. 2
      src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs
  40. 2
      src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs
  41. 2
      src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs
  42. 2
      src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs
  43. 2
      src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs
  44. 2
      src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs
  45. 24
      tests/Directory.Build.targets
  46. 2
      tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs
  47. 2
      tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs
  48. 2
      tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs
  49. 2
      tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs
  50. 2
      tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs
  51. 2
      tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs
  52. 2
      tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs
  53. 2
      tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs
  54. 2
      tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs
  55. 2
      tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs
  56. 2
      tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs
  57. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs
  58. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs
  59. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs
  60. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs
  61. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs
  62. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs
  63. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs
  64. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs
  65. 2
      tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs
  66. 2
      tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs
  67. 2
      tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs
  68. 2
      tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs
  69. 2
      tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs
  70. 2
      tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs
  71. 2
      tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs
  72. 2
      tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs
  73. 2
      tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs
  74. 2
      tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs
  75. 2
      tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs
  76. 6
      tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs
  77. 24
      tests/ImageSharp.Benchmarks/Config.cs
  78. 2
      tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs
  79. 2
      tests/ImageSharp.Benchmarks/General/CopyBuffers.cs
  80. 70
      tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs
  81. 2
      tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs
  82. 2
      tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs
  83. 2
      tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs
  84. 10
      tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj
  85. 6
      tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs
  86. 2
      tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs
  87. 2
      tests/ImageSharp.Benchmarks/Processing/Crop.cs
  88. 2
      tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs
  89. 2
      tests/ImageSharp.Benchmarks/Processing/Diffuse.cs
  90. 2
      tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs
  91. 2
      tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs
  92. 2
      tests/ImageSharp.Benchmarks/Processing/OilPaint.cs
  93. 2
      tests/ImageSharp.Benchmarks/Processing/Resize.cs
  94. 2
      tests/ImageSharp.Benchmarks/Processing/Rotate.cs
  95. 2
      tests/ImageSharp.Benchmarks/Processing/Skew.cs
  96. 8
      tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj
  97. 66
      tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs
  98. 10
      tests/ImageSharp.Tests/ImageSharp.Tests.csproj

3
.gitattributes

@ -133,3 +133,6 @@
*.pnm filter=lfs diff=lfs merge=lfs -text *.pnm filter=lfs diff=lfs merge=lfs -text
*.wbmp filter=lfs diff=lfs merge=lfs -text *.wbmp filter=lfs diff=lfs merge=lfs -text
*.exr filter=lfs diff=lfs merge=lfs -text *.exr filter=lfs diff=lfs merge=lfs -text
*.ico filter=lfs diff=lfs merge=lfs -text
*.cur filter=lfs diff=lfs merge=lfs -text
*.ani filter=lfs diff=lfs merge=lfs -text

43
.github/workflows/build-and-test.yml

@ -19,42 +19,23 @@ jobs:
- ${{ contains(github.event.pull_request.labels.*.name, 'arch:arm32') || contains(github.event.pull_request.labels.*.name, 'arch:arm64') }} - ${{ contains(github.event.pull_request.labels.*.name, 'arch:arm32') || contains(github.event.pull_request.labels.*.name, 'arch:arm64') }}
options: options:
- os: ubuntu-latest - os: ubuntu-latest
framework: net7.0 framework: net8.0
sdk: 7.0.x sdk: 8.0.x
sdk-preview: true
runtime: -x64 runtime: -x64
codecov: false codecov: false
- os: macos-latest - os: macos-latest
framework: net7.0 framework: net8.0
sdk: 7.0.x sdk: 8.0.x
sdk-preview: true
runtime: -x64 runtime: -x64
codecov: false codecov: false
- os: windows-latest - os: windows-latest
framework: net7.0 framework: net8.0
sdk: 7.0.x sdk: 8.0.x
sdk-preview: true
runtime: -x64 runtime: -x64
codecov: false codecov: false
- os: buildjet-4vcpu-ubuntu-2204-arm - os: buildjet-4vcpu-ubuntu-2204-arm
framework: net7.0 framework: net8.0
sdk: 7.0.x sdk: 8.0.x
sdk-preview: true
runtime: -x64
codecov: false
- os: ubuntu-latest
framework: net6.0
sdk: 6.0.x
runtime: -x64
codecov: false
- os: macos-latest
framework: net6.0
sdk: 6.0.x
runtime: -x64
codecov: false
- os: windows-latest
framework: net6.0
sdk: 6.0.x
runtime: -x64 runtime: -x64
codecov: false codecov: false
exclude: exclude:
@ -108,17 +89,17 @@ jobs:
- name: DotNet Setup - name: DotNet Setup
if: ${{ matrix.options.sdk-preview != true }} if: ${{ matrix.options.sdk-preview != true }}
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: | dotnet-version: |
6.0.x 8.0.x
- name: DotNet Setup Preview - name: DotNet Setup Preview
if: ${{ matrix.options.sdk-preview == true }} if: ${{ matrix.options.sdk-preview == true }}
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: | dotnet-version: |
7.0.x 8.0.x
- name: DotNet Build - name: DotNet Build
if: ${{ matrix.options.sdk-preview != true }} if: ${{ matrix.options.sdk-preview != true }}

6
.github/workflows/code-coverage.yml

@ -10,7 +10,7 @@ jobs:
matrix: matrix:
options: options:
- os: ubuntu-latest - os: ubuntu-latest
framework: net6.0 framework: net8.0
runtime: -x64 runtime: -x64
codecov: true codecov: true
@ -55,10 +55,10 @@ jobs:
restore-keys: ${{ runner.os }}-nuget- restore-keys: ${{ runner.os }}-nuget-
- name: DotNet Setup - name: DotNet Setup
uses: actions/setup-dotnet@v3 uses: actions/setup-dotnet@v4
with: with:
dotnet-version: | dotnet-version: |
6.0.x 8.0.x
- name: DotNet Build - name: DotNet Build
shell: pwsh shell: pwsh

4
README.md

@ -21,7 +21,7 @@ Designed to simplify image processing, ImageSharp brings you an incredibly power
ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations. ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations.
Built against [.NET 6](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. Built against [.NET 8](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
## License ## License
@ -64,7 +64,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!)
- Using [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) - Using [Visual Studio 2022](https://visualstudio.microsoft.com/vs/)
- Make sure you have the latest version installed - Make sure you have the latest version installed
- Make sure you have [the .NET 7 SDK](https://www.microsoft.com/net/core#windows) installed - Make sure you have [the .NET 8 SDK](https://www.microsoft.com/net/core#windows) installed
Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**: Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:

2
shared-infrastructure

@ -1 +1 @@
Subproject commit 353b9afe32a8000410312d17263407cd7bb82d19 Subproject commit 1c526a97eea8bcbc7c79de095676f7fb975a9fb1

2
src/ImageSharp.ruleset

@ -4,4 +4,4 @@
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1011" Action="None" /> <Rule Id="SA1011" Action="None" />
</Rules> </Rules>
</RuleSet> </RuleSet>

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

@ -51,7 +51,7 @@ public static partial class ParallelRowIterator
for (int y = yMin; y < yMax; y++) for (int y = yMin; y < yMax; y++)
{ {
// Skip the safety copy when invoking a potentially impure method on a readonly field // Skip the safety copy when invoking a potentially impure method on a readonly field
Unsafe.AsRef(this.action).Invoke(y); Unsafe.AsRef(in this.action).Invoke(y);
} }
} }
} }
@ -102,7 +102,7 @@ public static partial class ParallelRowIterator
for (int y = yMin; y < yMax; y++) for (int y = yMin; y < yMax; y++)
{ {
Unsafe.AsRef(this.action).Invoke(y, span); Unsafe.AsRef(in this.action).Invoke(y, span);
} }
} }
} }

10
src/ImageSharp/Advanced/ParallelRowIterator.cs

@ -58,7 +58,7 @@ public static partial class ParallelRowIterator
{ {
for (int y = top; y < bottom; y++) for (int y = top; y < bottom; y++)
{ {
Unsafe.AsRef(operation).Invoke(y); Unsafe.AsRef(in operation).Invoke(y);
} }
return; return;
@ -118,7 +118,7 @@ public static partial class ParallelRowIterator
int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask); int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
MemoryAllocator allocator = parallelSettings.MemoryAllocator; MemoryAllocator allocator = parallelSettings.MemoryAllocator;
int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle); int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle);
// Avoid TPL overhead in this trivial case: // Avoid TPL overhead in this trivial case:
if (numOfSteps == 1) if (numOfSteps == 1)
@ -128,7 +128,7 @@ public static partial class ParallelRowIterator
for (int y = top; y < bottom; y++) for (int y = top; y < bottom; y++)
{ {
Unsafe.AsRef(operation).Invoke(y, span); Unsafe.AsRef(in operation).Invoke(y, span);
} }
return; return;
@ -245,7 +245,7 @@ public static partial class ParallelRowIterator
int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask); int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
MemoryAllocator allocator = parallelSettings.MemoryAllocator; MemoryAllocator allocator = parallelSettings.MemoryAllocator;
int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle); int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle);
// Avoid TPL overhead in this trivial case: // Avoid TPL overhead in this trivial case:
if (numOfSteps == 1) if (numOfSteps == 1)
@ -253,7 +253,7 @@ public static partial class ParallelRowIterator
var rows = new RowInterval(top, bottom); var rows = new RowInterval(top, bottom);
using IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(bufferLength); using IMemoryOwner<TBuffer> buffer = allocator.Allocate<TBuffer>(bufferLength);
Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); Unsafe.AsRef(in operation).Invoke(in rows, buffer.Memory.Span);
return; return;
} }

2
src/ImageSharp/Common/Helpers/DebugGuard.cs

@ -33,10 +33,12 @@ internal static partial class DebugGuard
[Conditional("DEBUG")] [Conditional("DEBUG")]
public static void NotDisposed(bool isDisposed, string objectName) public static void NotDisposed(bool isDisposed, string objectName)
{ {
#pragma warning disable CA1513
if (isDisposed) if (isDisposed)
{ {
throw new ObjectDisposedException(objectName); throw new ObjectDisposedException(objectName);
} }
#pragma warning restore CA1513
} }
/// <summary> /// <summary>

19
src/ImageSharp/Common/Helpers/Numerics.cs

@ -908,25 +908,6 @@ internal static class Numerics
return Sse2.ConvertToInt32(vsum); return Sse2.ConvertToInt32(vsum);
} }
/// <summary>
/// Reduces elements of the vector into one sum.
/// </summary>
/// <param name="accumulator">The accumulator to reduce.</param>
/// <returns>The sum of all elements.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static int ReduceSumArm(Vector128<uint> accumulator)
{
if (AdvSimd.Arm64.IsSupported)
{
Vector64<uint> sum = AdvSimd.Arm64.AddAcross(accumulator);
return (int)AdvSimd.Extract(sum, 0);
}
Vector128<ulong> sum2 = AdvSimd.AddPairwiseWidening(accumulator);
Vector64<uint> sum3 = AdvSimd.Add(sum2.GetLower().AsUInt32(), sum2.GetUpper().AsUInt32());
return (int)AdvSimd.Extract(sum3, 0);
}
/// <summary> /// <summary>
/// Reduces even elements of the vector into one sum. /// Reduces even elements of the vector into one sum.
/// </summary> /// </summary>

5
src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -59,7 +60,7 @@ internal static partial class SimdUtils
public static void Shuffle4Reduce( public static void Shuffle4Reduce(
ref ReadOnlySpan<float> source, ref ReadOnlySpan<float> source,
ref Span<float> dest, ref Span<float> dest,
byte control) [ConstantExpected] byte control)
{ {
if (Avx.IsSupported || Sse.IsSupported) if (Avx.IsSupported || Sse.IsSupported)
{ {
@ -218,7 +219,7 @@ internal static partial class SimdUtils
private static void Shuffle4( private static void Shuffle4(
ReadOnlySpan<float> source, ReadOnlySpan<float> source,
Span<float> dest, Span<float> dest,
byte control) [ConstantExpected] byte control)
{ {
if (Avx.IsSupported) if (Avx.IsSupported)
{ {

3
src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Diagnostics; using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -20,7 +21,7 @@ internal static partial class SimdUtils
public static void Shuffle4( public static void Shuffle4(
ReadOnlySpan<float> source, ReadOnlySpan<float> source,
Span<float> dest, Span<float> dest,
byte control) [ConstantExpected] byte control)
{ {
VerifyShuffle4SpanInput(source, dest); VerifyShuffle4SpanInput(source, dest);

69
src/ImageSharp/Compression/Zlib/Crc32.Lut.cs

@ -1,69 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Compression.Zlib;
/// <content>
/// Contains precalulated tables for scalar calculations.
/// </content>
internal static partial class Crc32
{
/// <summary>
/// The table of all possible eight bit values for fast scalar lookup.
/// </summary>
private static readonly uint[] CrcTable =
{
0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419,
0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4,
0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07,
0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE,
0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856,
0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9,
0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4,
0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B,
0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3,
0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A,
0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599,
0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924,
0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190,
0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F,
0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E,
0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01,
0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED,
0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950,
0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3,
0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2,
0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A,
0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5,
0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010,
0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F,
0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17,
0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6,
0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615,
0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8,
0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344,
0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB,
0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A,
0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5,
0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1,
0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C,
0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF,
0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236,
0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE,
0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31,
0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C,
0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713,
0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B,
0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242,
0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1,
0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C,
0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278,
0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7,
0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66,
0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9,
0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605,
0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8,
0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B,
0x2D02EF8D
};
}

308
src/ImageSharp/Compression/Zlib/Crc32.cs

@ -1,308 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
using ArmCrc32 = System.Runtime.Intrinsics.Arm.Crc32;
namespace SixLabors.ImageSharp.Compression.Zlib;
/// <summary>
/// Calculates the 32 bit Cyclic Redundancy Check (CRC) checksum of a given buffer
/// according to the IEEE 802.3 specification.
/// </summary>
internal static partial class Crc32
{
/// <summary>
/// The default initial seed value of a Crc32 checksum calculation.
/// </summary>
public const uint SeedValue = 0U;
private const int MinBufferSize = 64;
private const int ChunksizeMask = 15;
// Definitions of the bit-reflected domain constants k1, k2, k3, etc and
// the CRC32+Barrett polynomials given at the end of the paper.
private static readonly ulong[] K05Poly =
{
0x0154442bd4, 0x01c6e41596, // k1, k2
0x01751997d0, 0x00ccaa009e, // k3, k4
0x0163cd6124, 0x0000000000, // k5, k0
0x01db710641, 0x01f7011641 // polynomial
};
/// <summary>
/// Calculates the CRC checksum with the bytes taken from the span.
/// </summary>
/// <param name="buffer">The readonly span of bytes.</param>
/// <returns>The <see cref="uint"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint Calculate(ReadOnlySpan<byte> buffer)
=> Calculate(SeedValue, buffer);
/// <summary>
/// Calculates the CRC checksum with the bytes taken from the span and seed.
/// </summary>
/// <param name="crc">The input CRC value.</param>
/// <param name="buffer">The readonly span of bytes.</param>
/// <returns>The <see cref="uint"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static uint Calculate(uint crc, ReadOnlySpan<byte> buffer)
{
if (buffer.IsEmpty)
{
return crc;
}
if (Sse41.IsSupported && Pclmulqdq.IsSupported && buffer.Length >= MinBufferSize)
{
return ~CalculateSse(~crc, buffer);
}
if (ArmCrc32.Arm64.IsSupported)
{
return ~CalculateArm64(~crc, buffer);
}
if (ArmCrc32.IsSupported)
{
return ~CalculateArm(~crc, buffer);
}
return ~CalculateScalar(~crc, buffer);
}
// Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/crc32_simd.c
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateSse(uint crc, ReadOnlySpan<byte> buffer)
{
int chunksize = buffer.Length & ~ChunksizeMask;
int length = chunksize;
fixed (byte* bufferPtr = buffer)
{
fixed (ulong* k05PolyPtr = K05Poly)
{
byte* localBufferPtr = bufferPtr;
ulong* localK05PolyPtr = k05PolyPtr;
// There's at least one block of 64.
Vector128<ulong> x1 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00));
Vector128<ulong> x2 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10));
Vector128<ulong> x3 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20));
Vector128<ulong> x4 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30));
Vector128<ulong> x5;
x1 = Sse2.Xor(x1, Sse2.ConvertScalarToVector128UInt32(crc).AsUInt64());
// k1, k2
Vector128<ulong> x0 = Sse2.LoadVector128(localK05PolyPtr + 0x0);
localBufferPtr += 64;
length -= 64;
// Parallel fold blocks of 64, if any.
while (length >= 64)
{
x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
Vector128<ulong> x6 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00);
Vector128<ulong> x7 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x00);
Vector128<ulong> x8 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x00);
x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x11);
x3 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x11);
x4 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x11);
Vector128<ulong> y5 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00));
Vector128<ulong> y6 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10));
Vector128<ulong> y7 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20));
Vector128<ulong> y8 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30));
x1 = Sse2.Xor(x1, x5);
x2 = Sse2.Xor(x2, x6);
x3 = Sse2.Xor(x3, x7);
x4 = Sse2.Xor(x4, x8);
x1 = Sse2.Xor(x1, y5);
x2 = Sse2.Xor(x2, y6);
x3 = Sse2.Xor(x3, y7);
x4 = Sse2.Xor(x4, y8);
localBufferPtr += 64;
length -= 64;
}
// Fold into 128-bits.
// k3, k4
x0 = Sse2.LoadVector128(k05PolyPtr + 0x2);
x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
x1 = Sse2.Xor(x1, x2);
x1 = Sse2.Xor(x1, x5);
x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
x1 = Sse2.Xor(x1, x3);
x1 = Sse2.Xor(x1, x5);
x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
x1 = Sse2.Xor(x1, x4);
x1 = Sse2.Xor(x1, x5);
// Single fold blocks of 16, if any.
while (length >= 16)
{
x2 = Sse2.LoadVector128((ulong*)localBufferPtr);
x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11);
x1 = Sse2.Xor(x1, x2);
x1 = Sse2.Xor(x1, x5);
localBufferPtr += 16;
length -= 16;
}
// Fold 128 - bits to 64 - bits.
x2 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x10);
x3 = Vector128.Create(~0, 0, ~0, 0).AsUInt64(); // _mm_setr_epi32 on x86
x1 = Sse2.ShiftRightLogical128BitLane(x1, 8);
x1 = Sse2.Xor(x1, x2);
// k5, k0
x0 = Sse2.LoadScalarVector128(localK05PolyPtr + 0x4);
x2 = Sse2.ShiftRightLogical128BitLane(x1, 4);
x1 = Sse2.And(x1, x3);
x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00);
x1 = Sse2.Xor(x1, x2);
// Barret reduce to 32-bits.
// polynomial
x0 = Sse2.LoadVector128(localK05PolyPtr + 0x6);
x2 = Sse2.And(x1, x3);
x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x10);
x2 = Sse2.And(x2, x3);
x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00);
x1 = Sse2.Xor(x1, x2);
crc = (uint)Sse41.Extract(x1.AsInt32(), 1);
return buffer.Length - chunksize == 0 ? crc : CalculateScalar(crc, buffer[chunksize..]);
}
}
}
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateArm(uint crc, ReadOnlySpan<byte> buffer)
{
fixed (byte* bufferPtr = buffer)
{
byte* localBufferPtr = bufferPtr;
int len = buffer.Length;
while (len > 0 && ((ulong)localBufferPtr & 3) != 0)
{
crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++);
len--;
}
uint* intBufferPtr = (uint*)localBufferPtr;
while (len >= 8 * sizeof(uint))
{
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
len -= 8 * sizeof(uint);
}
while (len >= sizeof(uint))
{
crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++);
len -= sizeof(uint);
}
localBufferPtr = (byte*)intBufferPtr;
while (len > 0)
{
crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++);
len--;
}
return crc;
}
}
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static unsafe uint CalculateArm64(uint crc, ReadOnlySpan<byte> buffer)
{
fixed (byte* bufferPtr = buffer)
{
byte* localBufferPtr = bufferPtr;
int len = buffer.Length;
while (len > 0 && ((ulong)localBufferPtr & 7) != 0)
{
crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++);
len--;
}
ulong* longBufferPtr = (ulong*)localBufferPtr;
while (len >= 8 * sizeof(ulong))
{
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
len -= 8 * sizeof(ulong);
}
while (len >= sizeof(ulong))
{
crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++);
len -= sizeof(ulong);
}
localBufferPtr = (byte*)longBufferPtr;
while (len > 0)
{
crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++);
len--;
}
return crc;
}
}
[MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)]
private static uint CalculateScalar(uint crc, ReadOnlySpan<byte> buffer)
{
ref uint crcTableRef = ref MemoryMarshal.GetReference(CrcTable.AsSpan());
ref byte bufferRef = ref MemoryMarshal.GetReference(buffer);
for (int i = 0; i < buffer.Length; i++)
{
crc = Unsafe.Add(ref crcTableRef, (crc ^ Unsafe.Add(ref bufferRef, i)) & 0xFF) ^ (crc >> 8);
}
return crc;
}
}

BIN
src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf

Binary file not shown.

5
src/ImageSharp/Configuration.cs

@ -87,10 +87,7 @@ public sealed class Configuration
get => this.streamProcessingBufferSize; get => this.streamProcessingBufferSize;
set set
{ {
if (value <= 0) ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value);
{
throw new ArgumentOutOfRangeException(nameof(this.StreamProcessingBufferSize));
}
this.streamProcessingBufferSize = value; this.streamProcessingBufferSize = value;
} }

42
src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs

@ -1,42 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
#if NET6_0
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
namespace System.Diagnostics.CodeAnalysis
{
/// <summary>
/// Used to indicate a byref escapes and is not scoped.
/// </summary>
/// <remarks>
/// <para>
/// There are several cases where the C# compiler treats a <see langword="ref"/> as implicitly
/// <see langword="scoped"/> - where the compiler does not allow the <see langword="ref"/> to escape the method.
/// </para>
/// <para>
/// For example:
/// <list type="number">
/// <item><see langword="this"/> for <see langword="struct"/> instance methods.</item>
/// <item><see langword="ref"/> parameters that refer to <see langword="ref"/> <see langword="struct"/> types.</item>
/// <item><see langword="out"/> parameters.</item>
/// </list>
/// </para>
/// <para>
/// This attribute is used in those instances where the <see langword="ref"/> should be allowed to escape.
/// </para>
/// <para>
/// Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for
/// API authors to understand the lifetime implications of applying this attribute and how it may impact their users.
/// </para>
/// </remarks>
[global::System.AttributeUsage(
global::System.AttributeTargets.Method |
global::System.AttributeTargets.Property |
global::System.AttributeTargets.Parameter,
AllowMultiple = false,
Inherited = false)]
internal sealed class UnscopedRefAttribute : global::System.Attribute
{
}
}
#endif

1
src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.Formats;
internal class AnimatedImageFrameMetadata internal class AnimatedImageFrameMetadata
{ {
/// <summary> /// <summary>

1
src/ImageSharp/Formats/AnimatedImageMetadata.cs

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.Formats;
internal class AnimatedImageMetadata internal class AnimatedImageMetadata
{ {
/// <summary> /// <summary>

5
src/ImageSharp/Formats/ImageFormatManager.cs

@ -83,10 +83,7 @@ public class ImageFormatManager
lock (HashLock) lock (HashLock)
{ {
if (!this.imageFormats.Contains(format)) this.imageFormats.Add(format);
{
this.imageFormats.Add(format);
}
} }
} }

4
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs

@ -133,7 +133,7 @@ internal sealed class JpegFrame : IDisposable
for (int i = 0; i < this.ComponentCount; i++) for (int i = 0; i < this.ComponentCount; i++)
{ {
IJpegComponent component = this.Components[i]; JpegComponent component = this.Components[i];
component.Init(maxSubFactorH, maxSubFactorV); component.Init(maxSubFactorH, maxSubFactorV);
} }
} }
@ -143,7 +143,7 @@ internal sealed class JpegFrame : IDisposable
bool fullScan = this.Progressive || !this.Interleaved; bool fullScan = this.Progressive || !this.Interleaved;
for (int i = 0; i < this.ComponentCount; i++) for (int i = 0; i < this.ComponentCount; i++)
{ {
IJpegComponent component = this.Components[i]; JpegComponent component = this.Components[i];
component.AllocateSpectral(fullScan); component.AllocateSpectral(fullScan);
} }
} }

5
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -176,10 +176,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <exception cref="ArgumentNullException"><paramref name="tableConfigs"/> is <see langword="null"/>.</exception> /// <exception cref="ArgumentNullException"><paramref name="tableConfigs"/> is <see langword="null"/>.</exception>
private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Span<byte> buffer) private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Span<byte> buffer)
{ {
if (tableConfigs is null) ArgumentNullException.ThrowIfNull(tableConfigs);
{
throw new ArgumentNullException(nameof(tableConfigs));
}
int markerlen = 2; int markerlen = 2;

16
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -6,6 +6,7 @@ using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Globalization; using System.Globalization;
using System.IO.Compression; using System.IO.Compression;
using System.IO.Hashing;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Text; using System.Text;
@ -120,6 +121,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// </summary> /// </summary>
private readonly PngCrcChunkHandling pngCrcChunkHandling; private readonly PngCrcChunkHandling pngCrcChunkHandling;
/// <summary>
/// A reusable Crc32 hashing instance.
/// </summary>
private readonly Crc32 crc32 = new();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PngDecoderCore"/> class. /// Initializes a new instance of the <see cref="PngDecoderCore"/> class.
/// </summary> /// </summary>
@ -1911,10 +1917,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
Span<byte> chunkType = stackalloc byte[4]; Span<byte> chunkType = stackalloc byte[4];
BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type);
uint validCrc = Crc32.Calculate(chunkType); this.crc32.Reset();
validCrc = Crc32.Calculate(validCrc, chunk.Data.GetSpan()); this.crc32.Append(chunkType);
this.crc32.Append(chunk.Data.GetSpan());
if (validCrc != inputCrc) if (this.crc32.GetCurrentHashAsUInt32() != inputCrc)
{ {
string chunkTypeName = Encoding.ASCII.GetString(chunkType); string chunkTypeName = Encoding.ASCII.GetString(chunkType);
@ -2039,8 +2046,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
// Keywords should not be empty or have leading or trailing whitespace. // Keywords should not be empty or have leading or trailing whitespace.
name = PngConstants.Encoding.GetString(keywordBytes); name = PngConstants.Encoding.GetString(keywordBytes);
return !string.IsNullOrWhiteSpace(name) return !string.IsNullOrWhiteSpace(name)
&& !name.StartsWith(" ", StringComparison.Ordinal) && !name.StartsWith(' ') && !name.EndsWith(' ');
&& !name.EndsWith(" ", StringComparison.Ordinal);
} }
private static bool IsXmpTextData(ReadOnlySpan<byte> keywordBytes) private static bool IsXmpTextData(ReadOnlySpan<byte> keywordBytes)

20
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -3,6 +3,7 @@
using System.Buffers; using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.IO.Hashing;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Common.Helpers;
@ -123,6 +124,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// </summary> /// </summary>
private int derivedTransparencyIndex = -1; private int derivedTransparencyIndex = -1;
/// <summary>
/// A reusable Crc32 hashing instance.
/// </summary>
private readonly Crc32 crc32 = new();
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore" /> class. /// Initializes a new instance of the <see cref="PngEncoderCore" /> class.
/// </summary> /// </summary>
@ -1363,16 +1369,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
stream.Write(buffer); stream.Write(buffer);
uint crc = Crc32.Calculate(buffer[4..]); // Write the type buffer this.crc32.Reset();
this.crc32.Append(buffer[4..]); // Write the type buffer
if (data.Length > 0 && length > 0) if (data.Length > 0 && length > 0)
{ {
stream.Write(data, offset, length); stream.Write(data, offset, length);
crc = Crc32.Calculate(crc, data.Slice(offset, length)); this.crc32.Append(data.Slice(offset, length));
} }
BinaryPrimitives.WriteUInt32BigEndian(buffer, crc); BinaryPrimitives.WriteUInt32BigEndian(buffer, this.crc32.GetCurrentHashAsUInt32());
stream.Write(buffer, 0, 4); // write the crc stream.Write(buffer, 0, 4); // write the crc
} }
@ -1395,16 +1402,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
stream.Write(buffer); stream.Write(buffer);
uint crc = Crc32.Calculate(buffer[4..]); // Write the type buffer this.crc32.Reset();
this.crc32.Append(buffer[4..]); // Write the type buffer
if (data.Length > 0 && length > 0) if (data.Length > 0 && length > 0)
{ {
stream.Write(data, offset, length); stream.Write(data, offset, length);
crc = Crc32.Calculate(crc, data.Slice(offset, length)); this.crc32.Append(data.Slice(offset, length));
} }
BinaryPrimitives.WriteUInt32BigEndian(buffer, crc); BinaryPrimitives.WriteUInt32BigEndian(buffer, this.crc32.GetCurrentHashAsUInt32());
stream.Write(buffer, 0, 4); // write the crc stream.Write(buffer, 0, 4); // write the crc
} }

1
src/ImageSharp/Formats/Qoi/QoiDecoder.cs

@ -4,6 +4,7 @@
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Qoi; namespace SixLabors.ImageSharp.Formats.Qoi;
internal class QoiDecoder : ImageDecoder internal class QoiDecoder : ImageDecoder
{ {
private QoiDecoder() private QoiDecoder()

2
src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs

@ -71,7 +71,7 @@ internal class DirectoryReader
throw TiffThrowHelper.ThrowInvalidHeader(); throw TiffThrowHelper.ThrowInvalidHeader();
} }
private IList<ExifProfile> ReadIfds(bool isBigTiff) private List<ExifProfile> ReadIfds(bool isBigTiff)
{ {
List<EntryReader> readers = new(); List<EntryReader> readers = new();
while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length) while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length)

13
src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs

@ -230,11 +230,7 @@ internal static class LossyUtils
} }
} }
#if NET7_0_OR_GREATER
return (int)Vector128.Sum(sum); return (int)Vector128.Sum(sum);
#else
return Numerics.ReduceSumArm(sum);
#endif
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
@ -252,11 +248,7 @@ internal static class LossyUtils
} }
} }
#if NET7_0_OR_GREATER
return (int)Vector128.Sum(sum); return (int)Vector128.Sum(sum);
#else
return Numerics.ReduceSumArm(sum);
#endif
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
@ -275,11 +267,8 @@ internal static class LossyUtils
Vector128<uint> sum2 = AdvSimd.AddPairwiseWidening(prod2); Vector128<uint> sum2 = AdvSimd.AddPairwiseWidening(prod2);
Vector128<uint> sum = AdvSimd.Add(sum1, sum2); Vector128<uint> sum = AdvSimd.Add(sum1, sum2);
#if NET7_0_OR_GREATER
return (int)Vector128.Sum(sum); return (int)Vector128.Sum(sum);
#else
return Numerics.ReduceSumArm(sum);
#endif
} }
// Load all 4x4 pixels into a single Vector128<uint> // Load all 4x4 pixels into a single Vector128<uint>

12
src/ImageSharp/ImageSharp.csproj

@ -22,20 +22,20 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<!--Bump to v3.1 prior to tagged release.--> <!--Bump to v4.0 prior to tagged release.-->
<MinVerMinimumMajorMinor>3.1</MinVerMinimumMajorMinor> <MinVerMinimumMajorMinor>4.0</MinVerMinimumMajorMinor>
</PropertyGroup> </PropertyGroup>
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true"> <When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net7.0;net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
<IsTrimmable>true</IsTrimmable> <IsTrimmable>true</IsTrimmable>
</PropertyGroup> </PropertyGroup>
</When> </When>
<Otherwise> <Otherwise>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
<IsTrimmable>true</IsTrimmable> <IsTrimmable>true</IsTrimmable>
</PropertyGroup> </PropertyGroup>
</Otherwise> </Otherwise>
@ -47,6 +47,10 @@
<None Include="..\..\SixLabors.ImageSharp.props" Pack="true" PackagePath="build" /> <None Include="..\..\SixLabors.ImageSharp.props" Pack="true" PackagePath="build" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
</ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Update="Formats\Jpeg\Components\Block8x8F.Generated.cs"> <Compile Update="Formats\Jpeg\Components\Block8x8F.Generated.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>

8
src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs

@ -57,13 +57,7 @@ internal class SharedArrayPoolBuffer<T> : ManagedBufferBase<T>, IRefCounted
[Conditional("DEBUG")] [Conditional("DEBUG")]
[MemberNotNull(nameof(Array))] [MemberNotNull(nameof(Array))]
private void CheckDisposed() private void CheckDisposed() => ObjectDisposedException.ThrowIf(this.Array == null, this.Array);
{
if (this.Array == null)
{
throw new ObjectDisposedException("SharedArrayPoolBuffer");
}
}
private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard
{ {

2
src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs

@ -472,7 +472,7 @@ internal abstract class BaseExifReader
} }
} }
private void Add(IList<IExifValue> values, IExifValue exif, object? value) private void Add(IList<IExifValue> values, ExifValue exif, object? value)
{ {
if (!exif.TrySetValue(value)) if (!exif.TrySetValue(value))
{ {

2
src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs

@ -129,7 +129,7 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
public uint Abgr public uint Abgr
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<Abgr32, uint>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<Abgr32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Abgr32, uint>(ref this) = value; set => Unsafe.As<Abgr32, uint>(ref this) = value;

2
src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs

@ -129,7 +129,7 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
public uint Argb public uint Argb
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<Argb32, uint>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<Argb32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Argb32, uint>(ref this) = value; set => Unsafe.As<Argb32, uint>(ref this) = value;

2
src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs

@ -85,7 +85,7 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
public uint Bgra public uint Bgra
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<Bgra32, uint>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<Bgra32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Bgra32, uint>(ref this) = value; set => Unsafe.As<Bgra32, uint>(ref this) = value;

2
src/ImageSharp/PixelFormats/PixelImplementations/La16.cs

@ -45,7 +45,7 @@ public partial struct La16 : IPixel<La16>, IPackedVector<ushort>
/// <inheritdoc/> /// <inheritdoc/>
public ushort PackedValue public ushort PackedValue
{ {
readonly get => Unsafe.As<La16, ushort>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<La16, ushort>(ref Unsafe.AsRef(in this));
set => Unsafe.As<La16, ushort>(ref this) = value; set => Unsafe.As<La16, ushort>(ref this) = value;
} }

2
src/ImageSharp/PixelFormats/PixelImplementations/La32.cs

@ -45,7 +45,7 @@ public partial struct La32 : IPixel<La32>, IPackedVector<uint>
public uint PackedValue public uint PackedValue
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<La32, uint>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<La32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<La32, uint>(ref this) = value; set => Unsafe.As<La32, uint>(ref this) = value;

2
src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs

@ -124,7 +124,7 @@ public partial struct Rgba32 : IPixel<Rgba32>, IPackedVector<uint>
public uint Rgba public uint Rgba
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<Rgba32, uint>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<Rgba32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Rgba32, uint>(ref this) = value; set => Unsafe.As<Rgba32, uint>(ref this) = value;

4
src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs

@ -152,7 +152,7 @@ public partial struct Rgba64 : IPixel<Rgba64>, IPackedVector<ulong>
public Rgb48 Rgb public Rgb48 Rgb
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<Rgba64, Rgb48>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<Rgba64, Rgb48>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Rgba64, Rgb48>(ref this) = value; set => Unsafe.As<Rgba64, Rgb48>(ref this) = value;
@ -162,7 +162,7 @@ public partial struct Rgba64 : IPixel<Rgba64>, IPackedVector<ulong>
public ulong PackedValue public ulong PackedValue
{ {
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<Rgba64, ulong>(ref Unsafe.AsRef(this)); readonly get => Unsafe.As<Rgba64, ulong>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Rgba64, ulong>(ref this) = value; set => Unsafe.As<Rgba64, ulong>(ref this) = value;

2
src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs

@ -143,7 +143,7 @@ public readonly partial struct ErrorDither : IDither, IEquatable<ErrorDither>, I
for (int x = bounds.Left; x < bounds.Right; x++) for (int x = bounds.Left; x < bounds.Right; x++)
{ {
ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, (uint)x); ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, (uint)x);
TPixel transformed = Unsafe.AsRef(processor).GetPaletteColor(sourcePixel); TPixel transformed = Unsafe.AsRef(in processor).GetPaletteColor(sourcePixel);
this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale);
sourcePixel = transformed; sourcePixel = transformed;
} }

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

@ -96,7 +96,7 @@ internal sealed class PixelRowDelegateProcessor<TPixel, TDelegate> : ImageProces
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers);
// Run the user defined pixel shader to the current row of pixels // Run the user defined pixel shader to the current row of pixels
Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y)); Unsafe.AsRef(in this.rowProcessor).Invoke(span, new Point(this.startX, y));
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers);
} }

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

@ -78,7 +78,7 @@ internal class FilterProcessor<TPixel> : ImageProcessor<TPixel>
Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.startX, span.Length); Span<TPixel> rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.startX, span.Length);
PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale); PixelOperations<TPixel>.Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale);
ColorNumerics.Transform(span, ref Unsafe.AsRef(this.matrix)); ColorNumerics.Transform(span, ref Unsafe.AsRef(in this.matrix));
PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, rowSpan, PixelConversionModifiers.Scale); PixelOperations<TPixel>.Instance.FromVector4Destructive(this.configuration, span, rowSpan, PixelConversionModifiers.Scale);
} }

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

@ -126,7 +126,7 @@ public struct OctreeQuantizer<TPixel> : IQuantizer<TPixel>
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public readonly IndexedImageFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> source, Rectangle bounds) public readonly IndexedImageFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> source, Rectangle bounds)
=> QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds);
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]

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

@ -56,7 +56,7 @@ internal readonly struct PaletteQuantizer<TPixel> : IQuantizer<TPixel>
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public readonly IndexedImageFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> source, Rectangle bounds) public readonly IndexedImageFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> source, Rectangle bounds)
=> QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds);
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]

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

@ -161,7 +161,7 @@ public static class QuantizerUtilities
for (int x = 0; x < destinationRow.Length; x++) for (int x = 0; x < destinationRow.Length; x++)
{ {
destinationRow[x] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x + offsetX], out TPixel _); destinationRow[x] = Unsafe.AsRef(in quantizer).GetQuantizedColor(sourceRow[x + offsetX], out TPixel _);
} }
} }

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

@ -168,7 +168,7 @@ internal struct WuQuantizer<TPixel> : IQuantizer<TPixel>
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public readonly IndexedImageFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> source, Rectangle bounds) public readonly IndexedImageFrame<TPixel> QuantizeFrame(ImageFrame<TPixel> source, Rectangle bounds)
=> QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds);
/// <inheritdoc/> /// <inheritdoc/>
public readonly byte GetQuantizedColor(TPixel color, out TPixel match) public readonly byte GetQuantizedColor(TPixel color, out TPixel match)

24
tests/Directory.Build.targets

@ -18,20 +18,18 @@
<ItemGroup> <ItemGroup>
<!-- Test Dependencies --> <!-- Test Dependencies -->
<PackageReference Update="BenchmarkDotNet" Version="0.13.0" /> <PackageReference Update="Colourful" Version="3.1.0" />
<PackageReference Update="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.0" Condition="'$(IsWindows)'=='true'" /> <PackageReference Update="Magick.NET-Q16-AnyCPU" Version="13.4.0" />
<PackageReference Update="Colourful" Version="3.0.0" /> <PackageReference Update="Microsoft.DotNet.RemoteExecutor" Version="8.0.0-beta.23580.1" />
<PackageReference Update="Magick.NET-Q16-AnyCPU" Version="12.2.2" /> <PackageReference Update="Microsoft.DotNet.XUnitExtensions" Version="8.0.0-beta.23580.1" />
<PackageReference Update="Microsoft.DotNet.RemoteExecutor" Version="6.0.0-beta.21311.3" /> <PackageReference Update="Moq" Version="4.20.70" />
<PackageReference Update="Microsoft.DotNet.XUnitExtensions" Version="6.0.0-beta.21311.3" /> <PackageReference Update="NetVips" Version="2.4.0" />
<PackageReference Update="Moq" Version="4.14.6" /> <PackageReference Update="NetVips.Native" Version="8.15.0" />
<PackageReference Update="NetVips" Version="2.0.1" /> <PackageReference Update="PhotoSauce.MagicScaler" Version="0.14.0" />
<PackageReference Update="NetVips.Native" Version="8.11.0" /> <PackageReference Update="Pfim" Version="0.11.2" />
<PackageReference Update="PhotoSauce.MagicScaler" Version="0.12.1" /> <PackageReference Update="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Version="6.0.5.128" Condition="'$(IsOSX)'=='true'" />
<PackageReference Update="Pfim" Version="0.9.1" />
<PackageReference Update="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Version="5.8.64" Condition="'$(IsOSX)'=='true'" />
<PackageReference Update="SharpZipLib" Version="1.4.2" /> <PackageReference Update="SharpZipLib" Version="1.4.2" />
<PackageReference Update="SkiaSharp" Version="2.80.2" /> <PackageReference Update="SkiaSharp" Version="2.88.6" />
<PackageReference Update="System.Drawing.Common" Version="6.0.0" /> <PackageReference Update="System.Drawing.Common" Version="6.0.0" />
<PackageReference Update="System.IO.Compression" Version="4.3.0" /> <PackageReference Update="System.IO.Compression" Version="4.3.0" />
</ItemGroup> </ItemGroup>

2
tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs

@ -14,7 +14,7 @@ using SixLabors.ImageSharp.PixelFormats;
// ReSharper disable InconsistentNaming // ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Bulk; namespace SixLabors.ImageSharp.Benchmarks.Bulk;
[Config(typeof(Config.ShortCore31))] [Config(typeof(Config.Short))]
public abstract class FromVector4<TPixel> public abstract class FromVector4<TPixel>
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {

2
tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Bulk; namespace SixLabors.ImageSharp.Benchmarks.Bulk;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class FromVector4_Rgb24 : FromVector4<Rgb24> public class FromVector4_Rgb24 : FromVector4<Rgb24>
{ {
} }

2
tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Bulk; namespace SixLabors.ImageSharp.Benchmarks.Bulk;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class ToVector4_Bgra32 : ToVector4<Bgra32> public class ToVector4_Bgra32 : ToVector4<Bgra32>
{ {
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]

2
tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Bulk; namespace SixLabors.ImageSharp.Benchmarks.Bulk;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class ToVector4_Rgb24 : ToVector4<Rgb24> public class ToVector4_Rgb24 : ToVector4<Rgb24>
{ {
[Benchmark(Baseline = true)] [Benchmark(Baseline = true)]

2
tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs

@ -11,7 +11,7 @@ using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.Bulk; namespace SixLabors.ImageSharp.Benchmarks.Bulk;
[Config(typeof(Config.ShortCore31))] [Config(typeof(Config.Short))]
public class ToVector4_Rgba32 : ToVector4<Rgba32> public class ToVector4_Rgba32 : ToVector4<Rgba32>
{ {
[Benchmark] [Benchmark]

2
tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs

@ -9,7 +9,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeBmp public class DecodeBmp
{ {
private byte[] bmpBytes; private byte[] bmpBytes;

2
tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs

@ -9,7 +9,7 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeBmp public class EncodeBmp
{ {
private Stream bmpStream; private Stream bmpStream;

2
tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Formats.Bmp;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; protected override IEnumerable<string> InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" };

2
tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs

@ -9,7 +9,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeGif public class DecodeGif
{ {
private byte[] gifBytes; private byte[] gifBytes;

2
tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs

@ -12,7 +12,7 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeGif public class EncodeGif
{ {
// System.Drawing needs this. // System.Drawing needs this.

2
tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs

@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Processing.Processors.Quantization;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{ {
[Params(InputImageCategory.AllImages)] [Params(InputImageCategory.AllImages)]

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class CmykColorConversion : ColorConversionBenchmark public class CmykColorConversion : ColorConversionBenchmark
{ {
public CmykColorConversion() public CmykColorConversion()

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class GrayscaleColorConversion : ColorConversionBenchmark public class GrayscaleColorConversion : ColorConversionBenchmark
{ {
public GrayscaleColorConversion() public GrayscaleColorConversion()

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class RgbColorConversion : ColorConversionBenchmark public class RgbColorConversion : ColorConversionBenchmark
{ {
public RgbColorConversion() public RgbColorConversion()

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class YCbCrColorConversion : ColorConversionBenchmark public class YCbCrColorConversion : ColorConversionBenchmark
{ {
public YCbCrColorConversion() public YCbCrColorConversion()

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class YccKColorConverter : ColorConversionBenchmark public class YccKColorConverter : ColorConversionBenchmark
{ {
public YccKColorConverter() public YccKColorConverter()

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs

@ -10,7 +10,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeJpegParseStreamOnly public class DecodeJpegParseStreamOnly
{ {
[Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)] [Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)]

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
/// An expensive Jpeg benchmark, running on a wide range of input images, /// An expensive Jpeg benchmark, running on a wide range of input images,
/// showing aggregate results. /// showing aggregate results.
/// </summary> /// </summary>
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase
{ {
protected override IEnumerable<string> InputImageSubfoldersOrFiles protected override IEnumerable<string> InputImageSubfoldersOrFiles

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs

@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
/// <summary> /// <summary>
/// Image-specific Jpeg benchmarks /// Image-specific Jpeg benchmarks
/// </summary> /// </summary>
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeJpeg_ImageSpecific public class DecodeJpeg_ImageSpecific
{ {
private byte[] jpegBytes; private byte[] jpegBytes;

2
tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class IdentifyJpeg public class IdentifyJpeg
{ {
private byte[] jpegBytes; private byte[] jpegBytes;

2
tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeFilteredPng public class DecodeFilteredPng
{ {
private byte[] filter0; private byte[] filter0;

2
tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs

@ -9,7 +9,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodePng public class DecodePng
{ {
private byte[] pngBytes; private byte[] pngBytes;

2
tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
/// Benchmarks saving png files using different quantizers. /// Benchmarks saving png files using different quantizers.
/// System.Drawing cannot save indexed png files so we cannot compare. /// System.Drawing cannot save indexed png files so we cannot compare.
/// </summary> /// </summary>
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeIndexedPng public class EncodeIndexedPng
{ {
// System.Drawing needs this. // System.Drawing needs this.

2
tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs

@ -10,7 +10,7 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodePng public class EncodePng
{ {
// System.Drawing needs this. // System.Drawing needs this.

2
tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs

@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeTga public class DecodeTga
{ {
private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage);

2
tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs; namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeTga public class EncodeTga
{ {
private MagickImage tgaMagick; private MagickImage tgaMagick;

2
tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[MarkdownExporter] [MarkdownExporter]
[HtmlExporter] [HtmlExporter]
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeTiff public class DecodeTiff
{ {
private string prevImage; private string prevImage;

2
tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[MarkdownExporter] [MarkdownExporter]
[HtmlExporter] [HtmlExporter]
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeTiff public class EncodeTiff
{ {
private Stream stream; private Stream stream;

2
tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[MarkdownExporter] [MarkdownExporter]
[HtmlExporter] [HtmlExporter]
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class DecodeWebp public class DecodeWebp
{ {
private Configuration configuration; private Configuration configuration;

2
tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs

@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[MarkdownExporter] [MarkdownExporter]
[HtmlExporter] [HtmlExporter]
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class EncodeWebp public class EncodeWebp
{ {
private MagickImage webpMagick; private MagickImage webpMagick;

6
tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs

@ -56,7 +56,7 @@ public partial class Config
{ {
public HwIntrinsics_SSE_AVX() public HwIntrinsics_SSE_AVX()
{ {
this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80)
.WithEnvironmentVariables( .WithEnvironmentVariables(
new EnvironmentVariable(EnableHWIntrinsic, Off), new EnvironmentVariable(EnableHWIntrinsic, Off),
new EnvironmentVariable(FeatureSIMD, Off)) new EnvironmentVariable(FeatureSIMD, Off))
@ -64,14 +64,14 @@ public partial class Config
if (Sse.IsSupported) if (Sse.IsSupported)
{ {
this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80)
.WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off)) .WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off))
.WithId("2. SSE")); .WithId("2. SSE"));
} }
if (Avx.IsSupported) if (Avx.IsSupported)
{ {
this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80)
.WithId("3. AVX")); .WithId("3. AVX"));
} }
} }

24
tests/ImageSharp.Benchmarks/Config.cs

@ -29,25 +29,25 @@ public partial class Config : ManualConfig
this.SummaryStyle = SummaryStyle.Default.WithMaxParameterColumnWidth(50); this.SummaryStyle = SummaryStyle.Default.WithMaxParameterColumnWidth(50);
} }
public class MultiFramework : Config public class Standard : Config
{ {
public MultiFramework() => this.AddJob( public Standard() => this.AddJob(
Job.Default.WithRuntime(CoreRuntime.Core60).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); Job.Default.WithRuntime(CoreRuntime.Core80).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
} }
public class ShortMultiFramework : Config public class Short : Config
{ {
public ShortMultiFramework() => this.AddJob( public Short() => this.AddJob(
Job.Default.WithRuntime(CoreRuntime.Core60).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); Job.Default.WithRuntime(CoreRuntime.Core80)
} .WithLaunchCount(1)
.WithWarmupCount(3)
public class ShortCore31 : Config .WithIterationCount(3)
{ .WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
public ShortCore31()
=> this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3));
} }
#if OS_WINDOWS #if OS_WINDOWS
#pragma warning disable CA1416 // Validate platform compatibility
private bool IsElevated => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); private bool IsElevated => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator);
#pragma warning restore CA1416 // Validate platform compatibility
#endif #endif
} }

2
tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs

@ -7,7 +7,7 @@ using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32;
namespace SixLabors.ImageSharp.Benchmarks.General; namespace SixLabors.ImageSharp.Benchmarks.General;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class Adler32Benchmark public class Adler32Benchmark
{ {
private byte[] data; private byte[] data;

2
tests/ImageSharp.Benchmarks/General/CopyBuffers.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General;
/// - Span.CopyTo() has terrible performance on classic .NET Framework /// - Span.CopyTo() has terrible performance on classic .NET Framework
/// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning) /// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning)
/// </summary> /// </summary>
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class CopyBuffers public class CopyBuffers
{ {
private byte[] destArray; private byte[] destArray;

70
tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs

@ -1,70 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Compression.Zlib;
using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32;
namespace SixLabors.ImageSharp.Benchmarks.General;
[Config(typeof(Config.ShortMultiFramework))]
public class Crc32Benchmark
{
private byte[] data;
private readonly SharpCrc32 crc = new SharpCrc32();
[Params(1024, 2048, 4096)]
public int Count { get; set; }
[GlobalSetup]
public void SetUp()
{
this.data = new byte[this.Count];
new Random(1).NextBytes(this.data);
}
[Benchmark(Baseline = true)]
public long SharpZipLibCalculate()
{
this.crc.Reset();
this.crc.Update(this.data);
return this.crc.Value;
}
[Benchmark]
public long SixLaborsCalculate()
{
return Crc32.Calculate(this.data);
}
}
// ########## 17/05/2020 ##########
//
// | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated |
// |--------------------- |-------------- |------ |-------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:|
// | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 2,797.77 ns | 278.697 ns | 15.276 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,275.56 ns | 216.100 ns | 11.845 ns | 0.81 | 0.01 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 2,923.43 ns | 2,656.882 ns | 145.633 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,257.79 ns | 75.081 ns | 4.115 ns | 0.77 | 0.04 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 2,764.14 ns | 86.281 ns | 4.729 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET Core 3.1 | 1024 | 49.32 ns | 1.813 ns | 0.099 ns | 0.02 | 0.00 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 5,603.71 ns | 427.240 ns | 23.418 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET 4.7.2 | 2048 | 4,525.02 ns | 33.931 ns | 1.860 ns | 0.81 | 0.00 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 5,563.32 ns | 49.337 ns | 2.704 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,519.61 ns | 29.837 ns | 1.635 ns | 0.81 | 0.00 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,543.37 ns | 518.551 ns | 28.424 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET Core 3.1 | 2048 | 89.07 ns | 3.312 ns | 0.182 ns | 0.02 | 0.00 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 11,396.95 ns | 373.450 ns | 20.470 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET 4.7.2 | 4096 | 9,070.35 ns | 271.083 ns | 14.859 ns | 0.80 | 0.00 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,127.81 ns | 239.177 ns | 13.110 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,050.46 ns | 230.916 ns | 12.657 ns | 0.81 | 0.00 | - | - | - | - |
// | | | | | | | | | | | | |
// | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 11,098.62 ns | 687.978 ns | 37.710 ns | 1.00 | 0.00 | - | - | - | - |
// | SixLaborsCalculate | .NET Core 3.1 | 4096 | 168.11 ns | 3.633 ns | 0.199 ns | 0.02 | 0.00 | - | - | - | - |

2
tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs

@ -6,7 +6,7 @@ using SixLabors.ImageSharp.IO;
namespace SixLabors.ImageSharp.Benchmarks.IO; namespace SixLabors.ImageSharp.Benchmarks.IO;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class BufferedStreams public class BufferedStreams
{ {
private readonly byte[] buffer = CreateTestBytes(); private readonly byte[] buffer = CreateTestBytes();

2
tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs

@ -7,7 +7,7 @@ using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization; namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class UInt32ToSingle public class UInt32ToSingle
{ {
private float[] data; private float[] data;

2
tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs

@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization; namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization;
[Config(typeof(Config.ShortMultiFramework))] [Config(typeof(Config.Short))]
public class WidenBytesToUInt32 public class WidenBytesToUInt32
{ {
private byte[] source; private byte[] source;

10
tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj

@ -11,7 +11,7 @@
<IsTestProject>false</IsTestProject> <IsTestProject>false</IsTestProject>
<Configurations>Debug;Release</Configurations> <Configurations>Debug;Release</Configurations>
<!-- Uncomment this to run benchmarks depending on Colorful or Pfim (colorspaces and TGA): --> <!-- Uncomment this to run benchmarks depending on Colorful or Pfim (colorspaces and TGA): -->
<!--<SignAssembly>false</SignAssembly>--> <!--<SignAssembly>false</SignAssembly>-->
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
@ -23,12 +23,12 @@
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true"> <When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net7.0;net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
</When> </When>
<Otherwise> <Otherwise>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
</Otherwise> </Otherwise>
</Choose> </Choose>
@ -41,8 +41,8 @@
<ItemGroup> <ItemGroup>
<PackageReference Include="Magick.NET-Q16-AnyCPU" /> <PackageReference Include="Magick.NET-Q16-AnyCPU" />
<PackageReference Include="BenchmarkDotNet" /> <PackageReference Include="BenchmarkDotNet" Version="0.13.10" />
<PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Condition="'$(OS)' == 'Windows_NT'" /> <PackageReference Include="BenchmarkDotNet.Diagnostics.Windows" Version="0.13.10" Condition="'$(IsWindows)'=='true'" />
<PackageReference Include="Colourful" /> <PackageReference Include="Colourful" />
<PackageReference Include="NetVips" /> <PackageReference Include="NetVips" />
<PackageReference Include="NetVips.Native" /> <PackageReference Include="NetVips.Native" />

6
tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs

@ -269,9 +269,7 @@ public class LoadResizeSaveStressRunner
Width = this.ThumbnailSize, Width = this.ThumbnailSize,
Height = this.ThumbnailSize, Height = this.ThumbnailSize,
ResizeMode = CropScaleMode.Max, ResizeMode = CropScaleMode.Max,
SaveFormat = FileFormat.Jpeg, EncoderOptions = new JpegEncoderOptions(Quality, ChromaSubsampleMode.Subsample420, true)
JpegQuality = Quality,
JpegSubsampleMode = ChromaSubsampleMode.Subsample420
}; };
// TODO: Is there a way to capture input dimensions for IncreaseTotalMegapixels? // TODO: Is there a way to capture input dimensions for IncreaseTotalMegapixels?
@ -343,6 +341,6 @@ public class LoadResizeSaveStressRunner
using var thumb = NetVipsImage.Thumbnail(input, this.ThumbnailSize, this.ThumbnailSize); using var thumb = NetVipsImage.Thumbnail(input, this.ThumbnailSize, this.ThumbnailSize);
// Save the results // Save the results
thumb.Jpegsave(this.OutputPath(input), q: Quality, strip: true); thumb.Jpegsave(this.OutputPath(input), q: Quality, keep: NetVips.Enums.ForeignKeep.None);
} }
} }

2
tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class BokehBlur public class BokehBlur
{ {
[Benchmark] [Benchmark]

2
tests/ImageSharp.Benchmarks/Processing/Crop.cs

@ -11,7 +11,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class Crop public class Crop
{ {
[Benchmark(Baseline = true, Description = "System.Drawing Crop")] [Benchmark(Baseline = true, Description = "System.Drawing Crop")]

2
tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks; namespace SixLabors.ImageSharp.Benchmarks;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class DetectEdges public class DetectEdges
{ {
private Image<Rgba32> image; private Image<Rgba32> image;

2
tests/ImageSharp.Benchmarks/Processing/Diffuse.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class Diffuse public class Diffuse
{ {
[Benchmark] [Benchmark]

2
tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Samplers; namespace SixLabors.ImageSharp.Benchmarks.Samplers;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class GaussianBlur public class GaussianBlur
{ {
[Benchmark] [Benchmark]

2
tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs

@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class HistogramEqualization public class HistogramEqualization
{ {
private Image<Rgba32> image; private Image<Rgba32> image;

2
tests/ImageSharp.Benchmarks/Processing/OilPaint.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class OilPaint public class OilPaint
{ {
[Benchmark] [Benchmark]

2
tests/ImageSharp.Benchmarks/Processing/Resize.cs

@ -12,7 +12,7 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks; namespace SixLabors.ImageSharp.Benchmarks;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public abstract class Resize<TPixel> public abstract class Resize<TPixel>
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {

2
tests/ImageSharp.Benchmarks/Processing/Rotate.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class Rotate public class Rotate
{ {
[Benchmark] [Benchmark]

2
tests/ImageSharp.Benchmarks/Processing/Skew.cs

@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing;
namespace SixLabors.ImageSharp.Benchmarks.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))] [Config(typeof(Config.Standard))]
public class Skew public class Skew
{ {
[Benchmark] [Benchmark]

8
tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj

@ -7,7 +7,7 @@
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<Prefer32Bit>false</Prefer32Bit> <Prefer32Bit>false</Prefer32Bit>
<RootNamespace>SixLabors.ImageSharp.Tests.ProfilingSandbox</RootNamespace> <RootNamespace>SixLabors.ImageSharp.Tests.ProfilingSandbox</RootNamespace>
<RuntimeIdentifier>win7-x64</RuntimeIdentifier> <RuntimeIdentifier>win-x64</RuntimeIdentifier>
<StartupObject>SixLabors.ImageSharp.Tests.ProfilingSandbox.Program</StartupObject> <StartupObject>SixLabors.ImageSharp.Tests.ProfilingSandbox.Program</StartupObject>
<!--Used to hide test project from dotnet test--> <!--Used to hide test project from dotnet test-->
<IsTestProject>false</IsTestProject> <IsTestProject>false</IsTestProject>
@ -19,12 +19,12 @@
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true"> <When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net7.0;net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
</When> </When>
<Otherwise> <Otherwise>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
</Otherwise> </Otherwise>
</Choose> </Choose>
@ -43,7 +43,7 @@
<PackageReference Include="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Condition="'$(IsOSX)'=='true'" /> <PackageReference Include="runtime.osx.10.10-x64.CoreCompat.System.Drawing" Condition="'$(IsOSX)'=='true'" />
<PackageReference Include="SkiaSharp" /> <PackageReference Include="SkiaSharp" />
<PackageReference Include="System.Drawing.Common" /> <PackageReference Include="System.Drawing.Common" />
<PackageReference Include="CommandLineParser" Version="2.8.0" /> <PackageReference Include="CommandLineParser" Version="2.9.1" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>

66
tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs

@ -1,66 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.Tests.TestUtilities;
using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32;
namespace SixLabors.ImageSharp.Tests.Formats.Png;
[Trait("Format", "Png")]
public class Crc32Tests
{
[Theory]
[InlineData(0)]
[InlineData(1)]
[InlineData(2)]
public void CalculateCrc_ReturnsCorrectResultWhenEmpty(uint input) => Assert.Equal(input, Crc32.Calculate(input, default));
[Theory]
[InlineData(0)]
[InlineData(8)]
[InlineData(215)]
[InlineData(1024)]
[InlineData(1024 + 15)]
[InlineData(2034)]
[InlineData(4096)]
public void CalculateCrc_MatchesReference(int length) => CalculateCrcAndCompareToReference(length);
private static void CalculateCrcAndCompareToReference(int length)
{
// arrange
byte[] data = GetBuffer(length);
SharpCrc32 crc = new();
crc.Update(data);
long expected = crc.Value;
// act
long actual = Crc32.Calculate(data);
// assert
Assert.Equal(expected, actual);
}
private static byte[] GetBuffer(int length)
{
byte[] data = new byte[length];
new Random(1).NextBytes(data);
return data;
}
[Fact]
public void RunCalculateCrcTest_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateCrcTest, HwIntrinsics.AllowAll);
[Fact]
public void RunCalculateCrcTest_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateCrcTest, HwIntrinsics.DisableHWIntrinsic);
private static void RunCalculateCrcTest()
{
int[] testData = { 0, 8, 215, 1024, 1024 + 15, 2034, 4096 };
for (int i = 0; i < testData.Length; i++)
{
CalculateCrcAndCompareToReference(testData[i]);
}
}
}

10
tests/ImageSharp.Tests/ImageSharp.Tests.csproj

@ -12,12 +12,12 @@
<Choose> <Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true"> <When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net7.0;net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
</When> </When>
<Otherwise> <Otherwise>
<PropertyGroup> <PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks> <TargetFrameworks>net8.0</TargetFrameworks>
</PropertyGroup> </PropertyGroup>
</Otherwise> </Otherwise>
</Choose> </Choose>
@ -35,7 +35,11 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="BenchmarkDotNet" /> <!--
Do not update or consolidate BenchmarkDotNet.
https://github.com/dotnet/arcade/issues/8483
-->
<PackageReference Include="BenchmarkDotNet" Version="0.13.0" />
<PackageReference Include="Magick.NET-Q16-AnyCPU" /> <PackageReference Include="Magick.NET-Q16-AnyCPU" />
<PackageReference Include="Microsoft.DotNet.RemoteExecutor" /> <PackageReference Include="Microsoft.DotNet.RemoteExecutor" />
<PackageReference Include="Microsoft.DotNet.XUnitExtensions" /> <PackageReference Include="Microsoft.DotNet.XUnitExtensions" />

Loading…
Cancel
Save