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**
* 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?**
@ -37,7 +36,6 @@
#### 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.
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.

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"
description: Create a report to help us improve the project. OSS Issues are not guaranteed to be triaged.
name: "Bug Report"
description: Create a report to help us improve the project. Issues are not guaranteed to be triaged.
labels: ["needs triage"]
body:
- type: checkboxes

1
ImageSharp.sln

@ -28,7 +28,6 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".github", ".github", "{1799
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ISSUE_TEMPLATE", "ISSUE_TEMPLATE", "{FBE8C1AD-5AEC-4514-9B64-091D8E145865}"
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\oss-bug-report.yml = .github\ISSUE_TEMPLATE\oss-bug-report.yml
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.
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
- [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)
- [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)]
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);
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>
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))
{
@ -199,12 +199,12 @@ public static class SRgbCompanding
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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;
var scale = new Vector4(Scale);
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))
{

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

@ -37,7 +37,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -70,7 +70,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -103,7 +103,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -136,7 +136,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -169,7 +169,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -266,7 +266,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -299,7 +299,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -332,7 +332,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -365,7 +365,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -398,7 +398,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLab dp = ref Unsafe.Add(ref destRef, i);
@ -431,7 +431,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -200,7 +200,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -233,7 +233,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -266,7 +266,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -299,7 +299,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -332,7 +332,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -365,7 +365,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -398,7 +398,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLch dp = ref Unsafe.Add(ref destRef, i);
@ -431,7 +431,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -399,7 +399,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLchuv dp = ref Unsafe.Add(ref destRef, i);
@ -431,7 +431,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -67,7 +67,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -134,7 +134,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -169,7 +169,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -233,7 +233,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -265,7 +265,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -297,7 +297,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -329,7 +329,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -361,7 +361,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -393,7 +393,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieLuv dp = ref Unsafe.Add(ref destRef, i);
@ -425,7 +425,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -163,7 +163,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -196,7 +196,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -229,7 +229,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -262,7 +262,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -295,7 +295,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -328,7 +328,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -361,7 +361,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyy dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -76,7 +76,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -111,7 +111,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -146,7 +146,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -177,7 +177,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +210,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -243,7 +243,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -277,7 +277,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -310,7 +310,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -345,7 +345,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -374,7 +374,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -407,7 +407,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 CieXyz dp = ref Unsafe.Add(ref destRef, i);
@ -440,7 +440,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Cmyk dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsl dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -69,7 +69,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -102,7 +102,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -135,7 +135,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -168,7 +168,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -201,7 +201,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -267,7 +267,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -300,7 +300,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -333,7 +333,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -366,7 +366,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -394,7 +394,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Hsv dp = ref Unsafe.Add(ref destRef, i);
@ -427,7 +427,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 HunterLab dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 LinearRgb dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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.
using System.Runtime.CompilerServices;
@ -24,7 +24,7 @@ public partial class ColorSpaceConverter
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Lms dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 Rgb dp = ref Unsafe.Add(ref destRef, i);
@ -276,7 +276,7 @@ public partial class ColorSpaceConverter
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
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 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 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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -45,7 +45,7 @@ public partial class ColorSpaceConverter
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -66,7 +66,7 @@ public partial class ColorSpaceConverter
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -87,7 +87,7 @@ public partial class ColorSpaceConverter
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -108,7 +108,7 @@ public partial class ColorSpaceConverter
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -129,7 +129,7 @@ public partial class ColorSpaceConverter
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +150,7 @@ public partial class ColorSpaceConverter
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -171,7 +171,7 @@ public partial class ColorSpaceConverter
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -192,7 +192,7 @@ public partial class ColorSpaceConverter
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -213,7 +213,7 @@ public partial class ColorSpaceConverter
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -234,7 +234,7 @@ public partial class ColorSpaceConverter
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
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 YCbCr dp = ref Unsafe.Add(ref destRef, i);
@ -255,7 +255,7 @@ public partial class ColorSpaceConverter
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
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 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.
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 fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) / 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;
const float inv116 = 1 / 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 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 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 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>
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));
}
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");
}
else
{
// Slightly better performance in the loop below, allows us to skip a bounds check
// while still supporting output buffers that are larger than necessary
bytes = bytes[..(chars.Length / 2)];
}
// Slightly better performance in the loop below, allows us to skip a bounds check
// while still supporting output buffers that are larger than necessary
bytes = bytes[..(chars.Length >> 1)]; // bit-hack for / 2
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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
};
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

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

@ -55,6 +55,12 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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>
/// Calculates <paramref name="x"/> % 8
/// </summary>
@ -291,7 +297,7 @@ internal static class Numerics
if (remainder.Length > 0)
{
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))
{
@ -316,7 +322,7 @@ internal static class Numerics
if (remainder.Length > 0)
{
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))
{
@ -341,7 +347,7 @@ internal static class Numerics
if (remainder.Length > 0)
{
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))
{
@ -366,7 +372,7 @@ internal static class Numerics
if (remainder.Length > 0)
{
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))
{
@ -391,7 +397,7 @@ internal static class Numerics
if (remainder.Length > 0)
{
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))
{
@ -430,9 +436,9 @@ internal static class Numerics
var vmin = new Vector<T>(min);
var vmax = new Vector<T>(max);
int n = span.Length / Vector<T>.Count;
int m = Modulo4(n);
int u = n - m;
nint n = (nint)(uint)span.Length / Vector<T>.Count;
nint m = Modulo4(n);
nint u = n - m;
ref Vector<T> vs0 = ref Unsafe.As<T, Vector<T>>(ref MemoryMarshal.GetReference(span));
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>
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))
{
@ -510,7 +516,7 @@ internal static class Numerics
else
{
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))
{
@ -556,7 +562,7 @@ internal static class Numerics
{
// 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> 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);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
@ -576,7 +582,7 @@ internal static class Numerics
else
{
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))
{
@ -650,7 +656,7 @@ internal static class Numerics
public static unsafe void CubePowOnXYZ(Span<Vector4> 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))
{
@ -681,7 +687,7 @@ internal static class Numerics
if (Sse41.IsSupported)
{
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);
Vector128<int> v128_negativeZero = Vector128.Create(-0.0f).AsInt32();
@ -730,7 +736,7 @@ internal static class Numerics
else
{
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
while (Unsafe.IsAddressLessThan(ref vectorsRef, ref vectorsEnd))
@ -943,4 +949,94 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOutOfRange(int value, int min, int max)
=> (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 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 + 2) = Unsafe.Add(ref sBase, p2 + 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 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);
@ -108,9 +108,9 @@ internal readonly struct WZYXShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
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);
@ -132,9 +132,9 @@ internal readonly struct YZWXShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
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);
@ -156,9 +156,9 @@ internal readonly struct ZYXWShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
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);
@ -187,9 +187,9 @@ internal readonly struct XWZYShuffle4 : IShuffle4
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
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);

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 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];
ref byte t = ref MemoryMarshal.GetReference(temp);
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);
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 + 2) = Unsafe.Add(ref t, p2);
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 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);
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 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 + 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 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 + 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 Byte3 dBase = ref Unsafe.As<byte, Byte3>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 4;
int m = Numerics.Modulo4(n);
int u = n - m;
nint n = (nint)(uint)source.Length / 4;
nint m = Numerics.Modulo4(n);
nint u = n - m;
ref uint sLoopEnd = ref Unsafe.Add(ref sBase, u);
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);
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<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);
@ -132,13 +132,13 @@ internal static partial class SimdUtils
{
VerifySpanInput(source, dest, Vector<byte>.Count);
int n = dest.Length / Vector<byte>.Count;
nuint n = dest.VectorCount<byte>();
ref Vector<float> sourceBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
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);

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

@ -71,7 +71,7 @@ internal static partial class SimdUtils
{
VerifySpanInput(source, dest, 4);
int count = dest.Length / 4;
uint count = (uint)dest.Length / 4;
if (count == 0)
{
return;
@ -83,7 +83,7 @@ internal static partial class SimdUtils
const float scale = 1f / 255f;
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);
d.X = s.X;
@ -105,7 +105,7 @@ internal static partial class SimdUtils
{
VerifySpanInput(source, dest, 4);
int count = source.Length / 4;
uint count = (uint)source.Length / 4;
if (count == 0)
{
return;
@ -117,7 +117,7 @@ internal static partial class SimdUtils
var half = new Vector4(0.5f);
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);
s *= maxBytes;

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

@ -4,6 +4,7 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.PixelFormats;
@ -13,33 +14,38 @@ internal static partial class SimdUtils
{
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 =>
new 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
};
#pragma warning disable SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines
[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);
public static ReadOnlySpan<byte> PermuteMaskShiftAlpha8x32 =>
new byte[]
{
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
};
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector256<uint> PermuteMaskShiftAlpha8x32() => Vector256.Create(
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();
#pragma warning restore SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines
/// <summary>
/// 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 sourceCount = source.Length - remainder;
int destCount = sourceCount * 4 / 3;
int destCount = (int)((uint)sourceCount * 4 / 3);
if (sourceCount > 0)
{
@ -189,10 +195,10 @@ internal static partial class SimdUtils
{
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 destCount = sourceCount * 3 / 4;
int destCount = (int)((uint)sourceCount * 3 / 4);
if (sourceCount > 0)
{
@ -221,11 +227,11 @@ internal static partial class SimdUtils
ref Vector256<float> destBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector256<float>.Count;
int m = Numerics.Modulo4(n);
int u = n - m;
nint n = (nint)dest.Vector256Count<float>();
nint m = Numerics.Modulo4(n);
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> vs0 = ref Unsafe.Add(ref sourceBase, i);
@ -238,7 +244,7 @@ internal static partial class SimdUtils
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);
}
@ -253,11 +259,11 @@ internal static partial class SimdUtils
ref Vector128<float> destBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector128<float>.Count;
int m = Numerics.Modulo4(n);
int u = n - m;
nint n = (nint)((uint)dest.Length / (uint)Vector128<float>.Count);
nint m = Numerics.Modulo4(n);
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> vs0 = ref Unsafe.Add(ref sourceBase, i);
@ -276,7 +282,7 @@ internal static partial class SimdUtils
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);
Unsafe.Add(ref destBase, i) = Sse.Shuffle(vs, vs, control);
@ -306,11 +312,11 @@ internal static partial class SimdUtils
ref Vector256<byte> destBase =
ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector256<byte>.Count;
int m = Numerics.Modulo4(n);
int u = n - m;
nint n = (nint)((uint)dest.Length / (uint)Vector256<byte>.Count);
nint m = Numerics.Modulo4(n);
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> vd0 = ref Unsafe.Add(ref destBase, i);
@ -323,7 +329,7 @@ internal static partial class SimdUtils
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);
}
@ -342,11 +348,11 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
int n = dest.Length / Vector128<byte>.Count;
int m = Numerics.Modulo4(n);
int u = n - m;
nint n = (nint)((uint)dest.Length / (uint)Vector128<byte>.Count);
nint m = Numerics.Modulo4(n);
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> vd0 = ref Unsafe.Add(ref destBase, i);
@ -359,7 +365,7 @@ internal static partial class SimdUtils
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);
}
@ -375,10 +381,8 @@ internal static partial class SimdUtils
{
if (Ssse3.IsSupported)
{
ref byte vmaskBase = ref MemoryMarshal.GetReference(ShuffleMaskPad4Nx16);
Vector128<byte> vmask = Unsafe.As<byte, Vector128<byte>>(ref vmaskBase);
ref byte vmaskoBase = ref MemoryMarshal.GetReference(ShuffleMaskSlice4Nx16);
Vector128<byte> vmasko = Unsafe.As<byte, Vector128<byte>>(ref vmaskoBase);
Vector128<byte> vmask = ShuffleMaskPad4Nx16();
Vector128<byte> vmasko = ShuffleMaskSlice4Nx16();
Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12);
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
@ -391,9 +395,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase =
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);
@ -440,8 +444,7 @@ internal static partial class SimdUtils
{
if (Ssse3.IsSupported)
{
ref byte vmaskBase = ref MemoryMarshal.GetReference(ShuffleMaskPad4Nx16);
Vector128<byte> vmask = Unsafe.As<byte, Vector128<byte>>(ref vmaskBase);
Vector128<byte> vmask = ShuffleMaskPad4Nx16();
Vector128<byte> vfill = Vector128.Create(0xff000000ff000000ul).AsByte();
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
@ -454,9 +457,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase =
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);
Vector128<byte> v1 = Unsafe.Add(ref v0, 1);
@ -484,8 +487,7 @@ internal static partial class SimdUtils
{
if (Ssse3.IsSupported)
{
ref byte vmaskoBase = ref MemoryMarshal.GetReference(ShuffleMaskSlice4Nx16);
Vector128<byte> vmasko = Unsafe.As<byte, Vector128<byte>>(ref vmaskoBase);
Vector128<byte> vmasko = ShuffleMaskSlice4Nx16();
Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12);
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
@ -498,9 +500,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase =
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);
@ -542,9 +544,9 @@ internal static partial class SimdUtils
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.AlwaysInline)]
public static Vector256<float> MultiplyAdd(
in Vector256<float> va,
in Vector256<float> vm0,
in Vector256<float> vm1)
Vector256<float> va,
Vector256<float> vm0,
Vector256<float> vm1)
{
if (Fma.IsSupported)
{
@ -554,6 +556,34 @@ internal static partial class SimdUtils
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>
/// 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.
@ -565,9 +595,9 @@ internal static partial class SimdUtils
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector256<float> MultiplySubtract(
in Vector256<float> vs,
in Vector256<float> vm0,
in Vector256<float> vm1)
Vector256<float> vs,
Vector256<float> vm0,
Vector256<float> vm1)
{
if (Fma.IsSupported)
{
@ -587,9 +617,9 @@ internal static partial class SimdUtils
/// <returns>The <see cref="Vector256{T}"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Vector256<float> MultiplyAddNegated(
in Vector256<float> a,
in Vector256<float> b,
in Vector256<float> c)
Vector256<float> a,
Vector256<float> b,
Vector256<float> c)
{
if (Fma.IsSupported)
{
@ -650,16 +680,16 @@ internal static partial class SimdUtils
{
VerifySpanInput(source, dest, Vector256<byte>.Count);
int n = dest.Length / Vector256<byte>.Count;
nuint n = dest.Vector256Count<byte>();
ref Vector256<float> destBase =
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> i1 = Avx2.ConvertToVector256Int32(sourceBase + si + Vector256<int>.Count);
Vector256<int> i2 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256<int>.Count * 2));
@ -683,17 +713,17 @@ internal static partial class SimdUtils
// Sse
VerifySpanInput(source, dest, Vector128<byte>.Count);
int n = dest.Length / Vector128<byte>.Count;
nuint n = dest.Vector128Count<byte>();
ref Vector128<float> destBase =
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;
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;
if (Sse41.IsSupported)
@ -782,7 +812,7 @@ internal static partial class SimdUtils
{
VerifySpanInput(source, dest, Vector256<byte>.Count);
int n = dest.Length / Vector256<byte>.Count;
nuint n = dest.Vector256Count<byte>();
ref Vector256<float> sourceBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source));
@ -790,11 +820,10 @@ internal static partial class SimdUtils
ref Vector256<byte> destBase =
ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(dest));
var scale = Vector256.Create((float)byte.MaxValue);
ref byte maskBase = ref MemoryMarshal.GetReference(PermuteMaskDeinterleave8x32);
Vector256<int> mask = Unsafe.As<byte, Vector256<int>>(ref maskBase);
Vector256<float> scale = Vector256.Create((float)byte.MaxValue);
Vector256<int> mask = PermuteMaskDeinterleave8x32();
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);
@ -821,7 +850,7 @@ internal static partial class SimdUtils
// Sse
VerifySpanInput(source, dest, Vector128<byte>.Count);
int n = dest.Length / Vector128<byte>.Count;
nuint n = dest.Vector128Count<byte>();
ref Vector128<float> sourceBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(source));
@ -829,9 +858,9 @@ internal static partial class SimdUtils
ref Vector128<byte> destBase =
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);
@ -864,18 +893,16 @@ internal static partial class SimdUtils
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));
int count = redChannel.Length / Vector256<byte>.Count;
nuint count = redChannel.Vector256Count<byte>();
ref byte control1Bytes = ref MemoryMarshal.GetReference(PermuteMaskEvenOdd8x32);
Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes);
Vector256<uint> control1 = PermuteMaskEvenOdd8x32();
ref byte control2Bytes = ref MemoryMarshal.GetReference(PermuteMaskShiftAlpha8x32);
Vector256<uint> control2 = Unsafe.As<byte, Vector256<uint>>(ref control2Bytes);
var a = Vector256.Create((byte)255);
Vector256<uint> control2 = PermuteMaskShiftAlpha8x32();
Vector256<byte> 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> g0 = Unsafe.Add(ref gBase, i);
@ -918,7 +945,7 @@ internal static partial class SimdUtils
Unsafe.As<byte, Vector256<byte>>(ref d4) = rgb4;
}
int slice = count * Vector256<byte>.Count;
int slice = (int)count * Vector256<byte>.Count;
redChannel = redChannel[slice..];
greenChannel = greenChannel[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> dBase = ref Unsafe.As<Rgba32, Vector256<byte>>(ref MemoryMarshal.GetReference(destination));
int count = redChannel.Length / Vector256<byte>.Count;
ref byte control1Bytes = ref MemoryMarshal.GetReference(PermuteMaskEvenOdd8x32);
Vector256<uint> control1 = Unsafe.As<byte, Vector256<uint>>(ref control1Bytes);
var a = Vector256.Create((byte)255);
nuint count = redChannel.Vector256Count<byte>();
Vector256<uint> control1 = PermuteMaskEvenOdd8x32();
Vector256<byte> 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> g0 = Unsafe.Add(ref gBase, i);
@ -970,7 +996,7 @@ internal static partial class SimdUtils
Unsafe.Add(ref d0, 3) = rgb4;
}
int slice = count * Vector256<byte>.Count;
int slice = (int)count * Vector256<byte>.Count;
redChannel = redChannel[slice..];
greenChannel = greenChannel[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> destBRef = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(blueChannel));
Vector256<uint> extractToLanesMask = Unsafe.As<byte, Vector256<uint>>(ref MemoryMarshal.GetReference(MoveFirst24BytesToSeparateLanes));
Vector256<byte> extractRgbMask = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(ExtractRgb));
Vector256<uint> extractToLanesMask = MoveFirst24BytesToSeparateLanes();
Vector256<byte> extractRgbMask = ExtractRgb();
Vector256<byte> rgb, rg, bx;
Vector256<float> r, g, b;
const int bytesPerRgbStride = 24;
int count = (int)((uint)source.Length / 8);
for (int i = 0; i < count; i++)
nuint count = (uint)source.Length / 8;
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);
@ -1013,7 +1039,7 @@ internal static partial class SimdUtils
Unsafe.Add(ref destBRef, i) = b;
}
int sliceCount = count * 8;
int sliceCount = (int)(count * 8);
redChannel = redChannel.Slice(sliceCount);
greenChannel = greenChannel.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 Rgb24 rgb = ref MemoryMarshal.GetReference(destination);
int count = redChannel.Length / 4;
for (int i = 0; i < count; i++)
nuint count = (uint)redChannel.Length / 4;
for (nuint i = 0; i < count; i++)
{
ref Rgb24 d0 = ref Unsafe.Add(ref rgb, i * 4);
ref Rgb24 d1 = ref Unsafe.Add(ref d0, 1);
@ -115,7 +115,7 @@ internal static partial class SimdUtils
d3.B = bb.V3;
}
int finished = count * 4;
int finished = (int)(count * 4);
redChannel = redChannel[finished..];
greenChannel = greenChannel[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 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));
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 d1 = ref Unsafe.Add(ref d0, 1);
@ -163,7 +163,7 @@ internal static partial class SimdUtils
d3.B = bb.V3;
}
int finished = count * 4;
int finished = (int)(count * 4);
redChannel = redChannel[finished..];
greenChannel = greenChannel[finished..];
blueChannel = blueChannel[finished..];
@ -181,7 +181,7 @@ internal static partial class SimdUtils
ref byte b = ref MemoryMarshal.GetReference(blueChannel);
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);
d.R = Unsafe.Add(ref r, i);
@ -201,7 +201,7 @@ internal static partial class SimdUtils
ref byte b = ref MemoryMarshal.GetReference(blueChannel);
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);
d.R = Unsafe.Add(ref r, i);
@ -226,7 +226,7 @@ internal static partial class SimdUtils
ref float b = ref MemoryMarshal.GetReference(blueChannel);
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);
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 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 + 2) = Unsafe.Add(ref sBase, p2 + i);
Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i);
@ -492,16 +492,16 @@ internal static partial class SimdUtils
{
InverseMMShuffle(
control,
out int p3,
out int p2,
out int p1,
out int p0);
out uint p3,
out uint p2,
out uint p1,
out uint p0);
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 + 2) = (byte)(p2 + i);
Unsafe.Add(ref spanBase, i + 3) = (byte)(p3 + i);
@ -511,15 +511,15 @@ internal static partial class SimdUtils
[MethodImpl(InliningOptions.ShortMethod)]
public static void InverseMMShuffle(
byte control,
out int p3,
out int p2,
out int p1,
out int p0)
out uint p3,
out uint p2,
out uint p1,
out uint p0)
{
p3 = (control >> 6) & 0x3;
p2 = (control >> 4) & 0x3;
p1 = (control >> 2) & 0x3;
p0 = (control >> 0) & 0x3;
p3 = (uint)((control >> 6) & 0x3);
p2 = (uint)((control >> 4) & 0x3);
p1 = (uint)((control >> 2) & 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++)
{
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;

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

@ -3,6 +3,7 @@
using System.Buffers;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Compression.Zlib;
@ -426,8 +427,8 @@ internal sealed unsafe class DeflaterEngine : IDisposable
private void SlideWindow()
{
Unsafe.CopyBlockUnaligned(
ref this.window.Span[0],
ref this.window.Span[DeflaterConstants.WSIZE],
ref MemoryMarshal.GetReference(this.window.Span),
ref Unsafe.Add(ref MemoryMarshal.GetReference(this.window.Span), DeflaterConstants.WSIZE),
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);
this.literalTree.WriteSymbol(pendingBuffer, lc);
int bits = (lc - 261) / 4;
if (bits > 0 && bits <= 5)
int bits = (int)(((uint)lc - 261) / 4);
if (bits is > 0 and <= 5)
{
this.Pending.WriteBits(litlen & ((1 << bits) - 1), bits);
}
@ -286,13 +286,13 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int static_len = this.extraBits;
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);
}
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);
}
@ -364,7 +364,7 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
this.literalTree.Frequencies[lc]++;
if (lc >= 265 && lc < 285)
{
this.extraBits += (lc - 261) / 4;
this.extraBits += (int)(((uint)lc - 261) / 4);
}
int dc = Dcode(distance - 1);
@ -405,10 +405,10 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
ref byte bit4ReverseRef = ref MemoryMarshal.GetReference(Bit4Reverse);
return (short)(Unsafe.Add(ref bit4ReverseRef, toReverse & 0xF) << 12
| Unsafe.Add(ref bit4ReverseRef, (toReverse >> 4) & 0xF) << 8
| Unsafe.Add(ref bit4ReverseRef, (toReverse >> 8) & 0xF) << 4
| Unsafe.Add(ref bit4ReverseRef, toReverseRightShiftBy12));
return (short)((Unsafe.Add(ref bit4ReverseRef, (uint)toReverse & 0xF) << 12)
| (Unsafe.Add(ref bit4ReverseRef, (uint)(toReverse >> 4) & 0xF) << 8)
| (Unsafe.Add(ref bit4ReverseRef, (uint)(toReverse >> 8) & 0xF) << 4)
| Unsafe.Add(ref bit4ReverseRef, (uint)toReverseRightShiftBy12));
}
/// <inheritdoc/>
@ -551,8 +551,8 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int code = 0;
for (int bits = 0; bits < this.maxLength; bits++)
{
Unsafe.Add(ref nextCodeRef, bits) = code;
code += Unsafe.Add(ref bitLengthCountsRef, bits) << (15 - bits);
Unsafe.Add(ref nextCodeRef, (uint)bits) = code;
code += Unsafe.Add(ref bitLengthCountsRef, (uint)bits) << (15 - bits);
}
for (int i = 0; i < this.NumCodes; i++)
@ -560,8 +560,8 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int bits = this.Length[i];
if (bits > 0)
{
this.codes[i] = BitReverse(Unsafe.Add(ref nextCodeRef, bits - 1));
Unsafe.Add(ref nextCodeRef, bits - 1) += 1 << (16 - bits);
this.codes[i] = BitReverse(Unsafe.Add(ref nextCodeRef, (uint)(bits - 1)));
Unsafe.Add(ref nextCodeRef, (uint)(bits - 1)) += 1 << (16 - bits);
}
}
}
@ -593,13 +593,13 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
// Insert n into heap
int pos = heapLen++;
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;
}
Unsafe.Add(ref heapRef, pos) = n;
Unsafe.Add(ref heapRef, (uint)pos) = n;
maxCode = n;
}
@ -611,7 +611,7 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
// this case, both literals get a 1 bit code.
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);
@ -625,14 +625,14 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
ref int valuesRef = ref MemoryMarshal.GetReference(valuesMemoryOwner.Memory.Span);
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 i2 = 2 * i;
nuint i2 = 2 * i;
Unsafe.Add(ref childrenRef, i2) = node;
Unsafe.Add(ref childrenRef, i2 + 1) = -1;
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
@ -640,7 +640,7 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
do
{
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
int ppos = 0;
@ -648,35 +648,35 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
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++;
}
Unsafe.Add(ref heapRef, ppos) = Unsafe.Add(ref heapRef, path);
Unsafe.Add(ref heapRef, (uint)ppos) = Unsafe.Add(ref heapRef, (uint)path);
ppos = path;
path = (path * 2) + 1;
}
// Now propagate the last element down along path. Normally
// 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
&& 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);
// Create a new node father of first and second
last = numNodes++;
Unsafe.Add(ref childrenRef, 2 * last) = first;
Unsafe.Add(ref childrenRef, (2 * last) + 1) = second;
int mindepth = Math.Min(Unsafe.Add(ref valuesRef, first) & 0xFF, Unsafe.Add(ref valuesRef, second) & 0xFF);
Unsafe.Add(ref valuesRef, last) = lastVal = Unsafe.Add(ref valuesRef, first) + Unsafe.Add(ref valuesRef, second) - mindepth + 1;
Unsafe.Add(ref childrenRef, (uint)(2 * last)) = first;
Unsafe.Add(ref childrenRef, (uint)((2 * last) + 1)) = second;
int mindepth = Math.Min(Unsafe.Add(ref valuesRef, (uint)first) & 0xFF, Unsafe.Add(ref valuesRef, (uint)second) & 0xFF);
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
ppos = 0;
@ -685,23 +685,23 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
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)))
&& Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)path)) > Unsafe.Add(ref valuesRef, (uint)Unsafe.Add(ref heapRef, (uint)(path + 1))))
{
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;
path = (ppos * 2) + 1;
}
// 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);
@ -886,21 +886,21 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
{
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)
{
bitLength = maxLen;
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
{
// A leaf node
int bitLength = Unsafe.Add(ref lengthsRef, i);
Unsafe.Add(ref bitLengthCountsRef, bitLength - 1)++;
lengthPtr[Unsafe.Add(ref childrenRef, 2 * i)] = (byte)Unsafe.Add(ref lengthsRef, i);
int bitLength = Unsafe.Add(ref lengthsRef, (uint)i);
Unsafe.Add(ref bitLengthCountsRef, (uint)(bitLength - 1))++;
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
{
// 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.
do
{
Unsafe.Add(ref bitLengthCountsRef, incrBitLen)--;
Unsafe.Add(ref bitLengthCountsRef, ++incrBitLen)++;
Unsafe.Add(ref bitLengthCountsRef, (uint)incrBitLen)--;
Unsafe.Add(ref bitLengthCountsRef, (uint)++incrBitLen)++;
overflow -= 1 << (maxLen - 1 - incrBitLen);
}
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
// maxLength-1 in that case.
Unsafe.Add(ref bitLengthCountsRef, maxLen - 1) += overflow;
Unsafe.Add(ref bitLengthCountsRef, maxLen - 2) -= overflow;
Unsafe.Add(ref bitLengthCountsRef, (uint)(maxLen - 1)) += overflow;
Unsafe.Add(ref bitLengthCountsRef, (uint)(maxLen - 2)) -= overflow;
// Now recompute all bit lengths, scanning in increasing
// frequency. It is simpler to reconstruct all lengths instead of
@ -945,14 +945,14 @@ internal sealed unsafe class DeflaterHuffman : IDisposable
int nodeIndex = 2 * numLeafs;
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)
{
int childIndex = 2 * Unsafe.Add(ref childrenRef, nodeIndex++);
if (Unsafe.Add(ref childrenRef, childIndex + 1) == -1)
int childIndex = 2 * Unsafe.Add(ref childrenRef, (uint)nodeIndex++);
if (Unsafe.Add(ref childrenRef, (uint)(childIndex + 1)) == -1)
{
// We found another leaf
lengthPtr[Unsafe.Add(ref childrenRef, childIndex)] = (byte)bits;
lengthPtr[Unsafe.Add(ref childrenRef, (uint)childIndex)] = (byte)bits;
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>
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];
int count = 0;
@ -489,11 +490,11 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// If the second byte > 2, we are in 'absolute mode'.
// The second byte contains the number of color indexes that follow.
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;
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>
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];
int count = 0;
@ -596,13 +598,13 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// Take this number of bytes from the stream as uncompressed data.
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.
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>
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];
int uncompressedPixels = 0;
@ -675,17 +678,18 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// If the second byte > 2, we are in 'absolute mode'.
// Take this number of bytes from the stream as uncompressed data.
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;
// Absolute mode data is aligned to two-byte word-boundary.
int padding = run.Length & 1;
int padding = length3 & 1;
stream.Skip(padding);
@ -1286,18 +1290,18 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// color masks for each color channel follow the info header.
if (this.infoHeader.Compression == BmpCompression.BitFields)
{
byte[] bitfieldsBuffer = new byte[12];
stream.Read(bitfieldsBuffer, 0, 12);
Span<byte> data = bitfieldsBuffer.AsSpan();
Span<byte> bitfieldsBuffer = stackalloc byte[12];
stream.Read(bitfieldsBuffer);
Span<byte> data = bitfieldsBuffer;
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4));
this.infoHeader.BlueMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4));
}
else if (this.infoHeader.Compression == BmpCompression.BI_ALPHABITFIELDS)
{
byte[] bitfieldsBuffer = new byte[16];
stream.Read(bitfieldsBuffer, 0, 16);
Span<byte> data = bitfieldsBuffer.AsSpan();
Span<byte> bitfieldsBuffer = stackalloc byte[16];
stream.Read(bitfieldsBuffer);
Span<byte> data = bitfieldsBuffer;
this.infoHeader.RedMask = BinaryPrimitives.ReadInt32LittleEndian(data[..4]);
this.infoHeader.GreenMask = BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 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));
}
short bitsPerPixel = this.infoHeader.BitsPerPixel;
ushort bitsPerPixel = this.infoHeader.BitsPerPixel;
this.bmpMetadata = this.metadata.GetBmpMetadata();
this.bmpMetadata.InfoHeaderType = infoHeaderType;
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.
// 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(
$"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();
this.bitsPerPixel ??= bmpMetadata.BitsPerPixel;
short bpp = (short)this.bitsPerPixel;
int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32);
ushort bpp = (ushort)this.bitsPerPixel;
int bytesPerLine = (int)(4 * ((((uint)image.Width * bpp) + 31) / 32));
this.padding = bytesPerLine - (int)(image.Width * (bpp / 8F));
int colorPaletteSize = this.bitsPerPixel switch
@ -176,7 +176,7 @@ internal sealed class BmpEncoderCore : IImageEncoderInternals
/// <param name="metadata">The metadata.</param>
/// <param name="iccProfileData">The icc profile data.</param>
/// <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 vResolution = 0;

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

@ -70,7 +70,7 @@ internal struct BmpInfoHeader
int width,
int height,
short planes,
short bitsPerPixel,
ushort bitsPerPixel,
BmpCompression compression = default,
int imageSize = 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.
/// Typical values are 1, 4, 8, 16, 24 and 32.
/// </summary>
public short BitsPerPixel { get; set; }
public ushort BitsPerPixel { get; set; }
/// <summary>
/// Gets or sets the compression method being used.
@ -311,7 +311,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(4, 2)),
height: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(6, 2)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(8, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(10, 2)));
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(10, 2)));
/// <summary>
/// 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)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
planes: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(12, 2)),
bitsPerPixel: BinaryPrimitives.ReadInt16LittleEndian(data.Slice(14, 2)));
bitsPerPixel: BinaryPrimitives.ReadUInt16LittleEndian(data.Slice(14, 2)));
/// <summary>
/// Parses the full BMP Version 3 BITMAPINFOHEADER header (40 bytes).
@ -338,7 +338,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
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)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -359,7 +359,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
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)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 4)),
xPelsPerMeter: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(24, 4)),
@ -386,7 +386,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
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.
// Map the OS/2 value to the windows values.
@ -431,7 +431,7 @@ internal struct BmpInfoHeader
width: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(4, 4)),
height: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(8, 4)),
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)),
imageSize: BinaryPrimitives.ReadInt32LittleEndian(data.Slice(20, 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(8, 4), this.Height);
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(20, 4), this.ImageSize);
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(8, 4), this.Height);
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(20, 4), this.ImageSize);
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>
/// The temp buffer used to reduce allocations.
/// </summary>
private readonly byte[] buffer = new byte[16];
private ScratchBuffer buffer; // mutable struct, don't make readonly
/// <summary>
/// The global color table.
@ -249,13 +249,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
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)
{
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>
@ -264,13 +264,13 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
/// <param name="stream">The <see cref="BufferedReadStream"/> containing image data.</param>
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)
{
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)
{
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>
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)
{
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>
@ -306,8 +306,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
long position = stream.Position;
if (appLength == GifConstants.ApplicationBlockSize)
{
stream.Read(this.buffer, 0, GifConstants.ApplicationBlockSize);
bool isXmp = this.buffer.AsSpan().StartsWith(GifConstants.XmpApplicationIdentificationBytes);
stream.Read(this.buffer.Span, 0, GifConstants.ApplicationBlockSize);
bool isXmp = this.buffer.Span.StartsWith(GifConstants.XmpApplicationIdentificationBytes);
if (isXmp && !this.skipMetadata)
{
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
if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize)
{
stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize);
this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount;
stream.Read(this.buffer.Span, 0, GifConstants.NetscapeLoopingSubBlockSize);
this.gifMetadata!.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.Span.Slice(1)).RepeatCount;
stream.Skip(1); // Skip the terminator.
return;
}
@ -578,8 +578,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
// #403 The left + width value can be larger than the image width
for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
{
int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, x - descriptorLeft), 0, colorTableMaxIdx);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x);
Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb);
}
@ -588,7 +588,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
{
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.
if (rawIndex > colorTableMaxIdx || rawIndex == transIndex)
@ -597,7 +597,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
}
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];
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>
private readonly Configuration configuration;
/// <summary>
/// A reusable buffer used to reduce allocations.
/// </summary>
private readonly byte[] buffer = new byte[20];
/// <summary>
/// Whether to skip metadata during encode.
/// </summary>
@ -254,7 +249,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
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;
}
@ -324,9 +319,10 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
backgroundColorIndex: unchecked((byte)transparencyIndex),
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>
@ -365,12 +361,14 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
return;
}
Span<byte> buffer = stackalloc byte[2];
for (int i = 0; i < metadata.Comments.Count; i++)
{
string comment = metadata.Comments[i];
this.buffer[0] = GifConstants.ExtensionIntroducer;
this.buffer[1] = GifConstants.CommentLabel;
stream.Write(this.buffer, 0, 2);
buffer[1] = GifConstants.CommentLabel;
buffer[0] = GifConstants.ExtensionIntroducer;
stream.Write(buffer);
// Comment will be stored in chunks of 255 bytes, if it exceeds this size.
ReadOnlySpan<char> commentSpan = comment.AsSpan();
@ -437,22 +435,23 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
private void WriteExtension<TGifExtension>(TGifExtension extension, Stream stream)
where TGifExtension : struct, IGifExtension
{
IMemoryOwner<byte>? owner = null;
Span<byte> extensionBuffer;
int extensionSize = extension.ContentLength;
if (extensionSize == 0)
{
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);
extensionBuffer = owner.GetSpan();
}
else
{
extensionBuffer = this.buffer;
extensionBuffer = stackalloc byte[extensionSize + 3];
}
extensionBuffer[0] = GifConstants.ExtensionIntroducer;
@ -489,9 +488,10 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
height: (ushort)image.Height,
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>

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

@ -115,7 +115,7 @@ internal sealed class LzwDecoder : IDisposable
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];
@ -182,7 +182,7 @@ internal sealed class LzwDecoder : IDisposable
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;
first = code;
continue;
@ -191,27 +191,27 @@ internal sealed class LzwDecoder : IDisposable
int inCode = code;
if (code == availableCode)
{
Unsafe.Add(ref pixelStackRef, top++) = (byte)first;
Unsafe.Add(ref pixelStackRef, (uint)top++) = (byte)first;
code = oldCode;
}
while (code > clearCode)
{
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code);
code = Unsafe.Add(ref prefixRef, code);
Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)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;
Unsafe.Add(ref pixelStackRef, top++) = suffixCode;
Unsafe.Add(ref pixelStackRef, (uint)top++) = suffixCode;
// Fix for Gifs that have "deferred clear code" as per here :
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
if (availableCode < MaxStackSize)
{
Unsafe.Add(ref prefixRef, availableCode) = oldCode;
Unsafe.Add(ref suffixRef, availableCode) = first;
Unsafe.Add(ref prefixRef, (uint)availableCode) = oldCode;
Unsafe.Add(ref suffixRef, (uint)availableCode) = first;
availableCode++;
if (availableCode == codeMask + 1 && availableCode < MaxStackSize)
{
@ -228,7 +228,7 @@ internal sealed class LzwDecoder : IDisposable
// Clear missing pixels
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++)
{
Unsafe.Add(ref suffixRef, code) = (byte)code;
Unsafe.Add(ref suffixRef, (uint)code) = (byte)code;
}
Span<byte> buffer = stackalloc byte[byte.MaxValue];
@ -336,7 +336,7 @@ internal sealed class LzwDecoder : IDisposable
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;
first = code;
continue;
@ -345,27 +345,27 @@ internal sealed class LzwDecoder : IDisposable
int inCode = code;
if (code == availableCode)
{
Unsafe.Add(ref pixelStackRef, top++) = (byte)first;
Unsafe.Add(ref pixelStackRef, (uint)top++) = (byte)first;
code = oldCode;
}
while (code > clearCode)
{
Unsafe.Add(ref pixelStackRef, top++) = Unsafe.Add(ref suffixRef, code);
code = Unsafe.Add(ref prefixRef, code);
Unsafe.Add(ref pixelStackRef, (uint)top++) = Unsafe.Add(ref suffixRef, (uint)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;
Unsafe.Add(ref pixelStackRef, top++) = suffixCode;
Unsafe.Add(ref pixelStackRef, (uint)top++) = suffixCode;
// Fix for Gifs that have "deferred clear code" as per here :
// https://bugzilla.mozilla.org/show_bug.cgi?id=55918
if (availableCode < MaxStackSize)
{
Unsafe.Add(ref prefixRef, availableCode) = oldCode;
Unsafe.Add(ref suffixRef, availableCode) = first;
Unsafe.Add(ref prefixRef, (uint)availableCode) = oldCode;
Unsafe.Add(ref suffixRef, (uint)availableCode) = first;
availableCode++;
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)]
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)
{
this.FlushPacket(stream);
@ -278,18 +278,18 @@ internal sealed class LzwEncoder : IDisposable
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 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;
}
// Non-empty slot
if (Unsafe.Add(ref hashTableRef, hashIndex) >= 0)
if (Unsafe.Add(ref hashTableRef, (uint)hashIndex) >= 0)
{
int disp = 1;
if (hashIndex != 0)
@ -304,15 +304,15 @@ internal sealed class LzwEncoder : IDisposable
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;
}
}
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;
}
@ -322,8 +322,8 @@ internal sealed class LzwEncoder : IDisposable
entry = code;
if (this.freeEntry < MaxMaxCode)
{
Unsafe.Add(ref codeTableRef, hashIndex) = this.freeEntry++; // code -> hashtable
Unsafe.Add(ref hashTableRef, hashIndex) = freeCode;
Unsafe.Add(ref codeTableRef, (uint)hashIndex) = this.freeEntry++; // code -> hashtable
Unsafe.Add(ref hashTableRef, (uint)hashIndex) = freeCode;
}
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) =>
source.Save(
path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance));
encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance));
/// <summary>
/// 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)
=> source.SaveAsync(
path,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance),
encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance),
cancellationToken);
/// <summary>
@ -124,7 +124,7 @@ public static partial class ImageExtensions
public static void SaveAs<#= fmt #>(this Image source, Stream stream, <#= fmt #>Encoder encoder)
=> source.Save(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance));
encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance));
/// <summary>
/// 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)
=> source.SaveAsync(
stream,
encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(<#= fmt #>Format.Instance),
encoder ?? source.GetConfiguration().ImageFormatsManager.GetEncoder(<#= fmt #>Format.Instance),
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.
/// </summary>
// ReSharper disable once InconsistentNaming
[StructLayout(LayoutKind.Explicit)]
internal unsafe partial struct Block8x8
[StructLayout(LayoutKind.Explicit, Size = 2 * Size)]
internal partial struct Block8x8
{
/// <summary>
/// A number of scalar coefficients in a <see cref="Block8x8F"/>
/// </summary>
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>
/// Gets or sets a <see cref="short"/> value at the given index
/// </summary>
@ -47,7 +36,7 @@ internal unsafe partial struct Block8x8
DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx));
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)]
@ -56,7 +45,7 @@ internal unsafe partial struct Block8x8
DebugGuard.MustBeBetweenOrEqualTo(idx, 0, Size - 1, nameof(idx));
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)
{
Unsafe.SkipInit(out Block8x8 result);
result.LoadFrom(data);
return result;
DebugGuard.MustBeGreaterThanOrEqualTo(data.Length, Size, "data is too small");
ref byte src = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(data));
return Unsafe.ReadUnaligned<Block8x8>(ref src);
}
/// <summary>
@ -104,9 +94,10 @@ internal unsafe partial struct Block8x8
/// </summary>
public void CopyTo(Span<short> destination)
{
ref byte selfRef = ref Unsafe.As<Block8x8, byte>(ref this);
ref byte destRef = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<short, byte>(destination));
Unsafe.CopyBlockUnaligned(ref destRef, ref selfRef, Size * sizeof(short));
DebugGuard.MustBeGreaterThanOrEqualTo(destination.Length, Size, "destination is too small");
ref byte destRef = ref Unsafe.As<short, byte>(ref MemoryMarshal.GetReference(destination));
Unsafe.WriteUnaligned(ref destRef, this);
}
/// <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>
/// Cast and copy <see cref="Size"/> <see cref="int"/>-s from the beginning of 'source' span.
/// </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
// 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
// to get the exact number of zero elements in the stride
int strideRelativeIndex = 15 - (lzcnt / 2);
return (i * 16) + strideRelativeIndex;
uint strideRelativeIndex = 15 - (lzcnt / 2);
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 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.V0R = Numerics.Clamp(this.V0R + COff4, CMin4, CMax4);
@ -42,33 +42,33 @@ internal partial struct Block8x8F
[MethodImpl(InliningOptions.ShortMethod)]
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);
ref Vector<float> row0 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V0L);
row0 = NormalizeAndRound(row0, off, max);
ref Vector<float> row1 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V1L);
row1 = NormalizeAndRound(row1, off, max);
ref Vector<float> row2 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V2L);
row2 = NormalizeAndRound(row2, off, max);
ref Vector<float> row3 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V3L);
row3 = NormalizeAndRound(row3, off, max);
ref Vector<float> row4 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V4L);
row4 = NormalizeAndRound(row4, off, max);
ref Vector<float> row5 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V5L);
row5 = NormalizeAndRound(row5, off, max);
ref Vector<float> row6 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V6L);
row6 = NormalizeAndRound(row6, off, max);
ref Vector<float> row7 = ref Unsafe.As<Vector4, Vector<float>>(ref this.V7L);
row7 = NormalizeAndRound(row7, off, max);
}
/// <summary>

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

@ -29,7 +29,7 @@ internal partial struct Block8x8F
{
var CMin4 = new Vector4(0F);
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)]
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);
<#

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<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> 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);
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);
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> right = Sse2.ConvertToVector128Int32(Sse.Multiply(Unsafe.Add(ref aBase, i + 1), Unsafe.Add(ref bBase, i + 1)));
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!
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)
{
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, 1, destStride);
@ -48,12 +48,12 @@ internal partial struct Block8x8F
WidenCopyRowImpl2x2(ref this.V0L, ref destBase, 7, destStride);
[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 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 dBottomLeft = ref Unsafe.As<Vector2, Vector4>(ref Unsafe.Add(ref destBase, offset + destStride));
@ -86,23 +86,23 @@ internal partial struct Block8x8F
}
[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;
int y8 = y * 8;
nuint yy = y * verticalScale;
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];
nint baseIdx = (yy * areaStride) + xx;
float value = this[(int)(y8 + x)];
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;
Unsafe.Add(ref areaOrigin, baseIdx + j) = value;
@ -128,8 +128,8 @@ internal partial struct Block8x8F
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void CopyRowImpl(ref byte origin, ref byte dest, int destStride, int row)
{
origin = ref Unsafe.Add(ref origin, row * 8 * sizeof(float));
dest = ref Unsafe.Add(ref dest, row * destStride);
origin = ref Unsafe.Add(ref origin, (uint)row * 8 * sizeof(float));
dest = ref Unsafe.Add(ref dest, (uint)(row * destStride));
Unsafe.CopyBlock(ref dest, ref origin, 8 * sizeof(float));
}
}
@ -150,8 +150,8 @@ internal partial struct Block8x8F
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static void CopyRowImpl(ref byte origin, ref byte dest, int sourceStride, int row)
{
origin = ref Unsafe.Add(ref origin, row * sourceStride);
dest = ref Unsafe.Add(ref dest, row * 8 * sizeof(float));
origin = ref Unsafe.Add(ref origin, (uint)(row * sourceStride));
dest = ref Unsafe.Add(ref dest, (uint)row * 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>
/// <returns>The float value at the specified index</returns>
public float this[int idx]
{
get => this[(uint)idx];
set => this[(uint)idx] = value;
}
internal float this[nuint idx]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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);
return Unsafe.Add(ref selfRef, (nint)(uint)idx);
return Unsafe.Add(ref selfRef, idx);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
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);
Unsafe.Add(ref selfRef, (nint)(uint)idx) = value;
Unsafe.Add(ref selfRef, idx) = value;
}
}
public float this[int x, int y]
{
get => this[(y * 8) + x];
set => this[(y * 8) + x] = value;
}
public static Block8x8F Load(Span<float> data)
{
Block8x8F result = default;
result.LoadFrom(data);
return result;
get => this[((uint)y * 8) + (uint)x];
set => this[((uint)y * 8) + (uint)x] = value;
}
/// <summary>
/// Load raw 32bit floating point data from source.
/// </summary>
/// <param name="source">Source</param>
/// <param name="data">Source</param>
[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));
ref byte d = ref Unsafe.As<Block8x8F, byte>(ref this);
DebugGuard.MustBeGreaterThanOrEqualTo(data.Length, Size, "data is too small");
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>
@ -138,10 +137,10 @@ internal partial struct Block8x8F : IEquatable<Block8x8F>
[MethodImpl(InliningOptions.ShortMethod)]
public unsafe void ScaledCopyTo(float[] dest)
{
fixed (void* ptr = &this.V0L)
{
Marshal.Copy((IntPtr)ptr, dest, 0, Size);
}
DebugGuard.MustBeGreaterThanOrEqualTo(dest.Length, Size, "dest is too small");
ref byte destRef = ref Unsafe.As<float, byte>(ref MemoryMarshal.GetArrayDataReference(dest));
Unsafe.WriteUnaligned(ref destRef, this);
}
public float[] ToArray()
@ -425,7 +424,7 @@ internal partial struct Block8x8F : IEquatable<Block8x8F>
Vector256<int> targetVector = Vector256.Create(value);
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);
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);
for (int i = 0; i < Size; i++)
for (nuint i = 0; i < Size; i++)
{
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
var scale = Vector256.Create(1 / (this.MaximumValue * this.MaximumValue));
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector256<float> c = ref Unsafe.Add(ref c0Base, 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);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector256<float> ctmp = Avx.Subtract(scale, Unsafe.Add(ref srcR, 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));
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector<float> c = ref Unsafe.Add(ref cBase, 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
var scale = new Vector<float>(maxValue);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> ctmp = scale - Unsafe.Add(ref srcR, 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
var scale = Vector256.Create(1 / this.MaximumValue);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector256<float> c0 = ref Unsafe.Add(ref c0Base, i);
c0 = Avx.Multiply(c0, scale);
@ -53,8 +53,8 @@ internal abstract partial class JpegColorConverterBase
var f0587 = Vector256.Create(0.587f);
var f0114 = Vector256.Create(0.114f);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector256<float> r = ref Unsafe.Add(ref srcRed, 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);
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;
}

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);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector<float> c0 = ref Unsafe.Add(ref cBase, i);
c0 *= scale;
@ -53,8 +53,8 @@ internal abstract partial class JpegColorConverterBase
var gMult = new Vector<float>(0.587f);
var bMult = new Vector<float>(0.114f);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> r = 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
var scale = Vector128.Create(1 / this.MaximumValue);
nint n = (nint)(uint)values.Component0.Length / Vector128<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector128Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector128<float> r = ref Unsafe.Add(ref rBase, 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
var scale = Vector256.Create(1 / this.MaximumValue);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector256<float> r = ref Unsafe.Add(ref rBase, 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);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
ref Vector<float> r = ref Unsafe.Add(ref rBase, 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);
// Walking 8 elements at one step:
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
@ -98,8 +98,8 @@ internal abstract partial class JpegColorConverterBase
var fn0081312F = Vector256.Create(-0.081312F);
var f05 = Vector256.Create(0.5f);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector256<float> r = Unsafe.Add(ref srcR, 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 bCbMult = new Vector<float>(YCbCrScalar.BCbMult);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
@ -103,8 +103,8 @@ internal abstract partial class JpegColorConverterBase
var gCrMult = new Vector<float>(0.418688f);
var bCrMult = new Vector<float>(0.081312f);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> r = Unsafe.Add(ref srcR, 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);
// Walking 8 elements at one step:
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
@ -109,8 +109,8 @@ internal abstract partial class JpegColorConverterBase
var fn0081312F = Vector256.Create(-0.081312F);
var f05 = Vector256.Create(0.5f);
nint n = values.Component0.Length / Vector256<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.Vector256Count<float>();
for (nuint i = 0; i < n; i++)
{
Vector256<float> r = Avx.Subtract(maxSampleValue, Unsafe.Add(ref srcR, 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 bCbMult = new Vector<float>(YCbCrScalar.BCbMult);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
// y = yVals[i];
// cb = cbVals[i] - 128F;
@ -107,8 +107,8 @@ internal abstract partial class JpegColorConverterBase
var gCrMult = new Vector<float>(0.418688f);
var bCrMult = new Vector<float>(0.081312f);
nint n = values.Component0.Length / Vector<float>.Count;
for (nint i = 0; i < n; i++)
nuint n = values.Component0.VectorCount<float>();
for (nuint i = 0; i < n; i++)
{
Vector<float> r = maxSampleValue - Unsafe.Add(ref srcR, 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.Precision = precision;
this.MaximumValue = MathF.Pow(2, precision) - 1;
this.HalfValue = MathF.Ceiling(this.MaximumValue / 2);
this.HalfValue = MathF.Ceiling(this.MaximumValue * 0.5F); // /2
}
/// <summary>
@ -138,6 +138,11 @@ internal abstract partial class JpegColorConverterBase
return new YCbCrAvx(precision);
}
if (JpegColorConverterArm.IsSupported)
{
return new YCbCrArm(precision);
}
if (JpegColorConverterVector.IsSupported)
{
return new YCbCrVector(precision);
@ -157,6 +162,11 @@ internal abstract partial class JpegColorConverterBase
return new YccKAvx(precision);
}
if (JpegColorConverterArm64.IsSupported)
{
return new YccKArm64(precision);
}
if (JpegColorConverterVector.IsSupported)
{
return new YccKVector(precision);
@ -200,6 +210,11 @@ internal abstract partial class JpegColorConverterBase
return new GrayscaleAvx(precision);
}
if (JpegColorConverterArm.IsSupported)
{
return new GrayscaleArm(precision);
}
if (JpegColorConverterVector.IsSupported)
{
return new GrayScaleVector(precision);
@ -226,10 +241,10 @@ internal abstract partial class JpegColorConverterBase
if (JpegColorConverterVector.IsSupported)
{
return new RgbScalar(precision);
return new RgbVector(precision);
}
return new GrayscaleScalar(precision);
return new RgbScalar(precision);
}
/// <summary>

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

@ -62,7 +62,7 @@ internal readonly struct AdobeMarker : IEquatable<AdobeMarker>
/// </summary>
/// <param name="bytes">The byte array containing metadata to parse.</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))
{

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

@ -53,6 +53,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
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 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>
/// Decodes the entropy coded data.
@ -470,7 +471,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline(
component,
ref Unsafe.Add(ref blockRef, (nint)(uint)blockCol),
ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref acDecodingTable,
ref dcDecodingTable);
}
@ -521,7 +522,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline(
component,
ref Unsafe.Add(ref blockRef, (nint)(uint)k),
ref Unsafe.Add(ref blockRef, (uint)k),
ref acDecodingTable,
ref dcDecodingTable);
@ -560,7 +561,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline(
component,
ref Unsafe.Add(ref blockRef, (nint)(uint)i),
ref Unsafe.Add(ref blockRef, (uint)i),
ref acDecodingTable,
ref dcDecodingTable);
@ -611,7 +612,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDc(
component,
ref Unsafe.Add(ref blockRef, (nint)(uint)blockCol),
ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref dcDecodingTable);
}
}
@ -653,7 +654,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDc(
component,
ref Unsafe.Add(ref blockRef, (nint)(uint)i),
ref Unsafe.Add(ref blockRef, (uint)i),
ref dcDecodingTable);
this.HandleRestart();
@ -680,7 +681,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveAc(
component,
ref Unsafe.Add(ref blockRef, (nint)(uint)i),
ref Unsafe.Add(ref blockRef, (uint)i),
ref acDecodingTable);
this.HandleRestart();
@ -705,7 +706,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
// 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.
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
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.22: Decoding the sign of v.
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.
int m = this.DecodeBinaryDecision(ref reader, ref st);
@ -761,7 +762,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
}
}
v += 1;
v++;
if (sign != 0)
{
v = -v;
@ -856,7 +857,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
}
}
v += 1;
v++;
if (sign != 0)
{
v = -v;
@ -955,7 +956,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
// 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.
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 */
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.22: Decoding the sign of v
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.
int m = this.DecodeBinaryDecision(ref reader, ref st);
@ -1012,7 +1013,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
}
}
v += 1;
v++;
if (sign != 0)
{
v = -v;
@ -1082,7 +1083,7 @@ internal class ArithmeticScanDecoder : IJpegScanDecoder
}
}
v += 1;
v++;
if (sign != 0)
{
v = -v;

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

@ -1,6 +1,8 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
internal class ArithmeticStatistics
@ -18,7 +20,7 @@ internal class ArithmeticStatistics
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];

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;
float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2);
float normalizationValue = MathF.Ceiling(maximumValue * 0.5F);
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)
{
// 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)]
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;
int y8 = y * 8;
nuint yy = y * verticalScale;
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];
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;
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;
float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2);
float normalizationValue = MathF.Ceiling(maximumValue * 0.5F);
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)
{
// 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)]
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;
int y8 = y * 8;
nuint yy = y * verticalScale;
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];
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;
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;
float maximumValue = this.Frame.MaxColorChannelValue;
float normalizationValue = MathF.Ceiling(maximumValue / 2);
float normalizationValue = MathF.Ceiling(maximumValue * 0.5F);
int destAreaStride = this.ColorBuffer.Width;
@ -67,20 +67,20 @@ internal sealed class DownScalingComponentProcessor8 : ComponentProcessor
{
destRef = value;
Unsafe.Add(ref destRef, 1) = value;
Unsafe.Add(ref destRef, 0 + (nint)(uint)destStrideWidth) = value;
Unsafe.Add(ref destRef, 1 + (nint)(uint)destStrideWidth) = value;
Unsafe.Add(ref destRef, 0 + (uint)destStrideWidth) = value;
Unsafe.Add(ref destRef, 1 + (uint)destStrideWidth) = value;
return;
}
// 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(
component,
ref Unsafe.Add(ref blockRef, blockCol),
ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref dcHuffmanTable,
ref acHuffmanTable);
}
@ -255,7 +255,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline(
component,
ref Unsafe.Add(ref blockRef, i),
ref Unsafe.Add(ref blockRef, (uint)i),
ref dcHuffmanTable,
ref acHuffmanTable);
@ -297,7 +297,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockBaseline(
component,
ref Unsafe.Add(ref blockRef, k),
ref Unsafe.Add(ref blockRef, (uint)k),
ref dcHuffmanTable,
ref acHuffmanTable);
@ -417,7 +417,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDC(
component,
ref Unsafe.Add(ref blockRef, blockCol),
ref Unsafe.Add(ref blockRef, (uint)blockCol),
ref dcHuffmanTable);
}
}
@ -459,7 +459,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
this.DecodeBlockProgressiveDC(
component,
ref Unsafe.Add(ref blockRef, i),
ref Unsafe.Add(ref blockRef, (uint)i),
ref dcHuffmanTable);
this.HandleRestart();
@ -485,7 +485,7 @@ internal class HuffmanScanDecoder : IJpegScanDecoder
}
this.DecodeBlockProgressiveAC(
ref Unsafe.Add(ref blockRef, i),
ref Unsafe.Add(ref blockRef, (uint)i),
ref acHuffmanTable);
this.HandleRestart();

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

@ -69,7 +69,7 @@ internal readonly struct JFifMarker : IEquatable<JFifMarker>
/// </summary>
/// <param name="bytes">The byte array containing metadata to parse.</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))
{

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;
// color converter from RGB to TPixel
// Color converter from RGB to TPixel
JpegColorConverterBase converter = this.GetColorConverter(this.frame, this.jpegData);
this.colorConverter = converter;
// resulting image size
// Resulting image size
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 majorVerticalSamplingFactor = this.frame.Components.Max((component) => component.SamplingFactors.Height);
this.pixelRowsPerStep = majorVerticalSamplingFactor * blockPixelSize;
// pixel buffer for resulting image
// Pixel buffer for resulting image
this.pixelBuffer = allocator.Allocate2D<TPixel>(
pixelSize.Width,
pixelSize.Height,
this.Configuration.PreferContiguousImageBuffers);
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 batchSize = converter.ElementsPerBatch;
int batchRemainder = bufferWidth & (batchSize - 1);
Size postProcessorBufferSize = new(bufferWidth + (batchSize - batchRemainder), this.pixelRowsPerStep);
// Converters process pixels in batches and require target buffer size to be divisible by a batch size
// 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);
// 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);
}

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

@ -5,6 +5,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
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));
// Spans are guaranteed to be multiple of 8 so no extra 'remainder' steps are needed
nint count = source.Length / Vector256<float>.Count;
for (nint i = 0; i < count; i++)
DebugGuard.IsTrue(source.Length % 8 == 0, "source must be multiple of 8");
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));
}
}
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
{
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));
nint count = source.Length / Vector<float>.Count;
for (nint i = 0; i < count; i++)
nuint count = source.VectorCount<float>();
for (nuint i = 0; i < count; i++)
{
Unsafe.Add(ref targetVectorRef, i) += Unsafe.Add(ref sourceVectorRef, i);
}
ref float targetRef = ref MemoryMarshal.GetReference(target);
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);
}
@ -157,7 +172,7 @@ internal class ComponentProcessor : IDisposable
// Ideally we need to use log2: Numerics.Log2((uint)factor)
// 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'
// values for the scalar fallback code
@ -166,9 +181,9 @@ internal class ComponentProcessor : IDisposable
source = source.Slice(touchedCount);
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;
@ -200,26 +215,40 @@ internal class ComponentProcessor : IDisposable
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
nint count = target.Length / Vector256<float>.Count;
var multiplierVector = Vector256.Create(multiplier);
for (nint i = 0; i < count; i++)
DebugGuard.IsTrue(target.Length % 8 == 0, "target must be multiple of 8");
nuint count = target.Vector256Count<float>();
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);
}
}
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
{
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);
for (nint i = 0; i < count; i++)
for (nuint i = 0; i < count; i++)
{
Unsafe.Add(ref targetVectorRef, i) *= multiplierVector;
}
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;
}

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

@ -123,7 +123,7 @@ internal class HuffmanScanEncoder
private bool IsStreamFlushNeeded
{
[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)
@ -180,7 +180,7 @@ internal class HuffmanScanEncoder
Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: 0);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint k = 0; k < w; k++)
for (nuint k = 0; k < (uint)w; k++)
{
this.WriteBlock(
component,
@ -219,7 +219,7 @@ internal class HuffmanScanEncoder
Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y: i);
ref Block8x8 blockRef = ref MemoryMarshal.GetReference(blockSpan);
for (nint k = 0; k < w; k++)
for (nuint k = 0; k < (uint)w; k++)
{
this.WriteBlock(
component,
@ -246,9 +246,9 @@ internal class HuffmanScanEncoder
private void EncodeScanBaselineInterleaved<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
nint mcu = 0;
nint mcusPerColumn = frame.McusPerColumn;
nint mcusPerLine = frame.McusPerLine;
int mcu = 0;
int mcusPerColumn = frame.McusPerColumn;
int mcusPerLine = frame.McusPerLine;
for (int j = 0; j < mcusPerColumn; j++)
{
@ -258,21 +258,21 @@ internal class HuffmanScanEncoder
converter.ConvertStrideBaseline();
// 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
nint mcuCol = mcu % mcusPerLine;
for (nint k = 0; k < frame.Components.Length; k++)
int mcuCol = mcu % mcusPerLine;
for (int k = 0; k < frame.Components.Length; k++)
{
Component component = frame.Components[k];
ref HuffmanLut dcHuffmanTable = ref this.dcHuffmanTables[component.DcTableId];
ref HuffmanLut acHuffmanTable = ref this.acHuffmanTables[component.AcTableId];
nint h = component.HorizontalSamplingFactor;
int h = component.HorizontalSamplingFactor;
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
// by the basic H and V specified for the component
@ -281,9 +281,9 @@ internal class HuffmanScanEncoder
Span<Block8x8> blockSpan = component.SpectralBlocks.DangerousGetRowSpan(y);
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(
component,
@ -315,8 +315,8 @@ internal class HuffmanScanEncoder
private void EncodeThreeComponentBaselineInterleavedScanNoSubsampling<TPixel>(JpegFrame frame, SpectralConverter<TPixel> converter, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
nint mcusPerColumn = frame.McusPerColumn;
nint mcusPerLine = frame.McusPerLine;
nuint mcusPerColumn = (uint)frame.McusPerColumn;
nuint mcusPerLine = (uint)frame.McusPerLine;
Component c2 = frame.Components[2];
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 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();
@ -341,7 +341,7 @@ internal class HuffmanScanEncoder
converter.ConvertStrideBaseline();
// Encode spectral to binary
for (nint i = 0; i < mcusPerLine; i++)
for (nuint i = 0; i < mcusPerLine; i++)
{
this.WriteBlock(
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 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);
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 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);
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)
{
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);
elemRef = 0.125f * elemRef;
@ -103,10 +103,10 @@ internal static class ScaledFloatingPointDCT
// temporal result is saved to +4 shifted indices
// because result is saved into the top left 2x2 region of the
// input block
block[(ctr * 8) + 0 + 4] = (tmp10 + tmp2) / 2;
block[(ctr * 8) + 3 + 4] = (tmp10 - tmp2) / 2;
block[(ctr * 8) + 1 + 4] = (tmp12 + tmp0) / 2;
block[(ctr * 8) + 2 + 4] = (tmp12 - tmp0) / 2;
block[(ctr * 8) + 0 + 4] = (tmp10 + tmp2) * 0.5F;
block[(ctr * 8) + 3 + 4] = (tmp10 - tmp2) * 0.5F;
block[(ctr * 8) + 1 + 4] = (tmp12 + tmp0) * 0.5F;
block[(ctr * 8) + 2 + 4] = (tmp12 - tmp0) * 0.5F;
}
for (int ctr = 0; ctr < 4; ctr++)
@ -136,10 +136,10 @@ internal static class ScaledFloatingPointDCT
(z4 * FP32_2_562915447);
// 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) + 3] = MathF.Round(Numerics.Clamp(((tmp10 - tmp2) / 2) + normalizationValue, 0, maxValue));
block[(ctr * 8) + 1] = MathF.Round(Numerics.Clamp(((tmp12 + tmp0) / 2) + normalizationValue, 0, maxValue));
block[(ctr * 8) + 2] = MathF.Round(Numerics.Clamp(((tmp12 - tmp0) / 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) * 0.5F) + 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) * 0.5F) + normalizationValue, 0, maxValue));
}
}
@ -183,8 +183,8 @@ internal static class ScaledFloatingPointDCT
// temporal result is saved to +2 shifted indices
// because result is saved into the top left 2x2 region of the
// input block
block[(ctr * 8) + 2] = (tmp10 + tmp0) / 4;
block[(ctr * 8) + 3] = (tmp10 - tmp0) / 4;
block[(ctr * 8) + 2] = (tmp10 + tmp0) * 0.25F;
block[(ctr * 8) + 3] = (tmp10 - tmp0) * 0.25F;
}
for (int ctr = 0; ctr < 2; ctr++)
@ -199,8 +199,8 @@ internal static class ScaledFloatingPointDCT
(block[ctr + (8 * 1) + 2] * FP32_3_624509785);
// 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) + 1] = 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) * 0.25F) + normalizationValue, 0, maxValue));
}
}

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

@ -27,21 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg;
/// </summary>
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>
/// Whether the image has an EXIF marker.
/// </summary>
@ -139,6 +124,12 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
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 />
public DecoderOptions Options { get; }
@ -257,24 +248,26 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
using MemoryStream ms = new(tableBytes);
using BufferedReadStream stream = new(this.configuration, ms);
Span<byte> markerBuffer = stackalloc byte[2];
// Check for the Start Of Image marker.
int bytesRead = stream.Read(this.markerBuffer, 0, 2);
JpegFileMarker fileMarker = new(this.markerBuffer[1], 0);
int bytesRead = stream.Read(markerBuffer);
JpegFileMarker fileMarker = new(markerBuffer[1], 0);
if (fileMarker.Marker != JpegConstants.Markers.SOI)
{
JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker.");
}
// Read next marker.
bytesRead = stream.Read(this.markerBuffer, 0, 2);
fileMarker = new JpegFileMarker(this.markerBuffer[1], (int)stream.Position - 2);
bytesRead = stream.Read(markerBuffer);
fileMarker = new JpegFileMarker(markerBuffer[1], (int)stream.Position - 2);
while (fileMarker.Marker != JpegConstants.Markers.EOI || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid))
{
if (!fileMarker.Invalid)
{
// 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
// markerContentByteSize is always positive so we cast
@ -297,7 +290,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
this.ProcessDefineQuantizationTablesMarker(stream, markerContentByteSize);
break;
case JpegConstants.Markers.DRI:
this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize);
this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize, markerBuffer);
break;
case JpegConstants.Markers.EOI:
return;
@ -305,13 +298,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
}
// Read next marker.
bytesRead = stream.Read(this.markerBuffer, 0, 2);
bytesRead = stream.Read(markerBuffer);
if (bytesRead != 2)
{
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();
Span<byte> markerBuffer = stackalloc byte[2];
// Check for the Start Of Image marker.
stream.Read(this.markerBuffer, 0, 2);
JpegFileMarker fileMarker = new(this.markerBuffer[1], 0);
stream.Read(markerBuffer);
JpegFileMarker fileMarker = new(markerBuffer[1], 0);
if (fileMarker.Marker != JpegConstants.Markers.SOI)
{
JpegThrowHelper.ThrowInvalidImageContentException("Missing SOI marker.");
@ -349,7 +344,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
if (!fileMarker.Invalid)
{
// 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
// markerContentByteSize is always positive so we cast
@ -446,7 +441,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
}
else
{
this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize);
this.ProcessDefineRestartIntervalMarker(stream, markerContentByteSize, markerBuffer);
}
break;
@ -755,8 +750,10 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return;
}
stream.Read(this.temp, 0, JFifMarker.Length);
if (!JFifMarker.TryParse(this.temp, out this.jFif))
Span<byte> temp = stackalloc byte[2 * 16 * 4];
stream.Read(temp, 0, JFifMarker.Length);
if (!JFifMarker.TryParse(temp, out this.jFif))
{
JpegThrowHelper.ThrowNotSupportedException("Unknown App0 Marker - Expected JFIF.");
}
@ -796,11 +793,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
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.
stream.Read(this.temp, 0, exifMarkerLength);
stream.Read(temp, 0, exifMarkerLength);
remaining -= exifMarkerLength;
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.ExifMarker))
if (ProfileResolver.IsProfile(temp, ProfileResolver.ExifMarker))
{
this.hasExif = true;
byte[] profile = new byte[remaining];
@ -819,7 +818,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
remaining = 0;
}
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker[..exifMarkerLength]))
if (ProfileResolver.IsProfile(temp, ProfileResolver.XmpMarker[..exifMarkerLength]))
{
const int remainingXmpMarkerBytes = xmpMarkerLength - exifMarkerLength;
if (remaining < remainingXmpMarkerBytes || this.skipMetadata)
@ -829,9 +828,9 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return;
}
stream.Read(this.temp, exifMarkerLength, remainingXmpMarkerBytes);
stream.Read(temp, exifMarkerLength, remainingXmpMarkerBytes);
remaining -= remainingXmpMarkerBytes;
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.XmpMarker))
if (ProfileResolver.IsProfile(temp, ProfileResolver.XmpMarker))
{
this.hasXmp = true;
byte[] profile = new byte[remaining];
@ -870,8 +869,8 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return;
}
byte[] identifier = new byte[icclength];
stream.Read(identifier, 0, icclength);
Span<byte> identifier = stackalloc byte[icclength];
stream.Read(identifier);
remaining -= icclength; // We have read it by this point
if (ProfileResolver.IsProfile(identifier, ProfileResolver.IccMarker))
@ -911,13 +910,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
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;
if (ProfileResolver.IsProfile(this.temp, ProfileResolver.AdobePhotoshopApp13Marker))
if (ProfileResolver.IsProfile(temp, ProfileResolver.AdobePhotoshopApp13Marker))
{
byte[] resourceBlockData = new byte[remaining];
stream.Read(resourceBlockData, 0, remaining);
Span<byte> blockDataSpan = resourceBlockData.AsSpan();
Span<byte> blockDataSpan = remaining <= 128 ? stackalloc byte[remaining] : new byte[remaining];
stream.Read(blockDataSpan);
while (blockDataSpan.Length > 12)
{
@ -1047,10 +1046,12 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
return;
}
stream.Read(this.temp, 0, markerLength);
Span<byte> temp = stackalloc byte[2 * 16 * 4];
stream.Read(temp, 0, markerLength);
remaining -= markerLength;
if (AdobeMarker.TryParse(this.temp, out this.adobe))
if (AdobeMarker.TryParse(temp, out this.adobe))
{
this.hasAdobeMarker = true;
}
@ -1072,6 +1073,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
private void ProcessDefineQuantizationTablesMarker(BufferedReadStream stream, int remaining)
{
JpegMetadata jpegMetadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance);
Span<byte> temp = stackalloc byte[2 * 16 * 4];
while (remaining > 0)
{
@ -1102,13 +1104,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.DQT), remaining);
}
stream.Read(this.temp, 0, 64);
stream.Read(temp, 0, 64);
remaining -= 64;
// Parsing quantization table & saving it in natural order
for (int j = 0; j < 64; j++)
{
table[ZigZag.ZigZagOrder[j]] = this.temp[j];
table[ZigZag.ZigZagOrder[j]] = temp[j];
}
break;
@ -1121,13 +1123,13 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.DQT), remaining);
}
stream.Read(this.temp, 0, 128);
stream.Read(temp, 0, 128);
remaining -= 128;
// Parsing quantization table & saving it in natural order
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;
@ -1174,28 +1176,30 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowInvalidImageContentException("Multiple SOF markers. Only single frame jpegs supported.");
}
Span<byte> temp = stackalloc byte[2 * 16 * 4];
// Read initial marker definitions.
const int length = 6;
int bytesRead = stream.Read(this.temp, 0, length);
int bytesRead = stream.Read(temp, 0, length);
if (bytesRead != length)
{
JpegThrowHelper.ThrowInvalidImageContentException("SOF marker does not contain enough data.");
}
// 1 byte: Bits/sample precision.
byte precision = this.temp[0];
byte precision = temp[0];
// 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.");
}
// 2 byte: Height
int frameHeight = (this.temp[1] << 8) | this.temp[2];
int frameHeight = (temp[1] << 8) | temp[2];
// 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).
if (frameHeight == 0 || frameWidth == 0)
@ -1204,7 +1208,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
}
// 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
// reading so we must limit it to 4.
@ -1227,7 +1231,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
}
// 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
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++)
{
// 1 byte: component identifier
byte componentId = this.temp[index];
byte componentId = temp[index];
// 1 byte: component sampling factors
byte hv = this.temp[index + 1];
byte hv = temp[index + 1];
int h = (hv >> 4) & 15;
int v = hv & 15;
@ -1270,7 +1274,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
}
// 1 byte: quantization table destination selector
byte quantTableIndex = this.temp[index + 2];
byte quantTableIndex = temp[index + 2];
// Validate: 0-3 range
if (quantTableIndex > 3)
@ -1379,7 +1383,8 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
/// </summary>
/// <param name="stream">The input stream.</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)
{
@ -1388,7 +1393,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
// 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.
this.resetInterval = this.ReadUint16(stream);
this.resetInterval = ReadUint16(stream, markerBuffer);
if (this.scanDecoder != null)
{
@ -1425,14 +1430,16 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
JpegThrowHelper.ThrowBadMarker(nameof(JpegConstants.Markers.SOS), remaining);
}
Span<byte> temp = stackalloc byte[2 * 16 * 4];
// 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;
for (int i = 0; i < selectorsBytes; i += 2)
{
// 1 byte: Component id
int componentSelectorId = this.temp[i];
int componentSelectorId = temp[i];
int componentIndex = -1;
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.
// 4 bits - dc
// 4 bits - ac
int tableSpec = this.temp[i + 1];
int tableSpec = temp[i + 1];
int dcTableIndex = tableSpec >> 4;
int acTableIndex = tableSpec & 15;
@ -1475,17 +1482,17 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
}
// 3 bytes: Progressive scan decoding data.
int bytesRead = stream.Read(this.temp, 0, 3);
int bytesRead = stream.Read(temp, 0, 3);
if (bytesRead != 3)
{
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.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.
/// </summary>
/// <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>
[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)
{
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>
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;
/// <summary>
@ -67,6 +62,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
cancellationToken.ThrowIfCancellationRequested();
this.outputStream = stream;
Span<byte> buffer = stackalloc byte[20];
ImageMetadata metadata = image.Metadata;
JpegMetadata jpegMetadata = metadata.GetJpegMetadata();
@ -76,39 +72,39 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
using JpegFrame frame = new(image, frameConfig, interleaved);
// Write the Start Of Image marker.
this.WriteStartOfImage();
this.WriteStartOfImage(buffer);
// Write APP0 marker
if (frameConfig.AdobeColorTransformMarkerFlag is null)
{
this.WriteJfifApplicationHeader(metadata);
this.WriteJfifApplicationHeader(metadata, buffer);
}
// Write APP14 marker with adobe color extension
else
{
this.WriteApp14Marker(frameConfig.AdobeColorTransformMarkerFlag.Value);
this.WriteApp14Marker(frameConfig.AdobeColorTransformMarkerFlag.Value, buffer);
}
// Write Exif, XMP, ICC and IPTC profiles
this.WriteProfiles(metadata);
this.WriteProfiles(metadata, buffer);
// Write the image dimensions.
this.WriteStartOfFrame(image.Width, image.Height, frameConfig);
this.WriteStartOfFrame(image.Width, image.Height, frameConfig, buffer);
// Write the Huffman tables.
HuffmanScanEncoder scanEncoder = new(frame.BlocksPerMcu, stream);
this.WriteDefineHuffmanTables(frameConfig.HuffmanTables, scanEncoder);
this.WriteDefineHuffmanTables(frameConfig.HuffmanTables, scanEncoder, buffer);
// 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
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.
this.WriteEndOfImageMarker();
this.WriteEndOfImageMarker(buffer);
stream.Flush();
}
@ -116,58 +112,59 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <summary>
/// Write the start of image marker.
/// </summary>
private void WriteStartOfImage()
private void WriteStartOfImage(Span<byte> buffer)
{
// Markers are always prefixed with 0xff.
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.SOI;
buffer[1] = JpegConstants.Markers.SOI;
buffer[0] = JpegConstants.Markers.XFF;
this.outputStream.Write(this.buffer, 0, 2);
this.outputStream.Write(buffer, 0, 2);
}
/// <summary>
/// Writes the application header containing the JFIF identifier plus extra data.
/// </summary>
/// <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
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.APP0; // Application Marker
this.buffer[2] = 0x00;
this.buffer[3] = 0x10;
this.buffer[4] = 0x4a; // J
this.buffer[5] = 0x46; // F
this.buffer[6] = 0x49; // I
this.buffer[7] = 0x46; // F
this.buffer[8] = 0x00; // = "JFIF",'\0'
this.buffer[9] = 0x01; // versionhi
this.buffer[10] = 0x01; // versionlo
// Write the JFIF headers (highest index first to avoid additional bound checks)
buffer[10] = 0x01; // versionlo
buffer[0] = JpegConstants.Markers.XFF;
buffer[1] = JpegConstants.Markers.APP0; // Application Marker
buffer[2] = 0x00;
buffer[3] = 0x10;
buffer[4] = 0x4a; // J
buffer[5] = 0x46; // F
buffer[6] = 0x49; // I
buffer[7] = 0x46; // F
buffer[8] = 0x00; // = "JFIF",'\0'
buffer[9] = 0x01; // versionhi
// Resolution. Big Endian
Span<byte> hResolution = this.buffer.AsSpan(12, 2);
Span<byte> vResolution = this.buffer.AsSpan(14, 2);
Span<byte> hResolution = buffer.Slice(12, 2);
Span<byte> vResolution = buffer.Slice(14, 2);
if (meta.ResolutionUnits == PixelResolutionUnit.PixelsPerMeter)
{
// 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(vResolution, (short)Math.Round(UnitConverter.MeterToInch(meta.VerticalResolution)));
}
else
{
// 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(vResolution, (short)Math.Round(meta.VerticalResolution));
}
// No thumbnail
this.buffer[16] = 0x00; // Thumbnail width
this.buffer[17] = 0x00; // Thumbnail height
buffer[17] = 0x00; // Thumbnail height
buffer[16] = 0x00; // Thumbnail width
this.outputStream.Write(this.buffer, 0, 18);
this.outputStream.Write(buffer, 0, 18);
}
/// <summary>
@ -175,8 +172,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// </summary>
/// <param name="tableConfigs">The table configuration.</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>
private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder)
private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Span<byte> buffer)
{
if (tableConfigs is null)
{
@ -190,7 +188,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
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++)
{
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.
/// </summary>
/// <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".
this.buffer[0] = 0x41;
this.buffer[1] = 0x64;
this.buffer[2] = 0x6F;
this.buffer[3] = 0x62;
this.buffer[4] = 0x65;
// Identifier: ASCII "Adobe" (highest index first to avoid additional bound checks).
buffer[4] = 0x65;
buffer[0] = 0x41;
buffer[1] = 0x64;
buffer[2] = 0x6F;
buffer[3] = 0x62;
// Version, currently 100.
BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(5, 2), 100);
BinaryPrimitives.WriteInt16BigEndian(buffer.Slice(5, 2), 100);
// Flags0
BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(7, 2), 0);
BinaryPrimitives.WriteInt16BigEndian(buffer.Slice(7, 2), 0);
// Flags1
BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(9, 2), 0);
BinaryPrimitives.WriteInt16BigEndian(buffer.Slice(9, 2), 0);
// 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>
/// Writes the EXIF profile.
/// </summary>
/// <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)
{
@ -262,7 +262,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
int app1Length = bytesToWrite + 2;
// 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(data, 0, bytesToWrite - exifMarkerLength);
remaining -= bytesToWrite;
@ -273,7 +273,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
bytesToWrite = remaining > maxBytesWithExifId ? maxBytesWithExifId : remaining;
app1Length = bytesToWrite + 2 + exifMarkerLength;
this.WriteApp1Header(app1Length);
this.WriteApp1Header(app1Length, buffer);
// Write Exif00 marker
this.outputStream.Write(Components.Decoder.ProfileResolver.ExifMarker);
@ -289,10 +289,11 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the IPTC metadata.
/// </summary>
/// <param name="iptcProfile">The iptc metadata to write.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException">
/// Thrown if the IPTC profile size exceeds the limit of 65533 bytes.
/// </exception>
private void WriteIptcProfile(IptcProfile iptcProfile)
private void WriteIptcProfile(IptcProfile iptcProfile, Span<byte> buffer)
{
const int maxBytes = 65533;
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.AdobeIptcMarker.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.AdobeImageResourceBlockMarker);
this.outputStream.Write(Components.Decoder.ProfileResolver.AdobeIptcMarker);
this.outputStream.WriteByte(0); // a empty pascal string (padded to make size even)
this.outputStream.WriteByte(0);
BinaryPrimitives.WriteInt32BigEndian(this.buffer, data.Length);
this.outputStream.Write(this.buffer, 0, 4);
BinaryPrimitives.WriteInt32BigEndian(buffer, data.Length);
this.outputStream.Write(buffer, 0, 4);
this.outputStream.Write(data, 0, data.Length);
}
@ -331,10 +332,11 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the XMP metadata.
/// </summary>
/// <param name="xmpProfile">The XMP metadata to write.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException">
/// Thrown if the XMP profile size exceeds the limit of 65533 bytes.
/// </exception>
private void WriteXmpProfile(XmpProfile xmpProfile)
private void WriteXmpProfile(XmpProfile xmpProfile, Span<byte> buffer)
{
if (xmpProfile is null)
{
@ -367,7 +369,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
dataLength -= 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(data, offset, length);
@ -379,32 +381,35 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the App1 header.
/// </summary>
/// <param name="app1Length">The length of the data the app1 marker contains.</param>
private void WriteApp1Header(int app1Length)
=> this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1);
/// <param name="buffer">Temporary buffer.</param>
private void WriteApp1Header(int app1Length, Span<byte> buffer)
=> this.WriteAppHeader(app1Length, JpegConstants.Markers.APP1, buffer);
/// <summary>
/// Writes a AppX header.
/// </summary>
/// <param name="length">The length of the data the app marker contains.</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;
this.buffer[1] = appMarker;
this.buffer[2] = (byte)((length >> 8) & 0xFF);
this.buffer[3] = (byte)(length & 0xFF);
buffer[0] = JpegConstants.Markers.XFF;
buffer[1] = appMarker;
buffer[2] = (byte)((length >> 8) & 0xFF);
buffer[3] = (byte)(length & 0xFF);
this.outputStream.Write(this.buffer, 0, 4);
this.outputStream.Write(buffer, 0, 4);
}
/// <summary>
/// Writes the ICC profile.
/// </summary>
/// <param name="iccProfile">The ICC profile to write.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException">
/// Thrown if any of the ICC profiles size exceeds the limit.
/// </exception>
private void WriteIccProfile(IccProfile iccProfile)
private void WriteIccProfile(IccProfile iccProfile, Span<byte> buffer)
{
if (iccProfile is null)
{
@ -446,30 +451,31 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
dataLength -= length;
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.APP2; // Application Marker
buffer[0] = JpegConstants.Markers.XFF;
buffer[1] = JpegConstants.Markers.APP2; // Application Marker
int markerLength = length + 16;
this.buffer[2] = (byte)((markerLength >> 8) & 0xFF);
this.buffer[3] = (byte)(markerLength & 0xFF);
this.outputStream.Write(this.buffer, 0, 4);
this.buffer[0] = (byte)'I';
this.buffer[1] = (byte)'C';
this.buffer[2] = (byte)'C';
this.buffer[3] = (byte)'_';
this.buffer[4] = (byte)'P';
this.buffer[5] = (byte)'R';
this.buffer[6] = (byte)'O';
this.buffer[7] = (byte)'F';
this.buffer[8] = (byte)'I';
this.buffer[9] = (byte)'L';
this.buffer[10] = (byte)'E';
this.buffer[11] = 0x00;
this.buffer[12] = (byte)current; // The position within the collection.
this.buffer[13] = (byte)count; // The total number of profiles.
this.outputStream.Write(this.buffer, 0, iccOverheadLength);
buffer[2] = (byte)((markerLength >> 8) & 0xFF);
buffer[3] = (byte)(markerLength & 0xFF);
this.outputStream.Write(buffer, 0, 4);
// We write the highest index first, to have only one bound check.
buffer[13] = (byte)count; // The total number of profiles.
buffer[12] = (byte)current; // The position within the collection.
buffer[11] = 0x00;
buffer[0] = (byte)'I';
buffer[1] = (byte)'C';
buffer[2] = (byte)'C';
buffer[3] = (byte)'_';
buffer[4] = (byte)'P';
buffer[5] = (byte)'R';
buffer[6] = (byte)'O';
buffer[7] = (byte)'F';
buffer[8] = (byte)'I';
buffer[9] = (byte)'L';
buffer[10] = (byte)'E';
this.outputStream.Write(buffer, 0, iccOverheadLength);
this.outputStream.Write(data, offset, length);
current++;
@ -481,7 +487,8 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// Writes the metadata profiles to the image.
/// </summary>
/// <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)
{
@ -494,10 +501,10 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
// - APP2 ICC
// - APP13 IPTC
metadata.SyncProfiles();
this.WriteExifProfile(metadata.ExifProfile);
this.WriteXmpProfile(metadata.XmpProfile);
this.WriteIccProfile(metadata.IccProfile);
this.WriteIptcProfile(metadata.IptcProfile);
this.WriteExifProfile(metadata.ExifProfile, buffer);
this.WriteXmpProfile(metadata.XmpProfile, buffer);
this.WriteIccProfile(metadata.IccProfile, buffer);
this.WriteIptcProfile(metadata.IptcProfile, buffer);
}
/// <summary>
@ -506,25 +513,26 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <param name="width">The frame width.</param>
/// <param name="height">The frame height.</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;
// Length (high byte, low byte), 8 + components * 3.
int markerlen = 8 + (3 * components.Length);
this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen);
this.buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported
this.buffer[1] = (byte)(height >> 8);
this.buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
this.buffer[3] = (byte)(width >> 8);
this.buffer[4] = (byte)(width & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
this.buffer[5] = (byte)components.Length;
this.WriteMarkerHeader(JpegConstants.Markers.SOF0, markerlen, buffer);
buffer[5] = (byte)components.Length;
buffer[0] = 8; // Data Precision. 8 for now, 12 and 16 bit jpegs not supported
buffer[1] = (byte)(height >> 8);
buffer[2] = (byte)(height & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
buffer[3] = (byte)(width >> 8);
buffer[4] = (byte)(width & 0xff); // (2 bytes, Hi-Lo), must be > 0 if DNL not supported
// Components data
for (int i = 0; i < components.Length; 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
bufferSpan[2] = (byte)components[i].QuantizatioTableIndex;
@ -538,14 +546,15 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
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>
/// Writes the StartOfScan marker.
/// </summary>
/// <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:
// - 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
// 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.
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.SOS;
buffer[1] = JpegConstants.Markers.SOS;
buffer[0] = JpegConstants.Markers.XFF;
// Length (high byte, low byte), must be 6 + 2 * (number of components in scan)
int sosSize = 6 + (2 * components.Length);
this.buffer[2] = 0x00;
this.buffer[3] = (byte)sosSize;
this.buffer[4] = (byte)components.Length; // Number of components in a scan
buffer[4] = (byte)components.Length; // Number of components in a scan
buffer[3] = (byte)sosSize;
buffer[2] = 0x00;
// Components data
for (int i = 0; i < components.Length; i++)
@ -571,27 +580,28 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
int i2 = 2 * i;
// Id
this.buffer[i2 + 5] = components[i].Id;
buffer[i2 + 5] = components[i].Id;
// Table selectors
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.
this.buffer[sosSize] = 0x3f; // Se - End of spectral selection.
this.buffer[sosSize + 1] = 0x00; // Ah + Ah (Successive approximation bit position high + low)
this.outputStream.Write(this.buffer, 0, sosSize + 2);
buffer[sosSize - 1] = 0x00; // Ss - Start of spectral selection.
buffer[sosSize] = 0x3f; // Se - End of spectral selection.
buffer[sosSize + 1] = 0x00; // Ah + Ah (Successive approximation bit position high + low)
this.outputStream.Write(buffer, 0, sosSize + 2);
}
/// <summary>
/// Writes the EndOfImage marker.
/// </summary>
private void WriteEndOfImageMarker()
/// <param name="buffer">Temporary buffer.</param>
private void WriteEndOfImageMarker(Span<byte> buffer)
{
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = JpegConstants.Markers.EOI;
this.outputStream.Write(this.buffer, 0, 2);
buffer[1] = JpegConstants.Markers.EOI;
buffer[0] = JpegConstants.Markers.XFF;
this.outputStream.Write(buffer, 0, 2);
}
/// <summary>
@ -602,12 +612,14 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <param name="frameConfig">The frame configuration.</param>
/// <param name="spectralConverter">The spectral converter.</param>
/// <param name="encoder">The scan encoder.</param>
/// <param name="buffer">Temporary buffer.</param>
/// <param name="cancellationToken">The cancellation token.</param>
private void WriteHuffmanScans<TPixel>(
JpegFrame frame,
JpegFrameConfig frameConfig,
SpectralConverter<TPixel> spectralConverter,
HuffmanScanEncoder encoder,
Span<byte> buffer,
CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
@ -615,14 +627,14 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
{
frame.AllocateComponents(fullScan: false);
this.WriteStartOfScan(frameConfig.Components);
this.WriteStartOfScan(frameConfig.Components, buffer);
encoder.EncodeScanBaselineSingleComponent(frame.Components[0], spectralConverter, cancellationToken);
}
else if (frame.Interleaved)
{
frame.AllocateComponents(fullScan: false);
this.WriteStartOfScan(frameConfig.Components);
this.WriteStartOfScan(frameConfig.Components, buffer);
encoder.EncodeScanBaselineInterleaved(frameConfig.EncodingColor, frame, spectralConverter, cancellationToken);
}
else
@ -633,7 +645,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
Span<JpegComponentConfig> components = frameConfig.Components;
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);
}
}
@ -644,14 +656,16 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// </summary>
/// <param name="marker">The marker to write.</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.
this.buffer[0] = JpegConstants.Markers.XFF;
this.buffer[1] = marker;
this.buffer[2] = (byte)(length >> 8);
this.buffer[3] = (byte)(length & 0xff);
this.outputStream.Write(this.buffer, 0, 4);
buffer[3] = (byte)(length & 0xff);
buffer[2] = (byte)(length >> 8);
buffer[1] = marker;
buffer[0] = JpegConstants.Markers.XFF;
this.outputStream.Write(buffer, 0, 4);
}
/// <summary>
@ -668,15 +682,16 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals
/// <param name="configs">Quantization tables configs.</param>
/// <param name="optionsQuality">Optional quality value from the options.</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);
// Marker + quantization table lengths.
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;
Block8x8F workspaceBlock = default;

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

@ -67,16 +67,22 @@ internal static class Adam7
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static int ComputeColumns(int width, int passIndex)
{
switch (passIndex)
uint w = (uint)width;
uint result = passIndex switch
{
case 0: return (width + 7) / 8;
case 1: return (width + 3) / 8;
case 2: return (width + 3) / 4;
case 3: return (width + 1) / 4;
case 4: return (width + 1) / 2;
case 5: return width / 2;
case 6: return width;
default: throw new ArgumentException($"Not a valid pass index: {passIndex}");
}
0 => (w + 7) / 8,
1 => (w + 3) / 8,
2 => (w + 3) / 4,
3 => (w + 1) / 4,
4 => (w + 1) / 2,
5 => w / 2,
6 => w,
_ => 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
{
DecodeScalar(scanline, previousScanline, bytesPerPixel);
DecodeScalar(scanline, previousScanline, (uint)bytesPerPixel);
}
}
@ -56,7 +56,7 @@ internal static class AverageFilter
Vector128<byte> ones = Vector128.Create((byte)1);
int rb = scanline.Length;
nint offset = 1;
nuint offset = 1;
while (rb >= 4)
{
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -88,7 +88,7 @@ internal static class AverageFilter
Vector64<byte> d = Vector64<byte>.Zero;
int rb = scanline.Length;
int offset = 1;
nuint offset = 1;
const int bytesPerBatch = 4;
while (rb >= bytesPerBatch)
{
@ -108,12 +108,12 @@ internal static class AverageFilter
}
[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 prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
nint x = 1;
nuint x = 1;
for (; x <= bytesPerPixel /* Note the <= because x starts at 1 */; ++x)
{
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
@ -121,7 +121,7 @@ internal static class AverageFilter
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);
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="sum">The sum of the total variance of the filtered row.</param>
[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.MustBeSizedAtLeast(result, scanline, nameof(result));
@ -152,7 +152,7 @@ internal static class AverageFilter
// Average(x) = Raw(x) - floor((Raw(x-bpp)+Prior(x))/2)
resultBaseRef = (byte)FilterType.Average;
nint x = 0;
nuint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{
byte scan = Unsafe.Add(ref scanBaseRef, x);
@ -169,7 +169,7 @@ internal static class AverageFilter
Vector256<int> sumAccumulator = Vector256<int>.Zero;
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> 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);
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());
}
@ -192,7 +192,7 @@ internal static class AverageFilter
Vector128<int> sumAccumulator = Vector128<int>.Zero;
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> 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);
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;
if (Ssse3.IsSupported)
@ -221,7 +221,7 @@ internal static class AverageFilter
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 left = Unsafe.Add(ref scanBaseRef, xLeft);

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

@ -45,7 +45,7 @@ internal static class PaethFilter
}
else
{
DecodeScalar(scanline, previousScanline, bytesPerPixel);
DecodeScalar(scanline, previousScanline, (uint)bytesPerPixel);
}
}
@ -59,7 +59,7 @@ internal static class PaethFilter
Vector128<byte> d = Vector128<byte>.Zero;
int rb = scanline.Length;
nint offset = 1;
nuint offset = 1;
while (rb >= 4)
{
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -113,7 +113,7 @@ internal static class PaethFilter
Vector128<byte> d = Vector128<byte>.Zero;
int rb = scanline.Length;
nint offset = 1;
nuint offset = 1;
const int bytesPerBatch = 4;
while (rb >= bytesPerBatch)
{
@ -179,14 +179,14 @@ internal static class PaethFilter
}
[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 prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// Paeth(x) + PaethPredictor(Raw(x-bpp), Prior(x), Prior(x-bpp))
int offset = bytesPerPixel + 1; // Add one because x starts at one.
nint x = 1;
nuint offset = bytesPerPixel + 1; // Add one because x starts at one.
nuint x = 1;
for (; x < offset; x++)
{
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
@ -194,7 +194,7 @@ internal static class PaethFilter
scan = (byte)(scan + above);
}
for (; x < scanline.Length; x++)
for (; x < (uint)scanline.Length; x++)
{
ref byte scan = ref Unsafe.Add(ref scanBaseRef, x);
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))
resultBaseRef = (byte)FilterType.Paeth;
nint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
nuint x = 0;
for (; x < (uint)bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{
byte scan = Unsafe.Add(ref scanBaseRef, x);
byte above = Unsafe.Add(ref prevBaseRef, x);
@ -242,7 +242,7 @@ internal static class PaethFilter
Vector256<byte> zero = Vector256<byte>.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> 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));
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());
}
@ -262,7 +262,7 @@ internal static class PaethFilter
{
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> 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);
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))));
}
@ -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 left = Unsafe.Add(ref scanBaseRef, xLeft);

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

@ -36,7 +36,7 @@ internal static class SubFilter
}
else
{
DecodeScalar(scanline, bytesPerPixel);
DecodeScalar(scanline, (uint)bytesPerPixel);
}
}
@ -47,7 +47,7 @@ internal static class SubFilter
Vector128<byte> d = Vector128<byte>.Zero;
int rb = scanline.Length;
nint offset = 1;
nuint offset = 1;
while (rb >= 4)
{
ref byte scanRef = ref Unsafe.Add(ref scanBaseRef, offset);
@ -70,7 +70,7 @@ internal static class SubFilter
Vector64<byte> d = Vector64<byte>.Zero;
int rb = scanline.Length;
int offset = 1;
nuint offset = 1;
const int bytesPerBatch = 4;
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);
// Sub(x) + Raw(x-bpp)
nint x = bytesPerPixel + 1;
nuint x = bytesPerPixel + 1;
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);
byte prev = Unsafe.Add(ref scanBaseRef, x - bytesPerPixel);
@ -121,8 +121,8 @@ internal static class SubFilter
// Sub(x) = Raw(x) - Raw(x-bpp)
resultBaseRef = (byte)FilterType.Sub;
nint x = 0;
for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
nuint x = 0;
for (; x < (uint)bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */)
{
byte scan = Unsafe.Add(ref scanBaseRef, x);
++x;
@ -136,14 +136,14 @@ internal static class SubFilter
Vector256<byte> zero = Vector256<byte>.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> prev = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
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
x += Vector256<byte>.Count;
x += (uint)Vector256<byte>.Count;
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;
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> prev = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref scanBaseRef, xLeft));
Vector<byte> res = scan - prev;
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))));
}
@ -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 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)
int rb = scanline.Length;
nint offset = 1;
nuint offset = 1;
while (rb >= Vector256<byte>.Count)
{
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);
offset += Vector256<byte>.Count;
offset += (uint)Vector256<byte>.Count;
rb -= Vector256<byte>.Count;
}
// 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);
byte above = Unsafe.Add(ref prevBaseRef, offset);
@ -82,7 +82,7 @@ internal static class UpFilter
// Up(x) + Prior(x)
int rb = scanline.Length;
nint offset = 1;
nuint offset = 1;
while (rb >= Vector128<byte>.Count)
{
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);
offset += Vector128<byte>.Count;
offset += (uint)Vector128<byte>.Count;
rb -= Vector128<byte>.Count;
}
// 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);
byte above = Unsafe.Add(ref prevBaseRef, offset);
@ -112,7 +112,7 @@ internal static class UpFilter
// Up(x) + Prior(x)
int rb = scanline.Length;
nint offset = 1;
nuint offset = 1;
const int bytesPerBatch = 16;
while (rb >= bytesPerBatch)
{
@ -127,7 +127,7 @@ internal static class UpFilter
}
// 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);
byte above = Unsafe.Add(ref prevBaseRef, offset);
@ -143,7 +143,7 @@ internal static class UpFilter
ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline);
// 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);
byte above = Unsafe.Add(ref prevBaseRef, x);
@ -172,21 +172,21 @@ internal static class UpFilter
// Up(x) = Raw(x) - Prior(x)
resultBaseRef = (byte)FilterType.Up;
nint x = 0;
nuint x = 0;
if (Avx2.IsSupported)
{
Vector256<byte> zero = Vector256<byte>.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> above = Unsafe.As<byte, Vector256<byte>>(ref Unsafe.Add(ref prevBaseRef, x));
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
x += Vector256<byte>.Count;
x += (uint)Vector256<byte>.Count;
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;
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> above = Unsafe.As<byte, Vector<byte>>(ref Unsafe.Add(ref prevBaseRef, x));
Vector<byte> res = scan - above;
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))));
}
@ -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 above = Unsafe.Add(ref prevBaseRef, x);

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

@ -28,11 +28,6 @@ namespace SixLabors.ImageSharp.Formats.Png;
/// </summary>
internal sealed class PngDecoderCore : IImageDecoderInternals
{
/// <summary>
/// Reusable buffer.
/// </summary>
private readonly byte[] buffer = new byte[4];
/// <summary>
/// The general decoder options.
/// </summary>
@ -154,9 +149,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.currentStream = stream;
this.currentStream.Skip(8);
Image<TPixel> image = null;
Span<byte> buffer = stackalloc byte[20];
try
{
while (this.TryReadChunk(out PngChunk chunk))
while (this.TryReadChunk(buffer, out PngChunk chunk))
{
try
{
@ -252,10 +249,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
ImageMetadata metadata = new();
PngMetadata pngMetadata = metadata.GetPngMetadata();
this.currentStream = stream;
Span<byte> buffer = stackalloc byte[20];
this.currentStream.Skip(8);
try
{
while (this.TryReadChunk(out PngChunk chunk))
while (this.TryReadChunk(buffer, out PngChunk chunk))
{
try
{
@ -414,11 +414,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
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)
{
int colorIndex = (b >> (8 - bits - shift)) & mask;
Unsafe.Add(ref resultRef, resultOffset) = (byte)colorIndex;
Unsafe.Add(ref resultRef, (uint)resultOffset) = (byte)colorIndex;
resultOffset++;
}
}
@ -777,8 +777,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header,
scanlineSpan,
rowSpan,
this.bytesPerPixel,
this.bytesPerSample);
(uint)this.bytesPerPixel,
(uint)this.bytesPerSample);
break;
@ -858,8 +858,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header,
scanlineSpan,
rowSpan,
pixelOffset,
increment,
(uint)pixelOffset,
(uint)increment,
pngMetadata.HasTransparency,
pngMetadata.TransparentL16.GetValueOrDefault(),
pngMetadata.TransparentL8.GetValueOrDefault());
@ -871,10 +871,10 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header,
scanlineSpan,
rowSpan,
pixelOffset,
increment,
this.bytesPerPixel,
this.bytesPerSample);
(uint)pixelOffset,
(uint)increment,
(uint)this.bytesPerPixel,
(uint)this.bytesPerSample);
break;
@ -883,8 +883,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header,
scanlineSpan,
rowSpan,
pixelOffset,
increment,
(uint)pixelOffset,
(uint)increment,
this.palette,
this.paletteAlpha);
@ -895,8 +895,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header,
scanlineSpan,
rowSpan,
pixelOffset,
increment,
(uint)pixelOffset,
(uint)increment,
this.bytesPerPixel,
this.bytesPerSample,
pngMetadata.HasTransparency,
@ -910,8 +910,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
this.header,
scanlineSpan,
rowSpan,
pixelOffset,
increment,
(uint)pixelOffset,
(uint)increment,
this.bytesPerPixel,
this.bytesPerSample);
@ -1401,9 +1401,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
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)
{
@ -1420,11 +1422,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary>
/// Reads a chunk from the stream.
/// </summary>
/// <param name="buffer">Temporary buffer.</param>
/// <param name="chunk">The image format chunk.</param>
/// <returns>
/// The <see cref="PngChunk"/>.
/// </returns>
private bool TryReadChunk(out PngChunk chunk)
private bool TryReadChunk(Span<byte> buffer, out PngChunk chunk)
{
if (this.nextChunk != null)
{
@ -1435,7 +1438,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
return true;
}
if (!this.TryReadChunkLength(out int length))
if (!this.TryReadChunkLength(buffer, out int length))
{
chunk = default;
@ -1446,7 +1449,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
while (length < 0 || length > (this.currentStream.Length - this.currentStream.Position))
{
// 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;
@ -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.
// We can skip all other chunk data in the stream for better performance.
@ -1471,7 +1474,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
type: type,
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
// was only read to verifying the CRC is correct.
@ -1487,9 +1490,10 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// Validates the png chunk.
/// </summary>
/// <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)
{
@ -1513,13 +1517,14 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary>
/// Reads the cycle redundancy chunk from the data.
/// </summary>
/// <param name="buffer">Temporary buffer.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private uint ReadChunkCrc()
private uint ReadChunkCrc(Span<byte> buffer)
{
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;
@ -1554,15 +1559,16 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary>
/// Identifies the chunk type from the chunk.
/// </summary>
/// <param name="buffer">Temporary buffer.</param>
/// <exception cref="ImageFormatException">
/// Thrown if the input stream is not valid.
/// </exception>
[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();
@ -1574,16 +1580,17 @@ internal sealed class PngDecoderCore : IImageDecoderInternals
/// <summary>
/// Attempts to read the length of the next chunk.
/// </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>
/// <returns>
/// Whether the length was read.
/// </returns>
[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;
}

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

@ -38,15 +38,10 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
/// </summary>
private readonly Configuration configuration;
/// <summary>
/// Reusable buffer for writing general data.
/// </summary>
private readonly byte[] buffer = new byte[8];
/// <summary>
/// Reusable buffer for writing chunk data.
/// </summary>
private readonly byte[] chunkDataBuffer = new byte[16];
private ScratchBuffer chunkDataBuffer; // mutable struct, don't make readonly
/// <summary>
/// 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.
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);
}
}
@ -306,7 +301,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Can't map directly to byte array as it's big endian.
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, 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.
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, 2), rgba.G);
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.
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, 2), rgb.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B);
@ -455,7 +450,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
break;
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;
case PngFilterMethod.Paeth:
@ -547,7 +542,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
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)
{
min = sum;
@ -576,9 +571,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
filterMethod: 0,
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>
@ -617,17 +612,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// Loop, assign, and extract alpha values from the palette.
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;
Unsafe.Add(ref colorTableRef, i) = rgba.Rgb;
Unsafe.Add(ref colorTableRef, (uint)i) = rgba.Rgb;
if (alpha > this.encoder.Threshold)
{
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);
@ -652,9 +647,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
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>
@ -880,9 +875,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
// 4-byte unsigned integer of gamma * 100,000.
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;
}
Span<byte> alpha = this.chunkDataBuffer.AsSpan();
Span<byte> alpha = this.chunkDataBuffer.Span;
if (pngMetadata.ColorType == PngColorType.Rgb)
{
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(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)
{
@ -918,7 +913,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
alpha[1] = rgb.R;
alpha[3] = rgb.G;
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)
@ -926,13 +921,13 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
if (pngMetadata.TransparentL16.HasValue && this.use16Bit)
{
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)
{
alpha.Clear();
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>
private void WriteChunk(Stream stream, PngChunkType type, Span<byte> data, int offset, int length)
{
BinaryPrimitives.WriteInt32BigEndian(this.buffer, length);
BinaryPrimitives.WriteUInt32BigEndian(this.buffer.AsSpan(4, 4), (uint)type);
Span<byte> buffer = stackalloc byte[8];
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)
{
@ -1187,9 +1184,9 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
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>
@ -1412,4 +1409,12 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
Type t when t == typeof(RgbaVector) => PngBitDepth.Bit16,
_ => 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++)
{
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;
if (shift == 0)
{
shift = shift0;
Unsafe.Add(ref resultRef, resultOffset) = (byte)v;
Unsafe.Add(ref resultRef, (uint)resultOffset) = (byte)v;
resultOffset++;
v = 0;
}
@ -49,7 +49,7 @@ internal static class PngEncoderHelpers
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)
{
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));
pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
@ -41,7 +42,7 @@ internal static class PngScanlineProcessor
}
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);
pixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
@ -55,7 +56,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16)
{
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));
source.L = luminance;
@ -69,7 +71,7 @@ internal static class PngScanlineProcessor
{
La16 source = default;
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);
source.L = luminance;
@ -85,8 +87,8 @@ internal static class PngScanlineProcessor
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
int pixelOffset,
int increment,
uint pixelOffset,
uint increment,
bool hasTrans,
L16 luminance16Trans,
L8 luminanceTrans)
@ -101,7 +103,8 @@ internal static class PngScanlineProcessor
{
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));
pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
@ -110,7 +113,7 @@ internal static class PngScanlineProcessor
}
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);
pixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
@ -124,7 +127,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16)
{
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));
source.L = luminance;
@ -138,7 +142,7 @@ internal static class PngScanlineProcessor
{
La16 source = default;
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);
source.L = luminance;
@ -154,8 +158,8 @@ internal static class PngScanlineProcessor
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
int bytesPerPixel,
int bytesPerSample)
uint bytesPerPixel,
uint bytesPerSample)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel pixel = default;
@ -165,7 +169,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16)
{
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.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
@ -177,9 +182,9 @@ internal static class PngScanlineProcessor
else
{
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.A = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample);
@ -193,10 +198,10 @@ internal static class PngScanlineProcessor
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
int pixelOffset,
int increment,
int bytesPerPixel,
int bytesPerSample)
uint pixelOffset,
uint increment,
uint bytesPerPixel,
uint bytesPerSample)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel pixel = default;
@ -206,20 +211,21 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16)
{
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.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
Unsafe.Add(ref rowSpanRef, (uint)x) = pixel;
}
}
else
{
int offset = 0;
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.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
// channel and we should try to read it.
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.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue;
@ -269,7 +275,7 @@ internal static class PngScanlineProcessor
}
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);
Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
@ -284,8 +290,8 @@ internal static class PngScanlineProcessor
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
int pixelOffset,
int increment,
uint pixelOffset,
uint increment,
ReadOnlySpan<byte> palette,
byte[] paletteAlpha)
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
// channel and we should try to read it.
Rgba32 rgba = default;
ref byte paletteAlphaRef = ref paletteAlpha[0];
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++)
ref byte paletteAlphaRef = ref MemoryMarshal.GetArrayDataReference(paletteAlpha);
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.Rgb = Unsafe.Add(ref palettePixelsRef, index);
@ -314,7 +320,7 @@ internal static class PngScanlineProcessor
}
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);
Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
@ -345,7 +351,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16)
{
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.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -367,7 +374,8 @@ internal static class PngScanlineProcessor
{
Rgb48 rgb48 = 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.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -385,7 +393,7 @@ internal static class PngScanlineProcessor
Rgba32 rgba32 = default;
ReadOnlySpan<Rgb24> rgb24Span = MemoryMarshal.Cast<byte, Rgb24>(scanlineSpan);
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);
rgba32.Rgb = rgb24;
@ -401,8 +409,8 @@ internal static class PngScanlineProcessor
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
int pixelOffset,
int increment,
uint pixelOffset,
uint increment,
int bytesPerPixel,
int bytesPerSample,
bool hasTrans,
@ -420,7 +428,8 @@ internal static class PngScanlineProcessor
{
Rgb48 rgb48 = 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.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -436,7 +445,8 @@ internal static class PngScanlineProcessor
else
{
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.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -453,11 +463,12 @@ internal static class PngScanlineProcessor
if (hasTrans)
{
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.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample);
rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample));
rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue;
pixel.FromRgba32(rgba);
@ -467,11 +478,12 @@ internal static class PngScanlineProcessor
else
{
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.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample);
rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample));
rgb.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgb.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgb.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
pixel.FromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel;
@ -494,7 +506,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16)
{
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.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -515,8 +528,8 @@ internal static class PngScanlineProcessor
in PngHeader header,
ReadOnlySpan<byte> scanlineSpan,
Span<TPixel> rowSpan,
int pixelOffset,
int increment,
uint pixelOffset,
uint increment,
int bytesPerPixel,
int bytesPerSample)
where TPixel : unmanaged, IPixel<TPixel>
@ -528,7 +541,8 @@ internal static class PngScanlineProcessor
if (header.BitDepth == 16)
{
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.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
@ -542,12 +556,13 @@ internal static class PngScanlineProcessor
else
{
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.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample);
rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample));
rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * bytesPerSample));
rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
rgba.A = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample)));
pixel.FromRgba32(rgba);
Unsafe.Add(ref rowSpanRef, x) = pixel;

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

@ -4,6 +4,7 @@
using System.Buffers;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.IO;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
@ -16,11 +17,6 @@ namespace SixLabors.ImageSharp.Formats.Tga;
/// </summary>
internal sealed class TgaDecoderCore : IImageDecoderInternals
{
/// <summary>
/// A scratch buffer to reduce allocations.
/// </summary>
private readonly byte[] scratchBuffer = new byte[4];
/// <summary>
/// General configuration options.
/// </summary>
@ -406,6 +402,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
bool invertX = InvertX(origin);
using IMemoryOwner<byte> row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0);
Span<byte> rowSpan = row.GetSpan();
Span<byte> scratchBuffer = stackalloc byte[2];
for (int y = 0; y < height; y++)
{
@ -416,7 +413,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
int bytesRead = stream.Read(this.scratchBuffer, 0, 2);
int bytesRead = stream.Read(scratchBuffer);
if (bytesRead != 2)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a pixel row");
@ -424,16 +421,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (!this.hasAlpha)
{
this.scratchBuffer[1] |= 1 << 7;
scratchBuffer[1] |= 1 << 7;
}
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
{
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref this.scratchBuffer[0]));
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref MemoryMarshal.GetReference(scratchBuffer)));
}
pixelSpan[x] = color;
@ -483,6 +480,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
bool invertX = InvertX(origin);
if (invertX)
{
Span<byte> scratchBuffer = stackalloc byte[4];
TPixel color = default;
for (int y = 0; y < height; y++)
{
@ -490,7 +488,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
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;
}
Span<byte> scratchBuffer = stackalloc byte[4];
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
@ -565,14 +565,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadBgra32Pixel(stream, x, color, pixelRow);
this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
}
}
else
{
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)]
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>
{
int bytesRead = stream.Read(this.scratchBuffer, 0, 3);
int bytesRead = stream.Read(scratchBuffer, 0, 3);
if (bytesRead != 3)
{
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;
}
@ -714,10 +714,10 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
}
[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>
{
int bytesRead = stream.Read(this.scratchBuffer, 0, 4);
int bytesRead = stream.Read(scratchBuffer, 0, 4);
if (bytesRead != 4)
{
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgra pixel");
@ -725,8 +725,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
Guard.NotNull(this.tgaMetadata);
byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : this.scratchBuffer[3];
color.FromBgra32(new Bgra32(this.scratchBuffer[2], this.scratchBuffer[1], this.scratchBuffer[0], alpha));
byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : scratchBuffer[3];
color.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha));
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)
{
int uncompressedPixels = 0;
Span<byte> pixel = this.scratchBuffer.AsSpan(0, bytesPerPixel);
Span<byte> pixel = stackalloc byte[bytesPerPixel];
int totalPixels = width * height;
while (uncompressedPixels < totalPixels)
{
@ -824,7 +824,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (highBit == 1)
{
int runLength = runLengthByte & 127;
int bytesRead = stream.Read(pixel, 0, bytesPerPixel);
int bytesRead = stream.Read(pixel);
if (bytesRead != bytesPerPixel)
{
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;
for (int i = 0; i < runLength + 1; i++, uncompressedPixels++)
{
int bytesRead = stream.Read(pixel, 0, bytesPerPixel);
int bytesRead = stream.Read(pixel);
if (bytesRead != bytesPerPixel)
{
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>
private readonly MemoryAllocator memoryAllocator;
/// <summary>
/// Reusable buffer for writing data.
/// </summary>
private readonly byte[] buffer = new byte[2];
/// <summary>
/// The color depth, in number of bits per pixel.
/// </summary>
@ -221,9 +216,10 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
case TgaBitsPerPixel.Pixel16:
Bgra5551 bgra5551 = new(color.ToVector4());
BinaryPrimitives.WriteInt16LittleEndian(this.buffer, (short)bgra5551.PackedValue);
stream.WriteByte(this.buffer[0]);
stream.WriteByte(this.buffer[1]);
Span<byte> buffer = stackalloc byte[2];
BinaryPrimitives.WriteInt16LittleEndian(buffer, (short)bgra5551.PackedValue);
stream.WriteByte(buffer[0]);
stream.WriteByte(buffer[1]);
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 bufferPos = bitsWritten / 8;
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)
{

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

@ -18,21 +18,21 @@ internal class BlackIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
nint offset = 0;
var colorBlack = default(TPixel);
var colorWhite = default(TPixel);
nuint offset = 0;
TPixel colorBlack = default;
TPixel colorWhite = default;
colorBlack.FromRgba32(Color.Black);
colorWhite.FromRgba32(Color.White);
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);
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++);
nint maxShift = Math.Min(left + width - x, 8);
nuint maxShift = Math.Min((uint)(left + width) - x, 8);
if (maxShift == 8)
{
@ -70,9 +70,9 @@ internal class BlackIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
}
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);
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/>
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);
byte[] buffer = new byte[4];
Span<byte> buffer = stackalloc byte[4];
int offset = 0;
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float intensity = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float intensity = BitConverter.ToSingle(buffer);
offset += 4;
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
float intensity = BitConverter.ToSingle(buffer, 0);
float intensity = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
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);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
byte[] buffer = new byte[4];
Span<byte> buffer = stackalloc byte[4];
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float r = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float r = BitConverter.ToSingle(buffer);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float g = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float g = BitConverter.ToSingle(buffer);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float b = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float b = BitConverter.ToSingle(buffer);
offset += 4;
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
float r = BitConverter.ToSingle(buffer, 0);
float r = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float g = BitConverter.ToSingle(buffer, 0);
float g = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float b = BitConverter.ToSingle(buffer, 0);
float b = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
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);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
byte[] buffer = new byte[4];
Span<byte> buffer = stackalloc byte[4];
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float r = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float r = BitConverter.ToSingle(buffer);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float g = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float g = BitConverter.ToSingle(buffer);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float b = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float b = BitConverter.ToSingle(buffer);
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float a = BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float a = BitConverter.ToSingle(buffer);
offset += 4;
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
float r = BitConverter.ToSingle(buffer, 0);
float r = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float g = BitConverter.ToSingle(buffer, 0);
float g = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float b = BitConverter.ToSingle(buffer, 0);
float b = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
data.Slice(offset, 4).CopyTo(buffer);
float a = BitConverter.ToSingle(buffer, 0);
float a = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
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/>
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 colorWhite = default(TPixel);
colorBlack.FromRgba32(Color.Black);
colorWhite.FromRgba32(Color.White);
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);
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++);
nint maxShift = Math.Min(left + width - x, 8);
nuint maxShift = Math.Min((uint)(left + width) - x, 8);
if (maxShift == 8)
{
@ -69,9 +69,9 @@ internal class WhiteIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
}
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);
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);
color.FromScaledVector4(Vector4.Zero);
byte[] buffer = new byte[4];
Span<byte> buffer = stackalloc byte[4];
int offset = 0;
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
Array.Reverse(buffer);
float intensity = 1.0f - BitConverter.ToSingle(buffer, 0);
buffer.Reverse();
float intensity = 1.0f - BitConverter.ToSingle(buffer);
offset += 4;
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++)
{
data.Slice(offset, 4).CopyTo(buffer);
float intensity = 1.0f - BitConverter.ToSingle(buffer, 0);
float intensity = 1.0f - BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
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);
}
if (!tags.TryGetValue(ExifTag.TileWidth, out IExifValue<Number> valueLength))
if (!tags.TryGetValue(ExifTag.TileLength, out IExifValue<Number> valueLength))
{
ArgumentNullException.ThrowIfNull(valueLength);
}

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

Loading…
Cancel
Save