Browse Source

Merge branch 'SixLabors:main' into main

qoi
Luis Alfredo Figueroa Bracamontes 3 years ago
committed by GitHub
parent
commit
43bf27af42
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .github/CONTRIBUTING.md
  2. 56
      .github/ISSUE_TEMPLATE/commercial-bug-report.yml
  3. 4
      .github/ISSUE_TEMPLATE/oss-bug-report.yml
  4. 1
      ImageSharp.sln
  5. 9
      README.md
  6. 8
      src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs
  7. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  8. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  9. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs
  10. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  11. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs
  12. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  13. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  14. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  15. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  16. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
  17. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  18. 28
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
  19. 26
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs
  20. 24
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  21. 10
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs
  22. 2
      src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs
  23. 16
      src/ImageSharp/Common/Helpers/HexConverter.cs
  24. 126
      src/ImageSharp/Common/Helpers/Numerics.cs
  25. 26
      src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
  26. 8
      src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs
  27. 6
      src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs
  28. 12
      src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs
  29. 8
      src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
  30. 8
      src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
  31. 230
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  32. 18
      src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs
  33. 34
      src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
  34. 2
      src/ImageSharp/Compression/Zlib/Crc32.cs
  35. 5
      src/ImageSharp/Compression/Zlib/DeflaterEngine.cs
  36. 100
      src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs
  37. 42
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  38. 6
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  39. 20
      src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs
  40. 38
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  41. 34
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  42. 38
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  43. 22
      src/ImageSharp/Formats/Gif/LzwEncoder.cs
  44. 8
      src/ImageSharp/Formats/ImageExtensions.Save.tt
  45. 52
      src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs
  46. 22
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs
  47. 4
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt
  48. 10
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs
  49. 36
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopy.cs
  50. 47
      src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs
  51. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs
  52. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector.cs
  53. 68
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs
  54. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs
  55. 2
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs
  56. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector.cs
  57. 4
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbArm.cs
  58. 4
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs
  59. 4
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector.cs
  60. 122
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrArm.cs
  61. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs
  62. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs
  63. 133
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs
  64. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs
  65. 8
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector.cs
  66. 21
      src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs
  67. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs
  68. 31
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs
  69. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticStatistics.cs
  70. 24
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs
  71. 24
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs
  72. 14
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs
  73. 12
      src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs
  74. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
  75. 23
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
  76. 57
      src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs
  77. 34
      src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs
  78. 4
      src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.cs
  79. 26
      src/ImageSharp/Formats/Jpeg/Components/ScaledFloatingPointDCT.cs
  80. 146
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  81. 289
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  82. 26
      src/ImageSharp/Formats/Png/Adam7.cs
  83. 26
      src/ImageSharp/Formats/Png/Filters/AverageFilter.cs
  84. 28
      src/ImageSharp/Formats/Png/Filters/PaethFilter.cs
  85. 26
      src/ImageSharp/Formats/Png/Filters/SubFilter.cs
  86. 30
      src/ImageSharp/Formats/Png/Filters/UpFilter.cs
  87. 89
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  88. 69
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  89. 6
      src/ImageSharp/Formats/Png/PngEncoderHelpers.cs
  90. 129
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
  91. 44
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  92. 12
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  93. 2
      src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs
  94. 16
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs
  95. 11
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
  96. 23
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
  97. 30
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
  98. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs
  99. 9
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
  100. 2
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

2
.github/CONTRIBUTING.md

@ -29,7 +29,6 @@
#### **Running tests and Debugging** #### **Running tests and Debugging**
* Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/main/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules! * Expected test output is pulled in as a submodule from the [ImageSharp.Tests.Images repository](https://github.com/SixLabors/Imagesharp.Tests.Images/tree/main/ReferenceOutput). To succesfully run tests, make sure that you have updated the submodules!
* Debugging (running tests in Debug mode) is only supported on .NET Core 2.1+, because of JIT Code Generation bugs like [dotnet/coreclr#16443](https://github.com/dotnet/coreclr/issues/16443) or [dotnet/coreclr#20657](https://github.com/dotnet/coreclr/issues/20657)
#### **Do you have questions about consuming the library or the source code?** #### **Do you have questions about consuming the library or the source code?**
@ -37,7 +36,6 @@
#### Code of Conduct #### Code of Conduct
This project has adopted the code of conduct defined by the [Contributor Covenant](https://contributor-covenant.org/) to clarify expected behavior in our community. This project has adopted the code of conduct defined by the [Contributor Covenant](https://contributor-covenant.org/) to clarify expected behavior in our community.
For more information, see the [.NET Foundation Code of Conduct](https://dotnetfoundation.org/code-of-conduct).
And please remember. SixLabors.ImageSharp is the work of a very, very, small number of developers who struggle balancing time to contribute to the project with family time and work commitments. We encourage you to pitch in and help make our vision of simple accessible image processing available to all. Open Source can only exist with your help. And please remember. SixLabors.ImageSharp is the work of a very, very, small number of developers who struggle balancing time to contribute to the project with family time and work commitments. We encourage you to pitch in and help make our vision of simple accessible image processing available to all. Open Source can only exist with your help.

56
.github/ISSUE_TEMPLATE/commercial-bug-report.yml

@ -1,56 +0,0 @@
name: "Commercial License : Bug Report"
description: |
Create a report to help us improve the project. For Commercial License holders only.
Please contact help@sixlabors.com for issues requiring private support.
labels: ["commercial", "needs triage"]
body:
- type: checkboxes
attributes:
label: Prerequisites
options:
- label: I have bought a Commercial License
required: true
- label: I have written a descriptive issue title
required: true
- label: I have verified that I am running the latest version of ImageSharp
required: true
- label: I have verified if the problem exist in both `DEBUG` and `RELEASE` mode
required: true
- label: I have searched [open](https://github.com/SixLabors/ImageSharp/issues) and [closed](https://github.com/SixLabors/ImageSharp/issues?q=is%3Aissue+is%3Aclosed) issues to ensure it has not already been reported
required: true
- type: input
attributes:
label: ImageSharp version
validations:
required: true
- type: input
attributes:
label: Other ImageSharp packages and versions
validations:
required: true
- type: input
attributes:
label: Environment (Operating system, version and so on)
validations:
required: true
- type: input
attributes:
label: .NET Framework version
validations:
required: true
- type: textarea
attributes:
label: Description
description: A description of the bug
validations:
required: true
- type: textarea
attributes:
label: Steps to Reproduce
description: List of steps, sample code, failing test or link to a project that reproduces the behavior. Make sure you place a stack trace inside a code (```) block to avoid linking unrelated issues.
validations:
required: true
- type: textarea
attributes:
label: Images
description: Please upload images that can be used to reproduce issues in the area below. If the file type is not supported the file can be zipped and then uploaded instead.

4
.github/ISSUE_TEMPLATE/oss-bug-report.yml

@ -1,5 +1,5 @@
name: "OSS : Bug Report" name: "Bug Report"
description: Create a report to help us improve the project. OSS Issues are not guaranteed to be triaged. description: Create a report to help us improve the project. Issues are not guaranteed to be triaged.
labels: ["needs triage"] labels: ["needs triage"]
body: body:
- type: checkboxes - type: checkboxes

1
ImageSharp.sln

@ -28,7 +28,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1799
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{FBE8C1AD-5AEC-4514-9B64-091D8E145865}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{FBE8C1AD-5AEC-4514-9B64-091D8E145865}"
ProjectSection(SolutionItems) = preProject ProjectSection(SolutionItems) = preProject
.github\ISSUE_TEMPLATE\commercial-bug-report.yml = .github\ISSUE_TEMPLATE\commercial-bug-report.yml
.github\ISSUE_TEMPLATE\config.yml = .github\ISSUE_TEMPLATE\config.yml .github\ISSUE_TEMPLATE\config.yml = .github\ISSUE_TEMPLATE\config.yml
.github\ISSUE_TEMPLATE\oss-bug-report.yml = .github\ISSUE_TEMPLATE\oss-bug-report.yml .github\ISSUE_TEMPLATE\oss-bug-report.yml = .github\ISSUE_TEMPLATE\oss-bug-report.yml
EndProjectSection EndProjectSection

9
README.md

@ -101,6 +101,8 @@ git submodule update --init --recursive
Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little. Make sure to read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/main/.github/CONTRIBUTING.md) before opening a PR. Please... Spread the word, contribute algorithms, submit performance improvements, unit tests, no input is too little. Make sure to read our [Contribution Guide](https://github.com/SixLabors/ImageSharp/blob/main/.github/CONTRIBUTING.md) before opening a PR.
Useful tools for development and links to specifications can be found in our wikipage: [Useful-tools-and-links](https://github.com/SixLabors/ImageSharp/wiki/Useful-tools-and-links).
## The ImageSharp Team ## The ImageSharp Team
- [James Jackson-South](https://github.com/jimbobsquarepants) - [James Jackson-South](https://github.com/jimbobsquarepants)
@ -109,6 +111,11 @@ Please... Spread the word, contribute algorithms, submit performance improvement
- [Scott Williams](https://github.com/tocsoft) - [Scott Williams](https://github.com/tocsoft)
- [Brian Popow](https://github.com/brianpopow) - [Brian Popow](https://github.com/brianpopow)
---
<div>
<a href="https://www.jetbrains.com/?from=ImageSharp" align="right"><img src="https://resources.jetbrains.com/storage/products/company/brand/logos/jb_beam.svg" alt="JetBrains" class="logo-footer" width="72" align="left"></a>
<br/>
Special thanks to [JetBrains](https://www.jetbrains.com/?from=ImageSharp) for supporting us with open-source licenses for their IDEs.
</div>

8
src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs

@ -167,7 +167,7 @@ public static class SRgbCompanding
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table) private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
{ {
fixed (float* tablePointer = &table[0]) fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{ {
var scale = Vector256.Create((float)Scale); var scale = Vector256.Create((float)Scale);
Vector256<float> zero = Vector256<float>.Zero; Vector256<float> zero = Vector256<float>.Zero;
@ -175,7 +175,7 @@ public static class SRgbCompanding
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float> // Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors)); ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (IntPtr)((uint)vectors.Length / 2u)); ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{ {
@ -199,12 +199,12 @@ public static class SRgbCompanding
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table) private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)
{ {
fixed (float* tablePointer = &table[0]) fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{ {
Vector4 zero = Vector4.Zero; Vector4 zero = Vector4.Zero;
var scale = new Vector4(Scale); var scale = new Vector4(Scale);
ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors); ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, vectors.Length); ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{ {

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs

@ -37,7 +37,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -70,7 +70,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -103,7 +103,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -136,7 +136,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -169,7 +169,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -266,7 +266,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -299,7 +299,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -332,7 +332,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -365,7 +365,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -398,7 +398,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -431,7 +431,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination); ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs

@ -36,7 +36,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -200,7 +200,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -233,7 +233,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -266,7 +266,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -299,7 +299,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -332,7 +332,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -365,7 +365,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -398,7 +398,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -431,7 +431,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination); ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i); ref CieLch dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs

@ -36,7 +36,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -399,7 +399,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -431,7 +431,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs

@ -35,7 +35,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -67,7 +67,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -134,7 +134,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -169,7 +169,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -233,7 +233,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -265,7 +265,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -297,7 +297,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -329,7 +329,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -361,7 +361,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -393,7 +393,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -425,7 +425,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i); ref CieLuv dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs

@ -36,7 +36,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -163,7 +163,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -196,7 +196,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -229,7 +229,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -262,7 +262,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -295,7 +295,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -328,7 +328,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -361,7 +361,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i); ref CieXyy dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs

@ -41,7 +41,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -76,7 +76,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -111,7 +111,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -146,7 +146,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -177,7 +177,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +210,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -243,7 +243,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -277,7 +277,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -310,7 +310,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -345,7 +345,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -374,7 +374,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -407,7 +407,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -440,7 +440,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs

@ -36,7 +36,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i); ref Cmyk dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs

@ -36,7 +36,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination); ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i); ref Hsl dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs

@ -36,7 +36,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination); ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i); ref Hsv dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs

@ -24,7 +24,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i); ref HunterLab dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs

@ -24,7 +24,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);

28
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -24,7 +24,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination); ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i); ref Lms dp = ref Unsafe.Add(ref destRef, i);

26
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs

@ -24,7 +24,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination); ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i); ref Rgb dp = ref Unsafe.Add(ref destRef, i);

24
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs

@ -24,7 +24,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source); ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Lms sp = ref Unsafe.Add(ref sourceRef, i); ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i); ref YCbCr dp = ref Unsafe.Add(ref destRef, i);

10
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -42,9 +42,11 @@ internal sealed class CieXyzToCieLabConverter
float xr = input.X / wx, yr = input.Y / wy, zr = input.Z / wz; float xr = input.X / wx, yr = input.Y / wy, zr = input.Z / wz;
float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) / 116F; const float inv116 = 1 / 116F;
float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) / 116F;
float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) / 116F; float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116;
float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116;
float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116;
float l = (116F * fy) - 16F; float l = (116F * fy) - 16F;
float a = 500F * (fx - fy); float a = 500F * (fx - fy);

2
src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs

@ -81,7 +81,7 @@ public sealed class VonKriesChromaticAdaptation : IChromaticAdaptation
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < count; i++) for (nuint i = 0; i < (uint)count; i++)
{ {
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i); ref CieXyz dp = ref Unsafe.Add(ref destRef, i);

16
src/ImageSharp/Common/Helpers/HexConverter.cs

@ -16,21 +16,19 @@ internal static class HexConverter
/// <returns>The number of bytes written to <paramref name="bytes"/>.</returns> /// <returns>The number of bytes written to <paramref name="bytes"/>.</returns>
public static int HexStringToBytes(ReadOnlySpan<char> chars, Span<byte> bytes) public static int HexStringToBytes(ReadOnlySpan<char> chars, Span<byte> bytes)
{ {
if ((chars.Length % 2) != 0) if (Numerics.Modulo2(chars.Length) != 0)
{ {
throw new ArgumentException("Input string length must be a multiple of 2", nameof(chars)); throw new ArgumentException("Input string length must be a multiple of 2", nameof(chars));
} }
if ((bytes.Length * 2) < chars.Length) if ((bytes.Length << 1 /* bit-hack for *2 */) < chars.Length)
{ {
throw new ArgumentException("Output span must be at least half the length of the input string"); throw new ArgumentException("Output span must be at least half the length of the input string");
} }
else
{ // Slightly better performance in the loop below, allows us to skip a bounds check
// Slightly better performance in the loop below, allows us to skip a bounds check // while still supporting output buffers that are larger than necessary
// while still supporting output buffers that are larger than necessary bytes = bytes[..(chars.Length >> 1)]; // bit-hack for / 2
bytes = bytes[..(chars.Length / 2)];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static int FromChar(int c) static int FromChar(int c)
@ -57,7 +55,7 @@ internal static class HexConverter
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 255 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 255
}; };
return c >= charToHexLookup.Length ? 0xFF : charToHexLookup[c]; return (uint)c >= (uint)charToHexLookup.Length ? 0xFF : charToHexLookup[c];
} }
// See https://source.dot.net/#System.Private.CoreLib/HexConverter.cs,4681d45a0aa0b361 // See https://source.dot.net/#System.Private.CoreLib/HexConverter.cs,4681d45a0aa0b361

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

@ -55,6 +55,12 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int Modulo4(int x) => x & 3; public static int Modulo4(int x) => x & 3;
/// <summary>
/// Calculates <paramref name="x"/> % 4
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nint Modulo4(nint x) => x & 3;
/// <summary> /// <summary>
/// Calculates <paramref name="x"/> % 8 /// Calculates <paramref name="x"/> % 8
/// </summary> /// </summary>
@ -291,7 +297,7 @@ internal static class Numerics
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
ref byte remainderStart = ref MemoryMarshal.GetReference(remainder); ref byte remainderStart = ref MemoryMarshal.GetReference(remainder);
ref byte remainderEnd = ref Unsafe.Add(ref remainderStart, remainder.Length); ref byte remainderEnd = ref Unsafe.Add(ref remainderStart, (uint)remainder.Length);
while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd)) while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd))
{ {
@ -316,7 +322,7 @@ internal static class Numerics
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
ref uint remainderStart = ref MemoryMarshal.GetReference(remainder); ref uint remainderStart = ref MemoryMarshal.GetReference(remainder);
ref uint remainderEnd = ref Unsafe.Add(ref remainderStart, remainder.Length); ref uint remainderEnd = ref Unsafe.Add(ref remainderStart, (uint)remainder.Length);
while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd)) while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd))
{ {
@ -341,7 +347,7 @@ internal static class Numerics
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
ref int remainderStart = ref MemoryMarshal.GetReference(remainder); ref int remainderStart = ref MemoryMarshal.GetReference(remainder);
ref int remainderEnd = ref Unsafe.Add(ref remainderStart, remainder.Length); ref int remainderEnd = ref Unsafe.Add(ref remainderStart, (uint)remainder.Length);
while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd)) while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd))
{ {
@ -366,7 +372,7 @@ internal static class Numerics
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
ref float remainderStart = ref MemoryMarshal.GetReference(remainder); ref float remainderStart = ref MemoryMarshal.GetReference(remainder);
ref float remainderEnd = ref Unsafe.Add(ref remainderStart, remainder.Length); ref float remainderEnd = ref Unsafe.Add(ref remainderStart, (uint)remainder.Length);
while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd)) while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd))
{ {
@ -391,7 +397,7 @@ internal static class Numerics
if (remainder.Length > 0) if (remainder.Length > 0)
{ {
ref double remainderStart = ref MemoryMarshal.GetReference(remainder); ref double remainderStart = ref MemoryMarshal.GetReference(remainder);
ref double remainderEnd = ref Unsafe.Add(ref remainderStart, remainder.Length); ref double remainderEnd = ref Unsafe.Add(ref remainderStart, (uint)remainder.Length);
while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd)) while (Unsafe.IsAddressLessThan(ref remainderStart, ref remainderEnd))
{ {
@ -430,9 +436,9 @@ internal static class Numerics
var vmin = new Vector<T>(min); var vmin = new Vector<T>(min);
var vmax = new Vector<T>(max); var vmax = new Vector<T>(max);
int n = span.Length / Vector<T>.Count; nint n = (nint)(uint)span.Length / Vector<T>.Count;
int m = Modulo4(n); nint m = Modulo4(n);
int u = n - m; nint u = n - m;
ref Vector<T> vs0 = ref Unsafe.As<T, Vector<T>>(ref MemoryMarshal.GetReference(span)); ref Vector<T> vs0 = ref Unsafe.As<T, Vector<T>>(ref MemoryMarshal.GetReference(span));
ref Vector<T> vs1 = ref Unsafe.Add(ref vs0, 1); ref Vector<T> vs1 = ref Unsafe.Add(ref vs0, 1);
@ -491,7 +497,7 @@ internal static class Numerics
{ {
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float> // Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors)); ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (IntPtr)((uint)vectors.Length / 2u)); ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{ {
@ -510,7 +516,7 @@ internal static class Numerics
else else
{ {
ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors); ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, vectors.Length); ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref vectorsStart, ref vectorsEnd)) while (Unsafe.IsAddressLessThan(ref vectorsStart, ref vectorsEnd))
{ {
@ -556,7 +562,7 @@ internal static class Numerics
{ {
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float> // Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors)); ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (IntPtr)((uint)vectors.Length / 2u)); ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u);
Vector256<float> epsilon = Vector256.Create(Constants.Epsilon); Vector256<float> epsilon = Vector256.Create(Constants.Epsilon);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast)) while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
@ -576,7 +582,7 @@ internal static class Numerics
else else
{ {
ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors); ref Vector4 vectorsStart = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, vectors.Length); ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsStart, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref vectorsStart, ref vectorsEnd)) while (Unsafe.IsAddressLessThan(ref vectorsStart, ref vectorsEnd))
{ {
@ -650,7 +656,7 @@ internal static class Numerics
public static unsafe void CubePowOnXYZ(Span<Vector4> vectors) public static unsafe void CubePowOnXYZ(Span<Vector4> vectors)
{ {
ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors);
ref Vector4 endRef = ref Unsafe.Add(ref baseRef, vectors.Length); ref Vector4 endRef = ref Unsafe.Add(ref baseRef, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref baseRef, ref endRef)) while (Unsafe.IsAddressLessThan(ref baseRef, ref endRef))
{ {
@ -681,7 +687,7 @@ internal static class Numerics
if (Sse41.IsSupported) if (Sse41.IsSupported)
{ {
ref Vector128<float> vectors128Ref = ref Unsafe.As<Vector4, Vector128<float>>(ref MemoryMarshal.GetReference(vectors)); ref Vector128<float> vectors128Ref = ref Unsafe.As<Vector4, Vector128<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector128<float> vectors128End = ref Unsafe.Add(ref vectors128Ref, vectors.Length); ref Vector128<float> vectors128End = ref Unsafe.Add(ref vectors128Ref, (uint)vectors.Length);
var v128_341 = Vector128.Create(341); var v128_341 = Vector128.Create(341);
Vector128<int> v128_negativeZero = Vector128.Create(-0.0f).AsInt32(); Vector128<int> v128_negativeZero = Vector128.Create(-0.0f).AsInt32();
@ -730,7 +736,7 @@ internal static class Numerics
else else
{ {
ref Vector4 vectorsRef = ref MemoryMarshal.GetReference(vectors); ref Vector4 vectorsRef = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsRef, vectors.Length); ref Vector4 vectorsEnd = ref Unsafe.Add(ref vectorsRef, (uint)vectors.Length);
// Fallback with scalar preprocessing and vectorized approximation steps // Fallback with scalar preprocessing and vectorized approximation steps
while (Unsafe.IsAddressLessThan(ref vectorsRef, ref vectorsEnd)) while (Unsafe.IsAddressLessThan(ref vectorsRef, ref vectorsEnd))
@ -943,4 +949,94 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOutOfRange(int value, int min, int max) public static bool IsOutOfRange(int value, int min, int max)
=> (uint)(value - min) > (uint)(max - min); => (uint)(value - min) > (uint)(max - min);
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint VectorCount<TVector>(this Span<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector128Count<TVector>(this Span<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector128Count<TVector>(this ReadOnlySpan<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector256Count<TVector>(this Span<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector256Count<TVector>(this ReadOnlySpan<byte> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint VectorCount<TVector>(this Span<float> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector128Count<TVector>(this Span<float> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector128<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into the given span.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="span">The given span.</param>
/// <returns>Count of vectors that safely fit into the span.</returns>
public static nuint Vector256Count<TVector>(this Span<float> span)
where TVector : struct
=> (uint)span.Length / (uint)Vector256<TVector>.Count;
/// <summary>
/// Gets the count of vectors that safely fit into length.
/// </summary>
/// <typeparam name="TVector">The type of the vector.</typeparam>
/// <param name="length">The given length.</param>
/// <returns>Count of vectors that safely fit into the length.</returns>
public static nuint Vector256Count<TVector>(int length)
where TVector : struct
=> (uint)length / (uint)Vector256<TVector>.Count;
} }

26
src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs

@ -61,11 +61,11 @@ internal readonly struct DefaultShuffle4 : IShuffle4
ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest); ref byte dBase = ref MemoryMarshal.GetReference(dest);
Shuffle.InverseMMShuffle(this.Control, out int p3, out int p2, out int p1, out int p0); Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
for (int i = 0; i < source.Length; i += 4) for (nuint i = 0; i < (uint)source.Length; i += 4)
{ {
Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, p0 + i); Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i); Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i);
Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i); Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i);
Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i); Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i);
@ -84,9 +84,9 @@ internal readonly struct WXYZShuffle4 : IShuffle4
{ {
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source)); ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest)); ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4; uint n = (uint)source.Length / 4;
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
uint packed = Unsafe.Add(ref sBase, i); uint packed = Unsafe.Add(ref sBase, i);
@ -108,9 +108,9 @@ internal readonly struct WZYXShuffle4 : IShuffle4
{ {
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source)); ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest)); ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4; uint n = (uint)source.Length / 4;
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
uint packed = Unsafe.Add(ref sBase, i); uint packed = Unsafe.Add(ref sBase, i);
@ -132,9 +132,9 @@ internal readonly struct YZWXShuffle4 : IShuffle4
{ {
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source)); ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest)); ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4; uint n = (uint)source.Length / 4;
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
uint packed = Unsafe.Add(ref sBase, i); uint packed = Unsafe.Add(ref sBase, i);
@ -156,9 +156,9 @@ internal readonly struct ZYXWShuffle4 : IShuffle4
{ {
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source)); ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest)); ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4; uint n = (uint)source.Length / 4;
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
uint packed = Unsafe.Add(ref sBase, i); uint packed = Unsafe.Add(ref sBase, i);
@ -187,9 +187,9 @@ internal readonly struct XWZYShuffle4 : IShuffle4
{ {
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source)); ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest)); ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4; uint n = (uint)source.Length / 4;
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
uint packed = Unsafe.Add(ref sBase, i); uint packed = Unsafe.Add(ref sBase, i);

8
src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs

@ -29,18 +29,18 @@ internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4
ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest); ref byte dBase = ref MemoryMarshal.GetReference(dest);
Shuffle.InverseMMShuffle(this.Control, out int p3, out int p2, out int p1, out int p0); Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
Span<byte> temp = stackalloc byte[4]; Span<byte> temp = stackalloc byte[4];
ref byte t = ref MemoryMarshal.GetReference(temp); ref byte t = ref MemoryMarshal.GetReference(temp);
ref uint tu = ref Unsafe.As<byte, uint>(ref t); ref uint tu = ref Unsafe.As<byte, uint>(ref t);
for (int i = 0, j = 0; i < source.Length; i += 3, j += 4) for (nuint i = 0, j = 0; i < (uint)source.Length; i += 3, j += 4)
{ {
ref byte s = ref Unsafe.Add(ref sBase, i); ref byte s = ref Unsafe.Add(ref sBase, i);
tu = Unsafe.As<byte, uint>(ref s) | 0xFF000000; tu = Unsafe.As<byte, uint>(ref s) | 0xFF000000;
Unsafe.Add(ref dBase, j) = Unsafe.Add(ref t, p0); Unsafe.Add(ref dBase, j + 0) = Unsafe.Add(ref t, p0);
Unsafe.Add(ref dBase, j + 1) = Unsafe.Add(ref t, p1); Unsafe.Add(ref dBase, j + 1) = Unsafe.Add(ref t, p1);
Unsafe.Add(ref dBase, j + 2) = Unsafe.Add(ref t, p2); Unsafe.Add(ref dBase, j + 2) = Unsafe.Add(ref t, p2);
Unsafe.Add(ref dBase, j + 3) = Unsafe.Add(ref t, p3); Unsafe.Add(ref dBase, j + 3) = Unsafe.Add(ref t, p3);
@ -60,7 +60,7 @@ internal readonly struct XYZWPad3Shuffle4 : IPad3Shuffle4
ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest); ref byte dBase = ref MemoryMarshal.GetReference(dest);
ref byte sEnd = ref Unsafe.Add(ref sBase, source.Length); ref byte sEnd = ref Unsafe.Add(ref sBase, (uint)source.Length);
ref byte sLoopEnd = ref Unsafe.Subtract(ref sEnd, 4); ref byte sLoopEnd = ref Unsafe.Subtract(ref sEnd, 4);
while (Unsafe.IsAddressLessThan(ref sBase, ref sLoopEnd)) while (Unsafe.IsAddressLessThan(ref sBase, ref sLoopEnd))

6
src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs

@ -29,11 +29,11 @@ internal readonly struct DefaultShuffle3 : IShuffle3
ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest); ref byte dBase = ref MemoryMarshal.GetReference(dest);
Shuffle.InverseMMShuffle(this.Control, out _, out int p2, out int p1, out int p0); Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
for (int i = 0; i < source.Length; i += 3) for (nuint i = 0; i < (uint)source.Length; i += 3)
{ {
Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, p0 + i); Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i); Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i);
Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i); Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i);
} }

12
src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs

@ -29,11 +29,11 @@ internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3
ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest); ref byte dBase = ref MemoryMarshal.GetReference(dest);
Shuffle.InverseMMShuffle(this.Control, out _, out int p2, out int p1, out int p0); Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
for (int i = 0, j = 0; i < dest.Length; i += 3, j += 4) for (nuint i = 0, j = 0; i < (uint)dest.Length; i += 3, j += 4)
{ {
Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, p0 + j); Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + j);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + j); Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + j);
Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + j); Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + j);
} }
@ -52,9 +52,9 @@ internal readonly struct XYZWShuffle4Slice3 : IShuffle4Slice3
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source)); ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref Byte3 dBase = ref Unsafe.As<byte, Byte3>(ref MemoryMarshal.GetReference(dest)); ref Byte3 dBase = ref Unsafe.As<byte, Byte3>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4; nint n = (nint)(uint)source.Length / 4;
int m = Numerics.Modulo4(n); nint m = Numerics.Modulo4(n);
int u = n - m; nint u = n - m;
ref uint sLoopEnd = ref Unsafe.Add(ref sBase, u); ref uint sLoopEnd = ref Unsafe.Add(ref sBase, u);
ref uint sEnd = ref Unsafe.Add(ref sBase, n); ref uint sEnd = ref Unsafe.Add(ref sBase, n);

8
src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs

@ -97,12 +97,12 @@ internal static partial class SimdUtils
{ {
VerifySpanInput(source, dest, Vector<byte>.Count); VerifySpanInput(source, dest, Vector<byte>.Count);
int n = dest.Length / Vector<byte>.Count; nuint n = dest.VectorCount<byte>();
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(source)); ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dest)); ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dest));
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector<byte> b = Unsafe.Add(ref sourceBase, i); Vector<byte> b = Unsafe.Add(ref sourceBase, i);
@ -132,13 +132,13 @@ internal static partial class SimdUtils
{ {
VerifySpanInput(source, dest, Vector<byte>.Count); VerifySpanInput(source, dest, Vector<byte>.Count);
int n = dest.Length / Vector<byte>.Count; nuint n = dest.VectorCount<byte>();
ref Vector<float> sourceBase = ref Vector<float> sourceBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source)); ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Vector<byte> destBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(dest)); ref Vector<byte> destBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(dest));
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector<float> s = ref Unsafe.Add(ref sourceBase, i * 4); ref Vector<float> s = ref Unsafe.Add(ref sourceBase, i * 4);

8
src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs

@ -71,7 +71,7 @@ internal static partial class SimdUtils
{ {
VerifySpanInput(source, dest, 4); VerifySpanInput(source, dest, 4);
int count = dest.Length / 4; uint count = (uint)dest.Length / 4;
if (count == 0) if (count == 0)
{ {
return; return;
@ -83,7 +83,7 @@ internal static partial class SimdUtils
const float scale = 1f / 255f; const float scale = 1f / 255f;
Vector4 d = default; Vector4 d = default;
for (int i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
ref ByteVector4 s = ref Unsafe.Add(ref sBase, i); ref ByteVector4 s = ref Unsafe.Add(ref sBase, i);
d.X = s.X; d.X = s.X;
@ -105,7 +105,7 @@ internal static partial class SimdUtils
{ {
VerifySpanInput(source, dest, 4); VerifySpanInput(source, dest, 4);
int count = source.Length / 4; uint count = (uint)source.Length / 4;
if (count == 0) if (count == 0)
{ {
return; return;
@ -117,7 +117,7 @@ internal static partial class SimdUtils
var half = new Vector4(0.5f); var half = new Vector4(0.5f);
var maxBytes = new Vector4(255f); var maxBytes = new Vector4(255f);
for (int i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
Vector4 s = Unsafe.Add(ref sBase, i); Vector4 s = Unsafe.Add(ref sBase, i);
s *= maxBytes; s *= maxBytes;

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

@ -4,6 +4,7 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
@ -13,33 +14,38 @@ internal static partial class SimdUtils
{ {
public static class HwIntrinsics public static class HwIntrinsics
{ {
public static ReadOnlySpan<byte> PermuteMaskDeinterleave8x32 => new byte[] { 0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0 }; [MethodImpl(MethodImplOptions.AggressiveInlining)] // too much IL for JIT to inline, so give a hint
public static Vector256<int> PermuteMaskDeinterleave8x32() => Vector256.Create(0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsInt32();
public static ReadOnlySpan<byte> PermuteMaskEvenOdd8x32 => new byte[] { 0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0 }; [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<uint> PermuteMaskEvenOdd8x32() => Vector256.Create(0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0).AsUInt32();
public static ReadOnlySpan<byte> PermuteMaskSwitchInnerDWords8x32 => new byte[] { 0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0 }; [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<uint> PermuteMaskSwitchInnerDWords8x32() => Vector256.Create(0, 0, 0, 0, 1, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 3, 0, 0, 0, 6, 0, 0, 0, 7, 0, 0, 0).AsUInt32();
private static ReadOnlySpan<byte> MoveFirst24BytesToSeparateLanes => new byte[] { 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0 }; [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector256<uint> MoveFirst24BytesToSeparateLanes() => Vector256.Create(0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0).AsUInt32();
internal static ReadOnlySpan<byte> ExtractRgb => new byte[] { 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11, 0xFF, 0xFF, 0xFF, 0xFF }; [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector256<byte> ExtractRgb() => Vector256.Create(0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11, 0xFF, 0xFF, 0xFF, 0xFF, 0, 3, 6, 9, 1, 4, 7, 10, 2, 5, 8, 11, 0xFF, 0xFF, 0xFF, 0xFF);
private static ReadOnlySpan<byte> ShuffleMaskPad4Nx16 => new byte[] { 0, 1, 2, 0x80, 3, 4, 5, 0x80, 6, 7, 8, 0x80, 9, 10, 11, 0x80 }; [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<byte> ShuffleMaskPad4Nx16() => Vector128.Create(0, 1, 2, 0x80, 3, 4, 5, 0x80, 6, 7, 8, 0x80, 9, 10, 11, 0x80);
private static ReadOnlySpan<byte> ShuffleMaskSlice4Nx16 => new byte[] { 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80 }; [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector128<byte> ShuffleMaskSlice4Nx16() => Vector128.Create(0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80);
private static ReadOnlySpan<byte> ShuffleMaskShiftAlpha => #pragma warning disable SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines
new byte[] [MethodImpl(MethodImplOptions.AggressiveInlining)]
{ private static Vector256<byte> ShuffleMaskShiftAlpha() => Vector256.Create((byte)
0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15, 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15,
0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15);
};
public static ReadOnlySpan<byte> PermuteMaskShiftAlpha8x32 => [MethodImpl(MethodImplOptions.AggressiveInlining)]
new byte[] public static Vector256<uint> PermuteMaskShiftAlpha8x32() => Vector256.Create(
{ 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0,
0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 5, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsUInt32();
5, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0 #pragma warning restore SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines
};
/// <summary> /// <summary>
/// Shuffle single-precision (32-bit) floating-point elements in <paramref name="source"/> /// Shuffle single-precision (32-bit) floating-point elements in <paramref name="source"/>
@ -159,7 +165,7 @@ internal static partial class SimdUtils
int remainder = source.Length % (Vector128<byte>.Count * 3); int remainder = source.Length % (Vector128<byte>.Count * 3);
int sourceCount = source.Length - remainder; int sourceCount = source.Length - remainder;
int destCount = sourceCount * 4 / 3; int destCount = (int)((uint)sourceCount * 4 / 3);
if (sourceCount > 0) if (sourceCount > 0)
{ {
@ -189,10 +195,10 @@ internal static partial class SimdUtils
{ {
if (Ssse3.IsSupported) if (Ssse3.IsSupported)
{ {
int remainder = source.Length % (Vector128<byte>.Count * 4); int remainder = source.Length & ((Vector128<byte>.Count * 4) - 1); // bit-hack for modulo
int sourceCount = source.Length - remainder; int sourceCount = source.Length - remainder;
int destCount = sourceCount * 3 / 4; int destCount = (int)((uint)sourceCount * 3 / 4);
if (sourceCount > 0) if (sourceCount > 0)
{ {
@ -221,11 +227,11 @@ internal static partial class SimdUtils
ref Vector256<float> destBase = ref Vector256<float> destBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector256<float>.Count; nint n = (nint)dest.Vector256Count<float>();
int m = Numerics.Modulo4(n); nint m = Numerics.Modulo4(n);
int u = n - m; nint u = n - m;
for (int i = 0; i < u; i += 4) for (nint i = 0; i < u; i += 4)
{ {
ref Vector256<float> vd0 = ref Unsafe.Add(ref destBase, i); ref Vector256<float> vd0 = ref Unsafe.Add(ref destBase, i);
ref Vector256<float> vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector256<float> vs0 = ref Unsafe.Add(ref sourceBase, i);
@ -238,7 +244,7 @@ internal static partial class SimdUtils
if (m > 0) if (m > 0)
{ {
for (int i = u; i < n; i++) for (nint i = u; i < n; i++)
{ {
Unsafe.Add(ref destBase, i) = Avx.Permute(Unsafe.Add(ref sourceBase, i), control); Unsafe.Add(ref destBase, i) = Avx.Permute(Unsafe.Add(ref sourceBase, i), control);
} }
@ -253,11 +259,11 @@ internal static partial class SimdUtils
ref Vector128<float> destBase = ref Vector128<float> destBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector128<float>.Count; nint n = (nint)((uint)dest.Length / (uint)Vector128<float>.Count);
int m = Numerics.Modulo4(n); nint m = Numerics.Modulo4(n);
int u = n - m; nint u = n - m;
for (int i = 0; i < u; i += 4) for (nint i = 0; i < u; i += 4)
{ {
ref Vector128<float> vd0 = ref Unsafe.Add(ref destBase, i); ref Vector128<float> vd0 = ref Unsafe.Add(ref destBase, i);
ref Vector128<float> vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector128<float> vs0 = ref Unsafe.Add(ref sourceBase, i);
@ -276,7 +282,7 @@ internal static partial class SimdUtils
if (m > 0) if (m > 0)
{ {
for (int i = u; i < n; i++) for (nint i = u; i < n; i++)
{ {
Vector128<float> vs = Unsafe.Add(ref sourceBase, i); Vector128<float> vs = Unsafe.Add(ref sourceBase, i);
Unsafe.Add(ref destBase, i) = Sse.Shuffle(vs, vs, control); Unsafe.Add(ref destBase, i) = Sse.Shuffle(vs, vs, control);
@ -306,11 +312,11 @@ internal static partial class SimdUtils
ref Vector256<byte> destBase = ref Vector256<byte> destBase =
ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector256<byte>.Count; nint n = (nint)((uint)dest.Length / (uint)Vector256<byte>.Count);
int m = Numerics.Modulo4(n); nint m = Numerics.Modulo4(n);
int u = n - m; nint u = n - m;
for (int i = 0; i < u; i += 4) for (nint i = 0; i < u; i += 4)
{ {
ref Vector256<byte> vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector256<byte> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector256<byte> vd0 = ref Unsafe.Add(ref destBase, i); ref Vector256<byte> vd0 = ref Unsafe.Add(ref destBase, i);
@ -323,7 +329,7 @@ internal static partial class SimdUtils
if (m > 0) if (m > 0)
{ {
for (int i = u; i < n; i++) for (nint i = u; i < n; i++)
{ {
Unsafe.Add(ref destBase, i) = Avx2.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle); Unsafe.Add(ref destBase, i) = Avx2.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle);
} }
@ -342,11 +348,11 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase = ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector128<byte>.Count; nint n = (nint)((uint)dest.Length / (uint)Vector128<byte>.Count);
int m = Numerics.Modulo4(n); nint m = Numerics.Modulo4(n);
int u = n - m; nint u = n - m;
for (int i = 0; i < u; i += 4) for (nint i = 0; i < u; i += 4)
{ {
ref Vector128<byte> vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector128<byte> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector128<byte> vd0 = ref Unsafe.Add(ref destBase, i); ref Vector128<byte> vd0 = ref Unsafe.Add(ref destBase, i);
@ -359,7 +365,7 @@ internal static partial class SimdUtils
if (m > 0) if (m > 0)
{ {
for (int i = u; i < n; i++) for (nint i = u; i < n; i++)
{ {
Unsafe.Add(ref destBase, i) = Ssse3.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle); Unsafe.Add(ref destBase, i) = Ssse3.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle);
} }
@ -375,10 +381,8 @@ internal static partial class SimdUtils
{ {
if (Ssse3.IsSupported) if (Ssse3.IsSupported)
{ {
ref byte vmaskBase = ref MemoryMarshal.GetReference(ShuffleMaskPad4Nx16); Vector128<byte> vmask = ShuffleMaskPad4Nx16();
Vector128<byte> vmask = Unsafe.As<byte, Vector128<byte>>(ref vmaskBase); Vector128<byte> vmasko = ShuffleMaskSlice4Nx16();
ref byte vmaskoBase = ref MemoryMarshal.GetReference(ShuffleMaskSlice4Nx16);
Vector128<byte> vmasko = Unsafe.As<byte, Vector128<byte>>(ref vmaskoBase);
Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12); Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12);
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count]; Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
@ -391,9 +395,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase = ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / Vector128<byte>.Count; nuint n = source.Vector128Count<byte>();
for (int i = 0; i < n; i += 3) for (nuint i = 0; i < n; i += 3)
{ {
ref Vector128<byte> vs = ref Unsafe.Add(ref sourceBase, i); ref Vector128<byte> vs = ref Unsafe.Add(ref sourceBase, i);
@ -440,8 +444,7 @@ internal static partial class SimdUtils
{ {
if (Ssse3.IsSupported) if (Ssse3.IsSupported)
{ {
ref byte vmaskBase = ref MemoryMarshal.GetReference(ShuffleMaskPad4Nx16); Vector128<byte> vmask = ShuffleMaskPad4Nx16();
Vector128<byte> vmask = Unsafe.As<byte, Vector128<byte>>(ref vmaskBase);
Vector128<byte> vfill = Vector128.Create(0xff000000ff000000ul).AsByte(); Vector128<byte> vfill = Vector128.Create(0xff000000ff000000ul).AsByte();
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count]; Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
@ -454,9 +457,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase = ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / Vector128<byte>.Count; nuint n = source.Vector128Count<byte>();
for (int i = 0, j = 0; i < n; i += 3, j += 4) for (nuint i = 0, j = 0; i < n; i += 3, j += 4)
{ {
ref Vector128<byte> v0 = ref Unsafe.Add(ref sourceBase, i); ref Vector128<byte> v0 = ref Unsafe.Add(ref sourceBase, i);
Vector128<byte> v1 = Unsafe.Add(ref v0, 1); Vector128<byte> v1 = Unsafe.Add(ref v0, 1);
@ -484,8 +487,7 @@ internal static partial class SimdUtils
{ {
if (Ssse3.IsSupported) if (Ssse3.IsSupported)
{ {
ref byte vmaskoBase = ref MemoryMarshal.GetReference(ShuffleMaskSlice4Nx16); Vector128<byte> vmasko = ShuffleMaskSlice4Nx16();
Vector128<byte> vmasko = Unsafe.As<byte, Vector128<byte>>(ref vmaskoBase);
Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12); Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12);
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count]; Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
@ -498,9 +500,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase = ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / Vector128<byte>.Count; nuint n = source.Vector128Count<byte>();
for (int i = 0, j = 0; i < n; i += 4, j += 3) for (nuint i = 0, j = 0; i < n; i += 4, j += 3)
{ {
ref Vector128<byte> vs = ref Unsafe.Add(ref sourceBase, i); ref Vector128<byte> vs = ref Unsafe.Add(ref sourceBase, i);
@ -542,9 +544,9 @@ internal static partial class SimdUtils
/// <returns>The <see cref="Vector256{T}"/>.</returns> /// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.AlwaysInline)] [MethodImpl(InliningOptions.AlwaysInline)]
public static Vector256<float> MultiplyAdd( public static Vector256<float> MultiplyAdd(
in Vector256<float> va, Vector256<float> va,
in Vector256<float> vm0, Vector256<float> vm0,
in Vector256<float> vm1) Vector256<float> vm1)
{ {
if (Fma.IsSupported) if (Fma.IsSupported)
{ {
@ -554,6 +556,34 @@ internal static partial class SimdUtils
return Avx.Add(Avx.Multiply(vm0, vm1), va); return Avx.Add(Avx.Multiply(vm0, vm1), va);
} }
/// <summary>
/// Performs a multiplication and an addition of the <see cref="Vector128{Single}"/>.
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic.
/// </summary>
/// <remarks>ret = (vm0 * vm1) + va</remarks>
/// <param name="va">The vector to add to the intermediate result.</param>
/// <param name="vm0">The first vector to multiply.</param>
/// <param name="vm1">The second vector to multiply.</param>
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.AlwaysInline)]
public static Vector128<float> MultiplyAdd(
Vector128<float> va,
Vector128<float> vm0,
Vector128<float> vm1)
{
if (Fma.IsSupported)
{
return Fma.MultiplyAdd(vm1, vm0, va);
}
if (AdvSimd.IsSupported)
{
return AdvSimd.Add(AdvSimd.Multiply(vm0, vm1), va);
}
return Sse.Add(Sse.Multiply(vm0, vm1), va);
}
/// <summary> /// <summary>
/// Performs a multiplication and a subtraction of the <see cref="Vector256{Single}"/>. /// Performs a multiplication and a subtraction of the <see cref="Vector256{Single}"/>.
/// TODO: Fix. The arguments are in a different order to the FMA intrinsic. /// TODO: Fix. The arguments are in a different order to the FMA intrinsic.
@ -565,9 +595,9 @@ internal static partial class SimdUtils
/// <returns>The <see cref="Vector256{T}"/>.</returns> /// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static Vector256<float> MultiplySubtract( public static Vector256<float> MultiplySubtract(
in Vector256<float> vs, Vector256<float> vs,
in Vector256<float> vm0, Vector256<float> vm0,
in Vector256<float> vm1) Vector256<float> vm1)
{ {
if (Fma.IsSupported) if (Fma.IsSupported)
{ {
@ -587,9 +617,9 @@ internal static partial class SimdUtils
/// <returns>The <see cref="Vector256{T}"/>.</returns> /// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static Vector256<float> MultiplyAddNegated( public static Vector256<float> MultiplyAddNegated(
in Vector256<float> a, Vector256<float> a,
in Vector256<float> b, Vector256<float> b,
in Vector256<float> c) Vector256<float> c)
{ {
if (Fma.IsSupported) if (Fma.IsSupported)
{ {
@ -650,16 +680,16 @@ internal static partial class SimdUtils
{ {
VerifySpanInput(source, dest, Vector256<byte>.Count); VerifySpanInput(source, dest, Vector256<byte>.Count);
int n = dest.Length / Vector256<byte>.Count; nuint n = dest.Vector256Count<byte>();
ref Vector256<float> destBase = ref Vector256<float> destBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest));
var scale = Vector256.Create(1 / (float)byte.MaxValue); Vector256<float> scale = Vector256.Create(1 / (float)byte.MaxValue);
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
int si = Vector256<byte>.Count * i; nuint si = (uint)Vector256<byte>.Count * i;
Vector256<int> i0 = Avx2.ConvertToVector256Int32(sourceBase + si); Vector256<int> i0 = Avx2.ConvertToVector256Int32(sourceBase + si);
Vector256<int> i1 = Avx2.ConvertToVector256Int32(sourceBase + si + Vector256<int>.Count); Vector256<int> i1 = Avx2.ConvertToVector256Int32(sourceBase + si + Vector256<int>.Count);
Vector256<int> i2 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256<int>.Count * 2)); Vector256<int> i2 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256<int>.Count * 2));
@ -683,17 +713,17 @@ internal static partial class SimdUtils
// Sse // Sse
VerifySpanInput(source, dest, Vector128<byte>.Count); VerifySpanInput(source, dest, Vector128<byte>.Count);
int n = dest.Length / Vector128<byte>.Count; nuint n = dest.Vector128Count<byte>();
ref Vector128<float> destBase = ref Vector128<float> destBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(dest));
var scale = Vector128.Create(1 / (float)byte.MaxValue); Vector128<float> scale = Vector128.Create(1 / (float)byte.MaxValue);
Vector128<byte> zero = Vector128<byte>.Zero; Vector128<byte> zero = Vector128<byte>.Zero;
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
int si = Vector128<byte>.Count * i; nuint si = (uint)Vector128<byte>.Count * i;
Vector128<int> i0, i1, i2, i3; Vector128<int> i0, i1, i2, i3;
if (Sse41.IsSupported) if (Sse41.IsSupported)
@ -782,7 +812,7 @@ internal static partial class SimdUtils
{ {
VerifySpanInput(source, dest, Vector256<byte>.Count); VerifySpanInput(source, dest, Vector256<byte>.Count);
int n = dest.Length / Vector256<byte>.Count; nuint n = dest.Vector256Count<byte>();
ref Vector256<float> sourceBase = ref Vector256<float> sourceBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source)); ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source));
@ -790,11 +820,10 @@ internal static partial class SimdUtils
ref Vector256<byte> destBase = ref Vector256<byte> destBase =
ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(dest));
var scale = Vector256.Create((float)byte.MaxValue); Vector256<float> scale = Vector256.Create((float)byte.MaxValue);
ref byte maskBase = ref MemoryMarshal.GetReference(PermuteMaskDeinterleave8x32); Vector256<int> mask = PermuteMaskDeinterleave8x32();
Vector256<int> mask = Unsafe.As<byte, Vector256<int>>(ref maskBase);
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector256<float> s = ref Unsafe.Add(ref sourceBase, i * 4); ref Vector256<float> s = ref Unsafe.Add(ref sourceBase, i * 4);
@ -821,7 +850,7 @@ internal static partial class SimdUtils
// Sse // Sse
VerifySpanInput(source, dest, Vector128<byte>.Count); VerifySpanInput(source, dest, Vector128<byte>.Count);
int n = dest.Length / Vector128<byte>.Count; nuint n = dest.Vector128Count<byte>();
ref Vector128<float> sourceBase = ref Vector128<float> sourceBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(source)); ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(source));
@ -829,9 +858,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase = ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest)); ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
var scale = Vector128.Create((float)byte.MaxValue); Vector128<float> scale = Vector128.Create((float)byte.MaxValue);
for (int i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector128<float> s = ref Unsafe.Add(ref sourceBase, i * 4); ref Vector128<float> s = ref Unsafe.Add(ref sourceBase, i * 4);
@ -864,18 +893,16 @@ internal static partial class SimdUtils
ref Vector256<byte> bBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(blueChannel)); ref Vector256<byte> bBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(blueChannel));
ref byte dBase = ref Unsafe.As<Rgb24, byte>(ref MemoryMarshal.GetReference(destination)); ref byte dBase = ref Unsafe.As<Rgb24, byte>(ref MemoryMarshal.GetReference(destination));
int count = redChannel.Length / Vector256<byte>.Count; nuint count = redChannel.Vector256Count<byte>();
ref byte control1Bytes = ref MemoryMarshal.GetReference(PermuteMaskEvenOdd8x32); Vector256<uint> control1 = PermuteMaskEvenOdd8x32();
Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes);
ref byte control2Bytes = ref MemoryMarshal.GetReference(PermuteMaskShiftAlpha8x32); Vector256<uint> control2 = PermuteMaskShiftAlpha8x32();
Vector256<uint> control2 = Unsafe.As<byte, Vector256<uint>>(ref control2Bytes); Vector256<byte> a = Vector256.Create((byte)255);
var a = Vector256.Create((byte)255);
Vector256<byte> shuffleAlpha = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(ShuffleMaskShiftAlpha)); Vector256<byte> shuffleAlpha = ShuffleMaskShiftAlpha();
for (int i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
Vector256<byte> r0 = Unsafe.Add(ref rBase, i); Vector256<byte> r0 = Unsafe.Add(ref rBase, i);
Vector256<byte> g0 = Unsafe.Add(ref gBase, i); Vector256<byte> g0 = Unsafe.Add(ref gBase, i);
@ -918,7 +945,7 @@ internal static partial class SimdUtils
Unsafe.As<byte, Vector256<byte>>(ref d4) = rgb4; Unsafe.As<byte, Vector256<byte>>(ref d4) = rgb4;
} }
int slice = count * Vector256<byte>.Count; int slice = (int)count * Vector256<byte>.Count;
redChannel = redChannel[slice..]; redChannel = redChannel[slice..];
greenChannel = greenChannel[slice..]; greenChannel = greenChannel[slice..];
blueChannel = blueChannel[slice..]; blueChannel = blueChannel[slice..];
@ -936,12 +963,11 @@ internal static partial class SimdUtils
ref Vector256<byte> bBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(blueChannel)); ref Vector256<byte> bBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(blueChannel));
ref Vector256<byte> dBase = ref Unsafe.As<Rgba32, Vector256<byte>>(ref MemoryMarshal.GetReference(destination)); ref Vector256<byte> dBase = ref Unsafe.As<Rgba32, Vector256<byte>>(ref MemoryMarshal.GetReference(destination));
int count = redChannel.Length / Vector256<byte>.Count; nuint count = redChannel.Vector256Count<byte>();
ref byte control1Bytes = ref MemoryMarshal.GetReference(PermuteMaskEvenOdd8x32); Vector256<uint> control1 = PermuteMaskEvenOdd8x32();
Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes); Vector256<byte> a = Vector256.Create((byte)255);
var a = Vector256.Create((byte)255);
for (int i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
Vector256<byte> r0 = Unsafe.Add(ref rBase, i); Vector256<byte> r0 = Unsafe.Add(ref rBase, i);
Vector256<byte> g0 = Unsafe.Add(ref gBase, i); Vector256<byte> g0 = Unsafe.Add(ref gBase, i);
@ -970,7 +996,7 @@ internal static partial class SimdUtils
Unsafe.Add(ref d0, 3) = rgb4; Unsafe.Add(ref d0, 3) = rgb4;
} }
int slice = count * Vector256<byte>.Count; int slice = (int)count * Vector256<byte>.Count;
redChannel = redChannel[slice..]; redChannel = redChannel[slice..];
greenChannel = greenChannel[slice..]; greenChannel = greenChannel[slice..];
blueChannel = blueChannel[slice..]; blueChannel = blueChannel[slice..];
@ -988,16 +1014,16 @@ internal static partial class SimdUtils
ref Vector256<float> destGRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(greenChannel)); ref Vector256<float> destGRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(greenChannel));
ref Vector256<float> destBRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(blueChannel)); ref Vector256<float> destBRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(blueChannel));
Vector256<uint> extractToLanesMask = Unsafe.As<byte, Vector256<uint>>(ref MemoryMarshal.GetReference(MoveFirst24BytesToSeparateLanes)); Vector256<uint> extractToLanesMask = MoveFirst24BytesToSeparateLanes();
Vector256<byte> extractRgbMask = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(ExtractRgb)); Vector256<byte> extractRgbMask = ExtractRgb();
Vector256<byte> rgb, rg, bx; Vector256<byte> rgb, rg, bx;
Vector256<float> r, g, b; Vector256<float> r, g, b;
const int bytesPerRgbStride = 24; const int bytesPerRgbStride = 24;
int count = (int)((uint)source.Length / 8); nuint count = (uint)source.Length / 8;
for (int i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
rgb = Avx2.PermuteVar8x32(Unsafe.AddByteOffset(ref rgbByteSpan, (IntPtr)(bytesPerRgbStride * i)).AsUInt32(), extractToLanesMask).AsByte(); rgb = Avx2.PermuteVar8x32(Unsafe.AddByteOffset(ref rgbByteSpan, (uint)(bytesPerRgbStride * i)).AsUInt32(), extractToLanesMask).AsByte();
rgb = Avx2.Shuffle(rgb, extractRgbMask); rgb = Avx2.Shuffle(rgb, extractRgbMask);
@ -1013,7 +1039,7 @@ internal static partial class SimdUtils
Unsafe.Add(ref destBRef, i) = b; Unsafe.Add(ref destBRef, i) = b;
} }
int sliceCount = count * 8; int sliceCount = (int)(count * 8);
redChannel = redChannel.Slice(sliceCount); redChannel = redChannel.Slice(sliceCount);
greenChannel = greenChannel.Slice(sliceCount); greenChannel = greenChannel.Slice(sliceCount);
blueChannel = blueChannel.Slice(sliceCount); blueChannel = blueChannel.Slice(sliceCount);

18
src/ImageSharp/Common/Helpers/SimdUtils.Pack.cs

@ -86,8 +86,8 @@ internal static partial class SimdUtils
ref ByteTuple4 b = ref Unsafe.As<byte, ByteTuple4>(ref MemoryMarshal.GetReference(blueChannel)); ref ByteTuple4 b = ref Unsafe.As<byte, ByteTuple4>(ref MemoryMarshal.GetReference(blueChannel));
ref Rgb24 rgb = ref MemoryMarshal.GetReference(destination); ref Rgb24 rgb = ref MemoryMarshal.GetReference(destination);
int count = redChannel.Length / 4; nuint count = (uint)redChannel.Length / 4;
for (int i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
ref Rgb24 d0 = ref Unsafe.Add(ref rgb, i * 4); ref Rgb24 d0 = ref Unsafe.Add(ref rgb, i * 4);
ref Rgb24 d1 = ref Unsafe.Add(ref d0, 1); ref Rgb24 d1 = ref Unsafe.Add(ref d0, 1);
@ -115,7 +115,7 @@ internal static partial class SimdUtils
d3.B = bb.V3; d3.B = bb.V3;
} }
int finished = count * 4; int finished = (int)(count * 4);
redChannel = redChannel[finished..]; redChannel = redChannel[finished..];
greenChannel = greenChannel[finished..]; greenChannel = greenChannel[finished..];
blueChannel = blueChannel[finished..]; blueChannel = blueChannel[finished..];
@ -133,9 +133,9 @@ internal static partial class SimdUtils
ref ByteTuple4 b = ref Unsafe.As<byte, ByteTuple4>(ref MemoryMarshal.GetReference(blueChannel)); ref ByteTuple4 b = ref Unsafe.As<byte, ByteTuple4>(ref MemoryMarshal.GetReference(blueChannel));
ref Rgba32 rgb = ref MemoryMarshal.GetReference(destination); ref Rgba32 rgb = ref MemoryMarshal.GetReference(destination);
int count = redChannel.Length / 4; nuint count = (uint)redChannel.Length / 4;
destination.Fill(new Rgba32(0, 0, 0, 255)); destination.Fill(new Rgba32(0, 0, 0, 255));
for (int i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
ref Rgba32 d0 = ref Unsafe.Add(ref rgb, i * 4); ref Rgba32 d0 = ref Unsafe.Add(ref rgb, i * 4);
ref Rgba32 d1 = ref Unsafe.Add(ref d0, 1); ref Rgba32 d1 = ref Unsafe.Add(ref d0, 1);
@ -163,7 +163,7 @@ internal static partial class SimdUtils
d3.B = bb.V3; d3.B = bb.V3;
} }
int finished = count * 4; int finished = (int)(count * 4);
redChannel = redChannel[finished..]; redChannel = redChannel[finished..];
greenChannel = greenChannel[finished..]; greenChannel = greenChannel[finished..];
blueChannel = blueChannel[finished..]; blueChannel = blueChannel[finished..];
@ -181,7 +181,7 @@ internal static partial class SimdUtils
ref byte b = ref MemoryMarshal.GetReference(blueChannel); ref byte b = ref MemoryMarshal.GetReference(blueChannel);
ref Rgb24 rgb = ref MemoryMarshal.GetReference(destination); ref Rgb24 rgb = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < destination.Length; i++) for (nuint i = 0; i < (uint)destination.Length; i++)
{ {
ref Rgb24 d = ref Unsafe.Add(ref rgb, i); ref Rgb24 d = ref Unsafe.Add(ref rgb, i);
d.R = Unsafe.Add(ref r, i); d.R = Unsafe.Add(ref r, i);
@ -201,7 +201,7 @@ internal static partial class SimdUtils
ref byte b = ref MemoryMarshal.GetReference(blueChannel); ref byte b = ref MemoryMarshal.GetReference(blueChannel);
ref Rgba32 rgba = ref MemoryMarshal.GetReference(destination); ref Rgba32 rgba = ref MemoryMarshal.GetReference(destination);
for (int i = 0; i < destination.Length; i++) for (nuint i = 0; i < (uint)destination.Length; i++)
{ {
ref Rgba32 d = ref Unsafe.Add(ref rgba, i); ref Rgba32 d = ref Unsafe.Add(ref rgba, i);
d.R = Unsafe.Add(ref r, i); d.R = Unsafe.Add(ref r, i);
@ -226,7 +226,7 @@ internal static partial class SimdUtils
ref float b = ref MemoryMarshal.GetReference(blueChannel); ref float b = ref MemoryMarshal.GetReference(blueChannel);
ref Rgb24 rgb = ref MemoryMarshal.GetReference(source); ref Rgb24 rgb = ref MemoryMarshal.GetReference(source);
for (int i = 0; i < source.Length; i++) for (nuint i = 0; i < (uint)source.Length; i++)
{ {
ref Rgb24 src = ref Unsafe.Add(ref rgb, i); ref Rgb24 src = ref Unsafe.Add(ref rgb, i);
Unsafe.Add(ref r, i) = src.R; Unsafe.Add(ref r, i) = src.R;

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

@ -145,11 +145,11 @@ internal static partial class SimdUtils
{ {
ref float sBase = ref MemoryMarshal.GetReference(source); ref float sBase = ref MemoryMarshal.GetReference(source);
ref float dBase = ref MemoryMarshal.GetReference(dest); ref float dBase = ref MemoryMarshal.GetReference(dest);
Shuffle.InverseMMShuffle(control, out int p3, out int p2, out int p1, out int p0); Shuffle.InverseMMShuffle(control, out uint p3, out uint p2, out uint p1, out uint p0);
for (int i = 0; i < source.Length; i += 4) for (nuint i = 0; i < (uint)source.Length; i += 4)
{ {
Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, p0 + i); Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i); Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i);
Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i); Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i);
Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i); Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i);
@ -492,16 +492,16 @@ internal static partial class SimdUtils
{ {
InverseMMShuffle( InverseMMShuffle(
control, control,
out int p3, out uint p3,
out int p2, out uint p2,
out int p1, out uint p1,
out int p0); out uint p0);
ref byte spanBase = ref MemoryMarshal.GetReference(span); ref byte spanBase = ref MemoryMarshal.GetReference(span);
for (int i = 0; i < span.Length; i += 4) for (nuint i = 0; i < (uint)span.Length; i += 4)
{ {
Unsafe.Add(ref spanBase, i) = (byte)(p0 + i); Unsafe.Add(ref spanBase, i + 0) = (byte)(p0 + i);
Unsafe.Add(ref spanBase, i + 1) = (byte)(p1 + i); Unsafe.Add(ref spanBase, i + 1) = (byte)(p1 + i);
Unsafe.Add(ref spanBase, i + 2) = (byte)(p2 + i); Unsafe.Add(ref spanBase, i + 2) = (byte)(p2 + i);
Unsafe.Add(ref spanBase, i + 3) = (byte)(p3 + i); Unsafe.Add(ref spanBase, i + 3) = (byte)(p3 + i);
@ -511,15 +511,15 @@ internal static partial class SimdUtils
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public static void InverseMMShuffle( public static void InverseMMShuffle(
byte control, byte control,
out int p3, out uint p3,
out int p2, out uint p2,
out int p1, out uint p1,
out int p0) out uint p0)
{ {
p3 = (control >> 6) & 0x3; p3 = (uint)((control >> 6) & 0x3);
p2 = (control >> 4) & 0x3; p2 = (uint)((control >> 4) & 0x3);
p1 = (control >> 2) & 0x3; p1 = (uint)((control >> 2) & 0x3);
p0 = (control >> 0) & 0x3; p0 = (uint)((control >> 0) & 0x3);
} }
} }
} }

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

@ -300,7 +300,7 @@ internal static partial class Crc32
for (int i = 0; i < buffer.Length; i++) for (int i = 0; i < buffer.Length; i++)
{ {
crc = Unsafe.Add(ref crcTableRef, (int)((crc ^ Unsafe.Add(ref bufferRef, i)) & 0xFF)) ^ (crc >> 8); crc = Unsafe.Add(ref crcTableRef, (crc ^ Unsafe.Add(ref bufferRef, i)) & 0xFF) ^ (crc >> 8);
} }
return crc; return crc;

5
src/ImageSharp/Compression/Zlib/DeflaterEngine.cs

@ -3,6 +3,7 @@
using System.Buffers; using System.Buffers;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Compression.Zlib; namespace SixLabors.ImageSharp.Compression.Zlib;
@ -426,8 +427,8 @@ internal sealed unsafe class DeflaterEngine : IDisposable
private void SlideWindow() private void SlideWindow()
{ {
Unsafe.CopyBlockUnaligned( Unsafe.CopyBlockUnaligned(
ref this.window.Span[0], ref MemoryMarshal.GetReference(this.window.Span),
ref this.window.Span[DeflaterConstants.WSIZE], ref Unsafe.Add(ref MemoryMarshal.GetReference(this.window.Span), DeflaterConstants.WSIZE),
DeflaterConstants.WSIZE); DeflaterConstants.WSIZE);
this.matchStart -= DeflaterConstants.WSIZE; this.matchStart -= DeflaterConstants.WSIZE;

100
src/ImageSharp/Compression/Zlib/DeflaterHuffman.cs

@ -206,8 +206,8 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int lc = Lcode(litlen); int lc = Lcode(litlen);
this.literalTree.WriteSymbol(pendingBuffer, lc); this.literalTree.WriteSymbol(pendingBuffer, lc);
int bits = (lc - 261) / 4; int bits = (int)(((uint)lc - 261) / 4);
if (bits > 0 && bits <= 5) if (bits is > 0 and <= 5)
{ {
this.Pending.WriteBits(litlen & ((1 << bits) - 1), bits); this.Pending.WriteBits(litlen & ((1 << bits) - 1), bits);
} }
@ -286,13 +286,13 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int static_len = this.extraBits; int static_len = this.extraBits;
ref byte staticLLengthRef = ref MemoryMarshal.GetReference(StaticLLength); ref byte staticLLengthRef = ref MemoryMarshal.GetReference(StaticLLength);
for (int i = 0; i < LiteralNumber; i++) for (nuint i = 0; i < LiteralNumber; i++)
{ {
static_len += this.literalTree.Frequencies[i] * Unsafe.Add(ref staticLLengthRef, i); static_len += this.literalTree.Frequencies[i] * Unsafe.Add(ref staticLLengthRef, i);
} }
ref byte staticDLengthRef = ref MemoryMarshal.GetReference(StaticDLength); ref byte staticDLengthRef = ref MemoryMarshal.GetReference(StaticDLength);
for (int i = 0; i < DistanceNumber; i++) for (nuint i = 0; i < DistanceNumber; i++)
{ {
static_len += this.distTree.Frequencies[i] * Unsafe.Add(ref staticDLengthRef, i); static_len += this.distTree.Frequencies[i] * Unsafe.Add(ref staticDLengthRef, i);
} }
@ -364,7 +364,7 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
this.literalTree.Frequencies[lc]++; this.literalTree.Frequencies[lc]++;
if (lc >= 265 && lc < 285) if (lc >= 265 && lc < 285)
{ {
this.extraBits += (lc - 261) / 4; this.extraBits += (int)(((uint)lc - 261) / 4);
} }
int dc = Dcode(distance - 1); int dc = Dcode(distance - 1);
@ -405,10 +405,10 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
ref byte bit4ReverseRef = ref MemoryMarshal.GetReference(Bit4Reverse); ref byte bit4ReverseRef = ref MemoryMarshal.GetReference(Bit4Reverse);
return (short)(Unsafe.Add(ref bit4ReverseRef, toReverse & 0xF) << 12 return (short)((Unsafe.Add(ref bit4ReverseRef, (uint)toReverse & 0xF) << 12)
| Unsafe.Add(ref bit4ReverseRef, (toReverse >> 4) & 0xF) << 8 | (Unsafe.Add(ref bit4ReverseRef, (uint)(toReverse >> 4) & 0xF) << 8)
| Unsafe.Add(ref bit4ReverseRef, (toReverse >> 8) & 0xF) << 4 | (Unsafe.Add(ref bit4ReverseRef, (uint)(toReverse >> 8) & 0xF) << 4)
| Unsafe.Add(ref bit4ReverseRef, toReverseRightShiftBy12)); | Unsafe.Add(ref bit4ReverseRef, (uint)toReverseRightShiftBy12));
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -551,8 +551,8 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int code = 0; int code = 0;
for (int bits = 0; bits < this.maxLength; bits++) for (int bits = 0; bits < this.maxLength; bits++)
{ {
Unsafe.Add(ref nextCodeRef, bits) = code; Unsafe.Add(ref nextCodeRef, (uint)bits) = code;
code += Unsafe.Add(ref bitLengthCountsRef, bits) << (15 - bits); code += Unsafe.Add(ref bitLengthCountsRef, (uint)bits) << (15 - bits);
} }
for (int i = 0; i < this.NumCodes; i++) for (int i = 0; i < this.NumCodes; i++)
@ -560,8 +560,8 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int bits = this.Length[i]; int bits = this.Length[i];
if (bits > 0) if (bits > 0)
{ {
this.codes[i] = BitReverse(Unsafe.Add(ref nextCodeRef, bits - 1)); this.codes[i] = BitReverse(Unsafe.Add(ref nextCodeRef, (uint)(bits - 1)));
Unsafe.Add(ref nextCodeRef, bits - 1) += 1 << (16 - bits); Unsafe.Add(ref nextCodeRef, (uint)(bits - 1)) += 1 << (16 - bits);
} }
} }
} }
@ -593,13 +593,13 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
// Insert n into heap // Insert n into heap
int pos = heapLen++; int pos = heapLen++;
int ppos; int ppos;
while (pos > 0 && this.Frequencies[Unsafe.Add(ref heapRef, ppos = (pos - 1) >> 1)] > freq) while (pos > 0 && this.Frequencies[Unsafe.Add(ref heapRef, (uint)(ppos = (pos - 1) >> 1))] > freq)
{ {
Unsafe.Add(ref heapRef, pos) = Unsafe.Add(ref heapRef, ppos); Unsafe.Add(ref heapRef, pos) = Unsafe.Add(ref heapRef, (uint)ppos);
pos = ppos; pos = ppos;
} }
Unsafe.Add(ref heapRef, pos) = n; Unsafe.Add(ref heapRef, (uint)pos) = n;
maxCode = n; maxCode = n;
} }
@ -611,7 +611,7 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
// this case, both literals get a 1 bit code. // this case, both literals get a 1 bit code.
while (heapLen < 2) while (heapLen < 2)
{ {
Unsafe.Add(ref heapRef, heapLen++) = maxCode < 2 ? ++maxCode : 0; Unsafe.Add(ref heapRef, (uint)heapLen++) = maxCode < 2 ? ++maxCode : 0;
} }
this.NumCodes = Math.Max(maxCode + 1, this.minNumCodes); this.NumCodes = Math.Max(maxCode + 1, this.minNumCodes);
@ -625,14 +625,14 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
ref int valuesRef = ref MemoryMarshal.GetReference(valuesMemoryOwner.Memory.Span); ref int valuesRef = ref MemoryMarshal.GetReference(valuesMemoryOwner.Memory.Span);
int numNodes = numLeafs; int numNodes = numLeafs;
for (int i = 0; i < heapLen; i++) for (nuint i = 0; i < (uint)heapLen; i++)
{ {
int node = Unsafe.Add(ref heapRef, i); int node = Unsafe.Add(ref heapRef, i);
int i2 = 2 * i; nuint i2 = 2 * i;
Unsafe.Add(ref childrenRef, i2) = node; Unsafe.Add(ref childrenRef, i2) = node;
Unsafe.Add(ref childrenRef, i2 + 1) = -1; Unsafe.Add(ref childrenRef, i2 + 1) = -1;
Unsafe.Add(ref valuesRef, i) = this.Frequencies[node] << 8; Unsafe.Add(ref valuesRef, i) = this.Frequencies[node] << 8;
Unsafe.Add(ref heapRef, i) = i; Unsafe.Add(ref heapRef, i) = (int)i;
} }
// Construct the Huffman tree by repeatedly combining the least two // Construct the Huffman tree by repeatedly combining the least two
@ -640,7 +640,7 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
do do
{ {
int first = Unsafe.Add(ref heapRef, 0); int first = Unsafe.Add(ref heapRef, 0);
int last = Unsafe.Add(ref heapRef, --heapLen); int last = Unsafe.Add(ref heapRef, (uint)--heapLen);
// Propagate the hole to the leafs of the heap // Propagate the hole to the leafs of the heap
int ppos = 0; int ppos = 0;
@ -648,35 +648,35 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
while (path < heapLen) while (path < heapLen)
{ {
if (path + 1 < heapLen && Unsafe.Add(ref valuesRef, Unsafe.Add(ref heapRef, path)) > Unsafe.Add(ref valuesRef, Unsafe.Add(ref heapRef, path + 1))) if (path + 1 < heapLen && Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)path)) > Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)(path + 1))))
{ {
path++; path++;
} }
Unsafe.Add(ref heapRef, ppos) = Unsafe.Add(ref heapRef, path); Unsafe.Add(ref heapRef, (uint)ppos) = Unsafe.Add(ref heapRef, (uint)path);
ppos = path; ppos = path;
path = (path * 2) + 1; path = (path * 2) + 1;
} }
// Now propagate the last element down along path. Normally // Now propagate the last element down along path. Normally
// it shouldn't go too deep. // it shouldn't go too deep.
int lastVal = Unsafe.Add(ref valuesRef, last); int lastVal = Unsafe.Add(ref valuesRef, (uint)last);
while ((path = ppos) > 0 while ((path = ppos) > 0
&& Unsafe.Add(ref valuesRef, Unsafe.Add(ref heapRef, ppos = (path - 1) >> 1)) > lastVal) && Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)(ppos = (path - 1) >> 1))) > lastVal)
{ {
Unsafe.Add(ref heapRef, path) = Unsafe.Add(ref heapRef, ppos); Unsafe.Add(ref heapRef, (uint)path) = Unsafe.Add(ref heapRef, (uint)ppos);
} }
Unsafe.Add(ref heapRef, path) = last; Unsafe.Add(ref heapRef, (uint)path) = last;
int second = Unsafe.Add(ref heapRef, 0); int second = Unsafe.Add(ref heapRef, 0);
// Create a new node father of first and second // Create a new node father of first and second
last = numNodes++; last = numNodes++;
Unsafe.Add(ref childrenRef, 2 * last) = first; Unsafe.Add(ref childrenRef, (uint)(2 * last)) = first;
Unsafe.Add(ref childrenRef, (2 * last) + 1) = second; Unsafe.Add(ref childrenRef, (uint)((2 * last) + 1)) = second;
int mindepth = Math.Min(Unsafe.Add(ref valuesRef, first) & 0xFF, Unsafe.Add(ref valuesRef, second) & 0xFF); int mindepth = Math.Min(Unsafe.Add(ref valuesRef, (uint)first) & 0xFF, Unsafe.Add(ref valuesRef, (uint)second) & 0xFF);
Unsafe.Add(ref valuesRef, last) = lastVal = Unsafe.Add(ref valuesRef, first) + Unsafe.Add(ref valuesRef, second) - mindepth + 1; Unsafe.Add(ref valuesRef, (uint)last) = lastVal = Unsafe.Add(ref valuesRef, (uint)first) + Unsafe.Add(ref valuesRef, (uint)second) - mindepth + 1;
// Again, propagate the hole to the leafs // Again, propagate the hole to the leafs
ppos = 0; ppos = 0;
@ -685,23 +685,23 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
while (path < heapLen) while (path < heapLen)
{ {
if (path + 1 < heapLen if (path + 1 < heapLen
&& Unsafe.Add(ref valuesRef, Unsafe.Add(ref heapRef, path)) > Unsafe.Add(ref valuesRef, Unsafe.Add(ref heapRef, path + 1))) && Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)path)) > Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)(path + 1))))
{ {
path++; path++;
} }
Unsafe.Add(ref heapRef, ppos) = Unsafe.Add(ref heapRef, path); Unsafe.Add(ref heapRef, (uint)ppos) = Unsafe.Add(ref heapRef, (uint)path);
ppos = path; ppos = path;
path = (ppos * 2) + 1; path = (ppos * 2) + 1;
} }
// Now propagate the new element down along path // Now propagate the new element down along path
while ((path = ppos) > 0 && Unsafe.Add(ref valuesRef, Unsafe.Add(ref heapRef, ppos = (path - 1) >> 1)) > lastVal) while ((path = ppos) > 0 && Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)(ppos = (path - 1) >> 1))) > lastVal)
{ {
Unsafe.Add(ref heapRef, path) = Unsafe.Add(ref heapRef, ppos); Unsafe.Add(ref heapRef, (uint)path) = Unsafe.Add(ref heapRef, (uint)ppos);
} }
Unsafe.Add(ref heapRef, path) = last; Unsafe.Add(ref heapRef, (uint)path) = last;
} }
while (heapLen > 1); while (heapLen > 1);
@ -886,21 +886,21 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
{ {
if (children[(2 * i) + 1] != -1) if (children[(2 * i) + 1] != -1)
{ {
int bitLength = Unsafe.Add(ref lengthsRef, i) + 1; int bitLength = Unsafe.Add(ref lengthsRef, (uint)i) + 1;
if (bitLength > maxLen) if (bitLength > maxLen)
{ {
bitLength = maxLen; bitLength = maxLen;
overflow++; overflow++;
} }
Unsafe.Add(ref lengthsRef, Unsafe.Add(ref childrenRef, 2 * i)) = Unsafe.Add(ref lengthsRef, Unsafe.Add(ref childrenRef, (2 * i) + 1)) = bitLength; Unsafe.Add(ref lengthsRef, (uint)Unsafe.Add(ref childrenRef, (uint)(2 * i))) = Unsafe.Add(ref lengthsRef, (uint)Unsafe.Add(ref childrenRef, (uint)((2 * i) + 1))) = bitLength;
} }
else else
{ {
// A leaf node // A leaf node
int bitLength = Unsafe.Add(ref lengthsRef, i); int bitLength = Unsafe.Add(ref lengthsRef, (uint)i);
Unsafe.Add(ref bitLengthCountsRef, bitLength - 1)++; Unsafe.Add(ref bitLengthCountsRef, (uint)(bitLength - 1))++;
lengthPtr[Unsafe.Add(ref childrenRef, 2 * i)] = (byte)Unsafe.Add(ref lengthsRef, i); lengthPtr[Unsafe.Add(ref childrenRef, (uint)(2 * i))] = (byte)Unsafe.Add(ref lengthsRef, (uint)i);
} }
} }
} }
@ -914,7 +914,7 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
do do
{ {
// Find the first bit length which could increase: // Find the first bit length which could increase:
while (Unsafe.Add(ref bitLengthCountsRef, --incrBitLen) == 0) while (Unsafe.Add(ref bitLengthCountsRef, (uint)--incrBitLen) == 0)
{ {
} }
@ -922,8 +922,8 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
// number of overflow nodes. // number of overflow nodes.
do do
{ {
Unsafe.Add(ref bitLengthCountsRef, incrBitLen)--; Unsafe.Add(ref bitLengthCountsRef, (uint)incrBitLen)--;
Unsafe.Add(ref bitLengthCountsRef, ++incrBitLen)++; Unsafe.Add(ref bitLengthCountsRef, (uint)++incrBitLen)++;
overflow -= 1 << (maxLen - 1 - incrBitLen); overflow -= 1 << (maxLen - 1 - incrBitLen);
} }
while (overflow > 0 && incrBitLen < maxLen - 1); while (overflow > 0 && incrBitLen < maxLen - 1);
@ -932,8 +932,8 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
// We may have overshot above. Move some nodes from maxLength to // We may have overshot above. Move some nodes from maxLength to
// maxLength-1 in that case. // maxLength-1 in that case.
Unsafe.Add(ref bitLengthCountsRef, maxLen - 1) += overflow; Unsafe.Add(ref bitLengthCountsRef, (uint)(maxLen - 1)) += overflow;
Unsafe.Add(ref bitLengthCountsRef, maxLen - 2) -= overflow; Unsafe.Add(ref bitLengthCountsRef, (uint)(maxLen - 2)) -= overflow;
// Now recompute all bit lengths, scanning in increasing // Now recompute all bit lengths, scanning in increasing
// frequency. It is simpler to reconstruct all lengths instead of // frequency. It is simpler to reconstruct all lengths instead of
@ -945,14 +945,14 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int nodeIndex = 2 * numLeafs; int nodeIndex = 2 * numLeafs;
for (int bits = maxLen; bits != 0; bits--) for (int bits = maxLen; bits != 0; bits--)
{ {
int n = Unsafe.Add(ref bitLengthCountsRef, bits - 1); int n = Unsafe.Add(ref bitLengthCountsRef, (uint)(bits - 1));
while (n > 0) while (n > 0)
{ {
int childIndex = 2 * Unsafe.Add(ref childrenRef, nodeIndex++); int childIndex = 2 * Unsafe.Add(ref childrenRef, (uint)nodeIndex++);
if (Unsafe.Add(ref childrenRef, childIndex + 1) == -1) if (Unsafe.Add(ref childrenRef, (uint)(childIndex + 1)) == -1)
{ {
// We found another leaf // We found another leaf
lengthPtr[Unsafe.Add(ref childrenRef, childIndex)] = (byte)bits; lengthPtr[Unsafe.Add(ref childrenRef, (uint)childIndex)] = (byte)bits;
n--; n--;
} }
} }

42
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -453,6 +453,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param> /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle4(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels) private void UncompressRle4(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{ {
Span<byte> scratchBuffer = stackalloc byte[128];
Span<byte> cmd = stackalloc byte[2]; Span<byte> cmd = stackalloc byte[2];
int count = 0; int count = 0;
@ -489,11 +490,11 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// If the second byte > 2, we are in 'absolute mode'. // If the second byte > 2, we are in 'absolute mode'.
// The second byte contains the number of color indexes that follow. // The second byte contains the number of color indexes that follow.
int max = cmd[1]; int max = cmd[1];
int bytesToRead = (max + 1) / 2; int bytesToRead = (int)(((uint)max + 1) / 2);
byte[] run = new byte[bytesToRead]; Span<byte> run = bytesToRead <= 128 ? scratchBuffer.Slice(0, bytesToRead) : new byte[bytesToRead];
stream.Read(run, 0, run.Length); stream.Read(run);
int idx = 0; int idx = 0;
for (int i = 0; i < max; i++) for (int i = 0; i < max; i++)
@ -559,6 +560,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param> /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle8(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels) private void UncompressRle8(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{ {
Span<byte> scratchBuffer = stackalloc byte[128];
Span<byte> cmd = stackalloc byte[2]; Span<byte> cmd = stackalloc byte[2];
int count = 0; int count = 0;
@ -596,13 +598,13 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// Take this number of bytes from the stream as uncompressed data. // Take this number of bytes from the stream as uncompressed data.
int length = cmd[1]; int length = cmd[1];
byte[] run = new byte[length]; Span<byte> run = length <= 128 ? scratchBuffer.Slice(0, length) : new byte[length];
stream.Read(run, 0, run.Length); stream.Read(run);
run.AsSpan().CopyTo(buffer[count..]); run.CopyTo(buffer[count..]);
count += run.Length; count += length;
// Absolute mode data is aligned to two-byte word-boundary. // Absolute mode data is aligned to two-byte word-boundary.
int padding = length & 1; int padding = length & 1;
@ -639,6 +641,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
/// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param> /// <param name="rowsWithUndefinedPixels">Keeps track of rows, which have undefined pixels.</param>
private void UncompressRle24(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels) private void UncompressRle24(BufferedReadStream stream, int w, Span<byte> buffer, Span<bool> undefinedPixels, Span<bool> rowsWithUndefinedPixels)
{ {
Span<byte> scratchBuffer = stackalloc byte[128];
Span<byte> cmd = stackalloc byte[2]; Span<byte> cmd = stackalloc byte[2];
int uncompressedPixels = 0; int uncompressedPixels = 0;
@ -675,17 +678,18 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// If the second byte > 2, we are in 'absolute mode'. // If the second byte > 2, we are in 'absolute mode'.
// Take this number of bytes from the stream as uncompressed data. // Take this number of bytes from the stream as uncompressed data.
int length = cmd[1]; int length = cmd[1];
int length3 = length * 3;
byte[] run = new byte[length * 3]; Span<byte> run = length3 <= 128 ? scratchBuffer.Slice(0, length3) : new byte[length3];
stream.Read(run, 0, run.Length); stream.Read(run);
run.AsSpan().CopyTo(buffer[(uncompressedPixels * 3)..]); run.CopyTo(buffer[(uncompressedPixels * 3)..]);
uncompressedPixels += length; uncompressedPixels += length;
// Absolute mode data is aligned to two-byte word-boundary. // Absolute mode data is aligned to two-byte word-boundary.
int padding = run.Length & 1; int padding = length3 & 1;
stream.Skip(padding); stream.Skip(padding);
@ -1286,18 +1290,18 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// color masks for each color channel follow the info header. // color masks for each color channel follow the info header.
if (this.infoHeader.Compression == BmpCompression.BitFields) if (this.infoHeader.Compression == BmpCompression.BitFields)
{ {
byte[] bitfieldsBuffer = new byte[12]; Span<byte> bitfieldsBuffer = stackalloc byte[12];
stream.Read(bitfieldsBuffer, 0, 12); stream.Read(bitfieldsBuffer);
Span<byte> data = bitfieldsBuffer.AsSpan(); Span<byte> data = bitfieldsBuffer;
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]); this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)); this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)); this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
} }
else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS) else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS)
{ {
byte[] bitfieldsBuffer = new byte[16]; Span<byte> bitfieldsBuffer = stackalloc byte[16];
stream.Read(bitfieldsBuffer, 0, 16); stream.Read(bitfieldsBuffer);
Span<byte> data = bitfieldsBuffer.AsSpan(); Span<byte> data = bitfieldsBuffer;
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]); this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)); this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)); this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
@ -1361,7 +1365,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
this.metadata.VerticalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetadata.DefaultVerticalResolution)); this.metadata.VerticalResolution = Math.Round(UnitConverter.InchToMeter(ImageMetadata.DefaultVerticalResolution));
} }
short bitsPerPixel = this.infoHeader.BitsPerPixel; ushort bitsPerPixel = this.infoHeader.BitsPerPixel;
this.bmpMetadata = this.metadata.GetBmpMetadata(); this.bmpMetadata = this.metadata.GetBmpMetadata();
this.bmpMetadata.InfoHeaderType = infoHeaderType; this.bmpMetadata.InfoHeaderType = infoHeaderType;
this.bmpMetadata.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel; this.bmpMetadata.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel;
@ -1470,7 +1474,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
{ {
// Usually the color palette is 1024 byte (256 colors * 4), but the documentation does not mention a size limit. // Usually the color palette is 1024 byte (256 colors * 4), but the documentation does not mention a size limit.
// Make sure, that we will not read pass the bitmap offset (starting position of image data). // Make sure, that we will not read pass the bitmap offset (starting position of image data).
if ((stream.Position + colorMapSizeBytes) > this.fileHeader.Offset) if (stream.Position > this.fileHeader.Offset - colorMapSizeBytes)
{ {
BmpThrowHelper.ThrowInvalidImageContentException( BmpThrowHelper.ThrowInvalidImageContentException(
$"Reading the color map would read beyond the bitmap offset. Either the color map size of '{colorMapSizeBytes}' is invalid or the bitmap offset."); $"Reading the color map would read beyond the bitmap offset. Either the color map size of '{colorMapSizeBytes}' is invalid or the bitmap offset.");

6
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -123,8 +123,8 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
BmpMetadata bmpMetadata = metadata.GetBmpMetadata(); BmpMetadata bmpMetadata = metadata.GetBmpMetadata();
this.bitsPerPixel ??= bmpMetadata.BitsPerPixel; this.bitsPerPixel ??= bmpMetadata.BitsPerPixel;
short bpp = (short)this.bitsPerPixel; ushort bpp = (ushort)this.bitsPerPixel;
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); int bytesPerLine = (int)(4 * ((((uint)image.Width * bpp) + 31) / 32));
this.padding = bytesPerLine - (int)(image.Width * (bpp / 8F)); this.padding = bytesPerLine - (int)(image.Width * (bpp / 8F));
int colorPaletteSize = this.bitsPerPixel switch int colorPaletteSize = this.bitsPerPixel switch
@ -176,7 +176,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
/// <param name="metadata">The metadata.</param> /// <param name="metadata">The metadata.</param>
/// <param name="iccProfileData">The icc profile data.</param> /// <param name="iccProfileData">The icc profile data.</param>
/// <returns>The bitmap information header.</returns> /// <returns>The bitmap information header.</returns>
private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderSize, short bpp, int bytesPerLine, ImageMetadata metadata, byte[]? iccProfileData) private BmpInfoHeader CreateBmpInfoHeader(int width, int height, int infoHeaderSize, ushort bpp, int bytesPerLine, ImageMetadata metadata, byte[]? iccProfileData)
{ {
int hResolution = 0; int hResolution = 0;
int vResolution = 0; int vResolution = 0;

20
src/ImageSharp/Formats/Bmp/BmpInfoHeader.cs

@ -70,7 +70,7 @@ internal struct BmpInfoHeader
int width, int width,
int height, int height,
short planes, short planes,
short bitsPerPixel, ushort bitsPerPixel,
BmpCompression compression = default, BmpCompression compression = default,
int imageSize = 0, int imageSize = 0,
int xPelsPerMeter = 0, int xPelsPerMeter = 0,
@ -157,7 +157,7 @@ internal struct BmpInfoHeader
/// Gets or sets the number of bits per pixel, which is the color depth of the image. /// Gets or sets the number of bits per pixel, which is the color depth of the image.
/// Typical values are 1, 4, 8, 16, 24 and 32. /// Typical values are 1, 4, 8, 16, 24 and 32.
/// </summary> /// </summary>
public short BitsPerPixel { get; set; } public ushort BitsPerPixel { get; set; }
/// <summary> /// <summary>
/// Gets or sets the compression method being used. /// Gets or sets the compression method being used.
@ -311,7 +311,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(4, 2)), width: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(4, 2)),
height: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)), height: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(8, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(8, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(10, 2))); bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(10, 2)));
/// <summary> /// <summary>
/// Parses a short variant of the OS22XBITMAPHEADER. It is identical to the BITMAPCOREHEADER, except that the width and height /// Parses a short variant of the OS22XBITMAPHEADER. It is identical to the BITMAPCOREHEADER, except that the width and height
@ -325,7 +325,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2))); bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)));
/// <summary> /// <summary>
/// Parses the full BMP Version 3 BITMAPINFOHEADER header (40 bytes). /// Parses the full BMP Version 3 BITMAPINFOHEADER header (40 bytes).
@ -338,7 +338,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)), bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)), compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)), imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)), xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -359,7 +359,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)), bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)), compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)), imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)), xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -386,7 +386,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2))); bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)));
// The compression value in OS/2 bitmap has a different meaning than in windows bitmaps. // The compression value in OS/2 bitmap has a different meaning than in windows bitmaps.
// Map the OS/2 value to the windows values. // Map the OS/2 value to the windows values.
@ -431,7 +431,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)), width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)), height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)), planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)), bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)),
compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)), compression: (BmpCompression)BinaryPrimitives.ReadInt32LittleEndian(data.Slice(16, 4)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)), imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)), xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -484,7 +484,7 @@ internal struct BmpInfoHeader
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes); BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel); BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(16, 4), (int)this.Compression); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(16, 4), (int)this.Compression);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(20, 4), this.ImageSize); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(20, 4), this.ImageSize);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(24, 4), this.XPelsPerMeter); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(24, 4), this.XPelsPerMeter);
@ -504,7 +504,7 @@ internal struct BmpInfoHeader
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(4, 4), this.Width);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(8, 4), this.Height);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes); BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(12, 2), this.Planes);
BinaryPrimitives.WriteInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel); BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(14, 2), this.BitsPerPixel);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(16, 4), (int)this.Compression); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(16, 4), (int)this.Compression);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(20, 4), this.ImageSize); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(20, 4), this.ImageSize);
BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(24, 4), this.XPelsPerMeter); BinaryPrimitives.WriteInt32LittleEndian(buffer.Slice(24, 4), this.XPelsPerMeter);

38
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -22,7 +22,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// The temp buffer used to reduce allocations. /// The temp buffer used to reduce allocations.
/// </summary> /// </summary>
private readonly byte[] buffer = new byte[16]; private ScratchBuffer buffer; // mutable struct, don't make readonly
/// <summary> /// <summary>
/// The global color table. /// The global color table.
@ -249,13 +249,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param> /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
private void ReadGraphicalControlExtension(BufferedReadStream stream) private void ReadGraphicalControlExtension(BufferedReadStream stream)
{ {
int bytesRead = stream.Read(this.buffer, 0, 6); int bytesRead = stream.Read(this.buffer.Span, 0, 6);
if (bytesRead != 6) if (bytesRead != 6)
{ {
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the graphic control extension"); GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the graphic control extension");
} }
this.graphicsControlExtension = GifGraphicControlExtension.Parse(this.buffer); this.graphicsControlExtension = GifGraphicControlExtension.Parse(this.buffer.Span);
} }
/// <summary> /// <summary>
@ -264,13 +264,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param> /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
private void ReadImageDescriptor(BufferedReadStream stream) private void ReadImageDescriptor(BufferedReadStream stream)
{ {
int bytesRead = stream.Read(this.buffer, 0, 9); int bytesRead = stream.Read(this.buffer.Span, 0, 9);
if (bytesRead != 9) if (bytesRead != 9)
{ {
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the image descriptor"); GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the image descriptor");
} }
this.imageDescriptor = GifImageDescriptor.Parse(this.buffer); this.imageDescriptor = GifImageDescriptor.Parse(this.buffer.Span);
if (this.imageDescriptor.Height == 0 || this.imageDescriptor.Width == 0) if (this.imageDescriptor.Height == 0 || this.imageDescriptor.Width == 0)
{ {
GifThrowHelper.ThrowInvalidImageContentException("Width or height should not be 0"); GifThrowHelper.ThrowInvalidImageContentException("Width or height should not be 0");
@ -283,13 +283,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param> /// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
private void ReadLogicalScreenDescriptor(BufferedReadStream stream) private void ReadLogicalScreenDescriptor(BufferedReadStream stream)
{ {
int bytesRead = stream.Read(this.buffer, 0, 7); int bytesRead = stream.Read(this.buffer.Span, 0, 7);
if (bytesRead != 7) if (bytesRead != 7)
{ {
GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the logical screen descriptor"); GifThrowHelper.ThrowInvalidImageContentException("Not enough data to read the logical screen descriptor");
} }
this.logicalScreenDescriptor = GifLogicalScreenDescriptor.Parse(this.buffer); this.logicalScreenDescriptor = GifLogicalScreenDescriptor.Parse(this.buffer.Span);
} }
/// <summary> /// <summary>
@ -306,8 +306,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
long position = stream.Position; long position = stream.Position;
if (appLength == GifConstants.ApplicationBlockSize) if (appLength == GifConstants.ApplicationBlockSize)
{ {
stream.Read(this.buffer, 0, GifConstants.ApplicationBlockSize); stream.Read(this.buffer.Span, 0, GifConstants.ApplicationBlockSize);
bool isXmp = this.buffer.AsSpan().StartsWith(GifConstants.XmpApplicationIdentificationBytes); bool isXmp = this.buffer.Span.StartsWith(GifConstants.XmpApplicationIdentificationBytes);
if (isXmp && !this.skipMetadata) if (isXmp && !this.skipMetadata)
{ {
GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(stream, this.memoryAllocator); GifXmpApplicationExtension extension = GifXmpApplicationExtension.Read(stream, this.memoryAllocator);
@ -331,8 +331,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
// http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension // http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension
if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize) if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize)
{ {
stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize); stream.Read(this.buffer.Span, 0, GifConstants.NetscapeLoopingSubBlockSize);
this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount; this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.Span.Slice(1)).RepeatCount;
stream.Skip(1); // Skip the terminator. stream.Skip(1); // Skip the terminator.
return; return;
} }
@ -578,8 +578,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
// #403 The left + width value can be larger than the image width // #403 The left + width value can be larger than the image width
for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
{ {
int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, x - descriptorLeft), 0, colorTableMaxIdx); int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x);
Rgb24 rgb = colorTable[index]; Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb); pixel.FromRgb24(rgb);
} }
@ -588,7 +588,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
{ {
for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
{ {
int rawIndex = Unsafe.Add(ref indicesRowRef, x - descriptorLeft); int rawIndex = Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft));
// Treat any out of bounds values as transparent. // Treat any out of bounds values as transparent.
if (rawIndex > colorTableMaxIdx || rawIndex == transIndex) if (rawIndex > colorTableMaxIdx || rawIndex == transIndex)
@ -597,7 +597,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
} }
int index = Numerics.Clamp(rawIndex, 0, colorTableMaxIdx); int index = Numerics.Clamp(rawIndex, 0, colorTableMaxIdx);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x);
Rgb24 rgb = colorTable[index]; Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb); pixel.FromRgb24(rgb);
} }
@ -762,4 +762,12 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
} }
} }
} }
private unsafe struct ScratchBuffer
{
private const int Size = 16;
private fixed byte scratch[Size];
public Span<byte> Span => MemoryMarshal.CreateSpan(ref this.scratch[0], Size);
}
} }

34
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -28,11 +28,6 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
/// </summary> /// </summary>
private readonly Configuration configuration; private readonly Configuration configuration;
/// <summary>
/// A reusable buffer used to reduce allocations.
/// </summary>
private readonly byte[] buffer = new byte[20];
/// <summary> /// <summary>
/// Whether to skip metadata during encode. /// Whether to skip metadata during encode.
/// </summary> /// </summary>
@ -254,7 +249,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
for (int i = rgbaSpan.Length - 1; i >= 0; i--) for (int i = rgbaSpan.Length - 1; i >= 0; i--)
{ {
if (Unsafe.Add(ref rgbaSpanRef, i).Equals(default)) if (Unsafe.Add(ref rgbaSpanRef, (uint)i).Equals(default))
{ {
index = i; index = i;
} }
@ -324,9 +319,10 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
backgroundColorIndex: unchecked((byte)transparencyIndex), backgroundColorIndex: unchecked((byte)transparencyIndex),
ratio); ratio);
descriptor.WriteTo(this.buffer); Span<byte> buffer = stackalloc byte[20];
descriptor.WriteTo(buffer);
stream.Write(this.buffer, 0, GifLogicalScreenDescriptor.Size); stream.Write(buffer, 0, GifLogicalScreenDescriptor.Size);
} }
/// <summary> /// <summary>
@ -365,12 +361,14 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
return; return;
} }
Span<byte> buffer = stackalloc byte[2];
for (int i = 0; i < metadata.Comments.Count; i++) for (int i = 0; i < metadata.Comments.Count; i++)
{ {
string comment = metadata.Comments[i]; string comment = metadata.Comments[i];
this.buffer[0] = GifConstants.ExtensionIntroducer; buffer[1] = GifConstants.CommentLabel;
this.buffer[1] = GifConstants.CommentLabel; buffer[0] = GifConstants.ExtensionIntroducer;
stream.Write(this.buffer, 0, 2); stream.Write(buffer);
// Comment will be stored in chunks of 255 bytes, if it exceeds this size. // Comment will be stored in chunks of 255 bytes, if it exceeds this size.
ReadOnlySpan<char> commentSpan = comment.AsSpan(); ReadOnlySpan<char> commentSpan = comment.AsSpan();
@ -437,22 +435,23 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
private void WriteExtension<TGifExtension>(TGifExtension extension, Stream stream) private void WriteExtension<TGifExtension>(TGifExtension extension, Stream stream)
where TGifExtension : struct, IGifExtension where TGifExtension : struct, IGifExtension
{ {
IMemoryOwner<byte>? owner = null;
Span<byte> extensionBuffer;
int extensionSize = extension.ContentLength; int extensionSize = extension.ContentLength;
if (extensionSize == 0) if (extensionSize == 0)
{ {
return; return;
} }
else if (extensionSize > this.buffer.Length - 3)
IMemoryOwner<byte>? owner = null;
Span<byte> extensionBuffer = stackalloc byte[0]; // workaround compiler limitation
if (extensionSize > 128)
{ {
owner = this.memoryAllocator.Allocate<byte>(extensionSize + 3); owner = this.memoryAllocator.Allocate<byte>(extensionSize + 3);
extensionBuffer = owner.GetSpan(); extensionBuffer = owner.GetSpan();
} }
else else
{ {
extensionBuffer = this.buffer; extensionBuffer = stackalloc byte[extensionSize + 3];
} }
extensionBuffer[0] = GifConstants.ExtensionIntroducer; extensionBuffer[0] = GifConstants.ExtensionIntroducer;
@ -489,9 +488,10 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
height: (ushort)image.Height, height: (ushort)image.Height,
packed: packedValue); packed: packedValue);
descriptor.WriteTo(this.buffer); Span<byte> buffer = stackalloc byte[20];
descriptor.WriteTo(buffer);
stream.Write(this.buffer, 0, GifImageDescriptor.Size); stream.Write(buffer, 0, GifImageDescriptor.Size);
} }
/// <summary> /// <summary>

38
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -115,7 +115,7 @@ internal sealed class LzwDecoder : IDisposable
for (code = 0; code < clearCode; code++) for (code = 0; code < clearCode; code++)
{ {
Unsafe.Add(ref suffixRef, code) = (byte)code; Unsafe.Add(ref suffixRef, (uint)code) = (byte)code;
} }
Span<byte> buffer = stackalloc byte[byte.MaxValue]; Span<byte> buffer = stackalloc byte[byte.MaxValue];
@ -182,7 +182,7 @@ internal sealed class LzwDecoder : IDisposable
if (oldCode == NullCode) if (oldCode == NullCode)
{ {
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code); Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code);
oldCode = code; oldCode = code;
first = code; first = code;
continue; continue;
@ -191,27 +191,27 @@ internal sealed class LzwDecoder : IDisposable
int inCode = code; int inCode = code;
if (code == availableCode) if (code == availableCode)
{ {
Unsafe.Add(ref pixelStackRef, top++) = (byte)first; Unsafe.Add(ref pixelStackRef, (uint)top++) = (byte)first;
code = oldCode; code = oldCode;
} }
while (code > clearCode) while (code > clearCode)
{ {
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code); Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code);
code = Unsafe.Add(ref prefixRef, code); code = Unsafe.Add(ref prefixRef, (uint)code);
} }
int suffixCode = Unsafe.Add(ref suffixRef, code); int suffixCode = Unsafe.Add(ref suffixRef, (uint)code);
first = suffixCode; first = suffixCode;
Unsafe.Add(ref pixelStackRef, top++) = suffixCode; Unsafe.Add(ref pixelStackRef, (uint)top++) = suffixCode;
// Fix for Gifs that have "deferred clear code" as per here : // Fix for Gifs that have "deferred clear code" as per here :
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918 // https://bugzilla.mozilla.org/show_bug.cgi?id=55918
if (availableCode < MaxStackSize) if (availableCode < MaxStackSize)
{ {
Unsafe.Add(ref prefixRef, availableCode) = oldCode; Unsafe.Add(ref prefixRef, (uint)availableCode) = oldCode;
Unsafe.Add(ref suffixRef, availableCode) = first; Unsafe.Add(ref suffixRef, (uint)availableCode) = first;
availableCode++; availableCode++;
if (availableCode == codeMask + 1 && availableCode < MaxStackSize) if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{ {
@ -228,7 +228,7 @@ internal sealed class LzwDecoder : IDisposable
// Clear missing pixels // Clear missing pixels
xyz++; xyz++;
Unsafe.Add(ref pixelsRowRef, x++) = (byte)Unsafe.Add(ref pixelStackRef, top); Unsafe.Add(ref pixelsRowRef, (uint)x++) = (byte)Unsafe.Add(ref pixelStackRef, (uint)top);
} }
} }
@ -282,7 +282,7 @@ internal sealed class LzwDecoder : IDisposable
for (code = 0; code < clearCode; code++) for (code = 0; code < clearCode; code++)
{ {
Unsafe.Add(ref suffixRef, code) = (byte)code; Unsafe.Add(ref suffixRef, (uint)code) = (byte)code;
} }
Span<byte> buffer = stackalloc byte[byte.MaxValue]; Span<byte> buffer = stackalloc byte[byte.MaxValue];
@ -336,7 +336,7 @@ internal sealed class LzwDecoder : IDisposable
if (oldCode == NullCode) if (oldCode == NullCode)
{ {
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code); Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code);
oldCode = code; oldCode = code;
first = code; first = code;
continue; continue;
@ -345,27 +345,27 @@ internal sealed class LzwDecoder : IDisposable
int inCode = code; int inCode = code;
if (code == availableCode) if (code == availableCode)
{ {
Unsafe.Add(ref pixelStackRef, top++) = (byte)first; Unsafe.Add(ref pixelStackRef, (uint)top++) = (byte)first;
code = oldCode; code = oldCode;
} }
while (code > clearCode) while (code > clearCode)
{ {
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code); Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)code);
code = Unsafe.Add(ref prefixRef, code); code = Unsafe.Add(ref prefixRef, (uint)code);
} }
int suffixCode = Unsafe.Add(ref suffixRef, code); int suffixCode = Unsafe.Add(ref suffixRef, (uint)code);
first = suffixCode; first = suffixCode;
Unsafe.Add(ref pixelStackRef, top++) = suffixCode; Unsafe.Add(ref pixelStackRef, (uint)top++) = suffixCode;
// Fix for Gifs that have "deferred clear code" as per here : // Fix for Gifs that have "deferred clear code" as per here :
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918 // https://bugzilla.mozilla.org/show_bug.cgi?id=55918
if (availableCode < MaxStackSize) if (availableCode < MaxStackSize)
{ {
Unsafe.Add(ref prefixRef, availableCode) = oldCode; Unsafe.Add(ref prefixRef, (uint)availableCode) = oldCode;
Unsafe.Add(ref suffixRef, availableCode) = first; Unsafe.Add(ref suffixRef, (uint)availableCode) = first;
availableCode++; availableCode++;
if (availableCode == codeMask + 1 && availableCode < MaxStackSize) if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{ {

22
src/ImageSharp/Formats/Gif/LzwEncoder.cs

@ -216,7 +216,7 @@ internal sealed class LzwEncoder : IDisposable
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void AddCharacter(byte c, ref byte accumulatorsRef, Stream stream) private void AddCharacter(byte c, ref byte accumulatorsRef, Stream stream)
{ {
Unsafe.Add(ref accumulatorsRef, this.accumulatorCount++) = c; Unsafe.Add(ref accumulatorsRef, (uint)this.accumulatorCount++) = c;
if (this.accumulatorCount >= 254) if (this.accumulatorCount >= 254)
{ {
this.FlushPacket(stream); this.FlushPacket(stream);
@ -278,18 +278,18 @@ internal sealed class LzwEncoder : IDisposable
for (int x = offsetX; x < indexedPixels.Width; x++) for (int x = offsetX; x < indexedPixels.Width; x++)
{ {
int code = Unsafe.Add(ref rowSpanRef, x); int code = Unsafe.Add(ref rowSpanRef, (uint)x);
int freeCode = (code << MaxBits) + entry; int freeCode = (code << MaxBits) + entry;
int hashIndex = (code << HashShift) ^ entry; int hashIndex = (code << HashShift) ^ entry;
if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode) if (Unsafe.Add(ref hashTableRef, (uint)hashIndex) == freeCode)
{ {
entry = Unsafe.Add(ref codeTableRef, hashIndex); entry = Unsafe.Add(ref codeTableRef, (uint)hashIndex);
continue; continue;
} }
// Non-empty slot // Non-empty slot
if (Unsafe.Add(ref hashTableRef, hashIndex) >= 0) if (Unsafe.Add(ref hashTableRef, (uint)hashIndex) >= 0)
{ {
int disp = 1; int disp = 1;
if (hashIndex != 0) if (hashIndex != 0)
@ -304,15 +304,15 @@ internal sealed class LzwEncoder : IDisposable
hashIndex += HashSize; hashIndex += HashSize;
} }
if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode) if (Unsafe.Add(ref hashTableRef, (uint)hashIndex) == freeCode)
{ {
entry = Unsafe.Add(ref codeTableRef, hashIndex); entry = Unsafe.Add(ref codeTableRef, (uint)hashIndex);
break; break;
} }
} }
while (Unsafe.Add(ref hashTableRef, hashIndex) >= 0); while (Unsafe.Add(ref hashTableRef, (uint)hashIndex) >= 0);
if (Unsafe.Add(ref hashTableRef, hashIndex) == freeCode) if (Unsafe.Add(ref hashTableRef, (uint)hashIndex) == freeCode)
{ {
continue; continue;
} }
@ -322,8 +322,8 @@ internal sealed class LzwEncoder : IDisposable
entry = code; entry = code;
if (this.freeEntry < MaxMaxCode) if (this.freeEntry < MaxMaxCode)
{ {
Unsafe.Add(ref codeTableRef, hashIndex) = this.freeEntry++; // code -> hashtable Unsafe.Add(ref codeTableRef, (uint)hashIndex) = this.freeEntry++; // code -> hashtable
Unsafe.Add(ref hashTableRef, hashIndex) = freeCode; Unsafe.Add(ref hashTableRef, (uint)hashIndex) = freeCode;
} }
else else
{ {

8
src/ImageSharp/Formats/ImageExtensions.Save.tt

@ -77,7 +77,7 @@ public static partial class ImageExtensions
public static void SaveAs<#= fmt #>(this Image source, string path, <#= fmt #>Encoder encoder) => public static void SaveAs<#= fmt #>(this Image source, string path, <#= fmt #>Encoder encoder) =>
source.Save( source.Save(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the <#= fmt #> format. /// Saves the image to the given stream with the <#= fmt #> format.
@ -91,7 +91,7 @@ public static partial class ImageExtensions
public static Task SaveAs<#= fmt #>Async(this Image source, string path, <#= fmt #>Encoder encoder, CancellationToken cancellationToken = default) public static Task SaveAs<#= fmt #>Async(this Image source, string path, <#= fmt #>Encoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
path, path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance),
cancellationToken); cancellationToken);
/// <summary> /// <summary>
@ -124,7 +124,7 @@ public static partial class ImageExtensions
public static void SaveAs<#= fmt #>(this Image source, Stream stream, <#= fmt #>Encoder encoder) public static void SaveAs<#= fmt #>(this Image source, Stream stream, <#= fmt #>Encoder encoder)
=> source.Save( => source.Save(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance)); encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance));
/// <summary> /// <summary>
/// Saves the image to the given stream with the <#= fmt #> format. /// Saves the image to the given stream with the <#= fmt #> format.
@ -138,7 +138,7 @@ public static partial class ImageExtensions
public static Task SaveAs<#= fmt #>Async(this Image source, Stream stream, <#= fmt #>Encoder encoder, CancellationToken cancellationToken = default) public static Task SaveAs<#= fmt #>Async(this Image source, Stream stream, <#= fmt #>Encoder encoder, CancellationToken cancellationToken = default)
=> source.SaveAsync( => source.SaveAsync(
stream, stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance), encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance),
cancellationToken); cancellationToken);
<# <#

52
src/ImageSharp/Formats/Jpeg/Components/Block8x8.cs

@ -15,25 +15,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
/// 8x8 matrix of <see cref="short"/> coefficients. /// 8x8 matrix of <see cref="short"/> coefficients.
/// </summary> /// </summary>
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit, Size = 2 * Size)]
internal unsafe partial struct Block8x8 internal partial struct Block8x8
{ {
/// <summary> /// <summary>
/// A number of scalar coefficients in a <see cref="Block8x8F"/> /// A number of scalar coefficients in a <see cref="Block8x8F"/>
/// </summary> /// </summary>
public const int Size = 64; public const int Size = 64;
#pragma warning disable IDE0051 // Remove unused private member
/// <summary>
/// A placeholder buffer so the actual struct occupies exactly 64 * 2 bytes.
/// </summary>
/// <remarks>
/// This is not used directly in the code.
/// </remarks>
[FieldOffset(0)]
private fixed short data[Size];
#pragma warning restore IDE0051
/// <summary> /// <summary>
/// Gets or sets a <see cref="short"/> value at the given index /// Gets or sets a <see cref="short"/> value at the given index
/// </summary> /// </summary>
@ -47,7 +36,7 @@ internal unsafe partial struct Block8x8
DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx)); DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx));
ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this); ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this);
return Unsafe.Add(ref selfRef, idx); return Unsafe.Add(ref selfRef, (uint)idx);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -56,7 +45,7 @@ internal unsafe partial struct Block8x8
DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx)); DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx));
ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this); ref short selfRef = ref Unsafe.As<Block8x8, short>(ref this);
Unsafe.Add(ref selfRef, idx) = value; Unsafe.Add(ref selfRef, (uint)idx) = value;
} }
} }
@ -74,9 +63,10 @@ internal unsafe partial struct Block8x8
public static Block8x8 Load(Span<short> data) public static Block8x8 Load(Span<short> data)
{ {
Unsafe.SkipInit(out Block8x8 result); DebugGuard.MustBeGreaterThanOrEqualTo(data.Length, Size, "data is too small");
result.LoadFrom(data);
return result; ref byte src = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(data));
return Unsafe.ReadUnaligned<Block8x8>(ref src);
} }
/// <summary> /// <summary>
@ -104,9 +94,10 @@ internal unsafe partial struct Block8x8
/// </summary> /// </summary>
public void CopyTo(Span<short> destination) public void CopyTo(Span<short> destination)
{ {
ref byte selfRef = ref Unsafe.As<Block8x8, byte>(ref this); DebugGuard.MustBeGreaterThanOrEqualTo(destination.Length, Size, "destination is too small");
ref byte destRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<short, byte>(destination));
Unsafe.CopyBlockUnaligned(ref destRef, ref selfRef, Size * sizeof(short)); ref byte destRef = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(destination));
Unsafe.WriteUnaligned(ref destRef, this);
} }
/// <summary> /// <summary>
@ -135,19 +126,6 @@ internal unsafe partial struct Block8x8
} }
} }
/// <summary>
/// Load raw 16bit integers from source.
/// </summary>
/// <param name="source">Source</param>
[MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(Span<short> source)
{
ref byte sourceRef = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(source));
ref byte destRef = ref Unsafe.As<Block8x8, byte>(ref this);
Unsafe.CopyBlockUnaligned(ref destRef, ref sourceRef, Size * sizeof(short));
}
/// <summary> /// <summary>
/// Cast and copy <see cref="Size"/> <see cref="int"/>-s from the beginning of 'source' span. /// Cast and copy <see cref="Size"/> <see cref="int"/>-s from the beginning of 'source' span.
/// </summary> /// </summary>
@ -207,12 +185,12 @@ internal unsafe partial struct Block8x8
// Given mask is not actually suitable for lzcnt as 1's represent zero elements and 0's represent non-zero elements // Given mask is not actually suitable for lzcnt as 1's represent zero elements and 0's represent non-zero elements
// So we need to invert it // So we need to invert it
int lzcnt = BitOperations.LeadingZeroCount(~(uint)areEqual); uint lzcnt = (uint)BitOperations.LeadingZeroCount(~(uint)areEqual);
// As input number is represented by 2 bits in the mask, we need to divide lzcnt result by 2 // As input number is represented by 2 bits in the mask, we need to divide lzcnt result by 2
// to get the exact number of zero elements in the stride // to get the exact number of zero elements in the stride
int strideRelativeIndex = 15 - (lzcnt / 2); uint strideRelativeIndex = 15 - (lzcnt / 2);
return (i * 16) + strideRelativeIndex; return (i * 16) + (nint)strideRelativeIndex;
} }
} }

22
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.cs

@ -16,7 +16,7 @@ internal partial struct Block8x8F
{ {
var CMin4 = new Vector4(0F); var CMin4 = new Vector4(0F);
var CMax4 = new Vector4(maximum); var CMax4 = new Vector4(maximum);
var COff4 = new Vector4(MathF.Ceiling(maximum / 2)); var COff4 = new Vector4(MathF.Ceiling(maximum * 0.5F));
this.V0L = Numerics.Clamp(this.V0L + COff4, CMin4, CMax4); this.V0L = Numerics.Clamp(this.V0L + COff4, CMin4, CMax4);
this.V0R = Numerics.Clamp(this.V0R + COff4, CMin4, CMax4); this.V0R = Numerics.Clamp(this.V0R + COff4, CMin4, CMax4);
@ -42,33 +42,33 @@ internal partial struct Block8x8F
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void NormalizeColorsAndRoundInPlaceVector8(float maximum) public void NormalizeColorsAndRoundInPlaceVector8(float maximum)
{ {
var off = new Vector<float>(MathF.Ceiling(maximum / 2)); var off = new Vector<float>(MathF.Ceiling(maximum * 0.5F));
var max = new Vector<float>(maximum); var max = new Vector<float>(maximum);
ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V0L); ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V0L);
row0 = NormalizeAndRound(row0, off, max); row0 = NormalizeAndRound(row0, off, max);
ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V1L); ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V1L);
row1 = NormalizeAndRound(row1, off, max); row1 = NormalizeAndRound(row1, off, max);
ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V2L); ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V2L);
row2 = NormalizeAndRound(row2, off, max); row2 = NormalizeAndRound(row2, off, max);
ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V3L); ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V3L);
row3 = NormalizeAndRound(row3, off, max); row3 = NormalizeAndRound(row3, off, max);
ref Vector<float> row4 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V4L); ref Vector<float> row4 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V4L);
row4 = NormalizeAndRound(row4, off, max); row4 = NormalizeAndRound(row4, off, max);
ref Vector<float> row5 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V5L); ref Vector<float> row5 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V5L);
row5 = NormalizeAndRound(row5, off, max); row5 = NormalizeAndRound(row5, off, max);
ref Vector<float> row6 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V6L); ref Vector<float> row6 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V6L);
row6 = NormalizeAndRound(row6, off, max); row6 = NormalizeAndRound(row6, off, max);
ref Vector<float> row7 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V7L); ref Vector<float> row7 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V7L);
row7 = NormalizeAndRound(row7, off, max); row7 = NormalizeAndRound(row7, off, max);
} }
/// <summary> /// <summary>

4
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Generated.tt

@ -29,7 +29,7 @@ internal partial struct Block8x8F
{ {
var CMin4 = new Vector4(0F); var CMin4 = new Vector4(0F);
var CMax4 = new Vector4(maximum); var CMax4 = new Vector4(maximum);
var COff4 = new Vector4(MathF.Ceiling(maximum / 2)); var COff4 = new Vector4(MathF.Ceiling(maximum * 0.5F));
<# <#
@ -53,7 +53,7 @@ internal partial struct Block8x8F
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void NormalizeColorsAndRoundInPlaceVector8(float maximum) public void NormalizeColorsAndRoundInPlaceVector8(float maximum)
{ {
var off = new Vector<float>(MathF.Ceiling(maximum / 2)); var off = new Vector<float>(MathF.Ceiling(maximum * 0.5F));
var max = new Vector<float>(maximum); var max = new Vector<float>(maximum);
<# <#

10
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.Intrinsic.cs

@ -41,9 +41,9 @@ internal partial struct Block8x8F
ref Vector256<float> bBase = ref b.V0; ref Vector256<float> bBase = ref b.V0;
ref Vector256<short> destRef = ref dest.V01; ref Vector256<short> destRef = ref dest.V01;
var multiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7); Vector256<int> multiplyIntoInt16ShuffleMask = Vector256.Create(0, 1, 4, 5, 2, 3, 6, 7);
for (nint i = 0; i < 8; i += 2) for (nuint i = 0; i < 8; i += 2)
{ {
Vector256<int> row0 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0))); Vector256<int> row0 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0)));
Vector256<int> row1 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1))); Vector256<int> row1 = Avx.ConvertToVector256Int32(Avx.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1)));
@ -51,7 +51,7 @@ internal partial struct Block8x8F
Vector256<short> row = Avx2.PackSignedSaturate(row0, row1); Vector256<short> row = Avx2.PackSignedSaturate(row0, row1);
row = Avx2.PermuteVar8x32(row.AsInt32(), multiplyIntoInt16ShuffleMask).AsInt16(); row = Avx2.PermuteVar8x32(row.AsInt32(), multiplyIntoInt16ShuffleMask).AsInt16();
Unsafe.Add(ref destRef, (IntPtr)((uint)i / 2)) = row; Unsafe.Add(ref destRef, i / 2) = row;
} }
} }
@ -64,13 +64,13 @@ internal partial struct Block8x8F
ref Vector128<short> destBase = ref Unsafe.As<Block8x8, Vector128<short>>(ref dest); ref Vector128<short> destBase = ref Unsafe.As<Block8x8, Vector128<short>>(ref dest);
for (int i = 0; i < 16; i += 2) for (nuint i = 0; i < 16; i += 2)
{ {
Vector128<int> left = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0))); Vector128<int> left = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 0), Unsafe.Add(ref bBase, i + 0)));
Vector128<int> right = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1))); Vector128<int> right = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1)));
Vector128<short> row = Sse2.PackSignedSaturate(left, right); Vector128<short> row = Sse2.PackSignedSaturate(left, right);
Unsafe.Add(ref destBase, (IntPtr)((uint)i / 2)) = row; Unsafe.Add(ref destBase, i / 2) = row;
} }
} }

36
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.ScaledCopy.cs

@ -30,13 +30,13 @@ internal partial struct Block8x8F
} }
// TODO: Optimize: implement all cases with scale-specific, loopless code! // TODO: Optimize: implement all cases with scale-specific, loopless code!
this.CopyArbitraryScale(ref areaOrigin, areaStride, horizontalScale, verticalScale); this.CopyArbitraryScale(ref areaOrigin, (uint)areaStride, (uint)horizontalScale, (uint)verticalScale);
} }
private void CopyTo2x2Scale(ref float areaOrigin, int areaStride) private void CopyTo2x2Scale(ref float areaOrigin, int areaStride)
{ {
ref Vector2 destBase = ref Unsafe.As<float, Vector2>(ref areaOrigin); ref Vector2 destBase = ref Unsafe.As<float, Vector2>(ref areaOrigin);
int destStride = (int)((uint)areaStride / 2); nuint destStride = (uint)areaStride / 2;
WidenCopyRowImpl2x2(ref this.V0L, ref destBase, 0, destStride); WidenCopyRowImpl2x2(ref this.V0L, ref destBase, 0, destStride);
WidenCopyRowImpl2x2(ref this.V0L, ref destBase, 1, destStride); WidenCopyRowImpl2x2(ref this.V0L, ref destBase, 1, destStride);
@ -48,12 +48,12 @@ internal partial struct Block8x8F
WidenCopyRowImpl2x2(ref this.V0L, ref destBase, 7, destStride); WidenCopyRowImpl2x2(ref this.V0L, ref destBase, 7, destStride);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static void WidenCopyRowImpl2x2(ref Vector4 selfBase, ref Vector2 destBase, nint row, nint destStride) static void WidenCopyRowImpl2x2(ref Vector4 selfBase, ref Vector2 destBase, nuint row, nuint destStride)
{ {
ref Vector4 sLeft = ref Unsafe.Add(ref selfBase, 2 * row); ref Vector4 sLeft = ref Unsafe.Add(ref selfBase, 2 * row);
ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1); ref Vector4 sRight = ref Unsafe.Add(ref sLeft, 1);
nint offset = 2 * row * destStride; nuint offset = 2 * row * destStride;
ref Vector4 dTopLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset)); ref Vector4 dTopLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset));
ref Vector4 dBottomLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset + destStride)); ref Vector4 dBottomLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset + destStride));
@ -86,23 +86,23 @@ internal partial struct Block8x8F
} }
[MethodImpl(InliningOptions.ColdPath)] [MethodImpl(InliningOptions.ColdPath)]
private void CopyArbitraryScale(ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale) private void CopyArbitraryScale(ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
{ {
for (int y = 0; y < 8; y++) for (nuint y = 0; y < 8; y++)
{ {
int yy = y * verticalScale; nuint yy = y * verticalScale;
int y8 = y * 8; nuint y8 = y * 8;
for (int x = 0; x < 8; x++) for (nuint x = 0; x < 8; x++)
{ {
int xx = x * horizontalScale; nuint xx = x * horizontalScale;
float value = this[y8 + x]; float value = this[(int)(y8 + x)];
nint baseIdx = (yy * areaStride) + xx; nuint baseIdx = (yy * areaStride) + xx;
for (nint i = 0; i < verticalScale; i++, baseIdx += areaStride) for (nuint i = 0; i < verticalScale; i++, baseIdx += areaStride)
{ {
for (nint j = 0; j < horizontalScale; j++) for (nuint j = 0; j < horizontalScale; j++)
{ {
// area[xx + j, yy + i] = value; // area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value; Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
@ -128,8 +128,8 @@ internal partial struct Block8x8F
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static void CopyRowImpl(ref byte origin, ref byte dest, int destStride, int row) static void CopyRowImpl(ref byte origin, ref byte dest, int destStride, int row)
{ {
origin = ref Unsafe.Add(ref origin, row * 8 * sizeof(float)); origin = ref Unsafe.Add(ref origin, (uint)row * 8 * sizeof(float));
dest = ref Unsafe.Add(ref dest, row * destStride); dest = ref Unsafe.Add(ref dest, (uint)(row * destStride));
Unsafe.CopyBlock(ref dest, ref origin, 8 * sizeof(float)); Unsafe.CopyBlock(ref dest, ref origin, 8 * sizeof(float));
} }
} }
@ -150,8 +150,8 @@ internal partial struct Block8x8F
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
static void CopyRowImpl(ref byte origin, ref byte dest, int sourceStride, int row) static void CopyRowImpl(ref byte origin, ref byte dest, int sourceStride, int row)
{ {
origin = ref Unsafe.Add(ref origin, row * sourceStride); origin = ref Unsafe.Add(ref origin, (uint)(row * sourceStride));
dest = ref Unsafe.Add(ref dest, row * 8 * sizeof(float)); dest = ref Unsafe.Add(ref dest, (uint)row * 8 * sizeof(float));
Unsafe.CopyBlock(ref dest, ref origin, 8 * sizeof(float)); Unsafe.CopyBlock(ref dest, ref origin, 8 * sizeof(float));
} }
} }

47
src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs

@ -71,48 +71,47 @@ internal partial struct Block8x8F : IEquatable<Block8x8F>
/// <param name="idx">The index</param> /// <param name="idx">The index</param>
/// <returns>The float value at the specified index</returns> /// <returns>The float value at the specified index</returns>
public float this[int idx] public float this[int idx]
{
get => this[(uint)idx];
set => this[(uint)idx] = value;
}
internal float this[nuint idx]
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get get
{ {
DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx)); DebugGuard.MustBeBetweenOrEqualTo((int)idx, 0, Size - 1, nameof(idx));
ref float selfRef = ref Unsafe.As<Block8x8F, float>(ref this); ref float selfRef = ref Unsafe.As<Block8x8F, float>(ref this);
return Unsafe.Add(ref selfRef, (nint)(uint)idx); return Unsafe.Add(ref selfRef, idx);
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
set set
{ {
DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx)); DebugGuard.MustBeBetweenOrEqualTo((int)idx, 0, Size - 1, nameof(idx));
ref float selfRef = ref Unsafe.As<Block8x8F, float>(ref this); ref float selfRef = ref Unsafe.As<Block8x8F, float>(ref this);
Unsafe.Add(ref selfRef, (nint)(uint)idx) = value; Unsafe.Add(ref selfRef, idx) = value;
} }
} }
public float this[int x, int y] public float this[int x, int y]
{ {
get => this[(y * 8) + x]; get => this[((uint)y * 8) + (uint)x];
set => this[(y * 8) + x] = value; set => this[((uint)y * 8) + (uint)x] = value;
}
public static Block8x8F Load(Span<float> data)
{
Block8x8F result = default;
result.LoadFrom(data);
return result;
} }
/// <summary> /// <summary>
/// Load raw 32bit floating point data from source. /// Load raw 32bit floating point data from source.
/// </summary> /// </summary>
/// <param name="source">Source</param> /// <param name="data">Source</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(Span<float> source) public static Block8x8F Load(Span<float> data)
{ {
ref byte s = ref Unsafe.As<float, byte>(ref MemoryMarshal.GetReference(source)); DebugGuard.MustBeGreaterThanOrEqualTo(data.Length, Size, "data is too small");
ref byte d = ref Unsafe.As<Block8x8F, byte>(ref this);
Unsafe.CopyBlock(ref d, ref s, Size * sizeof(float)); ref byte src = ref Unsafe.As<float, byte>(ref MemoryMarshal.GetReference(data));
return Unsafe.ReadUnaligned<Block8x8F>(ref src);
} }
/// <summary> /// <summary>
@ -138,10 +137,10 @@ internal partial struct Block8x8F : IEquatable<Block8x8F>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
public unsafe void ScaledCopyTo(float[] dest) public unsafe void ScaledCopyTo(float[] dest)
{ {
fixed (void* ptr = &this.V0L) DebugGuard.MustBeGreaterThanOrEqualTo(dest.Length, Size, "dest is too small");
{
Marshal.Copy((IntPtr)ptr, dest, 0, Size); ref byte destRef = ref Unsafe.As<float, byte>(ref MemoryMarshal.GetArrayDataReference(dest));
} Unsafe.WriteUnaligned(ref destRef, this);
} }
public float[] ToArray() public float[] ToArray()
@ -425,7 +424,7 @@ internal partial struct Block8x8F : IEquatable<Block8x8F>
Vector256<int> targetVector = Vector256.Create(value); Vector256<int> targetVector = Vector256.Create(value);
ref Vector256<float> blockStride = ref this.V0; ref Vector256<float> blockStride = ref this.V0;
for (int i = 0; i < RowCount; i++) for (nuint i = 0; i < RowCount; i++)
{ {
Vector256<int> areEqual = Avx2.CompareEqual(Avx.ConvertToVector256Int32WithTruncation(Unsafe.Add(ref this.V0, i)), targetVector); Vector256<int> areEqual = Avx2.CompareEqual(Avx.ConvertToVector256Int32WithTruncation(Unsafe.Add(ref this.V0, i)), targetVector);
if (Avx2.MoveMask(areEqual.AsByte()) != equalityMask) if (Avx2.MoveMask(areEqual.AsByte()) != equalityMask)
@ -439,7 +438,7 @@ internal partial struct Block8x8F : IEquatable<Block8x8F>
ref float scalars = ref Unsafe.As<Block8x8F, float>(ref this); ref float scalars = ref Unsafe.As<Block8x8F, float>(ref this);
for (int i = 0; i < Size; i++) for (nuint i = 0; i < Size; i++)
{ {
if ((int)Unsafe.Add(ref scalars, i) != value) if ((int)Unsafe.Add(ref scalars, i) != value)
{ {

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykAvx.cs

@ -32,8 +32,8 @@ internal abstract partial class JpegColorConverterBase
// Used for the color conversion // Used for the color conversion
var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue)); var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector256<float> c = ref Unsafe.Add(ref c0Base, i); ref Vector256<float> c = ref Unsafe.Add(ref c0Base, i);
ref Vector256<float> m = ref Unsafe.Add(ref c1Base, i); ref Vector256<float> m = ref Unsafe.Add(ref c1Base, i);
@ -71,8 +71,8 @@ internal abstract partial class JpegColorConverterBase
var scale = Vector256.Create(maxValue); var scale = Vector256.Create(maxValue);
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector256<float> ctmp = Avx.Subtract(scale, Unsafe.Add(ref srcR, i)); Vector256<float> ctmp = Avx.Subtract(scale, Unsafe.Add(ref srcR, i));
Vector256<float> mtmp = Avx.Subtract(scale, Unsafe.Add(ref srcG, i)); Vector256<float> mtmp = Avx.Subtract(scale, Unsafe.Add(ref srcG, i));

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.CmykVector.cs

@ -30,8 +30,8 @@ internal abstract partial class JpegColorConverterBase
var scale = new Vector<float>(1 / (this.MaximumValue * this.MaximumValue)); var scale = new Vector<float>(1 / (this.MaximumValue * this.MaximumValue));
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector<float> c = ref Unsafe.Add(ref cBase, i); ref Vector<float> c = ref Unsafe.Add(ref cBase, i);
ref Vector<float> m = ref Unsafe.Add(ref mBase, i); ref Vector<float> m = ref Unsafe.Add(ref mBase, i);
@ -78,8 +78,8 @@ internal abstract partial class JpegColorConverterBase
// Used for the color conversion // Used for the color conversion
var scale = new Vector<float>(maxValue); var scale = new Vector<float>(maxValue);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector<float> ctmp = scale - Unsafe.Add(ref srcR, i); Vector<float> ctmp = scale - Unsafe.Add(ref srcR, i);
Vector<float> mtmp = scale - Unsafe.Add(ref srcG, i); Vector<float> mtmp = scale - Unsafe.Add(ref srcG, i);

68
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleArm.cs

@ -0,0 +1,68 @@
// 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.Arm;
using static SixLabors.ImageSharp.SimdUtils;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
internal abstract partial class JpegColorConverterBase
{
internal sealed class GrayscaleArm : JpegColorConverterArm
{
public GrayscaleArm(int precision)
: base(JpegColorSpace.Grayscale, precision)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
// Used for the color conversion
var scale = Vector128.Create(1 / this.MaximumValue);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i);
c0 = AdvSimd.Multiply(c0, scale);
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector128<float> destLuminance =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> srcRed =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector128<float> srcGreen =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector128<float> srcBlue =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane));
// Used for the color conversion
var f0299 = Vector128.Create(0.299f);
var f0587 = Vector128.Create(0.587f);
var f0114 = Vector128.Create(0.114f);
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> r = ref Unsafe.Add(ref srcRed, i);
ref Vector128<float> g = ref Unsafe.Add(ref srcGreen, i);
ref Vector128<float> b = ref Unsafe.Add(ref srcBlue, i);
// luminocity = (0.299 * r) + (0.587 * g) + (0.114 * b)
Unsafe.Add(ref destLuminance, i) = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r);
}
}
}
}

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleAvx.cs

@ -27,8 +27,8 @@ internal abstract partial class JpegColorConverterBase
// Used for the color conversion // Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue); var scale = Vector256.Create(1 / this.MaximumValue);
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector256<float> c0 = ref Unsafe.Add(ref c0Base, i); ref Vector256<float> c0 = ref Unsafe.Add(ref c0Base, i);
c0 = Avx.Multiply(c0, scale); c0 = Avx.Multiply(c0, scale);
@ -53,8 +53,8 @@ internal abstract partial class JpegColorConverterBase
var f0587 = Vector256.Create(0.587f); var f0587 = Vector256.Create(0.587f);
var f0114 = Vector256.Create(0.114f); var f0114 = Vector256.Create(0.114f);
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector256<float> r = ref Unsafe.Add(ref srcRed, i); ref Vector256<float> r = ref Unsafe.Add(ref srcRed, i);
ref Vector256<float> g = ref Unsafe.Add(ref srcGreen, i); ref Vector256<float> g = ref Unsafe.Add(ref srcGreen, i);

2
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleScalar.cs

@ -28,7 +28,7 @@ internal abstract partial class JpegColorConverterBase
ref float valuesRef = ref MemoryMarshal.GetReference(values); ref float valuesRef = ref MemoryMarshal.GetReference(values);
float scale = 1 / maxValue; float scale = 1 / maxValue;
for (nint i = 0; i < values.Length; i++) for (nuint i = 0; i < (uint)values.Length; i++)
{ {
Unsafe.Add(ref valuesRef, i) *= scale; Unsafe.Add(ref valuesRef, i) *= scale;
} }

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.GrayScaleVector.cs

@ -24,8 +24,8 @@ internal abstract partial class JpegColorConverterBase
var scale = new Vector<float>(1 / this.MaximumValue); var scale = new Vector<float>(1 / this.MaximumValue);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector<float> c0 = ref Unsafe.Add(ref cBase, i); ref Vector<float> c0 = ref Unsafe.Add(ref cBase, i);
c0 *= scale; c0 *= scale;
@ -53,8 +53,8 @@ internal abstract partial class JpegColorConverterBase
var gMult = new Vector<float>(0.587f); var gMult = new Vector<float>(0.587f);
var bMult = new Vector<float>(0.114f); var bMult = new Vector<float>(0.114f);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector<float> r = Unsafe.Add(ref srcR, i); Vector<float> r = Unsafe.Add(ref srcR, i);
Vector<float> g = Unsafe.Add(ref srcR, i); Vector<float> g = Unsafe.Add(ref srcR, i);

4
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbArm.cs

@ -30,8 +30,8 @@ internal abstract partial class JpegColorConverterBase
// Used for the color conversion // Used for the color conversion
var scale = Vector128.Create(1 / this.MaximumValue); var scale = Vector128.Create(1 / this.MaximumValue);
nint n = (nint)(uint)values.Component0.Length / Vector128<float>.Count; nuint n = values.Component0.Vector128Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector128<float> r = ref Unsafe.Add(ref rBase, i); ref Vector128<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector128<float> g = ref Unsafe.Add(ref gBase, i); ref Vector128<float> g = ref Unsafe.Add(ref gBase, i);

4
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbAvx.cs

@ -29,8 +29,8 @@ internal abstract partial class JpegColorConverterBase
// Used for the color conversion // Used for the color conversion
var scale = Vector256.Create(1 / this.MaximumValue); var scale = Vector256.Create(1 / this.MaximumValue);
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector256<float> r = ref Unsafe.Add(ref rBase, i); ref Vector256<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector256<float> g = ref Unsafe.Add(ref gBase, i); ref Vector256<float> g = ref Unsafe.Add(ref gBase, i);

4
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.RgbVector.cs

@ -28,8 +28,8 @@ internal abstract partial class JpegColorConverterBase
var scale = new Vector<float>(1 / this.MaximumValue); var scale = new Vector<float>(1 / this.MaximumValue);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
ref Vector<float> r = ref Unsafe.Add(ref rBase, i); ref Vector<float> r = ref Unsafe.Add(ref rBase, i);
ref Vector<float> g = ref Unsafe.Add(ref gBase, i); ref Vector<float> g = ref Unsafe.Add(ref gBase, i);

122
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrArm.cs

@ -0,0 +1,122 @@
// 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.Arm;
using System.Runtime.Intrinsics.X86;
using static SixLabors.ImageSharp.SimdUtils;
// ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
internal abstract partial class JpegColorConverterBase
{
internal sealed class YCbCrArm : JpegColorConverterArm
{
public YCbCrArm(int precision)
: base(JpegColorSpace.YCbCr, precision)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> c1Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> c2Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
// Used for the color conversion
var chromaOffset = Vector128.Create(-this.HalfValue);
var scale = Vector128.Create(1 / this.MaximumValue);
var rCrMult = Vector128.Create(YCbCrScalar.RCrMult);
var gCbMult = Vector128.Create(-YCbCrScalar.GCbMult);
var gCrMult = Vector128.Create(-YCbCrScalar.GCrMult);
var bCbMult = Vector128.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step:
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
// cr = crVals[i] - 128F;
ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector128<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector128<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector128<float> y = c0;
Vector128<float> cb = AdvSimd.Add(c1, chromaOffset);
Vector128<float> cr = AdvSimd.Add(c2, chromaOffset);
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
Vector128<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector128<float> g = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector128<float> b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult);
r = AdvSimd.Multiply(AdvSimd.RoundToNearest(r), scale);
g = AdvSimd.Multiply(AdvSimd.RoundToNearest(g), scale);
b = AdvSimd.Multiply(AdvSimd.RoundToNearest(b), scale);
c0 = r;
c1 = g;
c2 = b;
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
ref Vector128<float> destY =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> destCb =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> destCr =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> srcR =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(rLane));
ref Vector128<float> srcG =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(gLane));
ref Vector128<float> srcB =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(bLane));
// Used for the color conversion
var chromaOffset = Vector128.Create(this.HalfValue);
var f0299 = Vector128.Create(0.299f);
var f0587 = Vector128.Create(0.587f);
var f0114 = Vector128.Create(0.114f);
var fn0168736 = Vector128.Create(-0.168736f);
var fn0331264 = Vector128.Create(-0.331264f);
var fn0418688 = Vector128.Create(-0.418688f);
var fn0081312F = Vector128.Create(-0.081312F);
var f05 = Vector128.Create(0.5f);
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
for (nuint i = 0; i < n; i++)
{
Vector128<float> r = Unsafe.Add(ref srcR, i);
Vector128<float> g = Unsafe.Add(ref srcG, i);
Vector128<float> b = Unsafe.Add(ref srcB, i);
// y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b)
// cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b)
// cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b)
Vector128<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r);
Vector128<float> cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r));
Vector128<float> cr = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(fn0081312F, b), fn0418688, g), f05, r));
Unsafe.Add(ref destY, i) = y;
Unsafe.Add(ref destCb, i) = cb;
Unsafe.Add(ref destCr, i) = cr;
}
}
}
}

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrAvx.cs

@ -38,8 +38,8 @@ internal abstract partial class JpegColorConverterBase
var bCbMult = Vector256.Create(YCbCrScalar.BCbMult); var bCbMult = Vector256.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step: // Walking 8 elements at one step:
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
// y = yVals[i]; // y = yVals[i];
// cb = cbVals[i] - 128F; // cb = cbVals[i] - 128F;
@ -98,8 +98,8 @@ internal abstract partial class JpegColorConverterBase
var fn0081312F = Vector256.Create(-0.081312F); var fn0081312F = Vector256.Create(-0.081312F);
var f05 = Vector256.Create(0.5f); var f05 = Vector256.Create(0.5f);
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector256<float> r = Unsafe.Add(ref srcR, i); Vector256<float> r = Unsafe.Add(ref srcR, i);
Vector256<float> g = Unsafe.Add(ref srcG, i); Vector256<float> g = Unsafe.Add(ref srcG, i);

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YCbCrVector.cs

@ -35,8 +35,8 @@ internal abstract partial class JpegColorConverterBase
var gCrMult = new Vector<float>(-YCbCrScalar.GCrMult); var gCrMult = new Vector<float>(-YCbCrScalar.GCrMult);
var bCbMult = new Vector<float>(YCbCrScalar.BCbMult); var bCbMult = new Vector<float>(YCbCrScalar.BCbMult);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
// y = yVals[i]; // y = yVals[i];
// cb = cbVals[i] - 128F; // cb = cbVals[i] - 128F;
@ -103,8 +103,8 @@ internal abstract partial class JpegColorConverterBase
var gCrMult = new Vector<float>(0.418688f); var gCrMult = new Vector<float>(0.418688f);
var bCrMult = new Vector<float>(0.081312f); var bCrMult = new Vector<float>(0.081312f);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector<float> r = Unsafe.Add(ref srcR, i); Vector<float> r = Unsafe.Add(ref srcR, i);
Vector<float> g = Unsafe.Add(ref srcG, i); Vector<float> g = Unsafe.Add(ref srcG, i);

133
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKArm64.cs

@ -0,0 +1,133 @@
// 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.Arm;
using System.Runtime.Intrinsics.X86;
using static SixLabors.ImageSharp.SimdUtils;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components;
internal abstract partial class JpegColorConverterBase
{
internal sealed class YccKArm64 : JpegColorConverterArm64
{
public YccKArm64(int precision)
: base(JpegColorSpace.Ycck, precision)
{
}
/// <inheritdoc/>
public override void ConvertToRgbInplace(in ComponentValues values)
{
ref Vector128<float> c0Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> c1Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> c2Base =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> kBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component3));
// Used for the color conversion
var chromaOffset = Vector128.Create(-this.HalfValue);
var scale = Vector128.Create(1 / (this.MaximumValue * this.MaximumValue));
var max = Vector128.Create(this.MaximumValue);
var rCrMult = Vector128.Create(YCbCrScalar.RCrMult);
var gCbMult = Vector128.Create(-YCbCrScalar.GCbMult);
var gCrMult = Vector128.Create(-YCbCrScalar.GCrMult);
var bCbMult = Vector128.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step:
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
// cr = crVals[i] - 128F;
// k = kVals[i] / 256F;
ref Vector128<float> c0 = ref Unsafe.Add(ref c0Base, i);
ref Vector128<float> c1 = ref Unsafe.Add(ref c1Base, i);
ref Vector128<float> c2 = ref Unsafe.Add(ref c2Base, i);
Vector128<float> y = c0;
Vector128<float> cb = AdvSimd.Add(c1, chromaOffset);
Vector128<float> cr = AdvSimd.Add(c2, chromaOffset);
Vector128<float> scaledK = AdvSimd.Multiply(Unsafe.Add(ref kBase, i), scale);
// r = y + (1.402F * cr);
// g = y - (0.344136F * cb) - (0.714136F * cr);
// b = y + (1.772F * cb);
Vector128<float> r = HwIntrinsics.MultiplyAdd(y, cr, rCrMult);
Vector128<float> g =
HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(y, cb, gCbMult), cr, gCrMult);
Vector128<float> b = HwIntrinsics.MultiplyAdd(y, cb, bCbMult);
r = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(r));
g = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(g));
b = AdvSimd.Subtract(max, AdvSimd.RoundToNearest(b));
r = AdvSimd.Multiply(r, scaledK);
g = AdvSimd.Multiply(g, scaledK);
b = AdvSimd.Multiply(b, scaledK);
c0 = r;
c1 = g;
c2 = b;
}
}
/// <inheritdoc/>
public override void ConvertFromRgb(in ComponentValues values, Span<float> rLane, Span<float> gLane, Span<float> bLane)
{
// rgb -> cmyk
CmykArm64.ConvertFromRgb(in values, this.MaximumValue, rLane, gLane, bLane);
// cmyk -> ycck
ref Vector128<float> destY =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component0));
ref Vector128<float> destCb =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component1));
ref Vector128<float> destCr =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(values.Component2));
ref Vector128<float> srcR = ref destY;
ref Vector128<float> srcG = ref destCb;
ref Vector128<float> srcB = ref destCr;
// Used for the color conversion
var maxSampleValue = Vector128.Create(this.MaximumValue);
var chromaOffset = Vector128.Create(this.HalfValue);
var f0299 = Vector128.Create(0.299f);
var f0587 = Vector128.Create(0.587f);
var f0114 = Vector128.Create(0.114f);
var fn0168736 = Vector128.Create(-0.168736f);
var fn0331264 = Vector128.Create(-0.331264f);
var fn0418688 = Vector128.Create(-0.418688f);
var fn0081312F = Vector128.Create(-0.081312F);
var f05 = Vector128.Create(0.5f);
nuint n = (uint)values.Component0.Length / (uint)Vector128<float>.Count;
for (nuint i = 0; i < n; i++)
{
Vector128<float> r = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i));
Vector128<float> g = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i));
Vector128<float> b = AdvSimd.Subtract(maxSampleValue, Unsafe.Add(ref srcB, i));
// y = 0 + (0.299 * r) + (0.587 * g) + (0.114 * b)
// cb = 128 - (0.168736 * r) - (0.331264 * g) + (0.5 * b)
// cr = 128 + (0.5 * r) - (0.418688 * g) - (0.081312 * b)
Vector128<float> y = HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f0114, b), f0587, g), f0299, r);
Vector128<float> cb = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(f05, b), fn0331264, g), fn0168736, r));
Vector128<float> cr = AdvSimd.Add(chromaOffset, HwIntrinsics.MultiplyAdd(HwIntrinsics.MultiplyAdd(AdvSimd.Multiply(fn0081312F, b), fn0418688, g), f05, r));
Unsafe.Add(ref destY, i) = y;
Unsafe.Add(ref destCb, i) = cb;
Unsafe.Add(ref destCr, i) = cr;
}
}
}
}

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKAvx.cs

@ -40,8 +40,8 @@ internal abstract partial class JpegColorConverterBase
var bCbMult = Vector256.Create(YCbCrScalar.BCbMult); var bCbMult = Vector256.Create(YCbCrScalar.BCbMult);
// Walking 8 elements at one step: // Walking 8 elements at one step:
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
// y = yVals[i]; // y = yVals[i];
// cb = cbVals[i] - 128F; // cb = cbVals[i] - 128F;
@ -109,8 +109,8 @@ internal abstract partial class JpegColorConverterBase
var fn0081312F = Vector256.Create(-0.081312F); var fn0081312F = Vector256.Create(-0.081312F);
var f05 = Vector256.Create(0.5f); var f05 = Vector256.Create(0.5f);
nint n = values.Component0.Length / Vector256<float>.Count; nuint n = values.Component0.Vector256Count<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector256<float> r = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i)); Vector256<float> r = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcR, i));
Vector256<float> g = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i)); Vector256<float> g = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcG, i));

8
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverter.YccKVector.cs

@ -36,8 +36,8 @@ internal abstract partial class JpegColorConverterBase
var gCrMult = new Vector<float>(-YCbCrScalar.GCrMult); var gCrMult = new Vector<float>(-YCbCrScalar.GCrMult);
var bCbMult = new Vector<float>(YCbCrScalar.BCbMult); var bCbMult = new Vector<float>(YCbCrScalar.BCbMult);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
// y = yVals[i]; // y = yVals[i];
// cb = cbVals[i] - 128F; // cb = cbVals[i] - 128F;
@ -107,8 +107,8 @@ internal abstract partial class JpegColorConverterBase
var gCrMult = new Vector<float>(0.418688f); var gCrMult = new Vector<float>(0.418688f);
var bCrMult = new Vector<float>(0.081312f); var bCrMult = new Vector<float>(0.081312f);
nint n = values.Component0.Length / Vector<float>.Count; nuint n = values.Component0.VectorCount<float>();
for (nint i = 0; i < n; i++) for (nuint i = 0; i < n; i++)
{ {
Vector<float> r = maxSampleValue - Unsafe.Add(ref srcR, i); Vector<float> r = maxSampleValue - Unsafe.Add(ref srcR, i);
Vector<float> g = maxSampleValue - Unsafe.Add(ref srcG, i); Vector<float> g = maxSampleValue - Unsafe.Add(ref srcG, i);

21
src/ImageSharp/Formats/Jpeg/Components/ColorConverters/JpegColorConverterBase.cs

@ -26,7 +26,7 @@ internal abstract partial class JpegColorConverterBase
this.ColorSpace = colorSpace; this.ColorSpace = colorSpace;
this.Precision = precision; this.Precision = precision;
this.MaximumValue = MathF.Pow(2, precision) - 1; this.MaximumValue = MathF.Pow(2, precision) - 1;
this.HalfValue = MathF.Ceiling(this.MaximumValue / 2); this.HalfValue = MathF.Ceiling(this.MaximumValue * 0.5F); // /2
} }
/// <summary> /// <summary>
@ -138,6 +138,11 @@ internal abstract partial class JpegColorConverterBase
return new YCbCrAvx(precision); return new YCbCrAvx(precision);
} }
if (JpegColorConverterArm.IsSupported)
{
return new YCbCrArm(precision);
}
if (JpegColorConverterVector.IsSupported) if (JpegColorConverterVector.IsSupported)
{ {
return new YCbCrVector(precision); return new YCbCrVector(precision);
@ -157,6 +162,11 @@ internal abstract partial class JpegColorConverterBase
return new YccKAvx(precision); return new YccKAvx(precision);
} }
if (JpegColorConverterArm64.IsSupported)
{
return new YccKArm64(precision);
}
if (JpegColorConverterVector.IsSupported) if (JpegColorConverterVector.IsSupported)
{ {
return new YccKVector(precision); return new YccKVector(precision);
@ -200,6 +210,11 @@ internal abstract partial class JpegColorConverterBase
return new GrayscaleAvx(precision); return new GrayscaleAvx(precision);
} }
if (JpegColorConverterArm.IsSupported)
{
return new GrayscaleArm(precision);
}
if (JpegColorConverterVector.IsSupported) if (JpegColorConverterVector.IsSupported)
{ {
return new GrayScaleVector(precision); return new GrayScaleVector(precision);
@ -226,10 +241,10 @@ internal abstract partial class JpegColorConverterBase
if (JpegColorConverterVector.IsSupported) if (JpegColorConverterVector.IsSupported)
{ {
return new RgbScalar(precision); return new RgbVector(precision);
} }
return new GrayscaleScalar(precision); return new RgbScalar(precision);
} }
/// <summary> /// <summary>

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/AdobeMarker.cs

@ -62,7 +62,7 @@ internal readonly struct AdobeMarker : IEquatable<AdobeMarker>
/// </summary> /// </summary>
/// <param name="bytes">The byte array containing metadata to parse.</param> /// <param name="bytes">The byte array containing metadata to parse.</param>
/// <param name="marker">The marker to return.</param> /// <param name="marker">The marker to return.</param>
public static bool TryParse(byte[] bytes, out AdobeMarker marker) public static bool TryParse(ReadOnlySpan<byte> bytes, out AdobeMarker marker)
{ {
if (ProfileResolver.IsProfile(bytes, ProfileResolver.AdobeMarker)) if (ProfileResolver.IsProfile(bytes, ProfileResolver.AdobeMarker))
{ {

31
src/ImageSharp/Formats/Jpeg/Components/Decoder/ArithmeticScanDecoder.cs

@ -53,6 +53,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
private ArithmeticDecodingTable[] acDecodingTables; private ArithmeticDecodingTable[] acDecodingTables;
// Don't make this a ReadOnlySpan<byte>, as the values need to get updated.
private readonly byte[] fixedBin = { 113, 0, 0, 0 }; private readonly byte[] fixedBin = { 113, 0, 0, 0 };
private readonly CancellationToken cancellationToken; private readonly CancellationToken cancellationToken;
@ -231,7 +232,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
} }
} }
private ref byte GetFixedBinReference() => ref this.fixedBin[0]; private ref byte GetFixedBinReference() => ref MemoryMarshal.GetArrayDataReference(this.fixedBin);
/// <summary> /// <summary>
/// Decodes the entropy coded data. /// Decodes the entropy coded data.
@ -470,7 +471,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline( this.DecodeBlockBaseline(
component, component,
ref Unsafe.Add(ref blockRef, (nint)(uint)blockCol), ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref acDecodingTable, ref acDecodingTable,
ref dcDecodingTable); ref dcDecodingTable);
} }
@ -521,7 +522,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline( this.DecodeBlockBaseline(
component, component,
ref Unsafe.Add(ref blockRef, (nint)(uint)k), ref Unsafe.Add(ref blockRef, (uint)k),
ref acDecodingTable, ref acDecodingTable,
ref dcDecodingTable); ref dcDecodingTable);
@ -560,7 +561,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline( this.DecodeBlockBaseline(
component, component,
ref Unsafe.Add(ref blockRef, (nint)(uint)i), ref Unsafe.Add(ref blockRef, (uint)i),
ref acDecodingTable, ref acDecodingTable,
ref dcDecodingTable); ref dcDecodingTable);
@ -611,7 +612,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDc( this.DecodeBlockProgressiveDc(
component, component,
ref Unsafe.Add(ref blockRef, (nint)(uint)blockCol), ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref dcDecodingTable); ref dcDecodingTable);
} }
} }
@ -653,7 +654,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDc( this.DecodeBlockProgressiveDc(
component, component,
ref Unsafe.Add(ref blockRef, (nint)(uint)i), ref Unsafe.Add(ref blockRef, (uint)i),
ref dcDecodingTable); ref dcDecodingTable);
this.HandleRestart(); this.HandleRestart();
@ -680,7 +681,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveAc( this.DecodeBlockProgressiveAc(
component, component,
ref Unsafe.Add(ref blockRef, (nint)(uint)i), ref Unsafe.Add(ref blockRef, (uint)i),
ref acDecodingTable); ref acDecodingTable);
this.HandleRestart(); this.HandleRestart();
@ -705,7 +706,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
// Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients. // Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients.
// Table F.4: Point to statistics bin S0 for DC coefficient coding. // Table F.4: Point to statistics bin S0 for DC coefficient coding.
ref byte st = ref Unsafe.Add(ref component.DcStatistics.GetReference(), component.DcContext); ref byte st = ref Unsafe.Add(ref component.DcStatistics.GetReference(), (uint)component.DcContext);
// Figure F.19: Decode_DC_DIFF // Figure F.19: Decode_DC_DIFF
if (this.DecodeBinaryDecision(ref reader, ref st) == 0) if (this.DecodeBinaryDecision(ref reader, ref st) == 0)
@ -717,7 +718,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
// Figure F.21: Decoding nonzero value v. // Figure F.21: Decoding nonzero value v.
// Figure F.22: Decoding the sign of v. // Figure F.22: Decoding the sign of v.
int sign = this.DecodeBinaryDecision(ref reader, ref Unsafe.Add(ref st, 1)); int sign = this.DecodeBinaryDecision(ref reader, ref Unsafe.Add(ref st, 1));
st = ref Unsafe.Add(ref st, (nint)(uint)(2 + sign)); st = ref Unsafe.Add(ref st, (uint)(2 + sign));
// Figure F.23: Decoding the magnitude category of v. // Figure F.23: Decoding the magnitude category of v.
int m = this.DecodeBinaryDecision(ref reader, ref st); int m = this.DecodeBinaryDecision(ref reader, ref st);
@ -761,7 +762,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
} }
} }
v += 1; v++;
if (sign != 0) if (sign != 0)
{ {
v = -v; v = -v;
@ -856,7 +857,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
} }
} }
v += 1; v++;
if (sign != 0) if (sign != 0)
{ {
v = -v; v = -v;
@ -955,7 +956,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
// Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients. // Sections F.2.4.1 & F.1.4.4.1: Decoding of DC coefficients.
// Table F.4: Point to statistics bin S0 for DC coefficient coding. // Table F.4: Point to statistics bin S0 for DC coefficient coding.
ref byte st = ref Unsafe.Add(ref component.DcStatistics.GetReference(), component.DcContext); ref byte st = ref Unsafe.Add(ref component.DcStatistics.GetReference(), (uint)component.DcContext);
/* Figure F.19: Decode_DC_DIFF */ /* Figure F.19: Decode_DC_DIFF */
if (this.DecodeBinaryDecision(ref reader, ref st) == 0) if (this.DecodeBinaryDecision(ref reader, ref st) == 0)
@ -967,7 +968,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
// Figure F.21: Decoding nonzero value v // Figure F.21: Decoding nonzero value v
// Figure F.22: Decoding the sign of v // Figure F.22: Decoding the sign of v
int sign = this.DecodeBinaryDecision(ref reader, ref Unsafe.Add(ref st, 1)); int sign = this.DecodeBinaryDecision(ref reader, ref Unsafe.Add(ref st, 1));
st = ref Unsafe.Add(ref st, (nint)(uint)(2 + sign)); st = ref Unsafe.Add(ref st, (uint)(2 + sign));
// Figure F.23: Decoding the magnitude category of v. // Figure F.23: Decoding the magnitude category of v.
int m = this.DecodeBinaryDecision(ref reader, ref st); int m = this.DecodeBinaryDecision(ref reader, ref st);
@ -1012,7 +1013,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
} }
} }
v += 1; v++;
if (sign != 0) if (sign != 0)
{ {
v = -v; v = -v;
@ -1082,7 +1083,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
} }
} }
v += 1; v++;
if (sign != 0) if (sign != 0)
{ {
v = -v; v = -v;

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

@ -1,6 +1,8 @@
// Copyright (c) Six Labors. // Copyright (c) Six Labors.
// Licensed under the Six Labors Split License. // Licensed under the Six Labors Split License.
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
internal class ArithmeticStatistics internal class ArithmeticStatistics
@ -18,7 +20,7 @@ internal class ArithmeticStatistics
public int Identifier { get; private set; } public int Identifier { get; private set; }
public ref byte GetReference() => ref this.statistics[0]; public ref byte GetReference() => ref MemoryMarshal.GetArrayDataReference(this.statistics);
public ref byte GetReference(int offset) => ref this.statistics[offset]; public ref byte GetReference(int offset) => ref this.statistics[offset];

24
src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor2.cs

@ -25,7 +25,7 @@ internal sealed class DownScalingComponentProcessor2 : ComponentProcessor
Buffer2D<Block8x8> spectralBuffer = this.Component.SpectralBlocks; Buffer2D<Block8x8> spectralBuffer = this.Component.SpectralBlocks;
float maximumValue = this.Frame.MaxColorChannelValue; float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2); float normalizationValue = MathF.Ceiling(maximumValue * 0.5F);
int destAreaStride = this.ColorBuffer.Width; int destAreaStride = this.ColorBuffer.Width;
@ -67,30 +67,30 @@ internal sealed class DownScalingComponentProcessor2 : ComponentProcessor
public static void ScaledCopyTo(ref Block8x8F block, ref float destRef, int destStrideWidth, int horizontalScale, int verticalScale) public static void ScaledCopyTo(ref Block8x8F block, ref float destRef, int destStrideWidth, int horizontalScale, int verticalScale)
{ {
// TODO: Optimize: implement all cases with scale-specific, loopless code! // TODO: Optimize: implement all cases with scale-specific, loopless code!
CopyArbitraryScale(ref block, ref destRef, destStrideWidth, horizontalScale, verticalScale); CopyArbitraryScale(ref block, ref destRef, (uint)destStrideWidth, (uint)horizontalScale, (uint)verticalScale);
[MethodImpl(InliningOptions.ColdPath)] [MethodImpl(InliningOptions.ColdPath)]
static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale) static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
{ {
for (int y = 0; y < 4; y++) for (nuint y = 0; y < 4; y++)
{ {
int yy = y * verticalScale; nuint yy = y * verticalScale;
int y8 = y * 8; nuint y8 = y * 8;
for (int x = 0; x < 4; x++) for (nuint x = 0; x < 4; x++)
{ {
int xx = x * horizontalScale; nuint xx = x * horizontalScale;
float value = block[y8 + x]; float value = block[y8 + x];
for (int i = 0; i < verticalScale; i++) for (nuint i = 0; i < verticalScale; i++)
{ {
int baseIdx = ((yy + i) * areaStride) + xx; nuint baseIdx = ((yy + i) * areaStride) + xx;
for (int j = 0; j < horizontalScale; j++) for (nuint j = 0; j < horizontalScale; j++)
{ {
// area[xx + j, yy + i] = value; // area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, (nint)(uint)(baseIdx + j)) = value; Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
} }
} }
} }

24
src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor4.cs

@ -25,7 +25,7 @@ internal sealed class DownScalingComponentProcessor4 : ComponentProcessor
Buffer2D<Block8x8> spectralBuffer = this.Component.SpectralBlocks; Buffer2D<Block8x8> spectralBuffer = this.Component.SpectralBlocks;
float maximumValue = this.Frame.MaxColorChannelValue; float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2); float normalizationValue = MathF.Ceiling(maximumValue * 0.5F);
int destAreaStride = this.ColorBuffer.Width; int destAreaStride = this.ColorBuffer.Width;
@ -67,30 +67,30 @@ internal sealed class DownScalingComponentProcessor4 : ComponentProcessor
public static void ScaledCopyTo(ref Block8x8F block, ref float destRef, int destStrideWidth, int horizontalScale, int verticalScale) public static void ScaledCopyTo(ref Block8x8F block, ref float destRef, int destStrideWidth, int horizontalScale, int verticalScale)
{ {
// TODO: Optimize: implement all cases with scale-specific, loopless code! // TODO: Optimize: implement all cases with scale-specific, loopless code!
CopyArbitraryScale(ref block, ref destRef, destStrideWidth, horizontalScale, verticalScale); CopyArbitraryScale(ref block, ref destRef, (uint)destStrideWidth, (uint)horizontalScale, (uint)verticalScale);
[MethodImpl(InliningOptions.ColdPath)] [MethodImpl(InliningOptions.ColdPath)]
static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, int areaStride, int horizontalScale, int verticalScale) static void CopyArbitraryScale(ref Block8x8F block, ref float areaOrigin, uint areaStride, uint horizontalScale, uint verticalScale)
{ {
for (int y = 0; y < 2; y++) for (nuint y = 0; y < 2; y++)
{ {
int yy = y * verticalScale; nuint yy = y * verticalScale;
int y8 = y * 8; nuint y8 = y * 8;
for (int x = 0; x < 2; x++) for (nuint x = 0; x < 2; x++)
{ {
int xx = x * horizontalScale; nuint xx = x * horizontalScale;
float value = block[y8 + x]; float value = block[y8 + x];
for (int i = 0; i < verticalScale; i++) for (nuint i = 0; i < verticalScale; i++)
{ {
int baseIdx = ((yy + i) * areaStride) + xx; nuint baseIdx = ((yy + i) * areaStride) + xx;
for (int j = 0; j < horizontalScale; j++) for (nuint j = 0; j < horizontalScale; j++)
{ {
// area[xx + j, yy + i] = value; // area[xx + j, yy + i] = value;
Unsafe.Add(ref areaOrigin, (nint)(uint)(baseIdx + j)) = value; Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
} }
} }
} }

14
src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/DownScalingComponentProcessor8.cs

@ -22,7 +22,7 @@ internal sealed class DownScalingComponentProcessor8 : ComponentProcessor
Buffer2D<Block8x8> spectralBuffer = this.Component.SpectralBlocks; Buffer2D<Block8x8> spectralBuffer = this.Component.SpectralBlocks;
float maximumValue = this.Frame.MaxColorChannelValue; float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2); float normalizationValue = MathF.Ceiling(maximumValue * 0.5F);
int destAreaStride = this.ColorBuffer.Width; int destAreaStride = this.ColorBuffer.Width;
@ -67,20 +67,20 @@ internal sealed class DownScalingComponentProcessor8 : ComponentProcessor
{ {
destRef = value; destRef = value;
Unsafe.Add(ref destRef, 1) = value; Unsafe.Add(ref destRef, 1) = value;
Unsafe.Add(ref destRef, 0 + (nint)(uint)destStrideWidth) = value; Unsafe.Add(ref destRef, 0 + (uint)destStrideWidth) = value;
Unsafe.Add(ref destRef, 1 + (nint)(uint)destStrideWidth) = value; Unsafe.Add(ref destRef, 1 + (uint)destStrideWidth) = value;
return; return;
} }
// TODO: Optimize: implement all cases with scale-specific, loopless code! // TODO: Optimize: implement all cases with scale-specific, loopless code!
for (int y = 0; y < verticalScale; y++) for (nuint y = 0; y < (uint)verticalScale; y++)
{ {
for (int x = 0; x < horizontalScale; x++) for (nuint x = 0; x < (uint)horizontalScale; x++)
{ {
Unsafe.Add(ref destRef, (nint)(uint)x) = value; Unsafe.Add(ref destRef, x) = value;
} }
destRef = ref Unsafe.Add(ref destRef, (nint)(uint)destStrideWidth); destRef = ref Unsafe.Add(ref destRef, (uint)destStrideWidth);
} }
} }
} }

12
src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanScanDecoder.cs

@ -211,7 +211,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline( this.DecodeBlockBaseline(
component, component,
ref Unsafe.Add(ref blockRef, blockCol), ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref dcHuffmanTable, ref dcHuffmanTable,
ref acHuffmanTable); ref acHuffmanTable);
} }
@ -255,7 +255,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline( this.DecodeBlockBaseline(
component, component,
ref Unsafe.Add(ref blockRef, i), ref Unsafe.Add(ref blockRef, (uint)i),
ref dcHuffmanTable, ref dcHuffmanTable,
ref acHuffmanTable); ref acHuffmanTable);
@ -297,7 +297,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline( this.DecodeBlockBaseline(
component, component,
ref Unsafe.Add(ref blockRef, k), ref Unsafe.Add(ref blockRef, (uint)k),
ref dcHuffmanTable, ref dcHuffmanTable,
ref acHuffmanTable); ref acHuffmanTable);
@ -417,7 +417,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDC( this.DecodeBlockProgressiveDC(
component, component,
ref Unsafe.Add(ref blockRef, blockCol), ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref dcHuffmanTable); ref dcHuffmanTable);
} }
} }
@ -459,7 +459,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDC( this.DecodeBlockProgressiveDC(
component, component,
ref Unsafe.Add(ref blockRef, i), ref Unsafe.Add(ref blockRef, (uint)i),
ref dcHuffmanTable); ref dcHuffmanTable);
this.HandleRestart(); this.HandleRestart();
@ -485,7 +485,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
} }
this.DecodeBlockProgressiveAC( this.DecodeBlockProgressiveAC(
ref Unsafe.Add(ref blockRef, i), ref Unsafe.Add(ref blockRef, (uint)i),
ref acHuffmanTable); ref acHuffmanTable);
this.HandleRestart(); this.HandleRestart();

2
src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs

@ -69,7 +69,7 @@ internal readonly struct JFifMarker : IEquatable<JFifMarker>
/// </summary> /// </summary>
/// <param name="bytes">The byte array containing metadata to parse.</param> /// <param name="bytes">The byte array containing metadata to parse.</param>
/// <param name="marker">The marker to return.</param> /// <param name="marker">The marker to return.</param>
public static bool TryParse(byte[] bytes, out JFifMarker marker) public static bool TryParse(ReadOnlySpan<byte> bytes, out JFifMarker marker)
{ {
if (ProfileResolver.IsProfile(bytes, ProfileResolver.JFifMarker)) if (ProfileResolver.IsProfile(bytes, ProfileResolver.JFifMarker))
{ {

23
src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs

@ -184,34 +184,39 @@ internal class SpectralConverter<TPixel> : SpectralConverter, IDisposable
MemoryAllocator allocator = this.Configuration.MemoryAllocator; MemoryAllocator allocator = this.Configuration.MemoryAllocator;
// color converter from RGB to TPixel // Color converter from RGB to TPixel
JpegColorConverterBase converter = this.GetColorConverter(this.frame, this.jpegData); JpegColorConverterBase converter = this.GetColorConverter(this.frame, this.jpegData);
this.colorConverter = converter; this.colorConverter = converter;
// resulting image size // Resulting image size
Size pixelSize = CalculateResultingImageSize(this.frame.PixelSize, this.targetSize, out int blockPixelSize); Size pixelSize = CalculateResultingImageSize(this.frame.PixelSize, this.targetSize, out int blockPixelSize);
// iteration data // Iteration data
int majorBlockWidth = this.frame.Components.Max((component) => component.SizeInBlocks.Width); int majorBlockWidth = this.frame.Components.Max((component) => component.SizeInBlocks.Width);
int majorVerticalSamplingFactor = this.frame.Components.Max((component) => component.SamplingFactors.Height); int majorVerticalSamplingFactor = this.frame.Components.Max((component) => component.SamplingFactors.Height);
this.pixelRowsPerStep = majorVerticalSamplingFactor * blockPixelSize; this.pixelRowsPerStep = majorVerticalSamplingFactor * blockPixelSize;
// pixel buffer for resulting image // Pixel buffer for resulting image
this.pixelBuffer = allocator.Allocate2D<TPixel>( this.pixelBuffer = allocator.Allocate2D<TPixel>(
pixelSize.Width, pixelSize.Width,
pixelSize.Height, pixelSize.Height,
this.Configuration.PreferContiguousImageBuffers); this.Configuration.PreferContiguousImageBuffers);
this.paddedProxyPixelRow = allocator.Allocate<TPixel>(pixelSize.Width + 3); this.paddedProxyPixelRow = allocator.Allocate<TPixel>(pixelSize.Width + 3);
// component processors from spectral to RGB // Component processors from spectral to RGB
int bufferWidth = majorBlockWidth * blockPixelSize; int bufferWidth = majorBlockWidth * blockPixelSize;
int batchSize = converter.ElementsPerBatch;
int batchRemainder = bufferWidth & (batchSize - 1); // Converters process pixels in batches and require target buffer size to be divisible by a batch size
Size postProcessorBufferSize = new(bufferWidth + (batchSize - batchRemainder), this.pixelRowsPerStep); // Corner case: image size including jpeg padding is already divisible by a batch size or remainder == 0
int elementsPerBatch = converter.ElementsPerBatch;
int batchRemainder = bufferWidth & (elementsPerBatch - 1);
int widthComplementaryValue = batchRemainder == 0 ? 0 : elementsPerBatch - batchRemainder;
Size postProcessorBufferSize = new(bufferWidth + widthComplementaryValue, this.pixelRowsPerStep);
this.componentProcessors = this.CreateComponentProcessors(this.frame, this.jpegData, blockPixelSize, postProcessorBufferSize); this.componentProcessors = this.CreateComponentProcessors(this.frame, this.jpegData, blockPixelSize, postProcessorBufferSize);
// single 'stride' rgba32 buffer for conversion between spectral and TPixel // Single 'stride' rgba32 buffer for conversion between spectral and TPixel
this.rgbBuffer = allocator.Allocate<byte>(pixelSize.Width * 3); this.rgbBuffer = allocator.Allocate<byte>(pixelSize.Width * 3);
} }

57
src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs

@ -5,6 +5,7 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using System.Runtime.Intrinsics; using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86; using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
@ -122,26 +123,40 @@ internal class ComponentProcessor : IDisposable
ref Vector256<float> sourceVectorRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source)); ref Vector256<float> sourceVectorRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source));
// Spans are guaranteed to be multiple of 8 so no extra 'remainder' steps are needed // Spans are guaranteed to be multiple of 8 so no extra 'remainder' steps are needed
nint count = source.Length / Vector256<float>.Count; DebugGuard.IsTrue(source.Length % 8 == 0, "source must be multiple of 8");
for (nint i = 0; i < count; i++) nuint count = source.Vector256Count<float>();
for (nuint i = 0; i < count; i++)
{ {
Unsafe.Add(ref targetVectorRef, i) = Avx.Add(Unsafe.Add(ref targetVectorRef, i), Unsafe.Add(ref sourceVectorRef, i)); Unsafe.Add(ref targetVectorRef, i) = Avx.Add(Unsafe.Add(ref targetVectorRef, i), Unsafe.Add(ref sourceVectorRef, i));
} }
} }
else if (AdvSimd.IsSupported)
{
ref Vector128<float> targetVectorRef = ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(target));
ref Vector128<float> sourceVectorRef = ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(source));
// Spans are guaranteed to be multiple of 8 so no extra 'remainder' steps are needed
DebugGuard.IsTrue(source.Length % 8 == 0, "source must be multiple of 8");
nuint count = source.Vector128Count<float>();
for (nuint i = 0; i < count; i++)
{
Unsafe.Add(ref targetVectorRef, i) = AdvSimd.Add(Unsafe.Add(ref targetVectorRef, i), Unsafe.Add(ref sourceVectorRef, i));
}
}
else else
{ {
ref Vector<float> targetVectorRef = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(target)); ref Vector<float> targetVectorRef = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(target));
ref Vector<float> sourceVectorRef = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source)); ref Vector<float> sourceVectorRef = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
nint count = source.Length / Vector<float>.Count; nuint count = source.VectorCount<float>();
for (nint i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
Unsafe.Add(ref targetVectorRef, i) += Unsafe.Add(ref sourceVectorRef, i); Unsafe.Add(ref targetVectorRef, i) += Unsafe.Add(ref sourceVectorRef, i);
} }
ref float targetRef = ref MemoryMarshal.GetReference(target); ref float targetRef = ref MemoryMarshal.GetReference(target);
ref float sourceRef = ref MemoryMarshal.GetReference(source); ref float sourceRef = ref MemoryMarshal.GetReference(source);
for (nint i = count * Vector<float>.Count; i < source.Length; i++) for (nuint i = count * (uint)Vector<float>.Count; i < (uint)source.Length; i++)
{ {
Unsafe.Add(ref targetRef, i) += Unsafe.Add(ref sourceRef, i); Unsafe.Add(ref targetRef, i) += Unsafe.Add(ref sourceRef, i);
} }
@ -157,7 +172,7 @@ internal class ComponentProcessor : IDisposable
// Ideally we need to use log2: Numerics.Log2((uint)factor) // Ideally we need to use log2: Numerics.Log2((uint)factor)
// but division by 2 works just fine in this case // but division by 2 works just fine in this case
int haddIterationsCount = (int)((uint)factor / 2); uint haddIterationsCount = (uint)factor / 2;
// Transform spans so that it only contains 'remainder' // Transform spans so that it only contains 'remainder'
// values for the scalar fallback code // values for the scalar fallback code
@ -166,9 +181,9 @@ internal class ComponentProcessor : IDisposable
source = source.Slice(touchedCount); source = source.Slice(touchedCount);
target = target.Slice(touchedCount / factor); target = target.Slice(touchedCount / factor);
uint length = (uint)touchedCount / (uint)Vector256<float>.Count; nuint length = Numerics.Vector256Count<float>(touchedCount);
for (int i = 0; i < haddIterationsCount; i++) for (uint i = 0; i < haddIterationsCount; i++)
{ {
length /= 2; length /= 2;
@ -200,26 +215,40 @@ internal class ComponentProcessor : IDisposable
ref Vector256<float> targetVectorRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(target)); ref Vector256<float> targetVectorRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(target));
// Spans are guaranteed to be multiple of 8 so no extra 'remainder' steps are needed // Spans are guaranteed to be multiple of 8 so no extra 'remainder' steps are needed
nint count = target.Length / Vector256<float>.Count; DebugGuard.IsTrue(target.Length % 8 == 0, "target must be multiple of 8");
var multiplierVector = Vector256.Create(multiplier); nuint count = target.Vector256Count<float>();
for (nint i = 0; i < count; i++) Vector256<float> multiplierVector = Vector256.Create(multiplier);
for (nuint i = 0; i < count; i++)
{ {
Unsafe.Add(ref targetVectorRef, i) = Avx.Multiply(Unsafe.Add(ref targetVectorRef, i), multiplierVector); Unsafe.Add(ref targetVectorRef, i) = Avx.Multiply(Unsafe.Add(ref targetVectorRef, i), multiplierVector);
} }
} }
else if (AdvSimd.IsSupported)
{
ref Vector128<float> targetVectorRef = ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(target));
// Spans are guaranteed to be multiple of 8 so no extra 'remainder' steps are needed
DebugGuard.IsTrue(target.Length % 8 == 0, "target must be multiple of 8");
nuint count = target.Vector128Count<float>();
Vector128<float> multiplierVector = Vector128.Create(multiplier);
for (nuint i = 0; i < count; i++)
{
Unsafe.Add(ref targetVectorRef, i) = AdvSimd.Multiply(Unsafe.Add(ref targetVectorRef, i), multiplierVector);
}
}
else else
{ {
ref Vector<float> targetVectorRef = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(target)); ref Vector<float> targetVectorRef = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(target));
nint count = target.Length / Vector<float>.Count; nuint count = target.VectorCount<float>();
var multiplierVector = new Vector<float>(multiplier); var multiplierVector = new Vector<float>(multiplier);
for (nint i = 0; i < count; i++) for (nuint i = 0; i < count; i++)
{ {
Unsafe.Add(ref targetVectorRef, i) *= multiplierVector; Unsafe.Add(ref targetVectorRef, i) *= multiplierVector;
} }
ref float targetRef = ref MemoryMarshal.GetReference(target); ref float targetRef = ref MemoryMarshal.GetReference(target);
for (nint i = count * Vector<float>.Count; i < target.Length; i++) for (nuint i = count * (uint)Vector<float>.Count; i < (uint)target.Length; i++)
{ {
Unsafe.Add(ref targetRef, i) *= multiplier; Unsafe.Add(ref targetRef, i) *= multiplier;
} }

34
src/ImageSharp/Formats/Jpeg/Components/Encoder/HuffmanScanEncoder.cs

@ -123,7 +123,7 @@ internal class HuffmanScanEncoder
private bool IsStreamFlushNeeded private bool IsStreamFlushNeeded
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
get => this.emitWriteIndex < (uint)this.emitBuffer.Length / 2; get => this.emitWriteIndex < (int)((uint)this.emitBuffer.Length / 2);
} }
public void BuildHuffmanTable(JpegHuffmanTableConfig tableConfig) public void BuildHuffmanTable(JpegHuffmanTableConfig tableConfig)
@ -180,7 +180,7 @@ internal class HuffmanScanEncoder
Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: 0); Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: 0);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint k = 0; k < w; k++) for (nuint k = 0; k < (uint)w; k++)
{ {
this.WriteBlock( this.WriteBlock(
component, component,
@ -219,7 +219,7 @@ internal class HuffmanScanEncoder
Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: i); Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: i);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint k = 0; k < w; k++) for (nuint k = 0; k < (uint)w; k++)
{ {
this.WriteBlock( this.WriteBlock(
component, component,
@ -246,9 +246,9 @@ internal class HuffmanScanEncoder
private void EncodeScanBaselineInterleaved<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken) private void EncodeScanBaselineInterleaved<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
nint mcu = 0; int mcu = 0;
nint mcusPerColumn = frame.McusPerColumn; int mcusPerColumn = frame.McusPerColumn;
nint mcusPerLine = frame.McusPerLine; int mcusPerLine = frame.McusPerLine;
for (int j = 0; j < mcusPerColumn; j++) for (int j = 0; j < mcusPerColumn; j++)
{ {
@ -258,21 +258,21 @@ internal class HuffmanScanEncoder
converter.ConvertStrideBaseline(); converter.ConvertStrideBaseline();
// Encode spectral to binary // Encode spectral to binary
for (nint i = 0; i < mcusPerLine; i++) for (int i = 0; i < mcusPerLine; i++)
{ {
// Scan an interleaved mcu... process components in order // Scan an interleaved mcu... process components in order
nint mcuCol = mcu % mcusPerLine; int mcuCol = mcu % mcusPerLine;
for (nint k = 0; k < frame.Components.Length; k++) for (int k = 0; k < frame.Components.Length; k++)
{ {
Component component = frame.Components[k]; Component component = frame.Components[k];
ref HuffmanLut dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId]; ref HuffmanLut dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId];
ref HuffmanLut acHuffmanTable = ref this.acHuffmanTables[component.AcTableId]; ref HuffmanLut acHuffmanTable = ref this.acHuffmanTables[component.AcTableId];
nint h = component.HorizontalSamplingFactor; int h = component.HorizontalSamplingFactor;
int v = component.VerticalSamplingFactor; int v = component.VerticalSamplingFactor;
nint blockColBase = mcuCol * h; nuint blockColBase = (uint)(mcuCol * h);
// Scan out an mcu's worth of this component; that's just determined // Scan out an mcu's worth of this component; that's just determined
// by the basic H and V specified for the component // by the basic H and V specified for the component
@ -281,9 +281,9 @@ internal class HuffmanScanEncoder
Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y); Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan); ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint x = 0; x < h; x++) for (nuint x = 0; x < (uint)h; x++)
{ {
nint blockCol = blockColBase + x; nuint blockCol = blockColBase + x;
this.WriteBlock( this.WriteBlock(
component, component,
@ -315,8 +315,8 @@ internal class HuffmanScanEncoder
private void EncodeThreeComponentBaselineInterleavedScanNoSubsampling<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken) private void EncodeThreeComponentBaselineInterleavedScanNoSubsampling<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
nint mcusPerColumn = frame.McusPerColumn; nuint mcusPerColumn = (uint)frame.McusPerColumn;
nint mcusPerLine = frame.McusPerLine; nuint mcusPerLine = (uint)frame.McusPerLine;
Component c2 = frame.Components[2]; Component c2 = frame.Components[2];
Component c1 = frame.Components[1]; Component c1 = frame.Components[1];
@ -333,7 +333,7 @@ internal class HuffmanScanEncoder
ref Block8x8 c1BlockRef = ref MemoryMarshal.GetReference(c1.SpectralBlocks.DangerousGetRowSpan(y: 0)); ref Block8x8 c1BlockRef = ref MemoryMarshal.GetReference(c1.SpectralBlocks.DangerousGetRowSpan(y: 0));
ref Block8x8 c2BlockRef = ref MemoryMarshal.GetReference(c2.SpectralBlocks.DangerousGetRowSpan(y: 0)); ref Block8x8 c2BlockRef = ref MemoryMarshal.GetReference(c2.SpectralBlocks.DangerousGetRowSpan(y: 0));
for (nint j = 0; j < mcusPerColumn; j++) for (nuint j = 0; j < mcusPerColumn; j++)
{ {
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
@ -341,7 +341,7 @@ internal class HuffmanScanEncoder
converter.ConvertStrideBaseline(); converter.ConvertStrideBaseline();
// Encode spectral to binary // Encode spectral to binary
for (nint i = 0; i < mcusPerLine; i++) for (nuint i = 0; i < mcusPerLine; i++)
{ {
this.WriteBlock( this.WriteBlock(
c0, c0,

4
src/ImageSharp/Formats/Jpeg/Components/FloatingPointDCT.cs

@ -69,7 +69,7 @@ internal static partial class FloatingPointDCT
{ {
ref float tableRef = ref Unsafe.As<Block8x8F, float>(ref quantTable); ref float tableRef = ref Unsafe.As<Block8x8F, float>(ref quantTable);
ref float multipliersRef = ref MemoryMarshal.GetReference<float>(AdjustmentCoefficients); ref float multipliersRef = ref MemoryMarshal.GetReference<float>(AdjustmentCoefficients);
for (nint i = 0; i < Block8x8F.Size; i++) for (nuint i = 0; i < Block8x8F.Size; i++)
{ {
ref float elemRef = ref Unsafe.Add(ref tableRef, i); ref float elemRef = ref Unsafe.Add(ref tableRef, i);
elemRef = 0.125f * elemRef * Unsafe.Add(ref multipliersRef, i); elemRef = 0.125f * elemRef * Unsafe.Add(ref multipliersRef, i);
@ -88,7 +88,7 @@ internal static partial class FloatingPointDCT
{ {
ref float tableRef = ref Unsafe.As<Block8x8F, float>(ref quantTable); ref float tableRef = ref Unsafe.As<Block8x8F, float>(ref quantTable);
ref float multipliersRef = ref MemoryMarshal.GetReference<float>(AdjustmentCoefficients); ref float multipliersRef = ref MemoryMarshal.GetReference<float>(AdjustmentCoefficients);
for (nint i = 0; i < Block8x8F.Size; i++) for (nuint i = 0; i < Block8x8F.Size; i++)
{ {
ref float elemRef = ref Unsafe.Add(ref tableRef, i); ref float elemRef = ref Unsafe.Add(ref tableRef, i);
elemRef = 0.125f / (elemRef * Unsafe.Add(ref multipliersRef, i)); elemRef = 0.125f / (elemRef * Unsafe.Add(ref multipliersRef, i));

26
src/ImageSharp/Formats/Jpeg/Components/ScaledFloatingPointDCT.cs

@ -40,7 +40,7 @@ internal static class ScaledFloatingPointDCT
public static void AdjustToIDCT(ref Block8x8F quantTable) public static void AdjustToIDCT(ref Block8x8F quantTable)
{ {
ref float tableRef = ref Unsafe.As<Block8x8F, float>(ref quantTable); ref float tableRef = ref Unsafe.As<Block8x8F, float>(ref quantTable);
for (nint i = 0; i < Block8x8F.Size; i++) for (nuint i = 0; i < Block8x8F.Size; i++)
{ {
ref float elemRef = ref Unsafe.Add(ref tableRef, i); ref float elemRef = ref Unsafe.Add(ref tableRef, i);
elemRef = 0.125f * elemRef; elemRef = 0.125f * elemRef;
@ -103,10 +103,10 @@ internal static class ScaledFloatingPointDCT
// temporal result is saved to +4 shifted indices // temporal result is saved to +4 shifted indices
// because result is saved into the top left 2x2 region of the // because result is saved into the top left 2x2 region of the
// input block // input block
block[(ctr * 8) + 0 + 4] = (tmp10 + tmp2) / 2; block[(ctr * 8) + 0 + 4] = (tmp10 + tmp2) * 0.5F;
block[(ctr * 8) + 3 + 4] = (tmp10 - tmp2) / 2; block[(ctr * 8) + 3 + 4] = (tmp10 - tmp2) * 0.5F;
block[(ctr * 8) + 1 + 4] = (tmp12 + tmp0) / 2; block[(ctr * 8) + 1 + 4] = (tmp12 + tmp0) * 0.5F;
block[(ctr * 8) + 2 + 4] = (tmp12 - tmp0) / 2; block[(ctr * 8) + 2 + 4] = (tmp12 - tmp0) * 0.5F;
} }
for (int ctr = 0; ctr < 4; ctr++) for (int ctr = 0; ctr < 4; ctr++)
@ -136,10 +136,10 @@ internal static class ScaledFloatingPointDCT
(z4 * FP32_2_562915447); (z4 * FP32_2_562915447);
// Save results to the top left 4x4 subregion // Save results to the top left 4x4 subregion
block[(ctr * 8) + 0] = MathF.Round(Numerics.Clamp(((tmp10 + tmp2) / 2) + normalizationValue, 0, maxValue)); block[(ctr * 8) + 0] = MathF.Round(Numerics.Clamp(((tmp10 + tmp2) * 0.5F) + normalizationValue, 0, maxValue));
block[(ctr * 8) + 3] = MathF.Round(Numerics.Clamp(((tmp10 - tmp2) / 2) + normalizationValue, 0, maxValue)); block[(ctr * 8) + 3] = MathF.Round(Numerics.Clamp(((tmp10 - tmp2) * 0.5F) + normalizationValue, 0, maxValue));
block[(ctr * 8) + 1] = MathF.Round(Numerics.Clamp(((tmp12 + tmp0) / 2) + normalizationValue, 0, maxValue)); block[(ctr * 8) + 1] = MathF.Round(Numerics.Clamp(((tmp12 + tmp0) * 0.5F) + normalizationValue, 0, maxValue));
block[(ctr * 8) + 2] = MathF.Round(Numerics.Clamp(((tmp12 - tmp0) / 2) + normalizationValue, 0, maxValue)); block[(ctr * 8) + 2] = MathF.Round(Numerics.Clamp(((tmp12 - tmp0) * 0.5F) + normalizationValue, 0, maxValue));
} }
} }
@ -183,8 +183,8 @@ internal static class ScaledFloatingPointDCT
// temporal result is saved to +2 shifted indices // temporal result is saved to +2 shifted indices
// because result is saved into the top left 2x2 region of the // because result is saved into the top left 2x2 region of the
// input block // input block
block[(ctr * 8) + 2] = (tmp10 + tmp0) / 4; block[(ctr * 8) + 2] = (tmp10 + tmp0) * 0.25F;
block[(ctr * 8) + 3] = (tmp10 - tmp0) / 4; block[(ctr * 8) + 3] = (tmp10 - tmp0) * 0.25F;
} }
for (int ctr = 0; ctr < 2; ctr++) for (int ctr = 0; ctr < 2; ctr++)
@ -199,8 +199,8 @@ internal static class ScaledFloatingPointDCT
(block[ctr + (8 * 1) + 2] * FP32_3_624509785); (block[ctr + (8 * 1) + 2] * FP32_3_624509785);
// Save results to the top left 2x2 subregion // Save results to the top left 2x2 subregion
block[(ctr * 8) + 0] = MathF.Round(Numerics.Clamp(((tmp10 + tmp0) / 4) + normalizationValue, 0, maxValue)); block[(ctr * 8) + 0] = MathF.Round(Numerics.Clamp(((tmp10 + tmp0) * 0.25F) + normalizationValue, 0, maxValue));
block[(ctr * 8) + 1] = MathF.Round(Numerics.Clamp(((tmp10 - tmp0) / 4) + normalizationValue, 0, maxValue)); block[(ctr * 8) + 1] = MathF.Round(Numerics.Clamp(((tmp10 - tmp0) * 0.25F) + normalizationValue, 0, maxValue));
} }
} }

146
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -27,21 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg;
/// </summary> /// </summary>
internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
{ {
/// <summary>
/// The only supported precision
/// </summary>
private readonly byte[] supportedPrecisions = { 8, 12 };
/// <summary>
/// The buffer used to temporarily store bytes read from the stream.
/// </summary>
private readonly byte[] temp = new byte[2 * 16 * 4];
/// <summary>
/// The buffer used to read markers from the stream.
/// </summary>
private readonly byte[] markerBuffer = new byte[2];
/// <summary> /// <summary>
/// Whether the image has an EXIF marker. /// Whether the image has an EXIF marker.
/// </summary> /// </summary>
@ -139,6 +124,12 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
this.skipMetadata = options.GeneralOptions.SkipMetadata; this.skipMetadata = options.GeneralOptions.SkipMetadata;
} }
/// <summary>
/// Gets the only supported precisions
/// </summary>
// Refers to assembly's static data segment, no allocation occurs.
private static ReadOnlySpan<byte> SupportedPrecisions => new byte[] { 8, 12 };
/// <inheritdoc /> /// <inheritdoc />
public DecoderOptions Options { get; } public DecoderOptions Options { get; }
@ -257,24 +248,26 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
using MemoryStream ms = new(tableBytes); using MemoryStream ms = new(tableBytes);
using BufferedReadStream stream = new(this.configuration, ms); using BufferedReadStream stream = new(this.configuration, ms);
Span<byte> markerBuffer = stackalloc byte[2];
// Check for the Start Of Image marker. // Check for the Start Of Image marker.
int bytesRead = stream.Read(this.markerBuffer, 0, 2); int bytesRead = stream.Read(markerBuffer);
JpegFileMarker fileMarker = new(this.markerBuffer[1], 0); JpegFileMarker fileMarker = new(markerBuffer[1], 0);
if (fileMarker.Marker != JpegConstants.Markers.SOI) if (fileMarker.Marker != JpegConstants.Markers.SOI)
{ {
JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker."); JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker.");
} }
// Read next marker. // Read next marker.
bytesRead = stream.Read(this.markerBuffer, 0, 2); bytesRead = stream.Read(markerBuffer);
fileMarker = new JpegFileMarker(this.markerBuffer[1], (int)stream.Position - 2); fileMarker = new JpegFileMarker(markerBuffer[1], (int)stream.Position - 2);
while (fileMarker.Marker != JpegConstants.Markers.EOI || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid)) while (fileMarker.Marker != JpegConstants.Markers.EOI || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid))
{ {
if (!fileMarker.Invalid) if (!fileMarker.Invalid)
{ {
// Get the marker length. // Get the marker length.
int markerContentByteSize = this.ReadUint16(stream) - 2; int markerContentByteSize = ReadUint16(stream, markerBuffer) - 2;
// Check whether the stream actually has enough bytes to read // Check whether the stream actually has enough bytes to read
// markerContentByteSize is always positive so we cast // markerContentByteSize is always positive so we cast
@ -297,7 +290,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
this.ProcessDefineQuantizationTablesMarker(stream, markerContentByteSize); this.ProcessDefineQuantizationTablesMarker(stream, markerContentByteSize);
break; break;
case JpegConstants.Markers.DRI: case JpegConstants.Markers.DRI:
this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize); this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize, markerBuffer);
break; break;
case JpegConstants.Markers.EOI: case JpegConstants.Markers.EOI:
return; return;
@ -305,13 +298,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
} }
// Read next marker. // Read next marker.
bytesRead = stream.Read(this.markerBuffer, 0, 2); bytesRead = stream.Read(markerBuffer);
if (bytesRead != 2) if (bytesRead != 2)
{ {
JpegThrowHelper.ThrowInvalidImageContentException("Not enough data to read marker"); JpegThrowHelper.ThrowInvalidImageContentException("Not enough data to read marker");
} }
fileMarker = new JpegFileMarker(this.markerBuffer[1], 0); fileMarker = new JpegFileMarker(markerBuffer[1], 0);
} }
} }
@ -329,9 +322,11 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
this.Metadata = new ImageMetadata(); this.Metadata = new ImageMetadata();
Span<byte> markerBuffer = stackalloc byte[2];
// Check for the Start Of Image marker. // Check for the Start Of Image marker.
stream.Read(this.markerBuffer, 0, 2); stream.Read(markerBuffer);
JpegFileMarker fileMarker = new(this.markerBuffer[1], 0); JpegFileMarker fileMarker = new(markerBuffer[1], 0);
if (fileMarker.Marker != JpegConstants.Markers.SOI) if (fileMarker.Marker != JpegConstants.Markers.SOI)
{ {
JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker."); JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker.");
@ -349,7 +344,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
if (!fileMarker.Invalid) if (!fileMarker.Invalid)
{ {
// Get the marker length. // Get the marker length.
int markerContentByteSize = this.ReadUint16(stream) - 2; int markerContentByteSize = ReadUint16(stream, markerBuffer) - 2;
// Check whether stream actually has enough bytes to read // Check whether stream actually has enough bytes to read
// markerContentByteSize is always positive so we cast // markerContentByteSize is always positive so we cast
@ -446,7 +441,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
} }
else else
{ {
this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize); this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize, markerBuffer);
} }
break; break;
@ -755,8 +750,10 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return; return;
} }
stream.Read(this.temp, 0, JFifMarker.Length); Span<byte> temp = stackalloc byte[2 * 16 * 4];
if (!JFifMarker.TryParse(this.temp, out this.jFif))
stream.Read(temp, 0, JFifMarker.Length);
if (!JFifMarker.TryParse(temp, out this.jFif))
{ {
JpegThrowHelper.ThrowNotSupportedException("Unknown App0 Marker - Expected JFIF."); JpegThrowHelper.ThrowNotSupportedException("Unknown App0 Marker - Expected JFIF.");
} }
@ -796,11 +793,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowInvalidImageContentException("Bad App1 Marker length."); JpegThrowHelper.ThrowInvalidImageContentException("Bad App1 Marker length.");
} }
Span<byte> temp = stackalloc byte[2 * 16 * 4];
// XMP marker is the longer then the EXIF marker, so first try read the EXIF marker bytes. // XMP marker is the longer then the EXIF marker, so first try read the EXIF marker bytes.
stream.Read(this.temp, 0, exifMarkerLength); stream.Read(temp, 0, exifMarkerLength);
remaining -= exifMarkerLength; remaining -= exifMarkerLength;
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.ExifMarker)) if (ProfileResolver.IsProfile(temp, ProfileResolver.ExifMarker))
{ {
this.hasExif = true; this.hasExif = true;
byte[] profile = new byte[remaining]; byte[] profile = new byte[remaining];
@ -819,7 +818,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
remaining = 0; remaining = 0;
} }
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker[..exifMarkerLength])) if (ProfileResolver.IsProfile(temp, ProfileResolver.XmpMarker[..exifMarkerLength]))
{ {
const int remainingXmpMarkerBytes = xmpMarkerLength - exifMarkerLength; const int remainingXmpMarkerBytes = xmpMarkerLength - exifMarkerLength;
if (remaining < remainingXmpMarkerBytes || this.skipMetadata) if (remaining < remainingXmpMarkerBytes || this.skipMetadata)
@ -829,9 +828,9 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return; return;
} }
stream.Read(this.temp, exifMarkerLength, remainingXmpMarkerBytes); stream.Read(temp, exifMarkerLength, remainingXmpMarkerBytes);
remaining -= remainingXmpMarkerBytes; remaining -= remainingXmpMarkerBytes;
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker)) if (ProfileResolver.IsProfile(temp, ProfileResolver.XmpMarker))
{ {
this.hasXmp = true; this.hasXmp = true;
byte[] profile = new byte[remaining]; byte[] profile = new byte[remaining];
@ -870,8 +869,8 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return; return;
} }
byte[] identifier = new byte[icclength]; Span<byte> identifier = stackalloc byte[icclength];
stream.Read(identifier, 0, icclength); stream.Read(identifier);
remaining -= icclength; // We have read it by this point remaining -= icclength; // We have read it by this point
if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker)) if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker))
@ -911,13 +910,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return; return;
} }
stream.Read(this.temp, 0, ProfileResolver.AdobePhotoshopApp13Marker.Length); Span<byte> temp = stackalloc byte[2 * 16 * 4];
stream.Read(temp, 0, ProfileResolver.AdobePhotoshopApp13Marker.Length);
remaining -= ProfileResolver.AdobePhotoshopApp13Marker.Length; remaining -= ProfileResolver.AdobePhotoshopApp13Marker.Length;
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.AdobePhotoshopApp13Marker)) if (ProfileResolver.IsProfile(temp, ProfileResolver.AdobePhotoshopApp13Marker))
{ {
byte[] resourceBlockData = new byte[remaining]; Span<byte> blockDataSpan = remaining <= 128 ? stackalloc byte[remaining] : new byte[remaining];
stream.Read(resourceBlockData, 0, remaining); stream.Read(blockDataSpan);
Span<byte> blockDataSpan = resourceBlockData.AsSpan();
while (blockDataSpan.Length > 12) while (blockDataSpan.Length > 12)
{ {
@ -1047,10 +1046,12 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return; return;
} }
stream.Read(this.temp, 0, markerLength); Span<byte> temp = stackalloc byte[2 * 16 * 4];
stream.Read(temp, 0, markerLength);
remaining -= markerLength; remaining -= markerLength;
if (AdobeMarker.TryParse(this.temp, out this.adobe)) if (AdobeMarker.TryParse(temp, out this.adobe))
{ {
this.hasAdobeMarker = true; this.hasAdobeMarker = true;
} }
@ -1072,6 +1073,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
private void ProcessDefineQuantizationTablesMarker(BufferedReadStream stream, int remaining) private void ProcessDefineQuantizationTablesMarker(BufferedReadStream stream, int remaining)
{ {
JpegMetadata jpegMetadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance); JpegMetadata jpegMetadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance);
Span<byte> temp = stackalloc byte[2 * 16 * 4];
while (remaining > 0) while (remaining > 0)
{ {
@ -1102,13 +1104,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.DQT), remaining); JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.DQT), remaining);
} }
stream.Read(this.temp, 0, 64); stream.Read(temp, 0, 64);
remaining -= 64; remaining -= 64;
// Parsing quantization table & saving it in natural order // Parsing quantization table & saving it in natural order
for (int j = 0; j < 64; j++) for (int j = 0; j < 64; j++)
{ {
table[ZigZag.ZigZagOrder[j]] = this.temp[j]; table[ZigZag.ZigZagOrder[j]] = temp[j];
} }
break; break;
@ -1121,13 +1123,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.DQT), remaining); JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.DQT), remaining);
} }
stream.Read(this.temp, 0, 128); stream.Read(temp, 0, 128);
remaining -= 128; remaining -= 128;
// Parsing quantization table & saving it in natural order // Parsing quantization table & saving it in natural order
for (int j = 0; j < 64; j++) for (int j = 0; j < 64; j++)
{ {
table[ZigZag.ZigZagOrder[j]] = (this.temp[2 * j] << 8) | this.temp[(2 * j) + 1]; table[ZigZag.ZigZagOrder[j]] = (temp[2 * j] << 8) | temp[(2 * j) + 1];
} }
break; break;
@ -1174,28 +1176,30 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowInvalidImageContentException("Multiple SOF markers. Only single frame jpegs supported."); JpegThrowHelper.ThrowInvalidImageContentException("Multiple SOF markers. Only single frame jpegs supported.");
} }
Span<byte> temp = stackalloc byte[2 * 16 * 4];
// Read initial marker definitions. // Read initial marker definitions.
const int length = 6; const int length = 6;
int bytesRead = stream.Read(this.temp, 0, length); int bytesRead = stream.Read(temp, 0, length);
if (bytesRead != length) if (bytesRead != length)
{ {
JpegThrowHelper.ThrowInvalidImageContentException("SOF marker does not contain enough data."); JpegThrowHelper.ThrowInvalidImageContentException("SOF marker does not contain enough data.");
} }
// 1 byte: Bits/sample precision. // 1 byte: Bits/sample precision.
byte precision = this.temp[0]; byte precision = temp[0];
// Validate: only 8-bit and 12-bit precisions are supported. // Validate: only 8-bit and 12-bit precisions are supported.
if (Array.IndexOf(this.supportedPrecisions, precision) == -1) if (SupportedPrecisions.IndexOf(precision) < 0)
{ {
JpegThrowHelper.ThrowInvalidImageContentException("Only 8-Bit and 12-Bit precision is supported."); JpegThrowHelper.ThrowInvalidImageContentException("Only 8-Bit and 12-Bit precision is supported.");
} }
// 2 byte: Height // 2 byte: Height
int frameHeight = (this.temp[1] << 8) | this.temp[2]; int frameHeight = (temp[1] << 8) | temp[2];
// 2 byte: Width // 2 byte: Width
int frameWidth = (this.temp[3] << 8) | this.temp[4]; int frameWidth = (temp[3] << 8) | temp[4];
// Validate: width/height > 0 (they are upper-bounded by 2 byte max value so no need to check that). // Validate: width/height > 0 (they are upper-bounded by 2 byte max value so no need to check that).
if (frameHeight == 0 || frameWidth == 0) if (frameHeight == 0 || frameWidth == 0)
@ -1204,7 +1208,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
} }
// 1 byte: Number of components. // 1 byte: Number of components.
byte componentCount = this.temp[5]; byte componentCount = temp[5];
// Validate: componentCount more than 4 can lead to a buffer overflow during stream // Validate: componentCount more than 4 can lead to a buffer overflow during stream
// reading so we must limit it to 4. // reading so we must limit it to 4.
@ -1227,7 +1231,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
} }
// components*3 bytes: component data // components*3 bytes: component data
stream.Read(this.temp, 0, remaining); stream.Read(temp, 0, remaining);
// No need to pool this. They max out at 4 // No need to pool this. They max out at 4
this.Frame.ComponentIds = new byte[componentCount]; this.Frame.ComponentIds = new byte[componentCount];
@ -1240,10 +1244,10 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
for (int i = 0; i < this.Frame.Components.Length; i++) for (int i = 0; i < this.Frame.Components.Length; i++)
{ {
// 1 byte: component identifier // 1 byte: component identifier
byte componentId = this.temp[index]; byte componentId = temp[index];
// 1 byte: component sampling factors // 1 byte: component sampling factors
byte hv = this.temp[index + 1]; byte hv = temp[index + 1];
int h = (hv >> 4) & 15; int h = (hv >> 4) & 15;
int v = hv & 15; int v = hv & 15;
@ -1270,7 +1274,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
} }
// 1 byte: quantization table destination selector // 1 byte: quantization table destination selector
byte quantTableIndex = this.temp[index + 2]; byte quantTableIndex = temp[index + 2];
// Validate: 0-3 range // Validate: 0-3 range
if (quantTableIndex > 3) if (quantTableIndex > 3)
@ -1379,7 +1383,8 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
/// </summary> /// </summary>
/// <param name="stream">The input stream.</param> /// <param name="stream">The input stream.</param>
/// <param name="remaining">The remaining bytes in the segment block.</param> /// <param name="remaining">The remaining bytes in the segment block.</param>
private void ProcessDefineRestartIntervalMarker(BufferedReadStream stream, int remaining) /// <param name="markerBuffer">Scratch buffer.</param>
private void ProcessDefineRestartIntervalMarker(BufferedReadStream stream, int remaining, Span<byte> markerBuffer)
{ {
if (remaining != 2) if (remaining != 2)
{ {
@ -1388,7 +1393,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
// Save the reset interval, because it can come before or after the SOF marker. // Save the reset interval, because it can come before or after the SOF marker.
// If the reset interval comes after the SOF marker, the scanDecoder has not been created. // If the reset interval comes after the SOF marker, the scanDecoder has not been created.
this.resetInterval = this.ReadUint16(stream); this.resetInterval = ReadUint16(stream, markerBuffer);
if (this.scanDecoder != null) if (this.scanDecoder != null)
{ {
@ -1425,14 +1430,16 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.SOS), remaining); JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.SOS), remaining);
} }
Span<byte> temp = stackalloc byte[2 * 16 * 4];
// selectorsCount*2 bytes: component index + huffman tables indices // selectorsCount*2 bytes: component index + huffman tables indices
stream.Read(this.temp, 0, selectorsBytes); stream.Read(temp, 0, selectorsBytes);
this.Frame.Interleaved = this.Frame.ComponentCount == selectorsCount; this.Frame.Interleaved = this.Frame.ComponentCount == selectorsCount;
for (int i = 0; i < selectorsBytes; i += 2) for (int i = 0; i < selectorsBytes; i += 2)
{ {
// 1 byte: Component id // 1 byte: Component id
int componentSelectorId = this.temp[i]; int componentSelectorId = temp[i];
int componentIndex = -1; int componentIndex = -1;
for (int j = 0; j < this.Frame.ComponentIds.Length; j++) for (int j = 0; j < this.Frame.ComponentIds.Length; j++)
@ -1459,7 +1466,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
// 1 byte: Huffman table selectors. // 1 byte: Huffman table selectors.
// 4 bits - dc // 4 bits - dc
// 4 bits - ac // 4 bits - ac
int tableSpec = this.temp[i + 1]; int tableSpec = temp[i + 1];
int dcTableIndex = tableSpec >> 4; int dcTableIndex = tableSpec >> 4;
int acTableIndex = tableSpec & 15; int acTableIndex = tableSpec & 15;
@ -1475,17 +1482,17 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
} }
// 3 bytes: Progressive scan decoding data. // 3 bytes: Progressive scan decoding data.
int bytesRead = stream.Read(this.temp, 0, 3); int bytesRead = stream.Read(temp, 0, 3);
if (bytesRead != 3) if (bytesRead != 3)
{ {
JpegThrowHelper.ThrowInvalidImageContentException("Not enough data to read progressive scan decoding data"); JpegThrowHelper.ThrowInvalidImageContentException("Not enough data to read progressive scan decoding data");
} }
this.scanDecoder.SpectralStart = this.temp[0]; this.scanDecoder.SpectralStart = temp[0];
this.scanDecoder.SpectralEnd = this.temp[1]; this.scanDecoder.SpectralEnd = temp[1];
int successiveApproximation = this.temp[2]; int successiveApproximation = temp[2];
this.scanDecoder.SuccessiveHigh = successiveApproximation >> 4; this.scanDecoder.SuccessiveHigh = successiveApproximation >> 4;
this.scanDecoder.SuccessiveLow = successiveApproximation & 15; this.scanDecoder.SuccessiveLow = successiveApproximation & 15;
@ -1501,16 +1508,17 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
/// Reads a <see cref="ushort"/> from the stream advancing it by two bytes. /// Reads a <see cref="ushort"/> from the stream advancing it by two bytes.
/// </summary> /// </summary>
/// <param name="stream">The input stream.</param> /// <param name="stream">The input stream.</param>
/// <param name="markerBuffer">The scratch buffer used for reading from the stream.</param>
/// <returns>The <see cref="ushort"/></returns> /// <returns>The <see cref="ushort"/></returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private ushort ReadUint16(BufferedReadStream stream) private static ushort ReadUint16(BufferedReadStream stream, Span<byte> markerBuffer)
{ {
int bytesRead = stream.Read(this.markerBuffer, 0, 2); int bytesRead = stream.Read(markerBuffer, 0, 2);
if (bytesRead != 2) if (bytesRead != 2)
{ {
JpegThrowHelper.ThrowInvalidImageContentException("jpeg stream does not contain enough data, could not read ushort."); JpegThrowHelper.ThrowInvalidImageContentException("jpeg stream does not contain enough data, could not read ushort.");
} }
return BinaryPrimitives.ReadUInt16BigEndian(this.markerBuffer); return BinaryPrimitives.ReadUInt16BigEndian(markerBuffer);
} }
} }

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

@ -25,11 +25,6 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// </summary> /// </summary>
private static readonly JpegFrameConfig[] FrameConfigs = CreateFrameConfigs(); private static readonly JpegFrameConfig[] FrameConfigs = CreateFrameConfigs();
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
private readonly byte[] buffer = new byte[20];
private readonly JpegEncoder encoder; private readonly JpegEncoder encoder;
/// <summary> /// <summary>
@ -67,6 +62,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
cancellationToken.ThrowIfCancellationRequested(); cancellationToken.ThrowIfCancellationRequested();
this.outputStream = stream; this.outputStream = stream;
Span<byte> buffer = stackalloc byte[20];
ImageMetadata metadata = image.Metadata; ImageMetadata metadata = image.Metadata;
JpegMetadata jpegMetadata = metadata.GetJpegMetadata(); JpegMetadata jpegMetadata = metadata.GetJpegMetadata();
@ -76,39 +72,39 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
using JpegFrame frame = new(image, frameConfig, interleaved); using JpegFrame frame = new(image, frameConfig, interleaved);
// Write the Start Of Image marker. // Write the Start Of Image marker.
this.WriteStartOfImage(); this.WriteStartOfImage(buffer);
// Write APP0 marker // Write APP0 marker
if (frameConfig.AdobeColorTransformMarkerFlag is null) if (frameConfig.AdobeColorTransformMarkerFlag is null)
{ {
this.WriteJfifApplicationHeader(metadata); this.WriteJfifApplicationHeader(metadata, buffer);
} }
// Write APP14 marker with adobe color extension // Write APP14 marker with adobe color extension
else else
{ {
this.WriteApp14Marker(frameConfig.AdobeColorTransformMarkerFlag.Value); this.WriteApp14Marker(frameConfig.AdobeColorTransformMarkerFlag.Value, buffer);
} }
// Write Exif, XMP, ICC and IPTC profiles // Write Exif, XMP, ICC and IPTC profiles
this.WriteProfiles(metadata); this.WriteProfiles(metadata, buffer);
// Write the image dimensions. // Write the image dimensions.
this.WriteStartOfFrame(image.Width, image.Height, frameConfig); this.WriteStartOfFrame(image.Width, image.Height, frameConfig, buffer);
// Write the Huffman tables. // Write the Huffman tables.
HuffmanScanEncoder scanEncoder = new(frame.BlocksPerMcu, stream); HuffmanScanEncoder scanEncoder = new(frame.BlocksPerMcu, stream);
this.WriteDefineHuffmanTables(frameConfig.HuffmanTables, scanEncoder); this.WriteDefineHuffmanTables(frameConfig.HuffmanTables, scanEncoder, buffer);
// Write the quantization tables. // Write the quantization tables.
this.WriteDefineQuantizationTables(frameConfig.QuantizationTables, this.encoder.Quality, jpegMetadata); this.WriteDefineQuantizationTables(frameConfig.QuantizationTables, this.encoder.Quality, jpegMetadata, buffer);
// Write scans with actual pixel data // Write scans with actual pixel data
using SpectralConverter<TPixel> spectralConverter = new(frame, image, this.QuantizationTables); using SpectralConverter<TPixel> spectralConverter = new(frame, image, this.QuantizationTables);
this.WriteHuffmanScans(frame, frameConfig, spectralConverter, scanEncoder, cancellationToken); this.WriteHuffmanScans(frame, frameConfig, spectralConverter, scanEncoder, buffer, cancellationToken);
// Write the End Of Image marker. // Write the End Of Image marker.
this.WriteEndOfImageMarker(); this.WriteEndOfImageMarker(buffer);
stream.Flush(); stream.Flush();
} }
@ -116,58 +112,59 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <summary> /// <summary>
/// Write the start of image marker. /// Write the start of image marker.
/// </summary> /// </summary>
private void WriteStartOfImage() private void WriteStartOfImage(Span<byte> buffer)
{ {
// Markers are always prefixed with 0xff. // Markers are always prefixed with 0xff.
this.buffer[0] = JpegConstants.Markers.XFF; buffer[1] = JpegConstants.Markers.SOI;
this.buffer[1] = JpegConstants.Markers.SOI; buffer[0] = JpegConstants.Markers.XFF;
this.outputStream.Write(this.buffer, 0, 2); this.outputStream.Write(buffer, 0, 2);
} }
/// <summary> /// <summary>
/// Writes the application header containing the JFIF identifier plus extra data. /// Writes the application header containing the JFIF identifier plus extra data.
/// </summary> /// </summary>
/// <param name="meta">The image metadata.</param> /// <param name="meta">The image metadata.</param>
private void WriteJfifApplicationHeader(ImageMetadata meta) /// <param name="buffer">Temporary buffer.</param>
private void WriteJfifApplicationHeader(ImageMetadata meta, Span<byte> buffer)
{ {
// Write the JFIF headers // Write the JFIF headers (highest index first to avoid additional bound checks)
this.buffer[0] = JpegConstants.Markers.XFF; buffer[10] = 0x01; // versionlo
this.buffer[1] = JpegConstants.Markers.APP0; // Application Marker buffer[0] = JpegConstants.Markers.XFF;
this.buffer[2] = 0x00; buffer[1] = JpegConstants.Markers.APP0; // Application Marker
this.buffer[3] = 0x10; buffer[2] = 0x00;
this.buffer[4] = 0x4a; // J buffer[3] = 0x10;
this.buffer[5] = 0x46; // F buffer[4] = 0x4a; // J
this.buffer[6] = 0x49; // I buffer[5] = 0x46; // F
this.buffer[7] = 0x46; // F buffer[6] = 0x49; // I
this.buffer[8] = 0x00; // = "JFIF",'\0' buffer[7] = 0x46; // F
this.buffer[9] = 0x01; // versionhi buffer[8] = 0x00; // = "JFIF",'\0'
this.buffer[10] = 0x01; // versionlo buffer[9] = 0x01; // versionhi
// Resolution. Big Endian // Resolution. Big Endian
Span<byte> hResolution = this.buffer.AsSpan(12, 2); Span<byte> hResolution = buffer.Slice(12, 2);
Span<byte> vResolution = this.buffer.AsSpan(14, 2); Span<byte> vResolution = buffer.Slice(14, 2);
if (meta.ResolutionUnits == PixelResolutionUnit.PixelsPerMeter) if (meta.ResolutionUnits == PixelResolutionUnit.PixelsPerMeter)
{ {
// Scale down to PPI // Scale down to PPI
this.buffer[11] = (byte)PixelResolutionUnit.PixelsPerInch; // xyunits buffer[11] = (byte)PixelResolutionUnit.PixelsPerInch; // xyunits
BinaryPrimitives.WriteInt16BigEndian(hResolution, (short)Math.Round(UnitConverter.MeterToInch(meta.HorizontalResolution))); BinaryPrimitives.WriteInt16BigEndian(hResolution, (short)Math.Round(UnitConverter.MeterToInch(meta.HorizontalResolution)));
BinaryPrimitives.WriteInt16BigEndian(vResolution, (short)Math.Round(UnitConverter.MeterToInch(meta.VerticalResolution))); BinaryPrimitives.WriteInt16BigEndian(vResolution, (short)Math.Round(UnitConverter.MeterToInch(meta.VerticalResolution)));
} }
else else
{ {
// We can simply pass the value. // We can simply pass the value.
this.buffer[11] = (byte)meta.ResolutionUnits; // xyunits buffer[11] = (byte)meta.ResolutionUnits; // xyunits
BinaryPrimitives.WriteInt16BigEndian(hResolution, (short)Math.Round(meta.HorizontalResolution)); BinaryPrimitives.WriteInt16BigEndian(hResolution, (short)Math.Round(meta.HorizontalResolution));
BinaryPrimitives.WriteInt16BigEndian(vResolution, (short)Math.Round(meta.VerticalResolution)); BinaryPrimitives.WriteInt16BigEndian(vResolution, (short)Math.Round(meta.VerticalResolution));
} }
// No thumbnail // No thumbnail
this.buffer[16] = 0x00; // Thumbnail width buffer[17] = 0x00; // Thumbnail height
this.buffer[17] = 0x00; // Thumbnail height buffer[16] = 0x00; // Thumbnail width
this.outputStream.Write(this.buffer, 0, 18); this.outputStream.Write(buffer, 0, 18);
} }
/// <summary> /// <summary>
@ -175,8 +172,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// </summary> /// </summary>
/// <param name="tableConfigs">The table configuration.</param> /// <param name="tableConfigs">The table configuration.</param>
/// <param name="scanEncoder">The scan encoder.</param> /// <param name="scanEncoder">The scan encoder.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <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) private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Span<byte> buffer)
{ {
if (tableConfigs is null) if (tableConfigs is null)
{ {
@ -190,7 +188,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
markerlen += 1 + 16 + tableConfigs[i].Table.Values.Length; markerlen += 1 + 16 + tableConfigs[i].Table.Values.Length;
} }
this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen); this.WriteMarkerHeader(JpegConstants.Markers.DHT, markerlen, buffer);
for (int i = 0; i < tableConfigs.Length; i++) for (int i = 0; i < tableConfigs.Length; i++)
{ {
JpegHuffmanTableConfig tableConfig = tableConfigs[i]; JpegHuffmanTableConfig tableConfig = tableConfigs[i];
@ -208,37 +206,39 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the APP14 marker to indicate the image is in RGB color space. /// Writes the APP14 marker to indicate the image is in RGB color space.
/// </summary> /// </summary>
/// <param name="colorTransform">The color transform byte.</param> /// <param name="colorTransform">The color transform byte.</param>
private void WriteApp14Marker(byte colorTransform) /// <param name="buffer">Temporary buffer.</param>
private void WriteApp14Marker(byte colorTransform, Span<byte> buffer)
{ {
this.WriteMarkerHeader(JpegConstants.Markers.APP14, 2 + Components.Decoder.AdobeMarker.Length); this.WriteMarkerHeader(JpegConstants.Markers.APP14, 2 + Components.Decoder.AdobeMarker.Length, buffer);
// Identifier: ASCII "Adobe". // Identifier: ASCII "Adobe" (highest index first to avoid additional bound checks).
this.buffer[0] = 0x41; buffer[4] = 0x65;
this.buffer[1] = 0x64; buffer[0] = 0x41;
this.buffer[2] = 0x6F; buffer[1] = 0x64;
this.buffer[3] = 0x62; buffer[2] = 0x6F;
this.buffer[4] = 0x65; buffer[3] = 0x62;
// Version, currently 100. // Version, currently 100.
BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(5, 2), 100); BinaryPrimitives.WriteInt16BigEndian(buffer.Slice(5, 2), 100);
// Flags0 // Flags0
BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(7, 2), 0); BinaryPrimitives.WriteInt16BigEndian(buffer.Slice(7, 2), 0);
// Flags1 // Flags1
BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(9, 2), 0); BinaryPrimitives.WriteInt16BigEndian(buffer.Slice(9, 2), 0);
// Color transform byte // Color transform byte
this.buffer[11] = colorTransform; buffer[11] = colorTransform;
this.outputStream.Write(this.buffer.AsSpan(0, 12)); this.outputStream.Write(buffer.Slice(0, 12));
} }
/// <summary> /// <summary>
/// Writes the EXIF profile. /// Writes the EXIF profile.
/// </summary> /// </summary>
/// <param name="exifProfile">The exif profile.</param> /// <param name="exifProfile">The exif profile.</param>
private void WriteExifProfile(ExifProfile exifProfile) /// <param name="buffer">Temporary buffer.</param>
private void WriteExifProfile(ExifProfile exifProfile, Span<byte> buffer)
{ {
if (exifProfile is null || exifProfile.Values.Count == 0) if (exifProfile is null || exifProfile.Values.Count == 0)
{ {
@ -262,7 +262,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
int app1Length = bytesToWrite + 2; int app1Length = bytesToWrite + 2;
// Write the app marker, EXIF marker, and data // Write the app marker, EXIF marker, and data
this.WriteApp1Header(app1Length); this.WriteApp1Header(app1Length, buffer);
this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker); this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
this.outputStream.Write(data, 0, bytesToWrite - exifMarkerLength); this.outputStream.Write(data, 0, bytesToWrite - exifMarkerLength);
remaining -= bytesToWrite; remaining -= bytesToWrite;
@ -273,7 +273,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
bytesToWrite = remaining > maxBytesWithExifId ? maxBytesWithExifId : remaining; bytesToWrite = remaining > maxBytesWithExifId ? maxBytesWithExifId : remaining;
app1Length = bytesToWrite + 2 + exifMarkerLength; app1Length = bytesToWrite + 2 + exifMarkerLength;
this.WriteApp1Header(app1Length); this.WriteApp1Header(app1Length, buffer);
// Write Exif00 marker // Write Exif00 marker
this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker); this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
@ -289,10 +289,11 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the IPTC metadata. /// Writes the IPTC metadata.
/// </summary> /// </summary>
/// <param name="iptcProfile">The iptc metadata to write.</param> /// <param name="iptcProfile">The iptc metadata to write.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException"> /// <exception cref="ImageFormatException">
/// Thrown if the IPTC profile size exceeds the limit of 65533 bytes. /// Thrown if the IPTC profile size exceeds the limit of 65533 bytes.
/// </exception> /// </exception>
private void WriteIptcProfile(IptcProfile iptcProfile) private void WriteIptcProfile(IptcProfile iptcProfile, Span<byte> buffer)
{ {
const int maxBytes = 65533; const int maxBytes = 65533;
if (iptcProfile is null || !iptcProfile.Values.Any()) if (iptcProfile is null || !iptcProfile.Values.Any())
@ -316,14 +317,14 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker.Length + Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker.Length +
Components.Decoder.ProfileResolver.AdobeIptcMarker.Length + Components.Decoder.ProfileResolver.AdobeIptcMarker.Length +
2 + 4 + data.Length; 2 + 4 + data.Length;
this.WriteAppHeader(app13Length, JpegConstants.Markers.APP13); this.WriteAppHeader(app13Length, JpegConstants.Markers.APP13, buffer);
this.outputStream.Write(Components.Decoder.ProfileResolver.AdobePhotoshopApp13Marker); this.outputStream.Write(Components.Decoder.ProfileResolver.AdobePhotoshopApp13Marker);
this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker); this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeImageResourceBlockMarker);
this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeIptcMarker); this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeIptcMarker);
this.outputStream.WriteByte(0); // a empty pascal string (padded to make size even) this.outputStream.WriteByte(0); // a empty pascal string (padded to make size even)
this.outputStream.WriteByte(0); this.outputStream.WriteByte(0);
BinaryPrimitives.WriteInt32BigEndian(this.buffer, data.Length); BinaryPrimitives.WriteInt32BigEndian(buffer, data.Length);
this.outputStream.Write(this.buffer, 0, 4); this.outputStream.Write(buffer, 0, 4);
this.outputStream.Write(data, 0, data.Length); this.outputStream.Write(data, 0, data.Length);
} }
@ -331,10 +332,11 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the XMP metadata. /// Writes the XMP metadata.
/// </summary> /// </summary>
/// <param name="xmpProfile">The XMP metadata to write.</param> /// <param name="xmpProfile">The XMP metadata to write.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException"> /// <exception cref="ImageFormatException">
/// Thrown if the XMP profile size exceeds the limit of 65533 bytes. /// Thrown if the XMP profile size exceeds the limit of 65533 bytes.
/// </exception> /// </exception>
private void WriteXmpProfile(XmpProfile xmpProfile) private void WriteXmpProfile(XmpProfile xmpProfile, Span<byte> buffer)
{ {
if (xmpProfile is null) if (xmpProfile is null)
{ {
@ -367,7 +369,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
dataLength -= length; dataLength -= length;
int app1Length = 2 + Components.Decoder.ProfileResolver.XmpMarker.Length + length; int app1Length = 2 + Components.Decoder.ProfileResolver.XmpMarker.Length + length;
this.WriteApp1Header(app1Length); this.WriteApp1Header(app1Length, buffer);
this.outputStream.Write(Components.Decoder.ProfileResolver.XmpMarker); this.outputStream.Write(Components.Decoder.ProfileResolver.XmpMarker);
this.outputStream.Write(data, offset, length); this.outputStream.Write(data, offset, length);
@ -379,32 +381,35 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the App1 header. /// Writes the App1 header.
/// </summary> /// </summary>
/// <param name="app1Length">The length of the data the app1 marker contains.</param> /// <param name="app1Length">The length of the data the app1 marker contains.</param>
private void WriteApp1Header(int app1Length) /// <param name="buffer">Temporary buffer.</param>
=> this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1); private void WriteApp1Header(int app1Length, Span<byte> buffer)
=> this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1, buffer);
/// <summary> /// <summary>
/// Writes a AppX header. /// Writes a AppX header.
/// </summary> /// </summary>
/// <param name="length">The length of the data the app marker contains.</param> /// <param name="length">The length of the data the app marker contains.</param>
/// <param name="appMarker">The app marker to write.</param> /// <param name="appMarker">The app marker to write.</param>
private void WriteAppHeader(int length, byte appMarker) /// <param name="buffer">Temporary buffer.</param>
private void WriteAppHeader(int length, byte appMarker, Span<byte> buffer)
{ {
this.buffer[0] = JpegConstants.Markers.XFF; buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = appMarker; buffer[1] = appMarker;
this.buffer[2] = (byte)((length >> 8) & 0xFF); buffer[2] = (byte)((length >> 8) & 0xFF);
this.buffer[3] = (byte)(length & 0xFF); buffer[3] = (byte)(length & 0xFF);
this.outputStream.Write(this.buffer, 0, 4); this.outputStream.Write(buffer, 0, 4);
} }
/// <summary> /// <summary>
/// Writes the ICC profile. /// Writes the ICC profile.
/// </summary> /// </summary>
/// <param name="iccProfile">The ICC profile to write.</param> /// <param name="iccProfile">The ICC profile to write.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException"> /// <exception cref="ImageFormatException">
/// Thrown if any of the ICC profiles size exceeds the limit. /// Thrown if any of the ICC profiles size exceeds the limit.
/// </exception> /// </exception>
private void WriteIccProfile(IccProfile iccProfile) private void WriteIccProfile(IccProfile iccProfile, Span<byte> buffer)
{ {
if (iccProfile is null) if (iccProfile is null)
{ {
@ -446,30 +451,31 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
dataLength -= length; dataLength -= length;
this.buffer[0] = JpegConstants.Markers.XFF; buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.APP2; // Application Marker buffer[1] = JpegConstants.Markers.APP2; // Application Marker
int markerLength = length + 16; int markerLength = length + 16;
this.buffer[2] = (byte)((markerLength >> 8) & 0xFF); buffer[2] = (byte)((markerLength >> 8) & 0xFF);
this.buffer[3] = (byte)(markerLength & 0xFF); buffer[3] = (byte)(markerLength & 0xFF);
this.outputStream.Write(this.buffer, 0, 4); this.outputStream.Write(buffer, 0, 4);
this.buffer[0] = (byte)'I'; // We write the highest index first, to have only one bound check.
this.buffer[1] = (byte)'C'; buffer[13] = (byte)count; // The total number of profiles.
this.buffer[2] = (byte)'C'; buffer[12] = (byte)current; // The position within the collection.
this.buffer[3] = (byte)'_'; buffer[11] = 0x00;
this.buffer[4] = (byte)'P'; buffer[0] = (byte)'I';
this.buffer[5] = (byte)'R'; buffer[1] = (byte)'C';
this.buffer[6] = (byte)'O'; buffer[2] = (byte)'C';
this.buffer[7] = (byte)'F'; buffer[3] = (byte)'_';
this.buffer[8] = (byte)'I'; buffer[4] = (byte)'P';
this.buffer[9] = (byte)'L'; buffer[5] = (byte)'R';
this.buffer[10] = (byte)'E'; buffer[6] = (byte)'O';
this.buffer[11] = 0x00; buffer[7] = (byte)'F';
this.buffer[12] = (byte)current; // The position within the collection. buffer[8] = (byte)'I';
this.buffer[13] = (byte)count; // The total number of profiles. buffer[9] = (byte)'L';
buffer[10] = (byte)'E';
this.outputStream.Write(this.buffer, 0, iccOverheadLength);
this.outputStream.Write(buffer, 0, iccOverheadLength);
this.outputStream.Write(data, offset, length); this.outputStream.Write(data, offset, length);
current++; current++;
@ -481,7 +487,8 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the metadata profiles to the image. /// Writes the metadata profiles to the image.
/// </summary> /// </summary>
/// <param name="metadata">The image metadata.</param> /// <param name="metadata">The image metadata.</param>
private void WriteProfiles(ImageMetadata metadata) /// <param name="buffer">Temporary buffer.</param>
private void WriteProfiles(ImageMetadata metadata, Span<byte> buffer)
{ {
if (metadata is null) if (metadata is null)
{ {
@ -494,10 +501,10 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
// - APP2 ICC // - APP2 ICC
// - APP13 IPTC // - APP13 IPTC
metadata.SyncProfiles(); metadata.SyncProfiles();
this.WriteExifProfile(metadata.ExifProfile); this.WriteExifProfile(metadata.ExifProfile, buffer);
this.WriteXmpProfile(metadata.XmpProfile); this.WriteXmpProfile(metadata.XmpProfile, buffer);
this.WriteIccProfile(metadata.IccProfile); this.WriteIccProfile(metadata.IccProfile, buffer);
this.WriteIptcProfile(metadata.IptcProfile); this.WriteIptcProfile(metadata.IptcProfile, buffer);
} }
/// <summary> /// <summary>
@ -506,25 +513,26 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <param name="width">The frame width.</param> /// <param name="width">The frame width.</param>
/// <param name="height">The frame height.</param> /// <param name="height">The frame height.</param>
/// <param name="frame">The frame configuration.</param> /// <param name="frame">The frame configuration.</param>
private void WriteStartOfFrame(int width, int height, JpegFrameConfig frame) /// <param name="buffer">Temporary buffer.</param>
private void WriteStartOfFrame(int width, int height, JpegFrameConfig frame, Span<byte> buffer)
{ {
JpegComponentConfig[] components = frame.Components; JpegComponentConfig[] components = frame.Components;
// Length (high byte, low byte), 8 + components * 3. // Length (high byte, low byte), 8 + components * 3.
int markerlen = 8 + (3 * components.Length); int markerlen = 8 + (3 * components.Length);
this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen); this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen, buffer);
this.buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported buffer[5] = (byte)components.Length;
this.buffer[1] = (byte)(height >> 8); buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported
this.buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported buffer[1] = (byte)(height >> 8);
this.buffer[3] = (byte)(width >> 8); buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
this.buffer[4] = (byte)(width & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported buffer[3] = (byte)(width >> 8);
this.buffer[5] = (byte)components.Length; buffer[4] = (byte)(width & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
// Components data // Components data
for (int i = 0; i < components.Length; i++) for (int i = 0; i < components.Length; i++)
{ {
int i3 = 3 * i; int i3 = 3 * i;
Span<byte> bufferSpan = this.buffer.AsSpan(i3 + 6, 3); Span<byte> bufferSpan = buffer.Slice(i3 + 6, 3);
// Quantization table selector // Quantization table selector
bufferSpan[2] = (byte)components[i].QuantizatioTableIndex; bufferSpan[2] = (byte)components[i].QuantizatioTableIndex;
@ -538,14 +546,15 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
bufferSpan[0] = components[i].Id; bufferSpan[0] = components[i].Id;
} }
this.outputStream.Write(this.buffer, 0, (3 * (components.Length - 1)) + 9); this.outputStream.Write(buffer, 0, (3 * (components.Length - 1)) + 9);
} }
/// <summary> /// <summary>
/// Writes the StartOfScan marker. /// Writes the StartOfScan marker.
/// </summary> /// </summary>
/// <param name="components">The collecction of component configuration items.</param> /// <param name="components">The collecction of component configuration items.</param>
private void WriteStartOfScan(Span<JpegComponentConfig> components) /// <param name="buffer">Temporary buffer.</param>
private void WriteStartOfScan(Span<JpegComponentConfig> components, Span<byte> buffer)
{ {
// Write the SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes: // Write the SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes:
// - the marker length "\x00\x0c", // - the marker length "\x00\x0c",
@ -556,14 +565,14 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for // - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al) // sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
// should be 0x00, 0x3f, 0x00&lt;&lt;4 | 0x00. // should be 0x00, 0x3f, 0x00&lt;&lt;4 | 0x00.
this.buffer[0] = JpegConstants.Markers.XFF; buffer[1] = JpegConstants.Markers.SOS;
this.buffer[1] = JpegConstants.Markers.SOS; buffer[0] = JpegConstants.Markers.XFF;
// Length (high byte, low byte), must be 6 + 2 * (number of components in scan) // Length (high byte, low byte), must be 6 + 2 * (number of components in scan)
int sosSize = 6 + (2 * components.Length); int sosSize = 6 + (2 * components.Length);
this.buffer[2] = 0x00; buffer[4] = (byte)components.Length; // Number of components in a scan
this.buffer[3] = (byte)sosSize; buffer[3] = (byte)sosSize;
this.buffer[4] = (byte)components.Length; // Number of components in a scan buffer[2] = 0x00;
// Components data // Components data
for (int i = 0; i < components.Length; i++) for (int i = 0; i < components.Length; i++)
@ -571,27 +580,28 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
int i2 = 2 * i; int i2 = 2 * i;
// Id // Id
this.buffer[i2 + 5] = components[i].Id; buffer[i2 + 5] = components[i].Id;
// Table selectors // Table selectors
int tableSelectors = (components[i].DcTableSelector << 4) | components[i].AcTableSelector; int tableSelectors = (components[i].DcTableSelector << 4) | components[i].AcTableSelector;
this.buffer[i2 + 6] = (byte)tableSelectors; buffer[i2 + 6] = (byte)tableSelectors;
} }
this.buffer[sosSize - 1] = 0x00; // Ss - Start of spectral selection. buffer[sosSize - 1] = 0x00; // Ss - Start of spectral selection.
this.buffer[sosSize] = 0x3f; // Se - End of spectral selection. buffer[sosSize] = 0x3f; // Se - End of spectral selection.
this.buffer[sosSize + 1] = 0x00; // Ah + Ah (Successive approximation bit position high + low) buffer[sosSize + 1] = 0x00; // Ah + Ah (Successive approximation bit position high + low)
this.outputStream.Write(this.buffer, 0, sosSize + 2); this.outputStream.Write(buffer, 0, sosSize + 2);
} }
/// <summary> /// <summary>
/// Writes the EndOfImage marker. /// Writes the EndOfImage marker.
/// </summary> /// </summary>
private void WriteEndOfImageMarker() /// <param name="buffer">Temporary buffer.</param>
private void WriteEndOfImageMarker(Span<byte> buffer)
{ {
this.buffer[0] = JpegConstants.Markers.XFF; buffer[1] = JpegConstants.Markers.EOI;
this.buffer[1] = JpegConstants.Markers.EOI; buffer[0] = JpegConstants.Markers.XFF;
this.outputStream.Write(this.buffer, 0, 2); this.outputStream.Write(buffer, 0, 2);
} }
/// <summary> /// <summary>
@ -602,12 +612,14 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <param name="frameConfig">The frame configuration.</param> /// <param name="frameConfig">The frame configuration.</param>
/// <param name="spectralConverter">The spectral converter.</param> /// <param name="spectralConverter">The spectral converter.</param>
/// <param name="encoder">The scan encoder.</param> /// <param name="encoder">The scan encoder.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <param name="cancellationToken">The cancellation token.</param> /// <param name="cancellationToken">The cancellation token.</param>
private void WriteHuffmanScans<TPixel>( private void WriteHuffmanScans<TPixel>(
JpegFrame frame, JpegFrame frame,
JpegFrameConfig frameConfig, JpegFrameConfig frameConfig,
SpectralConverter<TPixel> spectralConverter, SpectralConverter<TPixel> spectralConverter,
HuffmanScanEncoder encoder, HuffmanScanEncoder encoder,
Span<byte> buffer,
CancellationToken cancellationToken) CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
@ -615,14 +627,14 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
{ {
frame.AllocateComponents(fullScan: false); frame.AllocateComponents(fullScan: false);
this.WriteStartOfScan(frameConfig.Components); this.WriteStartOfScan(frameConfig.Components, buffer);
encoder.EncodeScanBaselineSingleComponent(frame.Components[0], spectralConverter, cancellationToken); encoder.EncodeScanBaselineSingleComponent(frame.Components[0], spectralConverter, cancellationToken);
} }
else if (frame.Interleaved) else if (frame.Interleaved)
{ {
frame.AllocateComponents(fullScan: false); frame.AllocateComponents(fullScan: false);
this.WriteStartOfScan(frameConfig.Components); this.WriteStartOfScan(frameConfig.Components, buffer);
encoder.EncodeScanBaselineInterleaved(frameConfig.EncodingColor, frame, spectralConverter, cancellationToken); encoder.EncodeScanBaselineInterleaved(frameConfig.EncodingColor, frame, spectralConverter, cancellationToken);
} }
else else
@ -633,7 +645,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
Span<JpegComponentConfig> components = frameConfig.Components; Span<JpegComponentConfig> components = frameConfig.Components;
for (int i = 0; i < frame.Components.Length; i++) for (int i = 0; i < frame.Components.Length; i++)
{ {
this.WriteStartOfScan(components.Slice(i, 1)); this.WriteStartOfScan(components.Slice(i, 1), buffer);
encoder.EncodeScanBaseline(frame.Components[i], cancellationToken); encoder.EncodeScanBaseline(frame.Components[i], cancellationToken);
} }
} }
@ -644,14 +656,16 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// </summary> /// </summary>
/// <param name="marker">The marker to write.</param> /// <param name="marker">The marker to write.</param>
/// <param name="length">The marker length.</param> /// <param name="length">The marker length.</param>
private void WriteMarkerHeader(byte marker, int length) /// <param name="buffer">Temporary buffer.</param>
private void WriteMarkerHeader(byte marker, int length, Span<byte> buffer)
{ {
// Markers are always prefixed with 0xff. // Markers are always prefixed with 0xff.
this.buffer[0] = JpegConstants.Markers.XFF; buffer[3] = (byte)(length & 0xff);
this.buffer[1] = marker; buffer[2] = (byte)(length >> 8);
this.buffer[2] = (byte)(length >> 8); buffer[1] = marker;
this.buffer[3] = (byte)(length & 0xff); buffer[0] = JpegConstants.Markers.XFF;
this.outputStream.Write(this.buffer, 0, 4);
this.outputStream.Write(buffer, 0, 4);
} }
/// <summary> /// <summary>
@ -668,15 +682,16 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <param name="configs">Quantization tables configs.</param> /// <param name="configs">Quantization tables configs.</param>
/// <param name="optionsQuality">Optional quality value from the options.</param> /// <param name="optionsQuality">Optional quality value from the options.</param>
/// <param name="metadata">Jpeg metadata instance.</param> /// <param name="metadata">Jpeg metadata instance.</param>
private void WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs, int? optionsQuality, JpegMetadata metadata) /// <param name="tmpBuffer">Temporary buffer.</param>
private void WriteDefineQuantizationTables(JpegQuantizationTableConfig[] configs, int? optionsQuality, JpegMetadata metadata, Span<byte> tmpBuffer)
{ {
int dataLen = configs.Length * (1 + Block8x8.Size); int dataLen = configs.Length * (1 + Block8x8.Size);
// Marker + quantization table lengths. // Marker + quantization table lengths.
int markerlen = 2 + dataLen; int markerlen = 2 + dataLen;
this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen); this.WriteMarkerHeader(JpegConstants.Markers.DQT, markerlen, tmpBuffer);
byte[] buffer = new byte[dataLen]; Span<byte> buffer = dataLen <= 256 ? stackalloc byte[dataLen] : new byte[dataLen];
int offset = 0; int offset = 0;
Block8x8F workspaceBlock = default; Block8x8F workspaceBlock = default;

26
src/ImageSharp/Formats/Png/Adam7.cs

@ -67,16 +67,22 @@ internal static class Adam7
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ComputeColumns(int width, int passIndex) public static int ComputeColumns(int width, int passIndex)
{ {
switch (passIndex) uint w = (uint)width;
uint result = passIndex switch
{ {
case 0: return (width + 7) / 8; 0 => (w + 7) / 8,
case 1: return (width + 3) / 8; 1 => (w + 3) / 8,
case 2: return (width + 3) / 4; 2 => (w + 3) / 4,
case 3: return (width + 1) / 4; 3 => (w + 1) / 4,
case 4: return (width + 1) / 2; 4 => (w + 1) / 2,
case 5: return width / 2; 5 => w / 2,
case 6: return width; 6 => w,
default: throw new ArgumentException($"Not a valid pass index: {passIndex}"); _ => Throw(passIndex)
} };
return (int)result;
static uint Throw(int passIndex) => throw new ArgumentException($"Not a valid pass index: {passIndex}");
} }
} }

26
src/ImageSharp/Formats/Png/Filters/AverageFilter.cs

@ -42,7 +42,7 @@ internal static class AverageFilter
} }
else else
{ {
DecodeScalar(scanline, previousScanline, bytesPerPixel); DecodeScalar(scanline, previousScanline, (uint)bytesPerPixel);
} }
} }
@ -56,7 +56,7 @@ internal static class AverageFilter
Vector128<byte> ones = Vector128.Create((byte)1); Vector128<byte> ones = Vector128.Create((byte)1);
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nuint offset = 1;
while (rb >= 4) while (rb >= 4)
{ {
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -88,7 +88,7 @@ internal static class AverageFilter
Vector64<byte> d = Vector64<byte>.Zero; Vector64<byte> d = Vector64<byte>.Zero;
int rb = scanline.Length; int rb = scanline.Length;
int offset = 1; nuint offset = 1;
const int bytesPerBatch = 4; const int bytesPerBatch = 4;
while (rb >= bytesPerBatch) while (rb >= bytesPerBatch)
{ {
@ -108,12 +108,12 @@ internal static class AverageFilter
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void DecodeScalar(Span<byte> scanline, Span<byte> previousScanline, int bytesPerPixel) private static void DecodeScalar(Span<byte> scanline, Span<byte> previousScanline, uint bytesPerPixel)
{ {
ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline); ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline);
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
nint x = 1; nuint x = 1;
for (; x <= bytesPerPixel /* Note the <= because x starts at 1 */; ++x) for (; x <= bytesPerPixel /* Note the <= because x starts at 1 */; ++x)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
@ -121,7 +121,7 @@ internal static class AverageFilter
scan = (byte)(scan + (above >> 1)); scan = (byte)(scan + (above >> 1));
} }
for (; x < scanline.Length; ++x) for (; x < (uint)scanline.Length; ++x)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel); byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
@ -139,7 +139,7 @@ internal static class AverageFilter
/// <param name="bytesPerPixel">The bytes per pixel.</param> /// <param name="bytesPerPixel">The bytes per pixel.</param>
/// <param name="sum">The sum of the total variance of the filtered row.</param> /// <param name="sum">The sum of the total variance of the filtered row.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Encode(ReadOnlySpan<byte> scanline, ReadOnlySpan<byte> previousScanline, Span<byte> result, int bytesPerPixel, out int sum) public static void Encode(ReadOnlySpan<byte> scanline, ReadOnlySpan<byte> previousScanline, Span<byte> result, uint bytesPerPixel, out int sum)
{ {
DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline)); DebugGuard.MustBeSameSized(scanline, previousScanline, nameof(scanline));
DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result)); DebugGuard.MustBeSizedAtLeast(result, scanline, nameof(result));
@ -152,7 +152,7 @@ internal static class AverageFilter
// Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2) // Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2)
resultBaseRef = (byte)FilterType.Average; resultBaseRef = (byte)FilterType.Average;
nint x = 0; nuint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
@ -169,7 +169,7 @@ internal static class AverageFilter
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
Vector256<byte> allBitsSet = Avx2.CompareEqual(sumAccumulator, sumAccumulator).AsByte(); Vector256<byte> allBitsSet = Avx2.CompareEqual(sumAccumulator, sumAccumulator).AsByte();
for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector256<byte>.Count; xLeft += Vector256<byte>.Count) for (nuint xLeft = x - bytesPerPixel; x <= (uint)(scanline.Length - Vector256<byte>.Count); xLeft += (uint)Vector256<byte>.Count)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -179,7 +179,7 @@ internal static class AverageFilter
Vector256<byte> res = Avx2.Subtract(scan, avg); Vector256<byte> res = Avx2.Subtract(scan, avg);
Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector256<byte>.Count; x += (uint)Vector256<byte>.Count;
sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32()); sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32());
} }
@ -192,7 +192,7 @@ internal static class AverageFilter
Vector128<int> sumAccumulator = Vector128<int>.Zero; Vector128<int> sumAccumulator = Vector128<int>.Zero;
Vector128<byte> allBitsSet = Sse2.CompareEqual(sumAccumulator, sumAccumulator).AsByte(); Vector128<byte> allBitsSet = Sse2.CompareEqual(sumAccumulator, sumAccumulator).AsByte();
for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector128<byte>.Count; xLeft += Vector128<byte>.Count) for (nuint xLeft = x - bytesPerPixel; x <= (uint)(scanline.Length - Vector128<byte>.Count); xLeft += (uint)Vector128<byte>.Count)
{ {
Vector128<byte> scan = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector128<byte> scan = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector128<byte> left = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector128<byte> left = Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -202,7 +202,7 @@ internal static class AverageFilter
Vector128<byte> res = Sse2.Subtract(scan, avg); Vector128<byte> res = Sse2.Subtract(scan, avg);
Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector128<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector128<byte>.Count; x += (uint)Vector128<byte>.Count;
Vector128<byte> absRes; Vector128<byte> absRes;
if (Ssse3.IsSupported) if (Ssse3.IsSupported)
@ -221,7 +221,7 @@ internal static class AverageFilter
sum += Numerics.EvenReduceSum(sumAccumulator); sum += Numerics.EvenReduceSum(sumAccumulator);
} }
for (nint xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) for (nuint xLeft = x - bytesPerPixel; x < (uint)scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, xLeft); byte left = Unsafe.Add(ref scanBaseRef, xLeft);

28
src/ImageSharp/Formats/Png/Filters/PaethFilter.cs

@ -45,7 +45,7 @@ internal static class PaethFilter
} }
else else
{ {
DecodeScalar(scanline, previousScanline, bytesPerPixel); DecodeScalar(scanline, previousScanline, (uint)bytesPerPixel);
} }
} }
@ -59,7 +59,7 @@ internal static class PaethFilter
Vector128<byte> d = Vector128<byte>.Zero; Vector128<byte> d = Vector128<byte>.Zero;
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nuint offset = 1;
while (rb >= 4) while (rb >= 4)
{ {
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -113,7 +113,7 @@ internal static class PaethFilter
Vector128<byte> d = Vector128<byte>.Zero; Vector128<byte> d = Vector128<byte>.Zero;
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nuint offset = 1;
const int bytesPerBatch = 4; const int bytesPerBatch = 4;
while (rb >= bytesPerBatch) while (rb >= bytesPerBatch)
{ {
@ -179,14 +179,14 @@ internal static class PaethFilter
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void DecodeScalar(Span<byte> scanline, Span<byte> previousScanline, int bytesPerPixel) private static void DecodeScalar(Span<byte> scanline, Span<byte> previousScanline, uint bytesPerPixel)
{ {
ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline); ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline);
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp)) // Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
int offset = bytesPerPixel + 1; // Add one because x starts at one. nuint offset = bytesPerPixel + 1; // Add one because x starts at one.
nint x = 1; nuint x = 1;
for (; x < offset; x++) for (; x < offset; x++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
@ -194,7 +194,7 @@ internal static class PaethFilter
scan = (byte)(scan + above); scan = (byte)(scan + above);
} }
for (; x < scanline.Length; x++) for (; x < (uint)scanline.Length; x++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel); byte left = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
@ -226,8 +226,8 @@ internal static class PaethFilter
// Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp)) // Paeth(x) = Raw(x) - PaethPredictor(Raw(x-bpp), Prior(x), Prior(x - bpp))
resultBaseRef = (byte)FilterType.Paeth; resultBaseRef = (byte)FilterType.Paeth;
nint x = 0; nuint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) for (; x < (uint)bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
@ -242,7 +242,7 @@ internal static class PaethFilter
Vector256<byte> zero = Vector256<byte>.Zero; Vector256<byte> zero = Vector256<byte>.Zero;
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector256<byte>.Count; xLeft += Vector256<byte>.Count) for (nuint xLeft = x - (uint)bytesPerPixel; (int)x <= scanline.Length - Vector256<byte>.Count; xLeft += (uint)Vector256<byte>.Count)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector256<byte> left = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -251,7 +251,7 @@ internal static class PaethFilter
Vector256<byte> res = Avx2.Subtract(scan, PaethPredictor(left, above, upperLeft)); Vector256<byte> res = Avx2.Subtract(scan, PaethPredictor(left, above, upperLeft));
Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector256<byte>.Count; x += (uint)Vector256<byte>.Count;
sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32()); sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32());
} }
@ -262,7 +262,7 @@ internal static class PaethFilter
{ {
Vector<uint> sumAccumulator = Vector<uint>.Zero; Vector<uint> sumAccumulator = Vector<uint>.Zero;
for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector<byte>.Count; xLeft += Vector<byte>.Count) for (nuint xLeft = x - (uint)bytesPerPixel; (int)x <= scanline.Length - Vector<byte>.Count; xLeft += (uint)Vector<byte>.Count)
{ {
Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector<byte> left = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector<byte> left = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
@ -271,7 +271,7 @@ internal static class PaethFilter
Vector<byte> res = scan - PaethPredictor(left, above, upperLeft); Vector<byte> res = scan - PaethPredictor(left, above, upperLeft);
Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector<byte>.Count; x += (uint)Vector<byte>.Count;
Numerics.Accumulate(ref sumAccumulator, Vector.AsVectorByte(Vector.Abs(Vector.AsVectorSByte(res)))); Numerics.Accumulate(ref sumAccumulator, Vector.AsVectorByte(Vector.Abs(Vector.AsVectorSByte(res))));
} }
@ -282,7 +282,7 @@ internal static class PaethFilter
} }
} }
for (nint xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) for (nuint xLeft = x - (uint)bytesPerPixel; (int)x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte left = Unsafe.Add(ref scanBaseRef, xLeft); byte left = Unsafe.Add(ref scanBaseRef, xLeft);

26
src/ImageSharp/Formats/Png/Filters/SubFilter.cs

@ -36,7 +36,7 @@ internal static class SubFilter
} }
else else
{ {
DecodeScalar(scanline, bytesPerPixel); DecodeScalar(scanline, (uint)bytesPerPixel);
} }
} }
@ -47,7 +47,7 @@ internal static class SubFilter
Vector128<byte> d = Vector128<byte>.Zero; Vector128<byte> d = Vector128<byte>.Zero;
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nuint offset = 1;
while (rb >= 4) while (rb >= 4)
{ {
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -70,7 +70,7 @@ internal static class SubFilter
Vector64<byte> d = Vector64<byte>.Zero; Vector64<byte> d = Vector64<byte>.Zero;
int rb = scanline.Length; int rb = scanline.Length;
int offset = 1; nuint offset = 1;
const int bytesPerBatch = 4; const int bytesPerBatch = 4;
while (rb >= bytesPerBatch) while (rb >= bytesPerBatch)
{ {
@ -87,14 +87,14 @@ internal static class SubFilter
} }
} }
private static void DecodeScalar(Span<byte> scanline, int bytesPerPixel) private static void DecodeScalar(Span<byte> scanline, nuint bytesPerPixel)
{ {
ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline); ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline);
// Sub(x) + Raw(x-bpp) // Sub(x) + Raw(x-bpp)
nint x = bytesPerPixel + 1; nuint x = bytesPerPixel + 1;
Unsafe.Add(ref scanBaseRef, x); Unsafe.Add(ref scanBaseRef, x);
for (; x < scanline.Length; ++x) for (; x < (uint)scanline.Length; ++x)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel); byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
@ -121,8 +121,8 @@ internal static class SubFilter
// Sub(x) = Raw(x) - Raw(x-bpp) // Sub(x) = Raw(x) - Raw(x-bpp)
resultBaseRef = (byte)FilterType.Sub; resultBaseRef = (byte)FilterType.Sub;
nint x = 0; nuint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) for (; x < (uint)bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
++x; ++x;
@ -136,14 +136,14 @@ internal static class SubFilter
Vector256<byte> zero = Vector256<byte>.Zero; Vector256<byte> zero = Vector256<byte>.Zero;
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector256<byte>.Count; xLeft += Vector256<byte>.Count) for (nuint xLeft = x - (uint)bytesPerPixel; x <= (uint)(scanline.Length - Vector256<byte>.Count); xLeft += (uint)Vector256<byte>.Count)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> prev = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector256<byte> prev = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
Vector256<byte> res = Avx2.Subtract(scan, prev); Vector256<byte> res = Avx2.Subtract(scan, prev);
Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector256<byte>.Count; x += (uint)Vector256<byte>.Count;
sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32()); sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32());
} }
@ -154,14 +154,14 @@ internal static class SubFilter
{ {
Vector<uint> sumAccumulator = Vector<uint>.Zero; Vector<uint> sumAccumulator = Vector<uint>.Zero;
for (nint xLeft = x - bytesPerPixel; x <= scanline.Length - Vector<byte>.Count; xLeft += Vector<byte>.Count) for (nuint xLeft = x - (uint)bytesPerPixel; x <= (uint)(scanline.Length - Vector<byte>.Count); xLeft += (uint)Vector<byte>.Count)
{ {
Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector<byte> prev = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft)); Vector<byte> prev = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
Vector<byte> res = scan - prev; Vector<byte> res = scan - prev;
Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector<byte>.Count; x += (uint)Vector<byte>.Count;
Numerics.Accumulate(ref sumAccumulator, Vector.AsVectorByte(Vector.Abs(Vector.AsVectorSByte(res)))); Numerics.Accumulate(ref sumAccumulator, Vector.AsVectorByte(Vector.Abs(Vector.AsVectorSByte(res))));
} }
@ -172,7 +172,7 @@ internal static class SubFilter
} }
} }
for (nint xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) for (nuint xLeft = x - (uint)bytesPerPixel; x < (uint)scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte prev = Unsafe.Add(ref scanBaseRef, xLeft); byte prev = Unsafe.Add(ref scanBaseRef, xLeft);

30
src/ImageSharp/Formats/Png/Filters/UpFilter.cs

@ -52,7 +52,7 @@ internal static class UpFilter
// Up(x) + Prior(x) // Up(x) + Prior(x)
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nuint offset = 1;
while (rb >= Vector256<byte>.Count) while (rb >= Vector256<byte>.Count)
{ {
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -61,12 +61,12 @@ internal static class UpFilter
Unsafe.As<byte, Vector256<byte>>(ref scanRef) = Avx2.Add(up, prior); Unsafe.As<byte, Vector256<byte>>(ref scanRef) = Avx2.Add(up, prior);
offset += Vector256<byte>.Count; offset += (uint)Vector256<byte>.Count;
rb -= Vector256<byte>.Count; rb -= Vector256<byte>.Count;
} }
// Handle left over. // Handle left over.
for (nint i = offset; i < scanline.Length; i++) for (nuint i = offset; i < (uint)scanline.Length; i++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scan = ref Unsafe.Add(ref scanBaseRef, offset);
byte above = Unsafe.Add(ref prevBaseRef, offset); byte above = Unsafe.Add(ref prevBaseRef, offset);
@ -82,7 +82,7 @@ internal static class UpFilter
// Up(x) + Prior(x) // Up(x) + Prior(x)
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nuint offset = 1;
while (rb >= Vector128<byte>.Count) while (rb >= Vector128<byte>.Count)
{ {
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -91,12 +91,12 @@ internal static class UpFilter
Unsafe.As<byte, Vector128<byte>>(ref scanRef) = Sse2.Add(up, prior); Unsafe.As<byte, Vector128<byte>>(ref scanRef) = Sse2.Add(up, prior);
offset += Vector128<byte>.Count; offset += (uint)Vector128<byte>.Count;
rb -= Vector128<byte>.Count; rb -= Vector128<byte>.Count;
} }
// Handle left over. // Handle left over.
for (nint i = offset; i < scanline.Length; i++) for (nuint i = offset; i < (uint)scanline.Length; i++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scan = ref Unsafe.Add(ref scanBaseRef, offset);
byte above = Unsafe.Add(ref prevBaseRef, offset); byte above = Unsafe.Add(ref prevBaseRef, offset);
@ -112,7 +112,7 @@ internal static class UpFilter
// Up(x) + Prior(x) // Up(x) + Prior(x)
int rb = scanline.Length; int rb = scanline.Length;
nint offset = 1; nuint offset = 1;
const int bytesPerBatch = 16; const int bytesPerBatch = 16;
while (rb >= bytesPerBatch) while (rb >= bytesPerBatch)
{ {
@ -127,7 +127,7 @@ internal static class UpFilter
} }
// Handle left over. // Handle left over.
for (nint i = offset; i < scanline.Length; i++) for (nuint i = offset; i < (uint)scanline.Length; i++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, offset); ref byte scan = ref Unsafe.Add(ref scanBaseRef, offset);
byte above = Unsafe.Add(ref prevBaseRef, offset); byte above = Unsafe.Add(ref prevBaseRef, offset);
@ -143,7 +143,7 @@ internal static class UpFilter
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// Up(x) + Prior(x) // Up(x) + Prior(x)
for (nint x = 1; x < scanline.Length; x++) for (nuint x = 1; x < (uint)scanline.Length; x++)
{ {
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);
@ -172,21 +172,21 @@ internal static class UpFilter
// Up(x) = Raw(x) - Prior(x) // Up(x) = Raw(x) - Prior(x)
resultBaseRef = (byte)FilterType.Up; resultBaseRef = (byte)FilterType.Up;
nint x = 0; nuint x = 0;
if (Avx2.IsSupported) if (Avx2.IsSupported)
{ {
Vector256<byte> zero = Vector256<byte>.Zero; Vector256<byte> zero = Vector256<byte>.Zero;
Vector256<int> sumAccumulator = Vector256<int>.Zero; Vector256<int> sumAccumulator = Vector256<int>.Zero;
for (; x <= scanline.Length - Vector256<byte>.Count;) for (; x <= (uint)(scanline.Length - Vector256<byte>.Count);)
{ {
Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector256<byte> scan = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector256<byte> above = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref prevBaseRef, x)); Vector256<byte> above = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref prevBaseRef, x));
Vector256<byte> res = Avx2.Subtract(scan, above); Vector256<byte> res = Avx2.Subtract(scan, above);
Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector256<byte>.Count; x += (uint)Vector256<byte>.Count;
sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32()); sumAccumulator = Avx2.Add(sumAccumulator, Avx2.SumAbsoluteDifferences(Avx2.Abs(res.AsSByte()), zero).AsInt32());
} }
@ -197,14 +197,14 @@ internal static class UpFilter
{ {
Vector<uint> sumAccumulator = Vector<uint>.Zero; Vector<uint> sumAccumulator = Vector<uint>.Zero;
for (; x <= scanline.Length - Vector<byte>.Count;) for (; x <= (uint)(scanline.Length - Vector<byte>.Count);)
{ {
Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x)); Vector<byte> scan = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, x));
Vector<byte> above = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref prevBaseRef, x)); Vector<byte> above = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref prevBaseRef, x));
Vector<byte> res = scan - above; Vector<byte> res = scan - above;
Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref resultBaseRef, x + 1)) = res; // +1 to skip filter type
x += Vector<byte>.Count; x += (uint)Vector<byte>.Count;
Numerics.Accumulate(ref sumAccumulator, Vector.AsVectorByte(Vector.Abs(Vector.AsVectorSByte(res)))); Numerics.Accumulate(ref sumAccumulator, Vector.AsVectorByte(Vector.Abs(Vector.AsVectorSByte(res))));
} }
@ -215,7 +215,7 @@ internal static class UpFilter
} }
} }
for (; x < scanline.Length; /* Note: ++x happens in the body to avoid one add operation */) for (; x < (uint)scanline.Length; /* Note: ++x happens in the body to avoid one add operation */)
{ {
byte scan = Unsafe.Add(ref scanBaseRef, x); byte scan = Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x);

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

@ -28,11 +28,6 @@ namespace SixLabors.ImageSharp.Formats.Png;
/// </summary> /// </summary>
internal sealed class PngDecoderCore : IImageDecoderInternals internal sealed class PngDecoderCore : IImageDecoderInternals
{ {
/// <summary>
/// Reusable buffer.
/// </summary>
private readonly byte[] buffer = new byte[4];
/// <summary> /// <summary>
/// The general decoder options. /// The general decoder options.
/// </summary> /// </summary>
@ -154,9 +149,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.currentStream = stream; this.currentStream = stream;
this.currentStream.Skip(8); this.currentStream.Skip(8);
Image<TPixel> image = null; Image<TPixel> image = null;
Span<byte> buffer = stackalloc byte[20];
try try
{ {
while (this.TryReadChunk(out PngChunk chunk)) while (this.TryReadChunk(buffer, out PngChunk chunk))
{ {
try try
{ {
@ -252,10 +249,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
ImageMetadata metadata = new(); ImageMetadata metadata = new();
PngMetadata pngMetadata = metadata.GetPngMetadata(); PngMetadata pngMetadata = metadata.GetPngMetadata();
this.currentStream = stream; this.currentStream = stream;
Span<byte> buffer = stackalloc byte[20];
this.currentStream.Skip(8); this.currentStream.Skip(8);
try try
{ {
while (this.TryReadChunk(out PngChunk chunk)) while (this.TryReadChunk(buffer, out PngChunk chunk))
{ {
try try
{ {
@ -414,11 +414,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
for (int i = 0; i < bytesPerScanline; i++) for (int i = 0; i < bytesPerScanline; i++)
{ {
byte b = Unsafe.Add(ref sourceRef, i); byte b = Unsafe.Add(ref sourceRef, (uint)i);
for (int shift = 0; shift < 8; shift += bits) for (int shift = 0; shift < 8; shift += bits)
{ {
int colorIndex = (b >> (8 - bits - shift)) & mask; int colorIndex = (b >> (8 - bits - shift)) & mask;
Unsafe.Add(ref resultRef, resultOffset) = (byte)colorIndex; Unsafe.Add(ref resultRef, (uint)resultOffset) = (byte)colorIndex;
resultOffset++; resultOffset++;
} }
} }
@ -777,8 +777,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header, this.header,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
this.bytesPerPixel, (uint)this.bytesPerPixel,
this.bytesPerSample); (uint)this.bytesPerSample);
break; break;
@ -858,8 +858,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header, this.header,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
pixelOffset, (uint)pixelOffset,
increment, (uint)increment,
pngMetadata.HasTransparency, pngMetadata.HasTransparency,
pngMetadata.TransparentL16.GetValueOrDefault(), pngMetadata.TransparentL16.GetValueOrDefault(),
pngMetadata.TransparentL8.GetValueOrDefault()); pngMetadata.TransparentL8.GetValueOrDefault());
@ -871,10 +871,10 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header, this.header,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
pixelOffset, (uint)pixelOffset,
increment, (uint)increment,
this.bytesPerPixel, (uint)this.bytesPerPixel,
this.bytesPerSample); (uint)this.bytesPerSample);
break; break;
@ -883,8 +883,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header, this.header,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
pixelOffset, (uint)pixelOffset,
increment, (uint)increment,
this.palette, this.palette,
this.paletteAlpha); this.paletteAlpha);
@ -895,8 +895,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header, this.header,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
pixelOffset, (uint)pixelOffset,
increment, (uint)increment,
this.bytesPerPixel, this.bytesPerPixel,
this.bytesPerSample, this.bytesPerSample,
pngMetadata.HasTransparency, pngMetadata.HasTransparency,
@ -910,8 +910,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header, this.header,
scanlineSpan, scanlineSpan,
rowSpan, rowSpan,
pixelOffset, (uint)pixelOffset,
increment, (uint)increment,
this.bytesPerPixel, this.bytesPerPixel,
this.bytesPerSample); this.bytesPerSample);
@ -1401,9 +1401,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
return 0; return 0;
} }
this.currentStream.Read(this.buffer, 0, 4); Span<byte> buffer = stackalloc byte[20];
this.currentStream.Read(buffer, 0, 4);
if (this.TryReadChunk(out PngChunk chunk)) if (this.TryReadChunk(buffer, out PngChunk chunk))
{ {
if (chunk.Type == PngChunkType.Data) if (chunk.Type == PngChunkType.Data)
{ {
@ -1420,11 +1422,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Reads a chunk from the stream. /// Reads a chunk from the stream.
/// </summary> /// </summary>
/// <param name="buffer">Temporary buffer.</param>
/// <param name="chunk">The image format chunk.</param> /// <param name="chunk">The image format chunk.</param>
/// <returns> /// <returns>
/// The <see cref="PngChunk"/>. /// The <see cref="PngChunk"/>.
/// </returns> /// </returns>
private bool TryReadChunk(out PngChunk chunk) private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
{ {
if (this.nextChunk != null) if (this.nextChunk != null)
{ {
@ -1435,7 +1438,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
return true; return true;
} }
if (!this.TryReadChunkLength(out int length)) if (!this.TryReadChunkLength(buffer, out int length))
{ {
chunk = default; chunk = default;
@ -1446,7 +1449,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
while (length < 0 || length > (this.currentStream.Length - this.currentStream.Position)) while (length < 0 || length > (this.currentStream.Length - this.currentStream.Position))
{ {
// Not a valid chunk so try again until we reach a known chunk. // Not a valid chunk so try again until we reach a known chunk.
if (!this.TryReadChunkLength(out length)) if (!this.TryReadChunkLength(buffer, out length))
{ {
chunk = default; chunk = default;
@ -1454,7 +1457,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
} }
} }
PngChunkType type = this.ReadChunkType(); PngChunkType type = this.ReadChunkType(buffer);
// If we're reading color metadata only we're only interested in the IHDR and tRNS chunks. // If we're reading color metadata only we're only interested in the IHDR and tRNS chunks.
// We can skip all other chunk data in the stream for better performance. // We can skip all other chunk data in the stream for better performance.
@ -1471,7 +1474,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
type: type, type: type,
data: this.ReadChunkData(length)); data: this.ReadChunkData(length));
this.ValidateChunk(chunk); this.ValidateChunk(chunk, buffer);
// Restore the stream position for IDAT chunks, because it will be decoded later and // Restore the stream position for IDAT chunks, because it will be decoded later and
// was only read to verifying the CRC is correct. // was only read to verifying the CRC is correct.
@ -1487,9 +1490,10 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// Validates the png chunk. /// Validates the png chunk.
/// </summary> /// </summary>
/// <param name="chunk">The <see cref="PngChunk"/>.</param> /// <param name="chunk">The <see cref="PngChunk"/>.</param>
private void ValidateChunk(in PngChunk chunk) /// <param name="buffer">Temporary buffer.</param>
private void ValidateChunk(in PngChunk chunk, Span<byte> buffer)
{ {
uint inputCrc = this.ReadChunkCrc(); uint inputCrc = this.ReadChunkCrc(buffer);
if (chunk.IsCritical) if (chunk.IsCritical)
{ {
@ -1513,13 +1517,14 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Reads the cycle redundancy chunk from the data. /// Reads the cycle redundancy chunk from the data.
/// </summary> /// </summary>
/// <param name="buffer">Temporary buffer.</param>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private uint ReadChunkCrc() private uint ReadChunkCrc(Span<byte> buffer)
{ {
uint crc = 0; uint crc = 0;
if (this.currentStream.Read(this.buffer, 0, 4) == 4) if (this.currentStream.Read(buffer, 0, 4) == 4)
{ {
crc = BinaryPrimitives.ReadUInt32BigEndian(this.buffer); crc = BinaryPrimitives.ReadUInt32BigEndian(buffer);
} }
return crc; return crc;
@ -1554,15 +1559,16 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Identifies the chunk type from the chunk. /// Identifies the chunk type from the chunk.
/// </summary> /// </summary>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException"> /// <exception cref="ImageFormatException">
/// Thrown if the input stream is not valid. /// Thrown if the input stream is not valid.
/// </exception> /// </exception>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private PngChunkType ReadChunkType() private PngChunkType ReadChunkType(Span<byte> buffer)
{ {
if (this.currentStream.Read(this.buffer, 0, 4) == 4) if (this.currentStream.Read(buffer, 0, 4) == 4)
{ {
return (PngChunkType)BinaryPrimitives.ReadUInt32BigEndian(this.buffer); return (PngChunkType)BinaryPrimitives.ReadUInt32BigEndian(buffer);
} }
PngThrowHelper.ThrowInvalidChunkType(); PngThrowHelper.ThrowInvalidChunkType();
@ -1574,16 +1580,17 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary> /// <summary>
/// Attempts to read the length of the next chunk. /// Attempts to read the length of the next chunk.
/// </summary> /// </summary>
/// <param name="buffer">Temporary buffer.</param>
/// <param name="result">The result length. If the return type is <see langword="false"/> this parameter is passed uninitialized.</param> /// <param name="result">The result length. If the return type is <see langword="false"/> this parameter is passed uninitialized.</param>
/// <returns> /// <returns>
/// Whether the length was read. /// Whether the length was read.
/// </returns> /// </returns>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private bool TryReadChunkLength(out int result) private bool TryReadChunkLength(Span<byte> buffer, out int result)
{ {
if (this.currentStream.Read(this.buffer, 0, 4) == 4) if (this.currentStream.Read(buffer, 0, 4) == 4)
{ {
result = BinaryPrimitives.ReadInt32BigEndian(this.buffer); result = BinaryPrimitives.ReadInt32BigEndian(buffer);
return true; return true;
} }

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

@ -38,15 +38,10 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// </summary> /// </summary>
private readonly Configuration configuration; private readonly Configuration configuration;
/// <summary>
/// Reusable buffer for writing general data.
/// </summary>
private readonly byte[] buffer = new byte[8];
/// <summary> /// <summary>
/// Reusable buffer for writing chunk data. /// Reusable buffer for writing chunk data.
/// </summary> /// </summary>
private readonly byte[] chunkDataBuffer = new byte[16]; private ScratchBuffer chunkDataBuffer; // mutable struct, don't make readonly
/// <summary> /// <summary>
/// The encoder with options /// The encoder with options
@ -266,7 +261,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Can't map directly to byte array as it's big-endian. // Can't map directly to byte array as it's big-endian.
for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2) for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2)
{ {
L16 luminance = Unsafe.Add(ref luminanceRef, x); L16 luminance = Unsafe.Add(ref luminanceRef, (uint)x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue);
} }
} }
@ -306,7 +301,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Can't map directly to byte array as it's big endian. // Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < laSpan.Length; x++, o += 4) for (int x = 0, o = 0; x < laSpan.Length; x++, o += 4)
{ {
La32 la = Unsafe.Add(ref laRef, x); La32 la = Unsafe.Add(ref laRef, (uint)x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), la.L); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), la.L);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), la.A); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), la.A);
} }
@ -366,7 +361,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Can't map directly to byte array as it's big endian. // Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8)
{ {
Rgba64 rgba = Unsafe.Add(ref rgbaRef, x); Rgba64 rgba = Unsafe.Add(ref rgbaRef, (uint)x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B);
@ -388,7 +383,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Can't map directly to byte array as it's big endian. // Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6)
{ {
Rgb48 rgb = Unsafe.Add(ref rgbRef, x); Rgb48 rgb = Unsafe.Add(ref rgbRef, (uint)x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B);
@ -455,7 +450,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
break; break;
case PngFilterMethod.Average: case PngFilterMethod.Average:
AverageFilter.Encode(this.currentScanline.GetSpan(), this.previousScanline.GetSpan(), filter, this.bytesPerPixel, out int _); AverageFilter.Encode(this.currentScanline.GetSpan(), this.previousScanline.GetSpan(), filter, (uint)this.bytesPerPixel, out int _);
break; break;
case PngFilterMethod.Paeth: case PngFilterMethod.Paeth:
@ -547,7 +542,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
RuntimeUtility.Swap(ref filter, ref attempt); RuntimeUtility.Swap(ref filter, ref attempt);
} }
AverageFilter.Encode(current, previous, attempt, this.bytesPerPixel, out sum); AverageFilter.Encode(current, previous, attempt, (uint)this.bytesPerPixel, out sum);
if (sum < min) if (sum < min)
{ {
min = sum; min = sum;
@ -576,9 +571,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
filterMethod: 0, filterMethod: 0,
interlaceMethod: this.interlaceMode); interlaceMethod: this.interlaceMode);
header.WriteTo(this.chunkDataBuffer); header.WriteTo(this.chunkDataBuffer.Span);
this.WriteChunk(stream, PngChunkType.Header, this.chunkDataBuffer, 0, PngHeader.Size); this.WriteChunk(stream, PngChunkType.Header, this.chunkDataBuffer.Span, 0, PngHeader.Size);
} }
/// <summary> /// <summary>
@ -617,17 +612,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Loop, assign, and extract alpha values from the palette. // Loop, assign, and extract alpha values from the palette.
for (int i = 0; i < paletteLength; i++) for (int i = 0; i < paletteLength; i++)
{ {
Rgba32 rgba = Unsafe.Add(ref rgbaPaletteRef, i); Rgba32 rgba = Unsafe.Add(ref rgbaPaletteRef, (uint)i);
byte alpha = rgba.A; byte alpha = rgba.A;
Unsafe.Add(ref colorTableRef, i) = rgba.Rgb; Unsafe.Add(ref colorTableRef, (uint)i) = rgba.Rgb;
if (alpha > this.encoder.Threshold) if (alpha > this.encoder.Threshold)
{ {
alpha = byte.MaxValue; alpha = byte.MaxValue;
} }
hasAlpha = hasAlpha || alpha < byte.MaxValue; hasAlpha = hasAlpha || alpha < byte.MaxValue;
Unsafe.Add(ref alphaTableRef, i) = alpha; Unsafe.Add(ref alphaTableRef, (uint)i) = alpha;
} }
this.WriteChunk(stream, PngChunkType.Palette, colorTable.GetSpan(), 0, colorTableLength); this.WriteChunk(stream, PngChunkType.Palette, colorTable.GetSpan(), 0, colorTableLength);
@ -652,9 +647,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
return; return;
} }
PhysicalChunkData.FromMetadata(meta).WriteTo(this.chunkDataBuffer); PhysicalChunkData.FromMetadata(meta).WriteTo(this.chunkDataBuffer.Span);
this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, PhysicalChunkData.Size); this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer.Span, 0, PhysicalChunkData.Size);
} }
/// <summary> /// <summary>
@ -880,9 +875,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// 4-byte unsigned integer of gamma * 100,000. // 4-byte unsigned integer of gamma * 100,000.
uint gammaValue = (uint)(this.gamma * 100_000F); uint gammaValue = (uint)(this.gamma * 100_000F);
BinaryPrimitives.WriteUInt32BigEndian(this.chunkDataBuffer.AsSpan(0, 4), gammaValue); BinaryPrimitives.WriteUInt32BigEndian(this.chunkDataBuffer.Span.Slice(0, 4), gammaValue);
this.WriteChunk(stream, PngChunkType.Gamma, this.chunkDataBuffer, 0, 4); this.WriteChunk(stream, PngChunkType.Gamma, this.chunkDataBuffer.Span, 0, 4);
} }
} }
@ -899,7 +894,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
return; return;
} }
Span<byte> alpha = this.chunkDataBuffer.AsSpan(); Span<byte> alpha = this.chunkDataBuffer.Span;
if (pngMetadata.ColorType == PngColorType.Rgb) if (pngMetadata.ColorType == PngColorType.Rgb)
{ {
if (pngMetadata.TransparentRgb48.HasValue && this.use16Bit) if (pngMetadata.TransparentRgb48.HasValue && this.use16Bit)
@ -909,7 +904,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G); BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(2, 2), rgb.G);
BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B); BinaryPrimitives.WriteUInt16LittleEndian(alpha.Slice(4, 2), rgb.B);
this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer.Span, 0, 6);
} }
else if (pngMetadata.TransparentRgb24.HasValue) else if (pngMetadata.TransparentRgb24.HasValue)
{ {
@ -918,7 +913,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
alpha[1] = rgb.R; alpha[1] = rgb.R;
alpha[3] = rgb.G; alpha[3] = rgb.G;
alpha[5] = rgb.B; alpha[5] = rgb.B;
this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 6); this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer.Span, 0, 6);
} }
} }
else if (pngMetadata.ColorType == PngColorType.Grayscale) else if (pngMetadata.ColorType == PngColorType.Grayscale)
@ -926,13 +921,13 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
if (pngMetadata.TransparentL16.HasValue && this.use16Bit) if (pngMetadata.TransparentL16.HasValue && this.use16Bit)
{ {
BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetadata.TransparentL16.Value.PackedValue); BinaryPrimitives.WriteUInt16LittleEndian(alpha, pngMetadata.TransparentL16.Value.PackedValue);
this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer.Span, 0, 2);
} }
else if (pngMetadata.TransparentL8.HasValue) else if (pngMetadata.TransparentL8.HasValue)
{ {
alpha.Clear(); alpha.Clear();
alpha[1] = pngMetadata.TransparentL8.Value.PackedValue; alpha[1] = pngMetadata.TransparentL8.Value.PackedValue;
this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer, 0, 2); this.WriteChunk(stream, PngChunkType.Transparency, this.chunkDataBuffer.Span, 0, 2);
} }
} }
} }
@ -1173,12 +1168,14 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// <param name="length">The of the data to write.</param> /// <param name="length">The of the data to write.</param>
private void WriteChunk(Stream stream, PngChunkType type, Span<byte> data, int offset, int length) private void WriteChunk(Stream stream, PngChunkType type, Span<byte> data, int offset, int length)
{ {
BinaryPrimitives.WriteInt32BigEndian(this.buffer, length); Span<byte> buffer = stackalloc byte[8];
BinaryPrimitives.WriteUInt32BigEndian(this.buffer.AsSpan(4, 4), (uint)type);
BinaryPrimitives.WriteInt32BigEndian(buffer, length);
BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(4, 4), (uint)type);
stream.Write(this.buffer, 0, 8); stream.Write(buffer);
uint crc = Crc32.Calculate(this.buffer.AsSpan(4, 4)); // Write the type buffer uint crc = Crc32.Calculate(buffer.Slice(4)); // Write the type buffer
if (data.Length > 0 && length > 0) if (data.Length > 0 && length > 0)
{ {
@ -1187,9 +1184,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
crc = Crc32.Calculate(crc, data.Slice(offset, length)); crc = Crc32.Calculate(crc, data.Slice(offset, length));
} }
BinaryPrimitives.WriteUInt32BigEndian(this.buffer, crc); BinaryPrimitives.WriteUInt32BigEndian(buffer, crc);
stream.Write(this.buffer, 0, 4); // write the crc stream.Write(buffer, 0, 4); // write the crc
} }
/// <summary> /// <summary>
@ -1412,4 +1409,12 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
Type t when t == typeof(RgbaVector) => PngBitDepth.Bit16, Type t when t == typeof(RgbaVector) => PngBitDepth.Bit16,
_ => PngBitDepth.Bit8 _ => PngBitDepth.Bit8
}; };
private unsafe struct ScratchBuffer
{
private const int Size = 16;
private fixed byte scratch[Size];
public Span<byte> Span => MemoryMarshal.CreateSpan(ref this.scratch[0], Size);
}
} }

6
src/ImageSharp/Formats/Png/PngEncoderHelpers.cs

@ -31,13 +31,13 @@ internal static class PngEncoderHelpers
for (int i = 0; i < source.Length; i++) for (int i = 0; i < source.Length; i++)
{ {
int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask; int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, (uint)i) / scale)) & mask;
v |= value << shift; v |= value << shift;
if (shift == 0) if (shift == 0)
{ {
shift = shift0; shift = shift0;
Unsafe.Add(ref resultRef, resultOffset) = (byte)v; Unsafe.Add(ref resultRef, (uint)resultOffset) = (byte)v;
resultOffset++; resultOffset++;
v = 0; v = 0;
} }
@ -49,7 +49,7 @@ internal static class PngEncoderHelpers
if (shift != shift0) if (shift != shift0)
{ {
Unsafe.Add(ref resultRef, resultOffset) = (byte)v; Unsafe.Add(ref resultRef, (uint)resultOffset) = (byte)v;
} }
} }
} }

129
src/ImageSharp/Formats/Png/PngScanlineProcessor.cs

@ -32,7 +32,8 @@ internal static class PngScanlineProcessor
{ {
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
for (int x = 0, o = 0; x < header.Width; x++, o += 2) int o = 0;
for (nuint x = 0; x < (uint)header.Width; x++, o += 2)
{ {
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance)); pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
@ -41,7 +42,7 @@ internal static class PngScanlineProcessor
} }
else else
{ {
for (int x = 0; x < header.Width; x++) for (nuint x = 0; x < (uint)header.Width; x++)
{ {
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor);
pixel.FromL8(Unsafe.As<byte, L8>(ref luminance)); pixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
@ -55,7 +56,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
La32 source = default; La32 source = default;
for (int x = 0, o = 0; x < header.Width; x++, o += 2) int o = 0;
for (nuint x = 0; x < (uint)header.Width; x++, o += 2)
{ {
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.L = luminance; source.L = luminance;
@ -69,7 +71,7 @@ internal static class PngScanlineProcessor
{ {
La16 source = default; La16 source = default;
byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor);
for (int x = 0; x < header.Width; x++) for (nuint x = 0; x < (uint)header.Width; x++)
{ {
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor);
source.L = luminance; source.L = luminance;
@ -85,8 +87,8 @@ internal static class PngScanlineProcessor
in PngHeader header, in PngHeader header,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int pixelOffset, uint pixelOffset,
int increment, uint increment,
bool hasTrans, bool hasTrans,
L16 luminance16Trans, L16 luminance16Trans,
L8 luminanceTrans) L8 luminanceTrans)
@ -101,7 +103,8 @@ internal static class PngScanlineProcessor
{ {
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += 2)
{ {
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance)); pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
@ -110,7 +113,7 @@ internal static class PngScanlineProcessor
} }
else else
{ {
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++)
{ {
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
pixel.FromL8(Unsafe.As<byte, L8>(ref luminance)); pixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
@ -124,7 +127,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
La32 source = default; La32 source = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += 2)
{ {
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.L = luminance; source.L = luminance;
@ -138,7 +142,7 @@ internal static class PngScanlineProcessor
{ {
La16 source = default; La16 source = default;
byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor); byte scaledLuminanceTrans = (byte)(luminanceTrans.PackedValue * scaleFactor);
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++)
{ {
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
source.L = luminance; source.L = luminance;
@ -154,8 +158,8 @@ internal static class PngScanlineProcessor
in PngHeader header, in PngHeader header,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int bytesPerPixel, uint bytesPerPixel,
int bytesPerSample) uint bytesPerSample)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
TPixel pixel = default; TPixel pixel = default;
@ -165,7 +169,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
La32 source = default; La32 source = default;
for (int x = 0, o = 0; x < header.Width; x++, o += 4) int o = 0;
for (nuint x = 0; x < (uint)header.Width; x++, o += 4)
{ {
source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
@ -177,9 +182,9 @@ internal static class PngScanlineProcessor
else else
{ {
La16 source = default; La16 source = default;
for (int x = 0; x < header.Width; x++) for (nuint x = 0; x < (uint)header.Width; x++)
{ {
int offset = x * bytesPerPixel; nuint offset = x * bytesPerPixel;
source.L = Unsafe.Add(ref scanlineSpanRef, offset); source.L = Unsafe.Add(ref scanlineSpanRef, offset);
source.A = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample); source.A = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample);
@ -193,10 +198,10 @@ internal static class PngScanlineProcessor
in PngHeader header, in PngHeader header,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int pixelOffset, uint pixelOffset,
int increment, uint increment,
int bytesPerPixel, uint bytesPerPixel,
int bytesPerSample) uint bytesPerSample)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
TPixel pixel = default; TPixel pixel = default;
@ -206,20 +211,21 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
La32 source = default; La32 source = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 4) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += 4)
{ {
source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
pixel.FromLa32(source); pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, (uint)x) = pixel;
} }
} }
else else
{ {
int offset = 0;
La16 source = default; La16 source = default;
for (int x = pixelOffset; x < header.Width; x += increment) nuint offset = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment)
{ {
source.L = Unsafe.Add(ref scanlineSpanRef, offset); source.L = Unsafe.Add(ref scanlineSpanRef, offset);
source.A = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample); source.A = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample);
@ -255,11 +261,11 @@ internal static class PngScanlineProcessor
// If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha
// channel and we should try to read it. // channel and we should try to read it.
Rgba32 rgba = default; Rgba32 rgba = default;
ref byte paletteAlphaRef = ref paletteAlpha[0]; ref byte paletteAlphaRef = ref MemoryMarshal.GetArrayDataReference(paletteAlpha);
for (int x = 0; x < header.Width; x++) for (nuint x = 0; x < (uint)header.Width; x++)
{ {
int index = Unsafe.Add(ref scanlineSpanRef, x); uint index = Unsafe.Add(ref scanlineSpanRef, x);
rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index);
rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue;
@ -269,7 +275,7 @@ internal static class PngScanlineProcessor
} }
else else
{ {
for (int x = 0; x < header.Width; x++) for (nuint x = 0; x < (uint)header.Width; x++)
{ {
int index = Unsafe.Add(ref scanlineSpanRef, x); int index = Unsafe.Add(ref scanlineSpanRef, x);
Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
@ -284,8 +290,8 @@ internal static class PngScanlineProcessor
in PngHeader header, in PngHeader header,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int pixelOffset, uint pixelOffset,
int increment, uint increment,
ReadOnlySpan<byte> palette, ReadOnlySpan<byte> palette,
byte[] paletteAlpha) byte[] paletteAlpha)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
@ -301,10 +307,10 @@ internal static class PngScanlineProcessor
// If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha
// channel and we should try to read it. // channel and we should try to read it.
Rgba32 rgba = default; Rgba32 rgba = default;
ref byte paletteAlphaRef = ref paletteAlpha[0]; ref byte paletteAlphaRef = ref MemoryMarshal.GetArrayDataReference(paletteAlpha);
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++)
{ {
int index = Unsafe.Add(ref scanlineSpanRef, o); uint index = Unsafe.Add(ref scanlineSpanRef, o);
rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue;
rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index);
@ -314,7 +320,7 @@ internal static class PngScanlineProcessor
} }
else else
{ {
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) for (nuint x = pixelOffset, o = 0; x < (uint)header.Width; x += increment, o++)
{ {
int index = Unsafe.Add(ref scanlineSpanRef, o); int index = Unsafe.Add(ref scanlineSpanRef, o);
Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
@ -345,7 +351,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
Rgb48 rgb48 = default; Rgb48 rgb48 = default;
for (int x = 0, o = 0; x < header.Width; x++, o += bytesPerPixel) int o = 0;
for (nuint x = 0; x < (uint)header.Width; x++, o += bytesPerPixel)
{ {
rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -367,7 +374,8 @@ internal static class PngScanlineProcessor
{ {
Rgb48 rgb48 = default; Rgb48 rgb48 = default;
Rgba64 rgba64 = default; Rgba64 rgba64 = default;
for (int x = 0, o = 0; x < header.Width; x++, o += bytesPerPixel) int o = 0;
for (nuint x = 0; x < (uint)header.Width; x++, o += bytesPerPixel)
{ {
rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -385,7 +393,7 @@ internal static class PngScanlineProcessor
Rgba32 rgba32 = default; Rgba32 rgba32 = default;
ReadOnlySpan<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(scanlineSpan); ReadOnlySpan<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(scanlineSpan);
ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span); ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span);
for (int x = 0; x < header.Width; x++) for (nuint x = 0; x < (uint)header.Width; x++)
{ {
ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x); ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x);
rgba32.Rgb = rgb24; rgba32.Rgb = rgb24;
@ -401,8 +409,8 @@ internal static class PngScanlineProcessor
in PngHeader header, in PngHeader header,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int pixelOffset, uint pixelOffset,
int increment, uint increment,
int bytesPerPixel, int bytesPerPixel,
int bytesPerSample, int bytesPerSample,
bool hasTrans, bool hasTrans,
@ -420,7 +428,8 @@ internal static class PngScanlineProcessor
{ {
Rgb48 rgb48 = default; Rgb48 rgb48 = default;
Rgba64 rgba64 = default; Rgba64 rgba64 = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel)
{ {
rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -436,7 +445,8 @@ internal static class PngScanlineProcessor
else else
{ {
Rgb48 rgb48 = default; Rgb48 rgb48 = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel)
{ {
rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -453,11 +463,12 @@ internal static class PngScanlineProcessor
if (hasTrans) if (hasTrans)
{ {
Rgba32 rgba = default; Rgba32 rgba = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel)
{ {
rgba.R = Unsafe.Add(ref scanlineSpanRef, o); rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue;
pixel.FromRgba32(rgba); pixel.FromRgba32(rgba);
@ -467,11 +478,12 @@ internal static class PngScanlineProcessor
else else
{ {
Rgb24 rgb = default; Rgb24 rgb = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel)
{ {
rgb.R = Unsafe.Add(ref scanlineSpanRef, o); rgb.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); rgb.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgb.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
pixel.FromRgb24(rgb); pixel.FromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
@ -494,7 +506,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
Rgba64 rgba64 = default; Rgba64 rgba64 = default;
for (int x = 0, o = 0; x < header.Width; x++, o += bytesPerPixel) int o = 0;
for (nuint x = 0; x < (uint)header.Width; x++, o += bytesPerPixel)
{ {
rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -515,8 +528,8 @@ internal static class PngScanlineProcessor
in PngHeader header, in PngHeader header,
ReadOnlySpan<byte> scanlineSpan, ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan, Span<TPixel> rowSpan,
int pixelOffset, uint pixelOffset,
int increment, uint increment,
int bytesPerPixel, int bytesPerPixel,
int bytesPerSample) int bytesPerSample)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
@ -528,7 +541,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
Rgba64 rgba64 = default; Rgba64 rgba64 = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel)
{ {
rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -542,12 +556,13 @@ internal static class PngScanlineProcessor
else else
{ {
Rgba32 rgba = default; Rgba32 rgba = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) int o = 0;
for (nuint x = pixelOffset; x < (uint)header.Width; x += increment, o += bytesPerPixel)
{ {
rgba.R = Unsafe.Add(ref scanlineSpanRef, o); rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * bytesPerSample)); rgba.A = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample)));
pixel.FromRgba32(rgba); pixel.FromRgba32(rgba);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;

44
src/ImageSharp/Formats/Tga/TgaDecoderCore.cs

@ -4,6 +4,7 @@
using System.Buffers; using System.Buffers;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata;
@ -16,11 +17,6 @@ namespace SixLabors.ImageSharp.Formats.Tga;
/// </summary> /// </summary>
internal sealed class TgaDecoderCore : IImageDecoderInternals internal sealed class TgaDecoderCore : IImageDecoderInternals
{ {
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
private readonly byte[] scratchBuffer = new byte[4];
/// <summary> /// <summary>
/// General configuration options. /// General configuration options.
/// </summary> /// </summary>
@ -406,6 +402,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
bool invertX = InvertX(origin); bool invertX = InvertX(origin);
using IMemoryOwner<byte> row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0); using IMemoryOwner<byte> row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0);
Span<byte> rowSpan = row.GetSpan(); Span<byte> rowSpan = row.GetSpan();
Span<byte> scratchBuffer = stackalloc byte[2];
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -416,7 +413,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{ {
for (int x = width - 1; x >= 0; x--) for (int x = width - 1; x >= 0; x--)
{ {
int bytesRead = stream.Read(this.scratchBuffer, 0, 2); int bytesRead = stream.Read(scratchBuffer);
if (bytesRead != 2) if (bytesRead != 2)
{ {
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel row"); TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel row");
@ -424,16 +421,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (!this.hasAlpha) if (!this.hasAlpha)
{ {
this.scratchBuffer[1] |= 1 << 7; scratchBuffer[1] |= 1 << 7;
} }
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite) if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{ {
color.FromLa16(Unsafe.As<byte, La16>(ref this.scratchBuffer[0])); color.FromLa16(Unsafe.As<byte, La16>(ref MemoryMarshal.GetReference(scratchBuffer)));
} }
else else
{ {
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref this.scratchBuffer[0])); color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref MemoryMarshal.GetReference(scratchBuffer)));
} }
pixelSpan[x] = color; pixelSpan[x] = color;
@ -483,6 +480,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
bool invertX = InvertX(origin); bool invertX = InvertX(origin);
if (invertX) if (invertX)
{ {
Span<byte> scratchBuffer = stackalloc byte[4];
TPixel color = default; TPixel color = default;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -490,7 +488,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY); Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = width - 1; x >= 0; x--) for (int x = width - 1; x >= 0; x--)
{ {
this.ReadBgr24Pixel(stream, color, x, pixelSpan); ReadBgr24Pixel(stream, color, x, pixelSpan, scratchBuffer);
} }
} }
@ -557,6 +555,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
return; return;
} }
Span<byte> scratchBuffer = stackalloc byte[4];
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
int newY = InvertY(y, height, origin); int newY = InvertY(y, height, origin);
@ -565,14 +565,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{ {
for (int x = width - 1; x >= 0; x--) for (int x = width - 1; x >= 0; x--)
{ {
this.ReadBgra32Pixel(stream, x, color, pixelRow); this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
} }
} }
else else
{ {
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
this.ReadBgra32Pixel(stream, x, color, pixelRow); this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
} }
} }
} }
@ -686,16 +686,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgr24Pixel<TPixel>(BufferedReadStream stream, TPixel color, int x, Span<TPixel> pixelSpan) private static void ReadBgr24Pixel<TPixel>(BufferedReadStream stream, TPixel color, int x, Span<TPixel> pixelSpan, Span<byte> scratchBuffer)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int bytesRead = stream.Read(this.scratchBuffer, 0, 3); int bytesRead = stream.Read(scratchBuffer, 0, 3);
if (bytesRead != 3) if (bytesRead != 3)
{ {
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel"); TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel");
} }
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref this.scratchBuffer[0])); color.FromBgr24(Unsafe.As<byte, Bgr24>(ref MemoryMarshal.GetReference(scratchBuffer)));
pixelSpan[x] = color; pixelSpan[x] = color;
} }
@ -714,10 +714,10 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgra32Pixel<TPixel>(BufferedReadStream stream, int x, TPixel color, Span<TPixel> pixelRow) private void ReadBgra32Pixel<TPixel>(BufferedReadStream stream, int x, TPixel color, Span<TPixel> pixelRow, Span<byte> scratchBuffer)
where TPixel : unmanaged, IPixel<TPixel> where TPixel : unmanaged, IPixel<TPixel>
{ {
int bytesRead = stream.Read(this.scratchBuffer, 0, 4); int bytesRead = stream.Read(scratchBuffer, 0, 4);
if (bytesRead != 4) if (bytesRead != 4)
{ {
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgra pixel"); TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgra pixel");
@ -725,8 +725,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
Guard.NotNull(this.tgaMetadata); Guard.NotNull(this.tgaMetadata);
byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : this.scratchBuffer[3]; byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : scratchBuffer[3];
color.FromBgra32(new Bgra32(this.scratchBuffer[2], this.scratchBuffer[1], this.scratchBuffer[0], alpha)); color.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha));
pixelRow[x] = color; pixelRow[x] = color;
} }
@ -813,7 +813,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
private void UncompressRle(BufferedReadStream stream, int width, int height, Span<byte> buffer, int bytesPerPixel) private void UncompressRle(BufferedReadStream stream, int width, int height, Span<byte> buffer, int bytesPerPixel)
{ {
int uncompressedPixels = 0; int uncompressedPixels = 0;
Span<byte> pixel = this.scratchBuffer.AsSpan(0, bytesPerPixel); Span<byte> pixel = stackalloc byte[bytesPerPixel];
int totalPixels = width * height; int totalPixels = width * height;
while (uncompressedPixels < totalPixels) while (uncompressedPixels < totalPixels)
{ {
@ -824,7 +824,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (highBit == 1) if (highBit == 1)
{ {
int runLength = runLengthByte & 127; int runLength = runLengthByte & 127;
int bytesRead = stream.Read(pixel, 0, bytesPerPixel); int bytesRead = stream.Read(pixel);
if (bytesRead != bytesPerPixel) if (bytesRead != bytesPerPixel)
{ {
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream"); TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream");
@ -844,7 +844,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
int bufferIdx = uncompressedPixels * bytesPerPixel; int bufferIdx = uncompressedPixels * bytesPerPixel;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++) for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{ {
int bytesRead = stream.Read(pixel, 0, bytesPerPixel); int bytesRead = stream.Read(pixel);
if (bytesRead != bytesPerPixel) if (bytesRead != bytesPerPixel)
{ {
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream"); TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel from the stream");

12
src/ImageSharp/Formats/Tga/TgaEncoderCore.cs

@ -22,11 +22,6 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
/// </summary> /// </summary>
private readonly MemoryAllocator memoryAllocator; private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// Reusable buffer for writing data.
/// </summary>
private readonly byte[] buffer = new byte[2];
/// <summary> /// <summary>
/// The color depth, in number of bits per pixel. /// The color depth, in number of bits per pixel.
/// </summary> /// </summary>
@ -221,9 +216,10 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
case TgaBitsPerPixel.Pixel16: case TgaBitsPerPixel.Pixel16:
Bgra5551 bgra5551 = new(color.ToVector4()); Bgra5551 bgra5551 = new(color.ToVector4());
BinaryPrimitives.WriteInt16LittleEndian(this.buffer, (short)bgra5551.PackedValue); Span<byte> buffer = stackalloc byte[2];
stream.WriteByte(this.buffer[0]); BinaryPrimitives.WriteInt16LittleEndian(buffer, (short)bgra5551.PackedValue);
stream.WriteByte(this.buffer[1]); stream.WriteByte(buffer[0]);
stream.WriteByte(buffer[1]);
break; break;

2
src/ImageSharp/Formats/Tiff/Compression/Decompressors/T6TiffCompression.cs

@ -78,7 +78,7 @@ internal sealed class T6TiffCompression : TiffBaseDecompressor
nint bitPos = Numerics.Modulo8(bitsWritten); nint bitPos = Numerics.Modulo8(bitsWritten);
nint bufferPos = bitsWritten / 8; nint bufferPos = bitsWritten / 8;
ref byte scanLineRef = ref MemoryMarshal.GetReference(scanLine); ref byte scanLineRef = ref MemoryMarshal.GetReference(scanLine);
for (nint i = 0; i < scanLine.Length; i++) for (nuint i = 0; i < (uint)scanLine.Length; i++)
{ {
if (Unsafe.Add(ref scanLineRef, i) != this.white) if (Unsafe.Add(ref scanLineRef, i) != this.white)
{ {

16
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs

@ -18,21 +18,21 @@ internal class BlackIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/> /// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{ {
nint offset = 0; nuint offset = 0;
var colorBlack = default(TPixel); TPixel colorBlack = default;
var colorWhite = default(TPixel); TPixel colorWhite = default;
colorBlack.FromRgba32(Color.Black); colorBlack.FromRgba32(Color.Black);
colorWhite.FromRgba32(Color.White); colorWhite.FromRgba32(Color.White);
ref byte dataRef = ref MemoryMarshal.GetReference(data); ref byte dataRef = ref MemoryMarshal.GetReference(data);
for (nint y = top; y < top + height; y++) for (nuint y = (uint)top; y < (uint)(top + height); y++)
{ {
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan((int)y); Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan((int)y);
ref TPixel pixelRowRef = ref MemoryMarshal.GetReference(pixelRowSpan); ref TPixel pixelRowRef = ref MemoryMarshal.GetReference(pixelRowSpan);
for (nint x = left; x < left + width; x += 8) for (nuint x = (uint)left; x < (uint)(left + width); x += 8)
{ {
byte b = Unsafe.Add(ref dataRef, offset++); byte b = Unsafe.Add(ref dataRef, offset++);
nint maxShift = Math.Min(left + width - x, 8); nuint maxShift = Math.Min((uint)(left + width) - x, 8);
if (maxShift == 8) if (maxShift == 8)
{ {
@ -70,9 +70,9 @@ internal class BlackIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
} }
else else
{ {
for (int shift = 0; shift < maxShift; shift++) for (nuint shift = 0; shift < maxShift; shift++)
{ {
int bit = (b >> (7 - shift)) & 1; int bit = (b >> (7 - (int)shift)) & 1;
ref TPixel pixel = ref Unsafe.Add(ref pixelRowRef, x + shift); ref TPixel pixel = ref Unsafe.Add(ref pixelRowRef, x + shift);
pixel = bit == 0 ? colorBlack : colorWhite; pixel = bit == 0 ? colorBlack : colorWhite;

11
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs

@ -24,9 +24,9 @@ internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
/// <inheritdoc/> /// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{ {
var color = default(TPixel); TPixel color = default;
color.FromScaledVector4(Vector4.Zero); color.FromScaledVector4(Vector4.Zero);
byte[] buffer = new byte[4]; Span<byte> buffer = stackalloc byte[4];
int offset = 0; int offset = 0;
for (int y = top; y < top + height; y++) for (int y = top; y < top + height; y++)
@ -37,8 +37,8 @@ internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float intensity = BitConverter.ToSingle(buffer, 0); float intensity = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
@ -50,8 +50,7 @@ internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
{ {
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); float intensity = BitConverter.ToSingle(data.Slice(offset, 4));
float intensity = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);

23
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs

@ -27,7 +27,7 @@ internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
var color = default(TPixel); var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero); color.FromScaledVector4(Vector4.Zero);
int offset = 0; int offset = 0;
byte[] buffer = new byte[4]; Span<byte> buffer = stackalloc byte[4];
for (int y = top; y < top + height; y++) for (int y = top; y < top + height; y++)
{ {
@ -38,18 +38,18 @@ internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float r = BitConverter.ToSingle(buffer, 0); float r = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float g = BitConverter.ToSingle(buffer, 0); float g = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float b = BitConverter.ToSingle(buffer, 0); float b = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
var colorVector = new Vector4(r, g, b, 1.0f); var colorVector = new Vector4(r, g, b, 1.0f);
@ -61,16 +61,13 @@ internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{ {
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); float r = BitConverter.ToSingle(data.Slice(offset, 4));
float r = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); float g = BitConverter.ToSingle(data.Slice(offset, 4));
float g = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); float b = BitConverter.ToSingle(data.Slice(offset, 4));
float b = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
var colorVector = new Vector4(r, g, b, 1.0f); var colorVector = new Vector4(r, g, b, 1.0f);

30
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs

@ -27,7 +27,7 @@ internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
var color = default(TPixel); var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero); color.FromScaledVector4(Vector4.Zero);
int offset = 0; int offset = 0;
byte[] buffer = new byte[4]; Span<byte> buffer = stackalloc byte[4];
for (int y = top; y < top + height; y++) for (int y = top; y < top + height; y++)
{ {
@ -38,23 +38,23 @@ internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float r = BitConverter.ToSingle(buffer, 0); float r = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float g = BitConverter.ToSingle(buffer, 0); float g = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float b = BitConverter.ToSingle(buffer, 0); float b = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float a = BitConverter.ToSingle(buffer, 0); float a = BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
var colorVector = new Vector4(r, g, b, a); var colorVector = new Vector4(r, g, b, a);
@ -66,20 +66,16 @@ internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{ {
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); float r = BitConverter.ToSingle(data.Slice(offset, 4));
float r = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); float g = BitConverter.ToSingle(data.Slice(offset, 4));
float g = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); float b = BitConverter.ToSingle(data.Slice(offset, 4));
float b = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
data.Slice(offset, 4).CopyTo(buffer); float a = BitConverter.ToSingle(data.Slice(offset, 4));
float a = BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
var colorVector = new Vector4(r, g, b, a); var colorVector = new Vector4(r, g, b, a);

12
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs

@ -17,21 +17,21 @@ internal class WhiteIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/> /// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{ {
nint offset = 0; nuint offset = 0;
var colorBlack = default(TPixel); var colorBlack = default(TPixel);
var colorWhite = default(TPixel); var colorWhite = default(TPixel);
colorBlack.FromRgba32(Color.Black); colorBlack.FromRgba32(Color.Black);
colorWhite.FromRgba32(Color.White); colorWhite.FromRgba32(Color.White);
ref byte dataRef = ref MemoryMarshal.GetReference(data); ref byte dataRef = ref MemoryMarshal.GetReference(data);
for (nint y = top; y < top + height; y++) for (nuint y = (uint)top; y < (uint)(top + height); y++)
{ {
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan((int)y); Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan((int)y);
ref TPixel pixelRowRef = ref MemoryMarshal.GetReference(pixelRowSpan); ref TPixel pixelRowRef = ref MemoryMarshal.GetReference(pixelRowSpan);
for (nint x = left; x < left + width; x += 8) for (nuint x = (uint)left; x < (uint)(left + width); x += 8)
{ {
byte b = Unsafe.Add(ref dataRef, offset++); byte b = Unsafe.Add(ref dataRef, offset++);
nint maxShift = Math.Min(left + width - x, 8); nuint maxShift = Math.Min((uint)(left + width) - x, 8);
if (maxShift == 8) if (maxShift == 8)
{ {
@ -69,9 +69,9 @@ internal class WhiteIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
} }
else else
{ {
for (int shift = 0; shift < maxShift; shift++) for (nuint shift = 0; shift < maxShift; shift++)
{ {
int bit = (b >> (7 - shift)) & 1; int bit = (b >> (7 - (int)shift)) & 1;
ref TPixel pixel = ref Unsafe.Add(ref pixelRowRef, x + shift); ref TPixel pixel = ref Unsafe.Add(ref pixelRowRef, x + shift);
pixel = bit == 0 ? colorWhite : colorBlack; pixel = bit == 0 ? colorWhite : colorBlack;

9
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs

@ -26,7 +26,7 @@ internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
{ {
var color = default(TPixel); var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero); color.FromScaledVector4(Vector4.Zero);
byte[] buffer = new byte[4]; Span<byte> buffer = stackalloc byte[4];
int offset = 0; int offset = 0;
for (int y = top; y < top + height; y++) for (int y = top; y < top + height; y++)
@ -37,8 +37,8 @@ internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer); buffer.Reverse();
float intensity = 1.0f - BitConverter.ToSingle(buffer, 0); float intensity = 1.0f - BitConverter.ToSingle(buffer);
offset += 4; offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
@ -50,8 +50,7 @@ internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
{ {
for (int x = 0; x < pixelRow.Length; x++) for (int x = 0; x < pixelRow.Length; x++)
{ {
data.Slice(offset, 4).CopyTo(buffer); float intensity = 1.0f - BitConverter.ToSingle(data.Slice(offset, 4));
float intensity = 1.0f - BitConverter.ToSingle(buffer, 0);
offset += 4; offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);

2
src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs

@ -344,7 +344,7 @@ internal class TiffDecoderCore : IImageDecoderInternals
ArgumentNullException.ThrowIfNull(valueWidth); ArgumentNullException.ThrowIfNull(valueWidth);
} }
if (!tags.TryGetValue(ExifTag.TileWidth, out IExifValue<Number> valueLength)) if (!tags.TryGetValue(ExifTag.TileLength, out IExifValue<Number> valueLength))
{ {
ArgumentNullException.ThrowIfNull(valueLength); ArgumentNullException.ThrowIfNull(valueLength);
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save