Browse Source

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

pull/2620/head
James Jackson-South 2 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
*.wbmp 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') }}
options:
- os: ubuntu-latest
framework: net7.0
sdk: 7.0.x
sdk-preview: true
framework: net8.0
sdk: 8.0.x
runtime: -x64
codecov: false
- os: macos-latest
framework: net7.0
sdk: 7.0.x
sdk-preview: true
framework: net8.0
sdk: 8.0.x
runtime: -x64
codecov: false
- os: windows-latest
framework: net7.0
sdk: 7.0.x
sdk-preview: true
framework: net8.0
sdk: 8.0.x
runtime: -x64
codecov: false
- os: buildjet-4vcpu-ubuntu-2204-arm
framework: net7.0
sdk: 7.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
framework: net8.0
sdk: 8.0.x
runtime: -x64
codecov: false
exclude:
@ -108,17 +89,17 @@ jobs:
- name: DotNet Setup
if: ${{ matrix.options.sdk-preview != true }}
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
6.0.x
8.0.x
- name: DotNet Setup Preview
if: ${{ matrix.options.sdk-preview == true }}
uses: actions/setup-dotnet@v3
uses: actions/setup-dotnet@v4
with:
dotnet-version: |
7.0.x
8.0.x
- name: DotNet Build
if: ${{ matrix.options.sdk-preview != true }}

6
.github/workflows/code-coverage.yml

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

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">
<Rule Id="SA1011" Action="None" />
</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++)
{
// 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++)
{
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++)
{
Unsafe.AsRef(operation).Invoke(y);
Unsafe.AsRef(in operation).Invoke(y);
}
return;
@ -118,7 +118,7 @@ public static partial class ParallelRowIterator
int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
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:
if (numOfSteps == 1)
@ -128,7 +128,7 @@ public static partial class ParallelRowIterator
for (int y = top; y < bottom; y++)
{
Unsafe.AsRef(operation).Invoke(y, span);
Unsafe.AsRef(in operation).Invoke(y, span);
}
return;
@ -245,7 +245,7 @@ public static partial class ParallelRowIterator
int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask);
int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps);
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:
if (numOfSteps == 1)
@ -253,7 +253,7 @@ public static partial class ParallelRowIterator
var rows = new RowInterval(top, bottom);
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;
}

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

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

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

@ -908,25 +908,6 @@ internal static class Numerics
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>
/// Reduces even elements of the vector into one sum.
/// </summary>

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

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

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

@ -2,6 +2,7 @@
// Licensed under the Six Labors Split License.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -20,7 +21,7 @@ internal static partial class SimdUtils
public static void Shuffle4(
ReadOnlySpan<float> source,
Span<float> dest,
byte control)
[ConstantExpected] byte control)
{
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;
set
{
if (value <= 0)
{
throw new ArgumentOutOfRangeException(nameof(this.StreamProcessingBufferSize));
}
ArgumentOutOfRangeException.ThrowIfNegativeOrZero(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.
namespace SixLabors.ImageSharp.Formats;
internal class AnimatedImageFrameMetadata
{
/// <summary>

1
src/ImageSharp/Formats/AnimatedImageMetadata.cs

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

5
src/ImageSharp/Formats/ImageFormatManager.cs

@ -83,10 +83,7 @@ public class ImageFormatManager
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++)
{
IJpegComponent component = this.Components[i];
JpegComponent component = this.Components[i];
component.Init(maxSubFactorH, maxSubFactorV);
}
}
@ -143,7 +143,7 @@ internal sealed class JpegFrame : IDisposable
bool fullScan = this.Progressive || !this.Interleaved;
for (int i = 0; i < this.ComponentCount; i++)
{
IJpegComponent component = this.Components[i];
JpegComponent component = this.Components[i];
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>
private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Span<byte> buffer)
{
if (tableConfigs is null)
{
throw new ArgumentNullException(nameof(tableConfigs));
}
ArgumentNullException.ThrowIfNull(tableConfigs);
int markerlen = 2;

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

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

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

@ -3,6 +3,7 @@
using System.Buffers;
using System.Buffers.Binary;
using System.IO.Hashing;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
@ -123,6 +124,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// </summary>
private int derivedTransparencyIndex = -1;
/// <summary>
/// A reusable Crc32 hashing instance.
/// </summary>
private readonly Crc32 crc32 = new();
/// <summary>
/// Initializes a new instance of the <see cref="PngEncoderCore" /> class.
/// </summary>
@ -1363,16 +1369,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
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)
{
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
}
@ -1395,16 +1402,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
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)
{
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
}

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

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

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

@ -71,7 +71,7 @@ internal class DirectoryReader
throw TiffThrowHelper.ThrowInvalidHeader();
}
private IList<ExifProfile> ReadIfds(bool isBigTiff)
private List<ExifProfile> ReadIfds(bool isBigTiff)
{
List<EntryReader> readers = new();
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);
#else
return Numerics.ReduceSumArm(sum);
#endif
}
[MethodImpl(InliningOptions.ShortMethod)]
@ -252,11 +248,7 @@ internal static class LossyUtils
}
}
#if NET7_0_OR_GREATER
return (int)Vector128.Sum(sum);
#else
return Numerics.ReduceSumArm(sum);
#endif
}
[MethodImpl(InliningOptions.ShortMethod)]
@ -275,11 +267,8 @@ internal static class LossyUtils
Vector128<uint> sum2 = AdvSimd.AddPairwiseWidening(prod2);
Vector128<uint> sum = AdvSimd.Add(sum1, sum2);
#if NET7_0_OR_GREATER
return (int)Vector128.Sum(sum);
#else
return Numerics.ReduceSumArm(sum);
#endif
}
// Load all 4x4 pixels into a single Vector128<uint>

12
src/ImageSharp/ImageSharp.csproj

@ -22,20 +22,20 @@
</PropertyGroup>
<PropertyGroup>
<!--Bump to v3.1 prior to tagged release.-->
<MinVerMinimumMajorMinor>3.1</MinVerMinimumMajorMinor>
<!--Bump to v4.0 prior to tagged release.-->
<MinVerMinimumMajorMinor>4.0</MinVerMinimumMajorMinor>
</PropertyGroup>
<Choose>
<When Condition="$(SIXLABORS_TESTING_PREVIEW) == true">
<PropertyGroup>
<TargetFrameworks>net7.0;net6.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
</When>
<Otherwise>
<PropertyGroup>
<TargetFrameworks>net6.0</TargetFrameworks>
<TargetFrameworks>net8.0</TargetFrameworks>
<IsTrimmable>true</IsTrimmable>
</PropertyGroup>
</Otherwise>
@ -47,6 +47,10 @@
<None Include="..\..\SixLabors.ImageSharp.props" Pack="true" PackagePath="build" />
</ItemGroup>
<ItemGroup>
<PackageReference Include="System.IO.Hashing" Version="8.0.0" />
</ItemGroup>
<ItemGroup>
<Compile Update="Formats\Jpeg\Components\Block8x8F.Generated.cs">
<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")]
[MemberNotNull(nameof(Array))]
private void CheckDisposed()
{
if (this.Array == null)
{
throw new ObjectDisposedException("SharedArrayPoolBuffer");
}
}
private void CheckDisposed() => ObjectDisposedException.ThrowIf(this.Array == null, this.Array);
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))
{

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

@ -129,7 +129,7 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
public uint Abgr
{
[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)]
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
{
[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)]
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
{
[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)]
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/>
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;
}

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

@ -45,7 +45,7 @@ public partial struct La32 : IPixel<La32>, IPackedVector<uint>
public uint PackedValue
{
[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)]
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
{
[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)]
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
{
[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)]
set => Unsafe.As<Rgba64, Rgb48>(ref this) = value;
@ -162,7 +162,7 @@ public partial struct Rgba64 : IPixel<Rgba64>, IPackedVector<ulong>
public ulong PackedValue
{
[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)]
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++)
{
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);
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);
// 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);
}

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);
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);
}

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

@ -126,7 +126,7 @@ public struct OctreeQuantizer<TPixel> : IQuantizer<TPixel>
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
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/>
[MethodImpl(InliningOptions.ShortMethod)]

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

@ -56,7 +56,7 @@ internal readonly struct PaletteQuantizer<TPixel> : IQuantizer<TPixel>
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
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/>
[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++)
{
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/>
[MethodImpl(InliningOptions.ShortMethod)]
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/>
public readonly byte GetQuantizedColor(TPixel color, out TPixel match)

24
tests/Directory.Build.targets

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

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

@ -14,7 +14,7 @@ using SixLabors.ImageSharp.PixelFormats;
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.Bulk;
[Config(typeof(Config.ShortCore31))]
[Config(typeof(Config.Short))]
public abstract class FromVector4<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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class ToVector4_Bgra32 : ToVector4<Bgra32>
{
[Benchmark(Baseline = true)]

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

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

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

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

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

@ -9,7 +9,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodeBmp
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class EncodeBmp
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodeGif
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class EncodeGif
{
// 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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded
{
[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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class CmykColorConversion : ColorConversionBenchmark
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class GrayscaleColorConversion : ColorConversionBenchmark
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class RgbColorConversion : ColorConversionBenchmark
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class YCbCrColorConversion : ColorConversionBenchmark
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class YccKColorConverter : ColorConversionBenchmark
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodeJpegParseStreamOnly
{
[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,
/// showing aggregate results.
/// </summary>
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase
{
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>
/// Image-specific Jpeg benchmarks
/// </summary>
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodeJpeg_ImageSpecific
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class IdentifyJpeg
{
private byte[] jpegBytes;

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

@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodeFilteredPng
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodePng
{
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.
/// System.Drawing cannot save indexed png files so we cannot compare.
/// </summary>
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class EncodeIndexedPng
{
// 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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class EncodePng
{
// 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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class DecodeTga
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class EncodeTga
{
private MagickImage tgaMagick;

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

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

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

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

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

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

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

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

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

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

24
tests/ImageSharp.Benchmarks/Config.cs

@ -29,25 +29,25 @@ public partial class Config : ManualConfig
this.SummaryStyle = SummaryStyle.Default.WithMaxParameterColumnWidth(50);
}
public class MultiFramework : Config
public class Standard : Config
{
public MultiFramework() => this.AddJob(
Job.Default.WithRuntime(CoreRuntime.Core60).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
public Standard() => this.AddJob(
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(
Job.Default.WithRuntime(CoreRuntime.Core60).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") }));
}
public class ShortCore31 : Config
{
public ShortCore31()
=> this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3));
public Short() => this.AddJob(
Job.Default.WithRuntime(CoreRuntime.Core80)
.WithLaunchCount(1)
.WithWarmupCount(3)
.WithIterationCount(3)
.WithArguments(new Argument[] { 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
}

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

@ -7,7 +7,7 @@ using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32;
namespace SixLabors.ImageSharp.Benchmarks.General;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class Adler32Benchmark
{
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
/// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning)
/// </summary>
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class CopyBuffers
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class BufferedStreams
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class UInt32ToSingle
{
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;
[Config(typeof(Config.ShortMultiFramework))]
[Config(typeof(Config.Short))]
public class WidenBytesToUInt32
{
private byte[] source;

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

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

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

@ -269,9 +269,7 @@ public class LoadResizeSaveStressRunner
Width = this.ThumbnailSize,
Height = this.ThumbnailSize,
ResizeMode = CropScaleMode.Max,
SaveFormat = FileFormat.Jpeg,
JpegQuality = Quality,
JpegSubsampleMode = ChromaSubsampleMode.Subsample420
EncoderOptions = new JpegEncoderOptions(Quality, ChromaSubsampleMode.Subsample420, true)
};
// 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);
// 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;
[Config(typeof(Config.MultiFramework))]
[Config(typeof(Config.Standard))]
public class BokehBlur
{
[Benchmark]

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

@ -11,7 +11,7 @@ using SDSize = System.Drawing.Size;
namespace SixLabors.ImageSharp.Benchmarks.Processing;
[Config(typeof(Config.MultiFramework))]
[Config(typeof(Config.Standard))]
public class 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;
[Config(typeof(Config.MultiFramework))]
[Config(typeof(Config.Standard))]
public class DetectEdges
{
private Image<Rgba32> image;

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

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

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

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

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

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

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

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

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

@ -12,7 +12,7 @@ using SDImage = System.Drawing.Image;
namespace SixLabors.ImageSharp.Benchmarks;
[Config(typeof(Config.MultiFramework))]
[Config(typeof(Config.Standard))]
public abstract class Resize<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;
[Config(typeof(Config.MultiFramework))]
[Config(typeof(Config.Standard))]
public class Rotate
{
[Benchmark]

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

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

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

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

Loading…
Cancel
Save