Browse Source

Merge branch 'master' into read-xmp-from-webp

pull/1918/head
James Jackson-South 4 years ago
committed by GitHub
parent
commit
3d981fe72f
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      src/ImageSharp/Advanced/AotCompilerTools.cs
  2. 24
      src/ImageSharp/Color/Color.Conversions.cs
  3. 98
      src/ImageSharp/Common/Helpers/HexConverter.cs
  4. 66
      src/ImageSharp/Common/Helpers/Numerics.cs
  5. 37
      src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
  6. 8
      src/ImageSharp/Formats/ImageExtensions.Save.cs
  7. 1
      src/ImageSharp/Formats/ImageExtensions.Save.tt
  8. 11
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs
  9. 2
      src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs
  10. 6
      src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs
  11. 39
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  12. 23
      src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs
  13. 210
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  14. 12
      src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs
  15. 10
      src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs
  16. 77
      src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs
  17. 68
      src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs
  18. 80
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  19. 13
      src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs
  20. 13
      src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs
  21. 21
      src/ImageSharp/Formats/Tiff/TiffFormatType.cs
  22. 41
      src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs
  23. 5
      src/ImageSharp/Formats/Tiff/TiffMetadata.cs
  24. 2
      src/ImageSharp/Formats/Tiff/TiffThrowHelper.cs
  25. 135
      src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs
  26. 1
      src/ImageSharp/IO/ChunkedMemoryStream.cs
  27. 11
      src/ImageSharp/ImageFrame{TPixel}.cs
  28. 9
      src/ImageSharp/ImageSharp.csproj
  29. 4
      src/ImageSharp/Image{TPixel}.cs
  30. 17
      src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs
  31. 10
      src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs
  32. 2
      src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs
  33. 65
      src/ImageSharp/Memory/Buffer2D{T}.cs
  34. 31
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs
  35. 52
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs
  36. 33
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs
  37. 83
      src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs
  38. 16
      src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs
  39. 17
      src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs
  40. 4
      src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs
  41. 287
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  42. 18
      src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
  43. 5
      src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs
  44. 66
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs
  45. 171
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs
  46. 34
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs
  47. 26
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8.cs
  48. 22
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8Array.cs
  49. 5
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs
  50. 6
      src/ImageSharp/PixelFormats/IPixel.cs
  51. 4
      src/ImageSharp/PixelFormats/PixelImplementations/A8.cs
  52. 396
      src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs
  53. 10
      src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
  54. 10
      src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
  55. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs
  56. 10
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
  57. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs
  58. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs
  59. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs
  60. 4
      src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs
  61. 4
      src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs
  62. 4
      src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
  63. 7
      src/ImageSharp/PixelFormats/PixelImplementations/L16.cs
  64. 4
      src/ImageSharp/PixelFormats/PixelImplementations/L8.cs
  65. 8
      src/ImageSharp/PixelFormats/PixelImplementations/La16.cs
  66. 12
      src/ImageSharp/PixelFormats/PixelImplementations/La32.cs
  67. 4
      src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs
  68. 4
      src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs
  69. 4
      src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs
  70. 4
      src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs
  71. 26
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs
  72. 346
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs
  73. 18
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.tt
  74. 41
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs
  75. 41
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs
  76. 41
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs
  77. 42
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs
  78. 42
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs
  79. 42
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs
  80. 42
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs
  81. 42
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs
  82. 41
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs
  83. 42
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs
  84. 41
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs
  85. 42
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs
  86. 5
      src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude
  87. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs
  88. 9
      src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs
  89. 9
      src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs
  90. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs
  91. 10
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs
  92. 37
      src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs
  93. 4
      src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs
  94. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs
  95. 4
      src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs
  96. 72
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs
  97. 3
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt
  98. 125
      src/ImageSharp/PixelFormats/Utils/PixelConverter.cs
  99. 1
      tests/Directory.Build.targets
  100. 46
      tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs

2
src/ImageSharp/Advanced/AotCompilerTools.cs

@ -75,6 +75,7 @@ namespace SixLabors.ImageSharp.Advanced
Seed<A8>();
Seed<Argb32>();
Seed<Abgr32>();
Seed<Bgr24>();
Seed<Bgr565>();
Seed<Bgra32>();
@ -149,6 +150,7 @@ namespace SixLabors.ImageSharp.Advanced
Image<TPixel> img = default;
img.CloneAs<A8>(default);
img.CloneAs<Argb32>(default);
img.CloneAs<Abgr32>(default);
img.CloneAs<Bgr24>(default);
img.CloneAs<Bgr565>(default);
img.CloneAs<Bgra32>(default);

24
src/ImageSharp/Color/Color.Conversions.cs

@ -89,6 +89,17 @@ namespace SixLabors.ImageSharp
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
/// <param name="pixel">The <see cref="Abgr32"/> containing the color information.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Color(Abgr32 pixel)
{
this.data = new Rgba64(pixel);
this.boxedHighPrecisionPixel = null;
}
/// <summary>
/// Initializes a new instance of the <see cref="Color"/> struct.
/// </summary>
@ -177,6 +188,19 @@ namespace SixLabors.ImageSharp
return value;
}
[MethodImpl(InliningOptions.ShortMethod)]
internal Abgr32 ToAbgr32()
{
if (this.boxedHighPrecisionPixel is null)
{
return this.data.ToAbgr32();
}
Abgr32 value = default;
value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
return value;
}
[MethodImpl(InliningOptions.ShortMethod)]
internal Rgb24 ToRgb24()
{

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

@ -0,0 +1,98 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Common.Helpers
{
internal static class HexConverter
{
/// <summary>
/// Parses a hexadecimal string into a byte array without allocations. Throws on non-hexadecimal character.
/// Adapted from https://source.dot.net/#System.Private.CoreLib/Convert.cs,c9e4fbeaca708991.
/// </summary>
/// <param name="chars">The hexadecimal string to parse.</param>
/// <param name="bytes">The destination for the parsed bytes. Must be at least <paramref name="chars"/>.Length / 2 bytes long.</param>
/// <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)
{
throw new ArgumentException("Input string length must be a multiple of 2", nameof(chars));
}
if ((bytes.Length * 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.Slice(0, chars.Length / 2);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
static int FromChar(int c)
{
// Map from an ASCII char to its hex value, e.g. arr['b'] == 11. 0xFF means it's not a hex digit.
// This doesn't actually allocate.
ReadOnlySpan<byte> charToHexLookup = new byte[]
{
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 15
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 31
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 47
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 63
0xFF, 0xA, 0xB, 0xC, 0xD, 0xE, 0xF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 79
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 95
0xFF, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 111
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 127
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 143
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 159
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 175
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 191
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 207
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 223
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 239
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // 255
};
return c >= charToHexLookup.Length ? 0xFF : charToHexLookup[c];
}
// See https://source.dot.net/#System.Private.CoreLib/HexConverter.cs,4681d45a0aa0b361
int i = 0;
int j = 0;
int byteLo = 0;
int byteHi = 0;
while (j < bytes.Length)
{
byteLo = FromChar(chars[i + 1]);
byteHi = FromChar(chars[i]);
// byteHi hasn't been shifted to the high half yet, so the only way the bitwise or produces this pattern
// is if either byteHi or byteLo was not a hex character.
if ((byteLo | byteHi) == 0xFF)
{
break;
}
bytes[j++] = (byte)((byteHi << 4) | byteLo);
i += 2;
}
if (byteLo == 0xFF)
{
i++;
}
if ((byteLo | byteHi) == 0xFF)
{
throw new ArgumentException("Input string contained non-hexadecimal characters", nameof(chars));
}
return j;
}
}
}

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

@ -907,5 +907,71 @@ namespace SixLabors.ImageSharp
/// <param name="divisor">Divisor value.</param>
/// <returns>Ceiled division result.</returns>
public static uint DivideCeil(uint value, uint divisor) => (value + divisor - 1) / divisor;
/// <summary>
/// Rotates the specified value left by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateLeft(uint value, int offset)
{
#if SUPPORTS_BITOPERATIONS
return BitOperations.RotateLeft(value, offset);
#else
return RotateLeftSoftwareFallback(value, offset);
#endif
}
#if !SUPPORTS_BITOPERATIONS
/// <summary>
/// Rotates the specified value left by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateLeftSoftwareFallback(uint value, int offset)
=> (value << offset) | (value >> (32 - offset));
#endif
/// <summary>
/// Rotates the specified value right by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateRight(uint value, int offset)
{
#if SUPPORTS_BITOPERATIONS
return BitOperations.RotateRight(value, offset);
#else
return RotateRightSoftwareFallback(value, offset);
#endif
}
#if !SUPPORTS_BITOPERATIONS
/// <summary>
/// Rotates the specified value right by the specified number of bits.
/// </summary>
/// <param name="value">The value to rotate.</param>
/// <param name="offset">The number of bits to rotate with.</param>
/// <returns>The rotated value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint RotateRightSoftwareFallback(uint value, int offset)
=> (value >> offset) | (value << (32 - offset));
#endif
/// <summary>
/// Tells whether input value is outside of the given range.
/// </summary>
/// <param name="value">Value.</param>
/// <param name="min">Mininum value, inclusive.</param>
/// <param name="max">Maximum value, inclusive.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool IsOutOfRange(int value, int min, int max)
=> (uint)(value - min) > (uint)(max - min);
}
}

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

@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp
// packed = [W Z Y X]
// ROTR(8, packedArgb) = [Y Z W X]
Unsafe.Add(ref dBase, i) = (packed >> 8) | (packed << 24);
Unsafe.Add(ref dBase, i) = Numerics.RotateRight(packed, 8);
}
}
}
@ -188,7 +188,40 @@ namespace SixLabors.ImageSharp
// tmp1 + tmp3 = [W X Y Z]
uint tmp1 = packed & 0xFF00FF00;
uint tmp2 = packed & 0x00FF00FF;
uint tmp3 = (tmp2 << 16) | (tmp2 >> 16);
uint tmp3 = Numerics.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}
}
}
internal readonly struct XWZYShuffle4 : IShuffle4
{
public byte Control
{
[MethodImpl(InliningOptions.ShortMethod)]
get => SimdUtils.Shuffle.MmShuffle(1, 2, 3, 0);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
{
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;
for (int i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// tmp1 = [0 Z 0 X]
// tmp2 = [W 0 Y 0]
// tmp3=ROTL(16, tmp2) = [Y 0 W 0]
// tmp1 + tmp3 = [Y Z W X]
uint tmp1 = packed & 0x00FF00FF;
uint tmp2 = packed & 0xFF00FF00;
uint tmp3 = Numerics.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}

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

@ -105,7 +105,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder)
=> source.Save(
stream,
@ -208,7 +207,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder)
=> source.Save(
stream,
@ -311,7 +309,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder)
=> source.Save(
stream,
@ -414,7 +411,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsPbm(this Image source, Stream stream, PbmEncoder encoder)
=> source.Save(
stream,
@ -517,7 +513,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder)
=> source.Save(
stream,
@ -620,7 +615,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsTga(this Image source, Stream stream, TgaEncoder encoder)
=> source.Save(
stream,
@ -723,7 +717,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsWebp(this Image source, Stream stream, WebpEncoder encoder)
=> source.Save(
stream,
@ -826,7 +819,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAsTiff(this Image source, Stream stream, TiffEncoder encoder)
=> source.Save(
stream,

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

@ -124,7 +124,6 @@ namespace SixLabors.ImageSharp
/// <param name="stream">The stream to save the image to.</param>
/// <param name="encoder">The encoder to save the image with.</param>
/// <exception cref="System.ArgumentNullException">Thrown if the stream is null.</exception>
/// <returns>A <see cref="Task"/> representing the asynchronous operation.</returns>
public static void SaveAs<#= fmt #>(this Image source, Stream stream, <#= fmt #>Encoder encoder)
=> source.Save(
stream,

11
src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegComponent.cs

@ -19,21 +19,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.Frame = frame;
this.Id = id;
// Validate sampling factors.
if (horizontalFactor == 0 || verticalFactor == 0)
{
JpegThrowHelper.ThrowBadSampling();
}
this.HorizontalSamplingFactor = horizontalFactor;
this.VerticalSamplingFactor = verticalFactor;
this.SamplingFactors = new Size(this.HorizontalSamplingFactor, this.VerticalSamplingFactor);
if (quantizationTableIndex > 3)
{
JpegThrowHelper.ThrowBadQuantizationTableIndex(quantizationTableIndex);
}
this.QuantizationTableIndex = quantizationTableIndex;
this.Index = index;
}

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

@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
// PackFromRgbPlanes expects the destination to be padded, so try to get padded span containing extra elements from the next row.
// If we can't get such a padded row because we are on a MemoryGroup boundary or at the last row,
// pack pixels to a temporary, padded proxy buffer, then copy the relevant values to the destination row.
if (this.pixelBuffer.TryGetPaddedRowSpan(yy, 3, out Span<TPixel> destRow))
if (this.pixelBuffer.DangerousTryGetPaddedRowSpan(yy, 3, out Span<TPixel> destRow))
{
PixelOperations<TPixel>.Instance.PackFromRgbPlanes(this.configuration, r, g, b, destRow);
}

6
src/ImageSharp/Formats/Jpeg/Components/FastFloatingPointDCT.cs

@ -146,11 +146,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
/// <summary>
/// Apply floating point IDCT inplace using <see cref="Vector4"/> API.
/// </summary>
/// <remarks>
/// This method can be used even if there's no SIMD intrinsics available
/// as <see cref="Vector4"/> can be compiled to scalar instructions.
/// </remarks>
/// <param name="transposedBlock">Input block.</param>
private static void IDCT_Vector4(ref Block8x8F transposedBlock)
{
DebugGuard.IsTrue(Vector.IsHardwareAccelerated, "Scalar implementation should be called for non-accelerated hardware.");
// First pass - process columns
IDCT8x4_Vector4(ref transposedBlock.V0L);
IDCT8x4_Vector4(ref transposedBlock.V0R);

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

@ -485,7 +485,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
: JpegColorSpace.Cmyk;
}
JpegThrowHelper.ThrowInvalidImageContentException($"Unsupported color mode. Supported component counts 1, 3, and 4; found {componentCount}");
JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount);
return default;
}
@ -1039,6 +1039,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
// 1 byte: Number of components
byte componentCount = this.temp[5];
// Validate: componentCount more than 4 can lead to a buffer overflow during stream
// reading so we must limit it to 4
// We do not support jpeg images with more than 4 components anyway
if (componentCount > 4)
{
JpegThrowHelper.ThrowNotSupportedComponentCount(componentCount);
}
this.Frame = new JpegFrame(frameMarker, precision, frameWidth, frameHeight, componentCount);
remaining -= length;
@ -1063,10 +1071,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
int index = 0;
for (int i = 0; i < componentCount; i++)
{
// 1 byte: component identifier
byte componentId = this.temp[index];
// 1 byte: component sampling factors
byte hv = this.temp[index + 1];
int h = (hv >> 4) & 15;
int v = hv & 15;
// Validate: 1-4 range
if (Numerics.IsOutOfRange(h, 1, 4))
{
JpegThrowHelper.ThrowBadSampling(h);
}
// Validate: 1-4 range
if (Numerics.IsOutOfRange(v, 1, 4))
{
JpegThrowHelper.ThrowBadSampling(v);
}
if (maxH < h)
{
maxH = h;
@ -1077,10 +1101,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
maxV = v;
}
var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, this.temp[index], h, v, this.temp[index + 2], i);
// 1 byte: quantization table destination selector
byte quantTableIndex = this.temp[index + 2];
// Validate: 0-3 range
if (quantTableIndex > 3)
{
JpegThrowHelper.ThrowBadQuantizationTableIndex(quantTableIndex);
}
var component = new JpegComponent(this.Configuration.MemoryAllocator, this.Frame, componentId, h, v, quantTableIndex, i);
this.Frame.Components[i] = component;
this.Frame.ComponentIds[i] = component.Id;
this.Frame.ComponentIds[i] = componentId;
index += componentBytes;
}

23
src/ImageSharp/Formats/Jpeg/JpegThrowHelper.cs

@ -22,23 +22,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowInvalidImageContentException(string errorMessage) => throw new InvalidImageContentException(errorMessage);
/// <summary>
/// Cold path optimization for throwing <see cref="InvalidImageContentException"/>'s.
/// </summary>
/// <param name="errorMessage">The error message for the exception.</param>
/// <param name="innerException">The exception that is the cause of the current exception, or a null reference
/// if no inner exception is specified.</param>
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowInvalidImageContentException(string errorMessage, Exception innerException) => throw new InvalidImageContentException(errorMessage, innerException);
/// <summary>
/// Cold path optimization for throwing <see cref="NotImplementedException"/>'s
/// </summary>
/// <param name="errorMessage">The error message for the exception.</param>
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowNotImplementedException(string errorMessage)
=> throw new NotImplementedException(errorMessage);
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowBadMarker(string marker, int length) => throw new InvalidImageContentException($"Marker {marker} has bad length {length}.");
@ -51,6 +34,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowBadSampling() => throw new InvalidImageContentException("Bad sampling factor.");
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowBadSampling(int factor) => throw new InvalidImageContentException($"Bad sampling factor: {factor}");
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowBadProgressiveScan(int ss, int se, int ah, int al) => throw new InvalidImageContentException($"Invalid progressive parameters Ss={ss} Se={se} Ah={ah} Al={al}.");
@ -59,5 +45,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowDimensionsTooLarge(int width, int height) => throw new ImageFormatException($"Image is too large to encode at {width}x{height} for JPEG format.");
[MethodImpl(InliningOptions.ColdPath)]
public static void ThrowNotSupportedComponentCount(int componentCount) => throw new NotSupportedException($"Images with {componentCount} components are not supported.");
}
}

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

@ -11,6 +11,7 @@ using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Compression.Zlib;
using SixLabors.ImageSharp.Formats.Png.Chunks;
using SixLabors.ImageSharp.Formats.Png.Filters;
@ -188,10 +189,10 @@ namespace SixLabors.ImageSharp.Formats.Png
this.AssignTransparentMarkers(alpha, pngMetadata);
break;
case PngChunkType.Text:
this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan());
this.ReadTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.CompressedText:
this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan());
this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.InternationalText:
this.ReadInternationalTextChunk(metadata, chunk.Data.GetSpan());
@ -201,7 +202,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
byte[] exifData = new byte[chunk.Length];
chunk.Data.GetSpan().CopyTo(exifData);
metadata.ExifProfile = new ExifProfile(exifData);
this.MergeOrSetExifProfile(metadata, new ExifProfile(exifData), replaceExistingKeys: true);
}
break;
@ -298,7 +299,7 @@ namespace SixLabors.ImageSharp.Formats.Png
break;
}
this.ReadTextChunk(pngMetadata, chunk.Data.GetSpan());
this.ReadTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.CompressedText:
if (this.colorMetadataOnly)
@ -307,7 +308,7 @@ namespace SixLabors.ImageSharp.Formats.Png
break;
}
this.ReadCompressedTextChunk(pngMetadata, chunk.Data.GetSpan());
this.ReadCompressedTextChunk(metadata, pngMetadata, chunk.Data.GetSpan());
break;
case PngChunkType.InternationalText:
if (this.colorMetadataOnly)
@ -329,7 +330,7 @@ namespace SixLabors.ImageSharp.Formats.Png
{
byte[] exifData = new byte[chunk.Length];
chunk.Data.GetSpan().CopyTo(exifData);
metadata.ExifProfile = new ExifProfile(exifData);
this.MergeOrSetExifProfile(metadata, new ExifProfile(exifData), replaceExistingKeys: true);
}
break;
@ -968,9 +969,10 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary>
/// Reads a text chunk containing image properties from the data.
/// </summary>
/// <param name="baseMetadata">The <see cref="ImageMetadata"/> object.</param>
/// <param name="metadata">The metadata to decode to.</param>
/// <param name="data">The <see cref="T:Span"/> containing the data.</param>
private void ReadTextChunk(PngMetadata metadata, ReadOnlySpan<byte> data)
private void ReadTextChunk(ImageMetadata baseMetadata, PngMetadata metadata, ReadOnlySpan<byte> data)
{
if (this.ignoreMetadata)
{
@ -993,15 +995,19 @@ namespace SixLabors.ImageSharp.Formats.Png
string value = PngConstants.Encoding.GetString(data.Slice(zeroIndex + 1));
metadata.TextData.Add(new PngTextData(name, value, string.Empty, string.Empty));
if (!this.TryReadTextChunkMetadata(baseMetadata, name, value))
{
metadata.TextData.Add(new PngTextData(name, value, string.Empty, string.Empty));
}
}
/// <summary>
/// Reads the compressed text chunk. Contains a uncompressed keyword and a compressed text string.
/// </summary>
/// <param name="baseMetadata">The <see cref="ImageMetadata"/> object.</param>
/// <param name="metadata">The metadata to decode to.</param>
/// <param name="data">The <see cref="T:Span"/> containing the data.</param>
private void ReadCompressedTextChunk(PngMetadata metadata, ReadOnlySpan<byte> data)
private void ReadCompressedTextChunk(ImageMetadata baseMetadata, PngMetadata metadata, ReadOnlySpan<byte> data)
{
if (this.ignoreMetadata)
{
@ -1029,12 +1035,185 @@ namespace SixLabors.ImageSharp.Formats.Png
ReadOnlySpan<byte> compressedData = data.Slice(zeroIndex + 2);
if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed))
if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string uncompressed) &&
!this.TryReadTextChunkMetadata(baseMetadata, name, uncompressed))
{
metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty));
}
}
/// <summary>
/// Checks if the given text chunk is actually storing parsable metadata.
/// </summary>
/// <param name="baseMetadata">The <see cref="ImageMetadata"/> object to store the parsed metadata in.</param>
/// <param name="chunkName">The name of the text chunk.</param>
/// <param name="chunkText">The contents of the text chunk.</param>
/// <returns>True if metadata was successfully parsed from the text chunk. False if the
/// text chunk was not identified as metadata, and should be stored in the metadata
/// object unmodified.</returns>
private bool TryReadTextChunkMetadata(ImageMetadata baseMetadata, string chunkName, string chunkText)
{
if (chunkName.Equals("Raw profile type exif", StringComparison.OrdinalIgnoreCase) &&
this.TryReadLegacyExifTextChunk(baseMetadata, chunkText))
{
// Successfully parsed legacy exif data from text
return true;
}
// TODO: "Raw profile type iptc", potentially others?
// No special chunk data identified
return false;
}
/// <summary>
/// Reads exif data encoded into a text chunk with the name "raw profile type exif".
/// This method was used by ImageMagick, exiftool, exiv2, digiKam, etc, before the
/// 2017 update to png that allowed a true exif chunk.
/// </summary>
/// <param name="metadata">The <see cref="ImageMetadata"/> to store the decoded exif tags into.</param>
/// <param name="data">The contents of the "raw profile type exif" text chunk.</param>
private bool TryReadLegacyExifTextChunk(ImageMetadata metadata, string data)
{
ReadOnlySpan<char> dataSpan = data.AsSpan();
dataSpan = dataSpan.TrimStart();
if (!StringEqualsInsensitive(dataSpan.Slice(0, 4), "exif".AsSpan()))
{
// "exif" identifier is missing from the beginning of the text chunk
return false;
}
// Skip to the data length
dataSpan = dataSpan.Slice(4).TrimStart();
int dataLengthEnd = dataSpan.IndexOf('\n');
int dataLength = ParseInt32(dataSpan.Slice(0, dataSpan.IndexOf('\n')));
// Skip to the hex-encoded data
dataSpan = dataSpan.Slice(dataLengthEnd).Trim();
// Sequence of bytes for the exif header ("Exif" ASCII and two zero bytes).
// This doesn't actually allocate.
ReadOnlySpan<byte> exifHeader = new byte[] { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
if (dataLength < exifHeader.Length)
{
// Not enough room for the required exif header, this data couldn't possibly be valid
return false;
}
// Parse the hex-encoded data into the byte array we are going to hand off to ExifProfile
byte[] exifBlob = new byte[dataLength - exifHeader.Length];
try
{
// Check for the presence of the exif header in the hex-encoded binary data
byte[] tempExifBuf = exifBlob;
if (exifBlob.Length < exifHeader.Length)
{
// Need to allocate a temporary array, this should be an extremely uncommon (TODO: impossible?) case
tempExifBuf = new byte[exifHeader.Length];
}
HexConverter.HexStringToBytes(dataSpan.Slice(0, exifHeader.Length * 2), tempExifBuf);
if (!tempExifBuf.AsSpan().Slice(0, exifHeader.Length).SequenceEqual(exifHeader))
{
// Exif header in the hex data is not valid
return false;
}
// Skip over the exif header we just tested
dataSpan = dataSpan.Slice(exifHeader.Length * 2);
dataLength -= exifHeader.Length;
// Load the hex-encoded data, one line at a time
for (int i = 0; i < dataLength;)
{
ReadOnlySpan<char> lineSpan = dataSpan;
int newlineIndex = dataSpan.IndexOf('\n');
if (newlineIndex != -1)
{
lineSpan = dataSpan.Slice(0, newlineIndex);
}
i += HexConverter.HexStringToBytes(lineSpan, exifBlob.AsSpan().Slice(i));
dataSpan = dataSpan.Slice(newlineIndex + 1);
}
}
catch
{
return false;
}
this.MergeOrSetExifProfile(metadata, new ExifProfile(exifBlob), replaceExistingKeys: false);
return true;
}
/// <summary>
/// Compares two ReadOnlySpan&lt;char&gt;s in a case-insensitive method.
/// This is only needed because older frameworks are missing the extension method.
/// </summary>
/// <param name="span1">The first <see cref="Span{T}"/> to compare.</param>
/// <param name="span2">The second <see cref="Span{T}"/> to compare.</param>
/// <returns>True if the spans were identical, false otherwise.</returns>
private static bool StringEqualsInsensitive(ReadOnlySpan<char> span1, ReadOnlySpan<char> span2)
{
#pragma warning disable IDE0022 // Use expression body for methods
#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER
return span1.Equals(span2, StringComparison.OrdinalIgnoreCase);
#else
return span1.ToString().Equals(span2.ToString(), StringComparison.OrdinalIgnoreCase);
#endif
#pragma warning restore IDE0022 // Use expression body for methods
}
/// <summary>
/// int.Parse() a ReadOnlySpan&lt;char&gt;, with a fallback for older frameworks.
/// </summary>
/// <param name="span">The <see cref="int"/> to parse.</param>
/// <returns>The parsed <see cref="int"/>.</returns>
private static int ParseInt32(ReadOnlySpan<char> span)
{
#pragma warning disable IDE0022 // Use expression body for methods
#if NETSTANDARD2_1 || NETCOREAPP2_1_OR_GREATER
return int.Parse(span);
#else
return int.Parse(span.ToString());
#endif
#pragma warning restore IDE0022 // Use expression body for methods
}
/// <summary>
/// Sets the <see cref="ExifProfile"/> in <paramref name="metadata"/> to <paramref name="newProfile"/>,
/// or copies exif tags if <paramref name="metadata"/> already contains an <see cref="ExifProfile"/>.
/// </summary>
/// <param name="metadata">The <see cref="ImageMetadata"/> to store the exif data in.</param>
/// <param name="newProfile">The <see cref="ExifProfile"/> to copy exif tags from.</param>
/// <param name="replaceExistingKeys">If <paramref name="metadata"/> already contains an <see cref="ExifProfile"/>,
/// controls whether existing exif tags in <paramref name="metadata"/> will be overwritten with any conflicting
/// tags from <paramref name="newProfile"/>.</param>
private void MergeOrSetExifProfile(ImageMetadata metadata, ExifProfile newProfile, bool replaceExistingKeys)
{
if (metadata.ExifProfile is null)
{
// No exif metadata was loaded yet, so just assign it
metadata.ExifProfile = newProfile;
}
else
{
// Try to merge existing keys with the ones from the new profile
foreach (IExifValue newKey in newProfile.Values)
{
if (replaceExistingKeys || metadata.ExifProfile.GetValueInternal(newKey.Tag) is null)
{
metadata.ExifProfile.SetValueInternal(newKey.Tag, newKey.GetValue());
}
}
}
}
/// <summary>
/// Reads a iTXt chunk, which contains international text data. It contains:
/// - A uncompressed keyword.
@ -1213,16 +1392,16 @@ namespace SixLabors.ImageSharp.Formats.Png
PngChunkType type = this.ReadChunkType();
// NOTE: Reading the Data chunk is the responsible of the caller
// 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.
if (type == PngChunkType.Data || (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency))
if (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency)
{
chunk = new PngChunk(length, type);
return true;
}
long pos = this.currentStream.Position;
chunk = new PngChunk(
length: length,
type: type,
@ -1230,6 +1409,13 @@ namespace SixLabors.ImageSharp.Formats.Png
this.ValidateChunk(chunk);
// Restore the stream position for IDAT chunks, because it will be decoded later and
// was only read to verifying the CRC is correct.
if (type == PngChunkType.Data)
{
this.currentStream.Position = pos;
}
return true;
}

12
src/ImageSharp/Formats/Tiff/Compression/TiffBaseDecompressor.cs

@ -34,17 +34,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Compression
/// <param name="stripByteCount">The number of bytes to read from the input stream.</param>
/// <param name="stripHeight">The height of the strip.</param>
/// <param name="buffer">The output buffer for uncompressed data.</param>
public void Decompress(BufferedReadStream stream, uint stripOffset, uint stripByteCount, int stripHeight, Span<byte> buffer)
public void Decompress(BufferedReadStream stream, ulong stripOffset, ulong stripByteCount, int stripHeight, Span<byte> buffer)
{
if (stripByteCount > int.MaxValue)
{
TiffThrowHelper.ThrowImageFormatException("The StripByteCount value is too big.");
}
DebugGuard.MustBeLessThanOrEqualTo(stripOffset, (ulong)long.MaxValue, nameof(stripOffset));
DebugGuard.MustBeLessThanOrEqualTo(stripByteCount, (ulong)long.MaxValue, nameof(stripByteCount));
stream.Seek(stripOffset, SeekOrigin.Begin);
stream.Seek((long)stripOffset, SeekOrigin.Begin);
this.Decompress(stream, (int)stripByteCount, stripHeight, buffer);
if (stripOffset + stripByteCount < stream.Position)
if ((long)stripOffset + (long)stripByteCount < stream.Position)
{
TiffThrowHelper.ThrowImageFormatException("Out of range when reading a strip.");
}

10
src/ImageSharp/Formats/Tiff/Constants/TiffConstants.cs

@ -35,6 +35,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.Constants
/// </summary>
public const ushort HeaderMagicNumber = 42;
/// <summary>
/// The big tiff header magic number
/// </summary>
public const ushort BigTiffHeaderMagicNumber = 43;
/// <summary>
/// The big tiff bytesize of offsets value.
/// </summary>
public const ushort BigTiffBytesize = 8;
/// <summary>
/// RowsPerStrip default value, which is effectively infinity.
/// </summary>

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

@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.IO;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Formats.Tiff
@ -14,23 +15,27 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
internal class DirectoryReader
{
private readonly Stream stream;
private const int DirectoryMax = 65534;
private uint nextIfdOffset;
private readonly Stream stream;
private const int DirectoryMax = 65534;
private readonly MemoryAllocator allocator;
// used for sequential read big values (actual for multiframe big files)
// todo: different tags can link to the same data (stream offset) - investigate
private readonly SortedList<uint, Action> lazyLoaders = new(new DuplicateKeyComparer<uint>());
private ulong nextIfdOffset;
public DirectoryReader(Stream stream) => this.stream = stream;
public DirectoryReader(Stream stream, MemoryAllocator allocator)
{
this.stream = stream;
this.allocator = allocator;
}
/// <summary>
/// Gets the byte order.
/// </summary>
public ByteOrder ByteOrder { get; private set; }
public bool IsBigTiff { get; private set; }
/// <summary>
/// Reads image file directories.
/// </summary>
@ -38,14 +43,19 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public IEnumerable<ExifProfile> Read()
{
this.ByteOrder = ReadByteOrder(this.stream);
this.nextIfdOffset = new HeaderReader(this.stream, this.ByteOrder).ReadFileHeader();
return this.ReadIfds();
var headerReader = new HeaderReader(this.stream, this.ByteOrder);
headerReader.ReadFileHeader();
this.nextIfdOffset = headerReader.FirstIfdOffset;
this.IsBigTiff = headerReader.IsBigTiff;
return this.ReadIfds(headerReader.IsBigTiff);
}
private static ByteOrder ReadByteOrder(Stream stream)
{
var headerBytes = new byte[2];
stream.Read(headerBytes, 0, 2);
Span<byte> headerBytes = stackalloc byte[2];
stream.Read(headerBytes);
if (headerBytes[0] == TiffConstants.ByteOrderLittleEndian && headerBytes[1] == TiffConstants.ByteOrderLittleEndian)
{
return ByteOrder.LittleEndian;
@ -59,16 +69,26 @@ namespace SixLabors.ImageSharp.Formats.Tiff
throw TiffThrowHelper.ThrowInvalidHeader();
}
private IEnumerable<ExifProfile> ReadIfds()
private IEnumerable<ExifProfile> ReadIfds(bool isBigTiff)
{
var readers = new List<EntryReader>();
while (this.nextIfdOffset != 0 && this.nextIfdOffset < this.stream.Length)
while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length)
{
var reader = new EntryReader(this.stream, this.ByteOrder, this.nextIfdOffset, this.lazyLoaders);
reader.ReadTags();
var reader = new EntryReader(this.stream, this.ByteOrder, this.allocator);
reader.ReadTags(isBigTiff, this.nextIfdOffset);
this.nextIfdOffset = reader.NextIfdOffset;
if (reader.BigValues.Count > 0)
{
reader.BigValues.Sort((t1, t2) => t1.Offset.CompareTo(t2.Offset));
// this means that most likely all elements are placed before next IFD
if (reader.BigValues[0].Offset < reader.NextIfdOffset)
{
reader.ReadBigValues();
}
}
this.nextIfdOffset = reader.NextIfdOffset;
readers.Add(reader);
if (readers.Count >= DirectoryMax)
@ -77,36 +97,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff
}
}
// Sequential reading big values.
foreach (Action loader in this.lazyLoaders.Values)
{
loader();
}
var list = new List<ExifProfile>();
var list = new List<ExifProfile>(readers.Count);
foreach (EntryReader reader in readers)
{
reader.ReadBigValues();
var profile = new ExifProfile(reader.Values, reader.InvalidTags);
list.Add(profile);
}
return list;
}
/// <summary>
/// <see cref="DuplicateKeyComparer{TKey}"/> used for possibility add a duplicate offsets (but tags don't duplicate).
/// </summary>
/// <typeparam name="TKey">The type of the key.</typeparam>
private class DuplicateKeyComparer<TKey> : IComparer<TKey>
where TKey : IComparable
{
public int Compare(TKey x, TKey y)
{
int result = x.CompareTo(y);
// Handle equality as being greater.
return (result == 0) ? 1 : result;
}
}
}
}

68
src/ImageSharp/Formats/Tiff/Ifd/EntryReader.cs

@ -1,64 +1,78 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.IO;
using SixLabors.ImageSharp.Formats.Tiff.Constants;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
namespace SixLabors.ImageSharp.Formats.Tiff
{
internal class EntryReader : BaseExifReader
{
private readonly uint startOffset;
private readonly SortedList<uint, Action> lazyLoaders;
public EntryReader(Stream stream, ByteOrder byteOrder, uint ifdOffset, SortedList<uint, Action> lazyLoaders)
: base(stream)
{
public EntryReader(Stream stream, ByteOrder byteOrder, MemoryAllocator allocator)
: base(stream, allocator) =>
this.IsBigEndian = byteOrder == ByteOrder.BigEndian;
this.startOffset = ifdOffset;
this.lazyLoaders = lazyLoaders;
}
public List<IExifValue> Values { get; } = new();
public uint NextIfdOffset { get; private set; }
public ulong NextIfdOffset { get; private set; }
public void ReadTags()
public void ReadTags(bool isBigTiff, ulong ifdOffset)
{
this.ReadValues(this.Values, this.startOffset);
this.NextIfdOffset = this.ReadUInt32();
if (!isBigTiff)
{
this.ReadValues(this.Values, (uint)ifdOffset);
this.NextIfdOffset = this.ReadUInt32();
this.ReadSubIfd(this.Values);
}
else
{
this.ReadValues64(this.Values, ifdOffset);
this.NextIfdOffset = this.ReadUInt64();
this.ReadSubIfd(this.Values);
//// this.ReadSubIfd64(this.Values);
}
}
protected override void RegisterExtLoader(uint offset, Action reader) =>
this.lazyLoaders.Add(offset, reader);
public void ReadBigValues() => this.ReadBigValues(this.Values);
}
internal class HeaderReader : BaseExifReader
{
public HeaderReader(Stream stream, ByteOrder byteOrder)
: base(stream) =>
: base(stream, null) =>
this.IsBigEndian = byteOrder == ByteOrder.BigEndian;
public uint FirstIfdOffset { get; private set; }
public bool IsBigTiff { get; private set; }
public uint ReadFileHeader()
public ulong FirstIfdOffset { get; private set; }
public void ReadFileHeader()
{
ushort magic = this.ReadUInt16();
if (magic != TiffConstants.HeaderMagicNumber)
if (magic == TiffConstants.HeaderMagicNumber)
{
TiffThrowHelper.ThrowInvalidHeader();
this.IsBigTiff = false;
this.FirstIfdOffset = this.ReadUInt32();
return;
}
else if (magic == TiffConstants.BigTiffHeaderMagicNumber)
{
this.IsBigTiff = true;
this.FirstIfdOffset = this.ReadUInt32();
return this.FirstIfdOffset;
}
ushort bytesize = this.ReadUInt16();
ushort reserve = this.ReadUInt16();
if (bytesize == TiffConstants.BigTiffBytesize && reserve == 0)
{
this.FirstIfdOffset = this.ReadUInt64();
return;
}
}
protected override void RegisterExtLoader(uint offset, Action reader) => throw new NotSupportedException();
TiffThrowHelper.ThrowInvalidHeader();
}
}
}

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

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
@ -42,6 +43,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
private ByteOrder byteOrder;
/// <summary>
/// Indicating whether is BigTiff format.
/// </summary>
private bool isBigTiff;
/// <summary>
/// Initializes a new instance of the <see cref="TiffDecoderCore" /> class.
/// </summary>
@ -142,10 +148,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
where TPixel : unmanaged, IPixel<TPixel>
{
this.inputStream = stream;
var reader = new DirectoryReader(stream);
var reader = new DirectoryReader(stream, this.Configuration.MemoryAllocator);
IEnumerable<ExifProfile> directories = reader.Read();
this.byteOrder = reader.ByteOrder;
this.isBigTiff = reader.IsBigTiff;
var frames = new List<ImageFrame<TPixel>>();
foreach (ExifProfile ifd in directories)
@ -155,7 +162,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
frames.Add(frame);
}
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(frames, this.ignoreMetadata, reader.ByteOrder);
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(frames, this.ignoreMetadata, reader.ByteOrder, reader.IsBigTiff);
// TODO: Tiff frames can have different sizes
ImageFrame<TPixel> root = frames[0];
@ -175,13 +182,13 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public IImageInfo Identify(BufferedReadStream stream, CancellationToken cancellationToken)
{
this.inputStream = stream;
var reader = new DirectoryReader(stream);
var reader = new DirectoryReader(stream, this.Configuration.MemoryAllocator);
IEnumerable<ExifProfile> directories = reader.Read();
ExifProfile rootFrameExifProfile = directories.First();
var rootMetadata = TiffFrameMetadata.Parse(rootFrameExifProfile);
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(reader.ByteOrder, rootFrameExifProfile);
ImageMetadata metadata = TiffDecoderMetadataCreator.Create(reader.ByteOrder, reader.IsBigTiff, rootFrameExifProfile);
int width = GetImageWidth(rootFrameExifProfile);
int height = GetImageHeight(rootFrameExifProfile);
@ -214,21 +221,58 @@ namespace SixLabors.ImageSharp.Formats.Tiff
var frame = new ImageFrame<TPixel>(this.Configuration, width, height, imageFrameMetaData);
int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity;
Number[] stripOffsets = tags.GetValue(ExifTag.StripOffsets)?.Value;
Number[] stripByteCounts = tags.GetValue(ExifTag.StripByteCounts)?.Value;
var stripOffsetsArray = (Array)tags.GetValueInternal(ExifTag.StripOffsets).GetValue();
var stripByteCountsArray = (Array)tags.GetValueInternal(ExifTag.StripByteCounts).GetValue();
IMemoryOwner<ulong> stripOffsetsMemory = this.ConvertNumbers(stripOffsetsArray, out Span<ulong> stripOffsets);
IMemoryOwner<ulong> stripByteCountsMemory = this.ConvertNumbers(stripByteCountsArray, out Span<ulong> stripByteCounts);
if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar)
{
this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken);
this.DecodeStripsPlanar(
frame,
rowsPerStrip,
stripOffsets,
stripByteCounts,
cancellationToken);
}
else
{
this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken);
this.DecodeStripsChunky(
frame,
rowsPerStrip,
stripOffsets,
stripByteCounts,
cancellationToken);
}
stripOffsetsMemory?.Dispose();
stripByteCountsMemory?.Dispose();
return frame;
}
private IMemoryOwner<ulong> ConvertNumbers(Array array, out Span<ulong> span)
{
if (array is Number[] numbers)
{
IMemoryOwner<ulong> memory = this.memoryAllocator.Allocate<ulong>(numbers.Length);
span = memory.GetSpan();
for (int i = 0; i < numbers.Length; i++)
{
span[i] = (uint)numbers[i];
}
return memory;
}
else
{
DebugGuard.IsTrue(array is ulong[], $"Expected {nameof(UInt64)} array.");
span = (ulong[])array;
return null;
}
}
/// <summary>
/// Calculates the size (in bytes) for a pixel buffer using the determined color format.
/// </summary>
@ -279,7 +323,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="stripOffsets">An array of byte offsets to each strip in the image.</param>
/// <param name="stripByteCounts">An array of the size of each strip (in bytes).</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken)
private void DecodeStripsPlanar<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Span<ulong> stripOffsets, Span<ulong> stripByteCounts, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
int stripsPerPixel = this.BitsPerSample.Channels;
@ -332,10 +376,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
{
decompressor.Decompress(
this.inputStream,
(uint)stripOffsets[stripIndex],
(uint)stripByteCounts[stripIndex],
stripOffsets[stripIndex],
stripByteCounts[stripIndex],
stripHeight,
stripBuffers[planeIndex].GetSpan());
stripIndex += stripsPerPlane;
}
@ -360,7 +405,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="stripOffsets">The strip offsets.</param>
/// <param name="stripByteCounts">The strip byte counts.</param>
/// <param name="cancellationToken">The token to monitor cancellation.</param>
private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Number[] stripOffsets, Number[] stripByteCounts, CancellationToken cancellationToken)
private void DecodeStripsChunky<TPixel>(ImageFrame<TPixel> frame, int rowsPerStrip, Span<ulong> stripOffsets, Span<ulong> stripByteCounts, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
// If the rowsPerStrip has the default value, which is effectively infinity. That is, the entire image is one strip.
@ -373,7 +418,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
int bitsPerPixel = this.BitsPerPixel;
using IMemoryOwner<byte> stripBuffer = this.memoryAllocator.Allocate<byte>(uncompressedStripSize, AllocationOptions.Clean);
System.Span<byte> stripBufferSpan = stripBuffer.GetSpan();
Span<byte> stripBufferSpan = stripBuffer.GetSpan();
Buffer2D<TPixel> pixels = frame.PixelBuffer;
using TiffBaseDecompressor decompressor = TiffDecompressorsFactory.Create(
@ -416,7 +461,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
break;
}
decompressor.Decompress(this.inputStream, (uint)stripOffsets[stripIndex], (uint)stripByteCounts[stripIndex], stripHeight, stripBufferSpan);
decompressor.Decompress(
this.inputStream,
stripOffsets[stripIndex],
stripByteCounts[stripIndex],
stripHeight,
stripBufferSpan);
colorDecoder.Decode(stripBufferSpan, pixels, 0, top, frame.Width, stripHeight);
}
@ -435,6 +485,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowImageFormatException("The TIFF image frame is missing the ImageWidth");
}
DebugGuard.MustBeLessThanOrEqualTo((ulong)width.Value, (ulong)int.MaxValue, nameof(ExifTag.ImageWidth));
return (int)width.Value;
}

13
src/ImageSharp/Formats/Tiff/TiffDecoderMetadataCreator.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
internal static class TiffDecoderMetadataCreator
{
public static ImageMetadata Create<TPixel>(List<ImageFrame<TPixel>> frames, bool ignoreMetadata, ByteOrder byteOrder)
public static ImageMetadata Create<TPixel>(List<ImageFrame<TPixel>> frames, bool ignoreMetadata, ByteOrder byteOrder, bool isBigTiff)
where TPixel : unmanaged, IPixel<TPixel>
{
if (frames.Count < 1)
@ -27,13 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
TiffThrowHelper.ThrowImageFormatException("Expected at least one frame.");
}
var imageMetaData = new ImageMetadata();
ExifProfile exifProfileRootFrame = frames[0].Metadata.ExifProfile;
SetResolution(imageMetaData, exifProfileRootFrame);
TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata();
tiffMetadata.ByteOrder = byteOrder;
ImageMetadata imageMetaData = Create(byteOrder, isBigTiff, frames[0].Metadata.ExifProfile);
if (!ignoreMetadata)
{
@ -63,13 +57,14 @@ namespace SixLabors.ImageSharp.Formats.Tiff
return imageMetaData;
}
public static ImageMetadata Create(ByteOrder byteOrder, ExifProfile exifProfile)
public static ImageMetadata Create(ByteOrder byteOrder, bool isBigTiff, ExifProfile exifProfile)
{
var imageMetaData = new ImageMetadata();
SetResolution(imageMetaData, exifProfile);
TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata();
tiffMetadata.ByteOrder = byteOrder;
tiffMetadata.FormatType = isBigTiff ? TiffFormatType.BigTIFF : TiffFormatType.Default;
return imageMetaData;
}

13
src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs

@ -24,12 +24,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// <param name="frameMetadata">The IFD entries container to read the image format information for current frame.</param>
public static void VerifyAndParse(this TiffDecoderCore options, ExifProfile exifProfile, TiffFrameMetadata frameMetadata)
{
if (exifProfile.GetValue(ExifTag.TileOffsets)?.Value != null)
if (exifProfile.GetValueInternal(ExifTag.TileOffsets) is not null || exifProfile.GetValueInternal(ExifTag.TileByteCounts) is not null)
{
TiffThrowHelper.ThrowNotSupported("Tiled images are not supported.");
}
if (exifProfile.GetValue(ExifTag.ExtraSamples)?.Value != null)
if (exifProfile.GetValueInternal(ExifTag.ExtraSamples) is not null)
{
TiffThrowHelper.ThrowNotSupported("ExtraSamples is not supported.");
}
@ -95,12 +95,12 @@ namespace SixLabors.ImageSharp.Formats.Tiff
private static void VerifyRequiredFieldsArePresent(ExifProfile exifProfile, TiffFrameMetadata frameMetadata)
{
if (exifProfile.GetValue(ExifTag.StripOffsets) == null)
if (exifProfile.GetValueInternal(ExifTag.StripOffsets) is null)
{
TiffThrowHelper.ThrowImageFormatException("StripOffsets are missing and are required for decoding the TIFF image!");
}
if (exifProfile.GetValue(ExifTag.StripByteCounts) == null)
if (exifProfile.GetValueInternal(ExifTag.StripByteCounts) is null)
{
TiffThrowHelper.ThrowImageFormatException("StripByteCounts are missing and are required for decoding the TIFF image!");
}
@ -384,7 +384,8 @@ namespace SixLabors.ImageSharp.Formats.Tiff
private static void ParseCompression(this TiffDecoderCore options, TiffCompression? compression, ExifProfile exifProfile)
{
switch (compression)
// Default 1 (No compression) https://www.awaresystems.be/imaging/tiff/tifftags/compression.html
switch (compression ?? TiffCompression.None)
{
case TiffCompression.None:
{
@ -441,7 +442,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
default:
{
TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format {compression} is not supported");
TiffThrowHelper.ThrowNotSupported($"The specified TIFF compression format '{compression}' is not supported");
break;
}
}

21
src/ImageSharp/Formats/Tiff/TiffFormatType.cs

@ -0,0 +1,21 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats.Tiff
{
/// <summary>
/// The TIFF format type enum.
/// </summary>
public enum TiffFormatType
{
/// <summary>
/// The TIFF file format type.
/// </summary>
Default,
/// <summary>
/// The BigTIFF format type.
/// </summary>
BigTIFF
}
}

41
src/ImageSharp/Formats/Tiff/TiffImageFormatDetector.cs

@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
public sealed class TiffImageFormatDetector : IImageFormatDetector
{
/// <inheritdoc/>
public int HeaderSize => 4;
public int HeaderSize => 8;
/// <inheritdoc/>
public IImageFormat DetectFormat(ReadOnlySpan<byte> header)
@ -26,9 +26,42 @@ namespace SixLabors.ImageSharp.Formats.Tiff
private bool IsSupportedFileFormat(ReadOnlySpan<byte> header)
{
return header.Length >= this.HeaderSize &&
((header[0] == 0x49 && header[1] == 0x49 && header[2] == 0x2A && header[3] == 0x00) || // Little-endian
(header[0] == 0x4D && header[1] == 0x4D && header[2] == 0x00 && header[3] == 0x2A)); // Big-endian
if (header.Length >= this.HeaderSize)
{
if (header[0] == 0x49 && header[1] == 0x49)
{
// Little-endian
if (header[2] == 0x2A && header[3] == 0x00)
{
// tiff
return true;
}
else if (header[2] == 0x2B && header[3] == 0x00
&& header[4] == 8 && header[5] == 0 && header[6] == 0 && header[7] == 0)
{
// big tiff
return true;
}
}
else if (header[0] == 0x4D && header[1] == 0x4D)
{
// Big-endian
if (header[2] == 0 && header[3] == 0x2A)
{
// tiff
return true;
}
else
if (header[2] == 0 && header[3] == 0x2B
&& header[4] == 0 && header[5] == 8 && header[6] == 0 && header[7] == 0)
{
// big tiff
return true;
}
}
}
return false;
}
}
}

5
src/ImageSharp/Formats/Tiff/TiffMetadata.cs

@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
public ByteOrder ByteOrder { get; set; }
/// <summary>
/// Gets or sets the format type.
/// </summary>
public TiffFormatType FormatType { get; set; }
/// <inheritdoc/>
public IDeepCloneable DeepClone() => new TiffMetadata(this);
}

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

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff
/// </summary>
/// <param name="errorMessage">The error message for the exception.</param>
[MethodImpl(MethodImplOptions.NoInlining)]
public static void ThrowImageFormatException(string errorMessage) => throw new ImageFormatException(errorMessage);
public static Exception ThrowImageFormatException(string errorMessage) => throw new ImageFormatException(errorMessage);
[MethodImpl(InliningOptions.ColdPath)]
public static Exception NotSupportedDecompressor(string compressionType) => throw new NotSupportedException($"Not supported decoder compression method: {compressionType}");

135
src/ImageSharp/Formats/Webp/Lossy/Vp8Residual.cs

@ -3,6 +3,11 @@
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
#if SUPPORTS_RUNTIME_INTRINSICS
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
#endif
namespace SixLabors.ImageSharp.Formats.Webp.Lossy
{
@ -11,6 +16,16 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
/// </summary>
internal class Vp8Residual
{
#if SUPPORTS_RUNTIME_INTRINSICS
private static readonly Vector256<byte> Cst2 = Vector256.Create((byte)2);
private static readonly Vector256<byte> Cst67 = Vector256.Create((byte)67);
#endif
private readonly byte[] scratch = new byte[32];
private readonly ushort[] scratchUShort = new ushort[16];
public int First { get; set; }
public int Last { get; set; }
@ -37,14 +52,39 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
public void SetCoeffs(Span<short> coeffs)
{
int n;
this.Last = -1;
for (n = 15; n >= 0; --n)
#if SUPPORTS_RUNTIME_INTRINSICS
if (Sse2.IsSupported)
{
ref short coeffsRef = ref MemoryMarshal.GetReference(coeffs);
Vector128<byte> c0 = Unsafe.As<short, Vector128<byte>>(ref coeffsRef);
Vector128<byte> c1 = Unsafe.As<short, Vector128<byte>>(ref Unsafe.Add(ref coeffsRef, 8));
// Use SSE2 to compare 16 values with a single instruction.
Vector128<sbyte> m0 = Sse2.PackSignedSaturate(c0.AsInt16(), c1.AsInt16());
Vector128<sbyte> m1 = Sse2.CompareEqual(m0, Vector128<sbyte>.Zero);
// Get the comparison results as a bitmask into 16bits. Negate the mask to get
// the position of entries that are not equal to zero. We don't need to mask
// out least significant bits according to res->first, since coeffs[0] is 0
// if res->first > 0.
uint mask = 0x0000ffffu ^ (uint)Sse2.MoveMask(m1);
// The position of the most significant non-zero bit indicates the position of
// the last non-zero value.
this.Last = mask != 0 ? Numerics.Log2(mask) : -1;
}
else
#endif
{
if (coeffs[n] != 0)
int n;
this.Last = -1;
for (n = 15; n >= 0; --n)
{
this.Last = n;
break;
if (coeffs[n] != 0)
{
this.Last = n;
break;
}
}
}
@ -129,27 +169,78 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
return LossyUtils.Vp8BitCost(0, (byte)p0);
}
int v;
for (; n < this.Last; ++n)
#if SUPPORTS_RUNTIME_INTRINSICS
if (Avx2.IsSupported)
{
Span<byte> ctxs = this.scratch.AsSpan(0, 16);
Span<byte> levels = this.scratch.AsSpan(16, 16);
Span<ushort> absLevels = this.scratchUShort.AsSpan();
// Precompute clamped levels and contexts, packed to 8b.
ref short outputRef = ref MemoryMarshal.GetReference<short>(this.Coeffs);
Vector256<short> c0 = Unsafe.As<short, Vector256<byte>>(ref outputRef).AsInt16();
Vector256<short> d0 = Avx2.Subtract(Vector256<short>.Zero, c0);
Vector256<short> e0 = Avx2.Max(c0, d0); // abs(v), 16b
Vector256<sbyte> f = Avx2.PackSignedSaturate(e0, e0);
Vector256<byte> g = Avx2.Min(f.AsByte(), Cst2);
Vector256<byte> h = Avx2.Min(f.AsByte(), Cst67); // clampLevel in [0..67]
ref byte ctxsRef = ref MemoryMarshal.GetReference(ctxs);
ref byte levelsRef = ref MemoryMarshal.GetReference(levels);
ref ushort absLevelsRef = ref MemoryMarshal.GetReference(absLevels);
Unsafe.As<byte, Vector128<byte>>(ref ctxsRef) = g.GetLower();
Unsafe.As<byte, Vector128<byte>>(ref levelsRef) = h.GetLower();
Unsafe.As<ushort, Vector256<ushort>>(ref absLevelsRef) = e0.AsUInt16();
int level;
int flevel;
for (; n < this.Last; ++n)
{
int ctx = ctxs[n];
level = levels[n];
flevel = absLevels[n];
cost += WebpLookupTables.Vp8LevelFixedCosts[flevel] + t.Costs[level];
t = costs[n + 1].Costs[ctx];
}
// Last coefficient is always non-zero.
level = levels[n];
flevel = absLevels[n];
cost += WebpLookupTables.Vp8LevelFixedCosts[flevel] + t.Costs[level];
if (n < 15)
{
int b = WebpConstants.Vp8EncBands[n + 1];
int ctx = ctxs[n];
int lastP0 = this.Prob[b].Probabilities[ctx].Probabilities[0];
cost += LossyUtils.Vp8BitCost(0, (byte)lastP0);
}
return cost;
}
#endif
{
int v;
for (; n < this.Last; ++n)
{
v = Math.Abs(this.Coeffs[n]);
int ctx = v >= 2 ? 2 : v;
cost += LevelCost(t.Costs, v);
t = costs[n + 1].Costs[ctx];
}
// Last coefficient is always non-zero
v = Math.Abs(this.Coeffs[n]);
int ctx = v >= 2 ? 2 : v;
cost += LevelCost(t.Costs, v);
t = costs[n + 1].Costs[ctx];
}
if (n < 15)
{
int b = WebpConstants.Vp8EncBands[n + 1];
int ctx = v == 1 ? 1 : 2;
int lastP0 = this.Prob[b].Probabilities[ctx].Probabilities[0];
cost += LossyUtils.Vp8BitCost(0, (byte)lastP0);
}
// Last coefficient is always non-zero
v = Math.Abs(this.Coeffs[n]);
cost += LevelCost(t.Costs, v);
if (n < 15)
{
int b = WebpConstants.Vp8EncBands[n + 1];
int ctx = v == 1 ? 1 : 2;
int lastP0 = this.Prob[b].Probabilities[ctx].Probabilities[0];
cost += LossyUtils.Vp8BitCost(0, (byte)lastP0);
return cost;
}
return cost;
}
[MethodImpl(InliningOptions.ShortMethod)]

1
src/ImageSharp/IO/ChunkedMemoryStream.cs

@ -168,7 +168,6 @@ namespace SixLabors.ImageSharp.IO
// Position is out of range
this.readChunk = backupReadChunk;
this.readOffset = backupReadOffset;
ThrowArgumentOutOfRange(nameof(value));
}
}
}

11
src/ImageSharp/ImageFrame{TPixel}.cs

@ -145,13 +145,8 @@ namespace SixLabors.ImageSharp
source.PixelBuffer.FastMemoryGroup.CopyTo(this.PixelBuffer.FastMemoryGroup);
}
/// <summary>
/// Gets the image pixels. Not private as Buffer2D requires an array in its constructor.
/// </summary>
internal Buffer2D<TPixel> PixelBuffer { get; private set; }
/// <inheritdoc/>
Buffer2D<TPixel> IPixelSource<TPixel>.PixelBuffer => this.PixelBuffer;
public Buffer2D<TPixel> PixelBuffer { get; private set; }
/// <summary>
/// Gets or sets the pixel at the specified position.
@ -443,12 +438,12 @@ namespace SixLabors.ImageSharp
[MethodImpl(InliningOptions.ShortMethod)]
private void VerifyCoords(int x, int y)
{
if (x < 0 || x >= this.Width)
if ((uint)x >= (uint)this.Width)
{
ThrowArgumentOutOfRangeException(nameof(x));
}
if (y < 0 || y >= this.Height)
if ((uint)y >= (uint)this.Height)
{
ThrowArgumentOutOfRangeException(nameof(y));
}

9
src/ImageSharp/ImageSharp.csproj

@ -75,6 +75,11 @@
<AutoGen>True</AutoGen>
<DependentUpon>Block8x8F.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelImplementations\PixelOperations\Generated\Abgr32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Abgr32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelOperations{TPixel}.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
@ -166,6 +171,10 @@
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Block8x8F.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelImplementations\PixelOperations\Generated\Abgr32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Abgr32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelOperations{TPixel}.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>PixelOperations{TPixel}.Generated.cs</LastGenOutput>

4
src/ImageSharp/Image{TPixel}.cs

@ -452,12 +452,12 @@ namespace SixLabors.ImageSharp
[MethodImpl(InliningOptions.ShortMethod)]
private void VerifyCoords(int x, int y)
{
if (x < 0 || x >= this.Width)
if ((uint)x >= (uint)this.Width)
{
ThrowArgumentOutOfRangeException(nameof(x));
}
if (y < 0 || y >= this.Height)
if ((uint)y >= (uint)this.Height)
{
ThrowArgumentOutOfRangeException(nameof(y));
}

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

@ -13,34 +13,35 @@ namespace SixLabors.ImageSharp.Memory.Internals
where T : struct
{
private readonly int lengthInBytes;
private byte[] array;
private LifetimeGuard lifetimeGuard;
public SharedArrayPoolBuffer(int lengthInElements)
{
this.lengthInBytes = lengthInElements * Unsafe.SizeOf<T>();
this.array = ArrayPool<byte>.Shared.Rent(this.lengthInBytes);
this.lifetimeGuard = new LifetimeGuard(this.array);
this.Array = ArrayPool<byte>.Shared.Rent(this.lengthInBytes);
this.lifetimeGuard = new LifetimeGuard(this.Array);
}
public byte[] Array { get; private set; }
protected override void Dispose(bool disposing)
{
if (this.array == null)
if (this.Array == null)
{
return;
}
this.lifetimeGuard.Dispose();
this.array = null;
this.Array = null;
}
public override Span<T> GetSpan()
{
this.CheckDisposed();
return MemoryMarshal.Cast<byte, T>(this.array.AsSpan(0, this.lengthInBytes));
return MemoryMarshal.Cast<byte, T>(this.Array.AsSpan(0, this.lengthInBytes));
}
protected override object GetPinnableObject() => this.array;
protected override object GetPinnableObject() => this.Array;
public void AddRef()
{
@ -53,7 +54,7 @@ namespace SixLabors.ImageSharp.Memory.Internals
[Conditional("DEBUG")]
private void CheckDisposed()
{
if (this.array == null)
if (this.Array == null)
{
throw new ObjectDisposedException("SharedArrayPoolBuffer");
}

10
src/ImageSharp/Memory/Allocators/Internals/UniformUnmanagedMemoryPool.cs

@ -8,12 +8,10 @@ using System.Threading;
namespace SixLabors.ImageSharp.Memory.Internals
{
internal partial class UniformUnmanagedMemoryPool
#if !NETSTANDARD1_3
// In case UniformUnmanagedMemoryPool is finalized, we prefer to run its finalizer after the guard finalizers,
// but we should not rely on this.
: System.Runtime.ConstrainedExecution.CriticalFinalizerObject
#endif
// CriticalFinalizerObject:
// In case UniformUnmanagedMemoryPool is finalized, we prefer to run its finalizer after the guard finalizers,
// but we should not rely on this.
internal partial class UniformUnmanagedMemoryPool : System.Runtime.ConstrainedExecution.CriticalFinalizerObject
{
private static int minTrimPeriodMilliseconds = int.MaxValue;
private static readonly List<WeakReference<UniformUnmanagedMemoryPool>> AllPools = new();

2
src/ImageSharp/Memory/Allocators/Internals/UnmanagedBuffer{T}.cs

@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Memory.Internals
this.lifetimeGuard = lifetimeGuard;
}
private void* Pointer => this.lifetimeGuard.Handle.Pointer;
public void* Pointer => this.lifetimeGuard.Handle.Pointer;
public override Span<T> GetSpan()
{

65
src/ImageSharp/Memory/Buffer2D{T}.cs

@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Memory
/// It's public counterpart is <see cref="MemoryGroup"/>,
/// which only exposes the view of the MemoryGroup.
/// </remarks>
internal MemoryGroup<T> FastMemoryGroup { get; }
internal MemoryGroup<T> FastMemoryGroup { get; private set; }
/// <summary>
/// Gets a reference to the element at the specified position.
@ -97,35 +97,37 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(InliningOptions.ShortMethod)]
public Span<T> DangerousGetRowSpan(int y)
{
DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
if ((uint)y >= (uint)this.Height)
{
this.ThrowYOutOfRangeException(y);
}
return this.GetRowMemoryCore(y).Span;
return this.FastMemoryGroup.GetRowSpanCoreUnsafe(y, this.Width);
}
internal bool TryGetPaddedRowSpan(int y, int padding, out Span<T> paddedSpan)
internal bool DangerousTryGetPaddedRowSpan(int y, int padding, out Span<T> paddedSpan)
{
DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
int stride = this.Width + padding;
Memory<T> memory = this.FastMemoryGroup.GetRemainingSliceOfBuffer(y * (long)this.Width);
Span<T> slice = this.FastMemoryGroup.GetRemainingSliceOfBuffer(y * (long)this.Width);
if (memory.Length < stride)
if (slice.Length < stride)
{
paddedSpan = default;
return false;
}
paddedSpan = memory.Span.Slice(0, stride);
paddedSpan = slice.Slice(0, stride);
return true;
}
[MethodImpl(InliningOptions.ShortMethod)]
internal ref T GetElementUnsafe(int x, int y)
{
Span<T> span = this.GetRowMemoryCore(y).Span;
Span<T> span = this.FastMemoryGroup.GetRowSpanCoreUnsafe(y, this.Width);
return ref span[x];
}
@ -139,7 +141,7 @@ namespace SixLabors.ImageSharp.Memory
{
DebugGuard.MustBeGreaterThanOrEqualTo(y, 0, nameof(y));
DebugGuard.MustBeLessThan(y, this.Height, nameof(y));
return this.FastMemoryGroup.View.GetBoundedSlice(y * (long)this.Width, this.Width);
return this.FastMemoryGroup.View.GetBoundedMemorySlice(y * (long)this.Width, this.Width);
}
/// <summary>
@ -168,25 +170,36 @@ namespace SixLabors.ImageSharp.Memory
/// Swaps the contents of 'destination' with 'source' if the buffers are owned (1),
/// copies the contents of 'source' to 'destination' otherwise (2). Buffers should be of same size in case 2!
/// </summary>
internal static void SwapOrCopyContent(Buffer2D<T> destination, Buffer2D<T> source)
{
MemoryGroup<T>.SwapOrCopyContent(destination.FastMemoryGroup, source.FastMemoryGroup);
SwapOwnData(destination, source);
}
[MethodImpl(InliningOptions.ShortMethod)]
private Memory<T> GetRowMemoryCore(int y) => this.FastMemoryGroup.GetBoundedSlice(y * (long)this.Width, this.Width);
private static void SwapOwnData(Buffer2D<T> a, Buffer2D<T> b)
internal static bool SwapOrCopyContent(Buffer2D<T> destination, Buffer2D<T> source)
{
Size aSize = a.Size();
Size bSize = b.Size();
bool swapped = false;
if (MemoryGroup<T>.CanSwapContent(destination.FastMemoryGroup, source.FastMemoryGroup))
{
(destination.FastMemoryGroup, source.FastMemoryGroup) =
(source.FastMemoryGroup, destination.FastMemoryGroup);
destination.FastMemoryGroup.RecreateViewAfterSwap();
source.FastMemoryGroup.RecreateViewAfterSwap();
swapped = true;
}
else
{
if (destination.FastMemoryGroup.TotalLength != source.FastMemoryGroup.TotalLength)
{
throw new InvalidMemoryOperationException(
"Trying to copy/swap incompatible buffers. This is most likely caused by applying an unsupported processor to wrapped-memory images.");
}
b.Width = aSize.Width;
b.Height = aSize.Height;
source.FastMemoryGroup.CopyTo(destination.MemoryGroup);
}
a.Width = bSize.Width;
a.Height = bSize.Height;
(destination.Width, source.Width) = (source.Width, destination.Width);
(destination.Height, source.Height) = (source.Height, destination.Height);
return swapped;
}
[MethodImpl(InliningOptions.ColdPath)]
private void ThrowYOutOfRangeException(int y) =>
throw new ArgumentOutOfRangeException(
$"DangerousGetRowSpan({y}). Y was out of range. Height={this.Height}");
}
}

31
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupExtensions.cs

@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Memory
/// Returns a slice that is expected to be within the bounds of a single buffer.
/// Otherwise <see cref="ArgumentOutOfRangeException"/> is thrown.
/// </summary>
internal static Memory<T> GetBoundedSlice<T>(this IMemoryGroup<T> group, long start, int length)
internal static Memory<T> GetBoundedMemorySlice<T>(this IMemoryGroup<T> group, long start, int length)
where T : struct
{
Guard.NotNull(group, nameof(group));
@ -37,7 +37,8 @@ namespace SixLabors.ImageSharp.Memory
Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length));
Guard.MustBeLessThan(start, group.TotalLength, nameof(start));
int bufferIdx = (int)(start / group.BufferLength);
int bufferIdx = (int)Math.DivRem(start, group.BufferLength, out long bufferStartLong);
int bufferStart = (int)bufferStartLong;
// if (bufferIdx < 0 || bufferIdx >= group.Count)
if ((uint)bufferIdx >= group.Count)
@ -45,7 +46,6 @@ namespace SixLabors.ImageSharp.Memory
throw new ArgumentOutOfRangeException(nameof(start));
}
int bufferStart = (int)(start % group.BufferLength);
int bufferEnd = bufferStart + length;
Memory<T> memory = group[bufferIdx];
@ -57,31 +57,6 @@ namespace SixLabors.ImageSharp.Memory
return memory.Slice(bufferStart, length);
}
/// <summary>
/// Returns the slice of the buffer starting at global index <paramref name="start"/> that goes until the end of the buffer.
/// </summary>
internal static Memory<T> GetRemainingSliceOfBuffer<T>(this IMemoryGroup<T> group, long start)
where T : struct
{
Guard.NotNull(group, nameof(group));
Guard.IsTrue(group.IsValid, nameof(group), "Group must be valid!");
Guard.MustBeLessThan(start, group.TotalLength, nameof(start));
int bufferIdx = (int)(start / group.BufferLength);
// if (bufferIdx < 0 || bufferIdx >= group.Count)
if ((uint)bufferIdx >= group.Count)
{
throw new ArgumentOutOfRangeException(nameof(start));
}
int bufferStart = (int)(start % group.BufferLength);
Memory<T> memory = group[bufferIdx];
return memory.Slice(bufferStart);
}
internal static void CopyTo<T>(this IMemoryGroup<T> source, Span<T> target)
where T : struct
{

52
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroupSpanCache.cs

@ -0,0 +1,52 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// Cached pointer or array data enabling fast <see cref="Span{T}"/> access from
/// known <see cref="IMemoryOwner{T}"/> implementations.
/// </summary>
internal unsafe struct MemoryGroupSpanCache
{
public SpanCacheMode Mode;
public byte[] SingleArray;
public void* SinglePointer;
public void*[] MultiPointer;
public static MemoryGroupSpanCache Create<T>(IMemoryOwner<T>[] memoryOwners)
where T : struct
{
IMemoryOwner<T> owner0 = memoryOwners[0];
MemoryGroupSpanCache memoryGroupSpanCache = default;
if (memoryOwners.Length == 1)
{
if (owner0 is SharedArrayPoolBuffer<T> sharedPoolBuffer)
{
memoryGroupSpanCache.Mode = SpanCacheMode.SingleArray;
memoryGroupSpanCache.SingleArray = sharedPoolBuffer.Array;
}
else if (owner0 is UnmanagedBuffer<T> unmanagedBuffer)
{
memoryGroupSpanCache.Mode = SpanCacheMode.SinglePointer;
memoryGroupSpanCache.SinglePointer = unmanagedBuffer.Pointer;
}
}
else if (owner0 is UnmanagedBuffer<T>)
{
memoryGroupSpanCache.Mode = SpanCacheMode.MultiPointer;
memoryGroupSpanCache.MultiPointer = new void*[memoryOwners.Length];
for (int i = 0; i < memoryOwners.Length; i++)
{
memoryGroupSpanCache.MultiPointer[i] = ((UnmanagedBuffer<T>)memoryOwners[i]).Pointer;
}
}
return memoryGroupSpanCache;
}
}
}

33
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.Owned.cs

@ -26,6 +26,7 @@ namespace SixLabors.ImageSharp.Memory
this.memoryOwners = memoryOwners;
this.Swappable = swappable;
this.View = new MemoryGroupView<T>(this);
this.memoryGroupSpanCache = MemoryGroupSpanCache.Create(memoryOwners);
}
public Owned(
@ -122,6 +123,12 @@ namespace SixLabors.ImageSharp.Memory
}
}
public override void RecreateViewAfterSwap()
{
this.View.Invalidate();
this.View = new MemoryGroupView<T>(this);
}
/// <inheritdoc/>
IEnumerator<Memory<T>> IEnumerable<Memory<T>>.GetEnumerator()
{
@ -167,32 +174,6 @@ namespace SixLabors.ImageSharp.Memory
[MethodImpl(MethodImplOptions.NoInlining)]
private static void ThrowObjectDisposedException() => throw new ObjectDisposedException(nameof(MemoryGroup<T>));
internal static void SwapContents(Owned a, Owned b)
{
a.EnsureNotDisposed();
b.EnsureNotDisposed();
IMemoryOwner<T>[] tempOwners = a.memoryOwners;
long tempTotalLength = a.TotalLength;
int tempBufferLength = a.BufferLength;
RefCountedLifetimeGuard tempGroupOwner = a.groupLifetimeGuard;
a.memoryOwners = b.memoryOwners;
a.TotalLength = b.TotalLength;
a.BufferLength = b.BufferLength;
a.groupLifetimeGuard = b.groupLifetimeGuard;
b.memoryOwners = tempOwners;
b.TotalLength = tempTotalLength;
b.BufferLength = tempBufferLength;
b.groupLifetimeGuard = tempGroupOwner;
a.View.Invalidate();
b.View.Invalidate();
a.View = new MemoryGroupView<T>(a);
b.View = new MemoryGroupView<T>(b);
}
// When the MemoryGroup points to multiple buffers via `groupLifetimeGuard`,
// the lifetime of the individual buffers is managed by the guard.
// Group buffer IMemoryOwner<T>-s d not manage ownership.

83
src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs

@ -6,6 +6,8 @@ using System.Buffers;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Threading;
using SixLabors.ImageSharp.Memory.Internals;
namespace SixLabors.ImageSharp.Memory
@ -21,6 +23,8 @@ namespace SixLabors.ImageSharp.Memory
{
private static readonly int ElementSize = Unsafe.SizeOf<T>();
private MemoryGroupSpanCache memoryGroupSpanCache;
private MemoryGroup(int bufferLength, long totalLength)
{
this.BufferLength = bufferLength;
@ -31,10 +35,10 @@ namespace SixLabors.ImageSharp.Memory
public abstract int Count { get; }
/// <inheritdoc />
public int BufferLength { get; private set; }
public int BufferLength { get; }
/// <inheritdoc />
public long TotalLength { get; private set; }
public long TotalLength { get; }
/// <inheritdoc />
public bool IsValid { get; private set; } = true;
@ -241,32 +245,62 @@ namespace SixLabors.ImageSharp.Memory
return new Owned(source, bufferLength, totalLength, false);
}
/// <summary>
/// Swaps the contents of 'target' with 'source' if the buffers are allocated (1),
/// copies the contents of 'source' to 'target' otherwise (2).
/// Groups should be of same TotalLength in case 2.
/// </summary>
public static bool SwapOrCopyContent(MemoryGroup<T> target, MemoryGroup<T> source)
[MethodImpl(InliningOptions.ShortMethod)]
public unsafe Span<T> GetRowSpanCoreUnsafe(int y, int width)
{
if (source is Owned ownedSrc && ownedSrc.Swappable &&
target is Owned ownedTarget && ownedTarget.Swappable)
switch (this.memoryGroupSpanCache.Mode)
{
Owned.SwapContents(ownedTarget, ownedSrc);
return true;
}
else
{
if (target.TotalLength != source.TotalLength)
case SpanCacheMode.SingleArray:
{
#if SUPPORTS_CREATESPAN
ref byte b0 = ref MemoryMarshal.GetReference<byte>(this.memoryGroupSpanCache.SingleArray);
ref T e0 = ref Unsafe.As<byte, T>(ref b0);
e0 = ref Unsafe.Add(ref e0, y * width);
return MemoryMarshal.CreateSpan(ref e0, width);
#else
return MemoryMarshal.Cast<byte, T>(this.memoryGroupSpanCache.SingleArray).Slice(y * width, width);
#endif
}
case SpanCacheMode.SinglePointer:
{
throw new InvalidMemoryOperationException(
"Trying to copy/swap incompatible buffers. This is most likely caused by applying an unsupported processor to wrapped-memory images.");
void* start = Unsafe.Add<T>(this.memoryGroupSpanCache.SinglePointer, y * width);
return new Span<T>(start, width);
}
source.CopyTo(target);
return false;
case SpanCacheMode.MultiPointer:
{
this.GetMultiBufferPosition(y, width, out int bufferIdx, out int bufferStart);
void* start = Unsafe.Add<T>(this.memoryGroupSpanCache.MultiPointer[bufferIdx], bufferStart);
return new Span<T>(start, width);
}
default:
{
this.GetMultiBufferPosition(y, width, out int bufferIdx, out int bufferStart);
return this[bufferIdx].Span.Slice(bufferStart, width);
}
}
}
/// <summary>
/// Returns the slice of the buffer starting at global index <paramref name="start"/> that goes until the end of the buffer.
/// </summary>
public Span<T> GetRemainingSliceOfBuffer(long start)
{
long bufferIdx = Math.DivRem(start, this.BufferLength, out long bufferStart);
Memory<T> memory = this[(int)bufferIdx];
return memory.Span.Slice((int)bufferStart);
}
public static bool CanSwapContent(MemoryGroup<T> target, MemoryGroup<T> source) =>
source is Owned { Swappable: true } && target is Owned { Swappable: true };
public virtual void RecreateViewAfterSwap()
{
}
public virtual void IncreaseRefCounts()
{
}
@ -274,5 +308,14 @@ namespace SixLabors.ImageSharp.Memory
public virtual void DecreaseRefCounts()
{
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void GetMultiBufferPosition(int y, int width, out int bufferIdx, out int bufferStart)
{
long start = y * (long)width;
long bufferIdxLong = Math.DivRem(start, this.BufferLength, out long bufferStartLong);
bufferIdx = (int)bufferIdxLong;
bufferStart = (int)bufferStartLong;
}
}
}

16
src/ImageSharp/Memory/DiscontiguousBuffers/SpanCacheMode.cs

@ -0,0 +1,16 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Memory
{
/// <summary>
/// Selects active values in <see cref="MemoryGroupSpanCache"/>.
/// </summary>
internal enum SpanCacheMode
{
Default = default,
SingleArray,
SinglePointer,
MultiPointer
}
}

17
src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs

@ -80,6 +80,21 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// <summary>
/// Reference to an IFD (32-bit (4-byte) unsigned integer).
/// </summary>
Ifd = 13
Ifd = 13,
/// <summary>
/// A 64-bit (8-byte) unsigned integer.
/// </summary>
Long8 = 16,
/// <summary>
/// A 64-bit (8-byte) signed integer (2's complement notation).
/// </summary>
SignedLong8 = 17,
/// <summary>
/// Reference to an IFD (64-bit (8-byte) unsigned integer).
/// </summary>
Ifd8 = 18,
}
}

4
src/ImageSharp/Metadata/Profiles/Exif/ExifDataTypes.cs

@ -32,10 +32,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifDataType.Long:
case ExifDataType.SignedLong:
case ExifDataType.SingleFloat:
case ExifDataType.Ifd:
return 4;
case ExifDataType.DoubleFloat:
case ExifDataType.Rational:
case ExifDataType.SignedRational:
case ExifDataType.Long8:
case ExifDataType.SignedLong8:
case ExifDataType.Ifd8:
return 8;
default:
throw new NotSupportedException(dataType.ToString());

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.Collections.ObjectModel;
@ -9,15 +10,19 @@ using System.Diagnostics;
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal class ExifReader : BaseExifReader
{
private readonly List<Action> loaders = new List<Action>();
public ExifReader(byte[] exifData)
: base(new MemoryStream(exifData ?? throw new ArgumentNullException(nameof(exifData))))
: this(exifData, null)
{
}
public ExifReader(byte[] exifData, MemoryAllocator allocator)
: base(new MemoryStream(exifData ?? throw new ArgumentNullException(nameof(exifData))), allocator)
{
}
@ -47,16 +52,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
this.ReadSubIfd(values);
foreach (Action loader in this.loaders)
{
loader();
}
this.ReadBigValues(values);
return values;
}
protected override void RegisterExtLoader(uint offset, Action loader) => this.loaders.Add(loader);
private void GetThumbnail(uint offset)
{
if (offset == 0)
@ -86,19 +86,21 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// </summary>
internal abstract class BaseExifReader
{
private readonly byte[] offsetBuffer = new byte[4];
private readonly byte[] buf8 = new byte[8];
private readonly byte[] buf4 = new byte[4];
private readonly byte[] buf2 = new byte[2];
private readonly MemoryAllocator allocator;
private readonly Stream data;
private List<ExifTag> invalidTags;
private uint exifOffset;
private uint gpsOffset;
private List<ulong> subIfds;
protected BaseExifReader(Stream stream) =>
protected BaseExifReader(Stream stream, MemoryAllocator allocator)
{
this.data = stream ?? throw new ArgumentNullException(nameof(stream));
this.allocator = allocator;
}
private delegate TDataType ConverterMethod<TDataType>(ReadOnlySpan<byte> data);
@ -119,7 +121,51 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
public bool IsBigEndian { get; protected set; }
protected abstract void RegisterExtLoader(uint offset, Action loader);
public List<(ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif)> BigValues { get; } = new();
protected void ReadBigValues(List<IExifValue> values)
{
if (this.BigValues.Count == 0)
{
return;
}
int maxSize = 0;
foreach ((ulong offset, ExifDataType dataType, ulong numberOfComponents, ExifValue exif) in this.BigValues)
{
ulong size = numberOfComponents * ExifDataTypes.GetSize(dataType);
DebugGuard.MustBeLessThanOrEqualTo<ulong>(size, int.MaxValue, nameof(size));
if ((int)size > maxSize)
{
maxSize = (int)size;
}
}
if (this.allocator != null)
{
// tiff, bigTiff
using IMemoryOwner<byte> memory = this.allocator.Allocate<byte>(maxSize);
Span<byte> buf = memory.GetSpan();
foreach ((ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif) tag in this.BigValues)
{
ulong size = tag.NumberOfComponents * ExifDataTypes.GetSize(tag.DataType);
this.ReadBigValue(values, tag, buf.Slice(0, (int)size));
}
}
else
{
// embedded exif
Span<byte> buf = maxSize <= 256 ? stackalloc byte[256] : new byte[maxSize];
foreach ((ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif) tag in this.BigValues)
{
ulong size = tag.NumberOfComponents * ExifDataTypes.GetSize(tag.DataType);
this.ReadBigValue(values, tag, buf.Slice(0, (int)size));
}
}
this.BigValues.Clear();
}
/// <summary>
/// Reads the values to the values collection.
@ -136,22 +182,45 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
this.Seek(offset);
int count = this.ReadUInt16();
Span<byte> offsetBuffer = stackalloc byte[4];
for (int i = 0; i < count; i++)
{
this.ReadValue(values);
this.ReadValue(values, offsetBuffer);
}
}
protected void ReadSubIfd(List<IExifValue> values)
{
if (this.exifOffset != 0)
if (this.subIfds is not null)
{
this.ReadValues(values, this.exifOffset);
foreach (ulong subIfdOffset in this.subIfds)
{
this.ReadValues(values, (uint)subIfdOffset);
}
}
}
protected void ReadValues64(List<IExifValue> values, ulong offset)
{
DebugGuard.MustBeLessThanOrEqualTo(offset, (ulong)this.data.Length, "By spec UInt64.MaxValue is supported, but .Net Stream.Length can Int64.MaxValue.");
if (this.gpsOffset != 0)
this.Seek(offset);
ulong count = this.ReadUInt64();
Span<byte> offsetBuffer = stackalloc byte[8];
for (ulong i = 0; i < count; i++)
{
this.ReadValue64(values, offsetBuffer);
}
}
protected void ReadBigValue(IList<IExifValue> values, (ulong Offset, ExifDataType DataType, ulong NumberOfComponents, ExifValue Exif) tag, Span<byte> buffer)
{
this.Seek(tag.Offset);
if (this.TryReadSpan(buffer))
{
this.ReadValues(values, this.gpsOffset);
object value = this.ConvertValue(tag.DataType, buffer, tag.NumberOfComponents > 1 || tag.Exif.IsArray);
this.Add(values, tag.Exif, value);
}
}
@ -186,7 +255,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return Encoding.UTF8.GetString(buffer);
}
private object ConvertValue(ExifDataType dataType, ReadOnlySpan<byte> buffer, uint numberOfComponents)
private object ConvertValue(ExifDataType dataType, ReadOnlySpan<byte> buffer, bool isArray)
{
if (buffer.Length == 0)
{
@ -200,88 +269,104 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifDataType.Ascii:
return this.ConvertToString(buffer);
case ExifDataType.Byte:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToByte(buffer);
}
return buffer.ToArray();
case ExifDataType.DoubleFloat:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToDouble(buffer);
}
return ToArray(dataType, buffer, this.ConvertToDouble);
case ExifDataType.Long:
if (numberOfComponents == 1)
case ExifDataType.Ifd:
if (!isArray)
{
return this.ConvertToUInt32(buffer);
}
return ToArray(dataType, buffer, this.ConvertToUInt32);
case ExifDataType.Rational:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ToRational(buffer);
}
return ToArray(dataType, buffer, this.ToRational);
case ExifDataType.Short:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToShort(buffer);
}
return ToArray(dataType, buffer, this.ConvertToShort);
case ExifDataType.SignedByte:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToSignedByte(buffer);
}
return ToArray(dataType, buffer, this.ConvertToSignedByte);
case ExifDataType.SignedLong:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToInt32(buffer);
}
return ToArray(dataType, buffer, this.ConvertToInt32);
case ExifDataType.SignedRational:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ToSignedRational(buffer);
}
return ToArray(dataType, buffer, this.ToSignedRational);
case ExifDataType.SignedShort:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToSignedShort(buffer);
}
return ToArray(dataType, buffer, this.ConvertToSignedShort);
case ExifDataType.SingleFloat:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToSingle(buffer);
}
return ToArray(dataType, buffer, this.ConvertToSingle);
case ExifDataType.Long8:
case ExifDataType.Ifd8:
if (!isArray)
{
return this.ConvertToUInt64(buffer);
}
return ToArray(dataType, buffer, this.ConvertToUInt64);
case ExifDataType.SignedLong8:
if (!isArray)
{
return this.ConvertToInt64(buffer);
}
return ToArray(dataType, buffer, this.ConvertToUInt64);
case ExifDataType.Undefined:
if (numberOfComponents == 1)
if (!isArray)
{
return this.ConvertToByte(buffer);
}
return buffer.ToArray();
default:
throw new NotSupportedException();
throw new NotSupportedException($"Data type {dataType} is not supported.");
}
}
private void ReadValue(List<IExifValue> values)
private void ReadValue(List<IExifValue> values, Span<byte> offsetBuffer)
{
// 2 | 2 | 4 | 4
// tag | type | count | value offset
@ -295,7 +380,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
uint numberOfComponents = this.ReadUInt32();
this.TryReadSpan(this.offsetBuffer);
this.TryReadSpan(offsetBuffer);
// Ensure that the data type is valid
if (dataType == ExifDataType.Unknown)
@ -305,9 +390,9 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
// Issue #132: ExifDataType == Undefined is treated like a byte array.
// If numberOfComponents == 0 this value can only be handled as an inline value and must fallback to 4 (bytes)
if (dataType == ExifDataType.Undefined && numberOfComponents == 0)
if (numberOfComponents == 0)
{
numberOfComponents = 4;
numberOfComponents = 4 / ExifDataTypes.GetSize(dataType);
}
ExifValue exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents);
@ -321,7 +406,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
uint size = numberOfComponents * ExifDataTypes.GetSize(dataType);
if (size > 4)
{
uint newOffset = this.ConvertToUInt32(this.offsetBuffer);
uint newOffset = this.ConvertToUInt32(offsetBuffer);
// Ensure that the new index does not overrun the data.
if (newOffset > int.MaxValue || (newOffset + size) > this.data.Length)
@ -330,21 +415,85 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return;
}
this.RegisterExtLoader(newOffset, () =>
{
byte[] dataBuffer = new byte[size];
this.Seek(newOffset);
if (this.TryReadSpan(dataBuffer))
{
object value = this.ConvertValue(dataType, dataBuffer, numberOfComponents);
this.Add(values, exifValue, value);
}
});
this.BigValues.Add((newOffset, dataType, numberOfComponents, exifValue));
}
else
{
object value = this.ConvertValue(dataType, this.offsetBuffer, numberOfComponents);
object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray);
this.Add(values, exifValue, value);
}
}
private void ReadValue64(List<IExifValue> values, Span<byte> offsetBuffer)
{
if ((this.data.Length - this.data.Position) < 20)
{
return;
}
var tag = (ExifTagValue)this.ReadUInt16();
ExifDataType dataType = EnumUtils.Parse(this.ReadUInt16(), ExifDataType.Unknown);
ulong numberOfComponents = this.ReadUInt64();
this.TryReadSpan(offsetBuffer);
if (dataType == ExifDataType.Unknown)
{
return;
}
if (numberOfComponents == 0)
{
numberOfComponents = 8 / ExifDataTypes.GetSize(dataType);
}
// The StripOffsets, StripByteCounts, TileOffsets, and TileByteCounts tags are allowed to have the datatype TIFF_LONG8 in BigTIFF.
// Old datatypes TIFF_LONG, and TIFF_SHORT where allowed in the TIFF 6.0 specification, are still valid in BigTIFF, too.
// Likewise, tags that point to other IFDs, like e.g. the SubIFDs tag, are now allowed to have the datatype TIFF_IFD8 in BigTIFF.
// Again, the old datatypes TIFF_IFD, and the hardly recommendable TIFF_LONG, are still valid, too.
// https://www.awaresystems.be/imaging/tiff/bigtiff.html
ExifValue exifValue = null;
switch (tag)
{
case ExifTagValue.StripOffsets:
exifValue = new ExifLong8Array(ExifTagValue.StripOffsets);
break;
case ExifTagValue.StripByteCounts:
exifValue = new ExifLong8Array(ExifTagValue.StripByteCounts);
break;
case ExifTagValue.TileOffsets:
exifValue = new ExifLong8Array(ExifTagValue.TileOffsets);
break;
case ExifTagValue.TileByteCounts:
exifValue = new ExifLong8Array(ExifTagValue.TileByteCounts);
break;
default:
exifValue = ExifValues.Create(tag) ?? ExifValues.Create(tag, dataType, numberOfComponents);
break;
}
if (exifValue is null)
{
this.AddInvalidTag(new UnkownExifTag(tag));
return;
}
ulong size = numberOfComponents * ExifDataTypes.GetSize(dataType);
if (size > 8)
{
ulong newOffset = this.ConvertToUInt64(offsetBuffer);
if (newOffset > ulong.MaxValue || newOffset > ((ulong)this.data.Length - size))
{
this.AddInvalidTag(new UnkownExifTag(tag));
return;
}
this.BigValues.Add((newOffset, dataType, numberOfComponents, exifValue));
}
else
{
object value = this.ConvertValue(dataType, offsetBuffer.Slice(0, (int)size), numberOfComponents > 1 || exifValue.IsArray);
this.Add(values, exifValue, value);
}
}
@ -368,11 +517,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
if (exif.Tag == ExifTag.SubIFDOffset)
{
this.exifOffset = (uint)value;
this.AddSubIfd(value);
}
else if (exif.Tag == ExifTag.GPSIFDOffset)
{
this.gpsOffset = (uint)value;
this.AddSubIfd(value);
}
else
{
@ -383,8 +532,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
private void AddInvalidTag(ExifTag tag)
=> (this.invalidTags ??= new List<ExifTag>()).Add(tag);
private void Seek(long pos)
=> this.data.Seek(pos, SeekOrigin.Begin);
private void AddSubIfd(object val)
=> (this.subIfds ??= new List<ulong>()).Add(Convert.ToUInt64(val));
private void Seek(ulong pos)
=> this.data.Seek((long)pos, SeekOrigin.Begin);
private bool TryReadSpan(Span<byte> span)
{
@ -398,6 +550,11 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return read == length;
}
protected ulong ReadUInt64() =>
this.TryReadSpan(this.buf8)
? this.ConvertToUInt64(this.buf8)
: default;
// Known as Long in Exif Specification.
protected uint ReadUInt32() =>
this.TryReadSpan(this.buf4)
@ -408,6 +565,30 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
? this.ConvertToShort(this.buf2)
: default;
private long ConvertToInt64(ReadOnlySpan<byte> buffer)
{
if (buffer.Length < 8)
{
return default;
}
return this.IsBigEndian
? BinaryPrimitives.ReadInt64BigEndian(buffer)
: BinaryPrimitives.ReadInt64LittleEndian(buffer);
}
private ulong ConvertToUInt64(ReadOnlySpan<byte> buffer)
{
if (buffer.Length < 8)
{
return default;
}
return this.IsBigEndian
? BinaryPrimitives.ReadUInt64BigEndian(buffer)
: BinaryPrimitives.ReadUInt64LittleEndian(buffer);
}
private double ConvertToDouble(ReadOnlySpan<byte> buffer)
{
if (buffer.Length < 8)

18
src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs

@ -150,6 +150,20 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
return offset + 4;
}
private static int WriteInt64(long value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteInt64LittleEndian(destination.Slice(offset, 8), value);
return offset + 8;
}
private static int WriteUInt64(ulong value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteUInt64LittleEndian(destination.Slice(offset, 8), value);
return offset + 8;
}
private static int WriteInt32(int value, Span<byte> destination, int offset)
{
BinaryPrimitives.WriteInt32LittleEndian(destination.Slice(offset, 4), value);
@ -390,6 +404,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
}
return WriteUInt32((uint)value, destination, offset);
case ExifDataType.Long8:
return WriteUInt64((ulong)value, destination, offset);
case ExifDataType.SignedLong8:
return WriteInt64((long)value, destination, offset);
case ExifDataType.Rational:
WriteRational(destination.Slice(offset, 8), (Rational)value);
return offset + 8;

5
src/ImageSharp/Metadata/Profiles/Exif/Tags/ExifTag.LongArray.cs

@ -65,5 +65,10 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
/// Gets the TimeZoneOffset exif tag.
/// </summary>
public static ExifTag<uint[]> TimeZoneOffset { get; } = new ExifTag<uint[]>(ExifTagValue.TimeZoneOffset);
/// <summary>
/// Gets the offset to child IFDs exif tag.
/// </summary>
public static ExifTag<uint[]> SubIFDs { get; } = new ExifTag<uint[]>(ExifTagValue.SubIFDs);
}
}

66
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8.cs

@ -0,0 +1,66 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Globalization;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal sealed class ExifLong8 : ExifValue<ulong>
{
public ExifLong8(ExifTag<ulong> tag)
: base(tag)
{
}
public ExifLong8(ExifTagValue tag)
: base(tag)
{
}
private ExifLong8(ExifLong8 value)
: base(value)
{
}
public override ExifDataType DataType => ExifDataType.Long8;
protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture);
public override bool TrySetValue(object value)
{
if (base.TrySetValue(value))
{
return true;
}
switch (value)
{
case int intValue:
if (intValue >= uint.MinValue)
{
this.Value = (uint)intValue;
return true;
}
return false;
case uint uintValue:
this.Value = uintValue;
return true;
case long intValue:
if (intValue >= 0)
{
this.Value = (ulong)intValue;
return true;
}
return false;
default:
return false;
}
}
public override IExifValue DeepClone() => new ExifLong8(this);
}
}

171
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifLong8Array.cs

@ -0,0 +1,171 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal sealed class ExifLong8Array : ExifArrayValue<ulong>
{
public ExifLong8Array(ExifTagValue tag)
: base(tag)
{
}
private ExifLong8Array(ExifLong8Array value)
: base(value)
{
}
public override ExifDataType DataType
{
get
{
if (this.Value is not null)
{
foreach (ulong value in this.Value)
{
if (value > uint.MaxValue)
{
return ExifDataType.Long8;
}
}
}
return ExifDataType.Long;
}
}
public override bool TrySetValue(object value)
{
if (base.TrySetValue(value))
{
return true;
}
switch (value)
{
case int val:
return this.SetSingle((ulong)Numerics.Clamp(val, 0, int.MaxValue));
case uint val:
return this.SetSingle((ulong)val);
case short val:
return this.SetSingle((ulong)Numerics.Clamp(val, 0, short.MaxValue));
case ushort val:
return this.SetSingle((ulong)val);
case long val:
return this.SetSingle((ulong)Numerics.Clamp(val, 0, long.MaxValue));
case long[] array:
{
if (value.GetType() == typeof(ulong[]))
{
return this.SetArray((ulong[])value);
}
return this.SetArray(array);
}
case int[] array:
{
if (value.GetType() == typeof(uint[]))
{
return this.SetArray((uint[])value);
}
return this.SetArray(array);
}
case short[] array:
{
if (value.GetType() == typeof(ushort[]))
{
return this.SetArray((ushort[])value);
}
return this.SetArray(array);
}
}
return false;
}
public override IExifValue DeepClone() => new ExifLong8Array(this);
private bool SetSingle(ulong value)
{
this.Value = new[] { value };
return true;
}
private bool SetArray(long[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)(values[i] < 0 ? 0 : values[i]);
}
this.Value = numbers;
return true;
}
private bool SetArray(ulong[] values)
{
this.Value = values;
return true;
}
private bool SetArray(int[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)Numerics.Clamp(values[i], 0, int.MaxValue);
}
this.Value = numbers;
return true;
}
private bool SetArray(uint[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)values[i];
}
this.Value = numbers;
return true;
}
private bool SetArray(short[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)Numerics.Clamp(values[i], 0, short.MaxValue);
}
this.Value = numbers;
return true;
}
private bool SetArray(ushort[] values)
{
var numbers = new ulong[values.Length];
for (int i = 0; i < values.Length; i++)
{
numbers[i] = (ulong)values[i];
}
this.Value = numbers;
return true;
}
}
}

34
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifNumberArray.cs

@ -19,16 +19,14 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
get
{
if (this.Value is null)
if (this.Value is not null)
{
return ExifDataType.Short;
}
for (int i = 0; i < this.Value.Length; i++)
{
if (this.Value[i] > ushort.MaxValue)
foreach (Number value in this.Value)
{
return ExifDataType.Long;
if (value > ushort.MaxValue)
{
return ExifDataType.Long;
}
}
}
@ -54,13 +52,25 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ushort val:
return this.SetSingle(val);
case int[] array:
{
// workaround for inconsistent covariance of value-typed arrays
if (value.GetType() == typeof(uint[]))
{
return this.SetArray((uint[])value);
}
return this.SetArray(array);
case uint[] array:
return this.SetArray(array);
}
case short[] array:
{
if (value.GetType() == typeof(ushort[]))
{
return this.SetArray((ushort[])value);
}
return this.SetArray(array);
case ushort[] array:
return this.SetArray(array);
}
}
return false;

26
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Globalization;
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal sealed class ExifSignedLong8 : ExifValue<long>
{
public ExifSignedLong8(ExifTagValue tag)
: base(tag)
{
}
private ExifSignedLong8(ExifSignedLong8 value)
: base(value)
{
}
public override ExifDataType DataType => ExifDataType.SignedLong8;
protected override string StringValue => this.Value.ToString(CultureInfo.InvariantCulture);
public override IExifValue DeepClone() => new ExifSignedLong8(this);
}
}

22
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifSignedLong8Array.cs

@ -0,0 +1,22 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
internal sealed class ExifSignedLong8Array : ExifArrayValue<long>
{
public ExifSignedLong8Array(ExifTagValue tag)
: base(tag)
{
}
private ExifSignedLong8Array(ExifSignedLong8Array value)
: base(value)
{
}
public override ExifDataType DataType => ExifDataType.SignedLong8;
public override IExifValue DeepClone() => new ExifSignedLong8Array(this);
}
}

5
src/ImageSharp/Metadata/Profiles/Exif/Values/ExifValues.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
public static ExifValue Create(ExifTag tag) => (ExifValue)CreateValue((ExifTagValue)(ushort)tag);
public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, uint numberOfComponents) => Create(tag, dataType, numberOfComponents != 1);
public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, ulong numberOfComponents) => Create(tag, dataType, numberOfComponents != 1);
public static ExifValue Create(ExifTagValue tag, ExifDataType dataType, bool isArray)
{
@ -19,10 +19,12 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifDataType.DoubleFloat: return isArray ? (ExifValue)new ExifDoubleArray(tag) : new ExifDouble(tag);
case ExifDataType.SingleFloat: return isArray ? (ExifValue)new ExifFloatArray(tag) : new ExifFloat(tag);
case ExifDataType.Long: return isArray ? (ExifValue)new ExifLongArray(tag) : new ExifLong(tag);
case ExifDataType.Long8: return isArray ? (ExifValue)new ExifLong8Array(tag) : new ExifLong8(tag);
case ExifDataType.Rational: return isArray ? (ExifValue)new ExifRationalArray(tag) : new ExifRational(tag);
case ExifDataType.Short: return isArray ? (ExifValue)new ExifShortArray(tag) : new ExifShort(tag);
case ExifDataType.SignedByte: return isArray ? (ExifValue)new ExifSignedByteArray(tag) : new ExifSignedByte(tag);
case ExifDataType.SignedLong: return isArray ? (ExifValue)new ExifSignedLongArray(tag) : new ExifSignedLong(tag);
case ExifDataType.SignedLong8: return isArray ? (ExifValue)new ExifSignedLong8Array(tag) : new ExifSignedLong8(tag);
case ExifDataType.SignedRational: return isArray ? (ExifValue)new ExifSignedRationalArray(tag) : new ExifSignedRational(tag);
case ExifDataType.SignedShort: return isArray ? (ExifValue)new ExifSignedShortArray(tag) : new ExifSignedShort(tag);
case ExifDataType.Ascii: return new ExifString(tag);
@ -90,6 +92,7 @@ namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
case ExifTagValue.StripRowCounts: return new ExifLongArray(ExifTag.StripRowCounts);
case ExifTagValue.IntergraphRegisters: return new ExifLongArray(ExifTag.IntergraphRegisters);
case ExifTagValue.TimeZoneOffset: return new ExifLongArray(ExifTag.TimeZoneOffset);
case ExifTagValue.SubIFDs: return new ExifLongArray(ExifTag.SubIFDs);
case ExifTagValue.ImageWidth: return new ExifNumber(ExifTag.ImageWidth);
case ExifTagValue.ImageLength: return new ExifNumber(ExifTag.ImageLength);

6
src/ImageSharp/PixelFormats/IPixel.cs

@ -79,6 +79,12 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="source">The <see cref="Bgra32"/> value.</param>
void FromBgra32(Bgra32 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Abgr32"/> value.
/// </summary>
/// <param name="source">The <see cref="Abgr32"/> value.</param>
void FromAbgr32(Abgr32 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="L8"/> value.
/// </summary>

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

@ -87,6 +87,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.PackedValue = source.A;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.PackedValue = source.A;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -0,0 +1,396 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Packed pixel type containing four 8-bit unsigned normalized values ranging from 0 to 255.
/// The color components are stored in alpha, red, green, and blue order (least significant to most significant byte).
/// <para>
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
/// <remarks>
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
[StructLayout(LayoutKind.Sequential)]
public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
{
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
public byte A;
/// <summary>
/// Gets or sets the blue component.
/// </summary>
public byte B;
/// <summary>
/// Gets or sets the green component.
/// </summary>
public byte G;
/// <summary>
/// Gets or sets the red component.
/// </summary>
public byte R;
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Abgr32(byte r, byte g, byte b)
{
this.R = r;
this.G = g;
this.B = b;
this.A = byte.MaxValue;
}
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Abgr32(byte r, byte g, byte b, byte a)
{
this.R = r;
this.G = g;
this.B = b;
this.A = a;
}
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Abgr32(float r, float g, float b, float a = 1)
: this() => this.Pack(r, g, b, a);
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
public Abgr32(Vector3 vector)
: this() => this.Pack(ref vector);
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
public Abgr32(Vector4 vector)
: this() => this.Pack(ref vector);
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
/// </summary>
/// <param name="packed">
/// The packed value.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
public Abgr32(uint packed)
: this() => this.Abgr = packed;
/// <summary>
/// Gets or sets the packed representation of the Abgrb32 struct.
/// </summary>
public uint Abgr
{
[MethodImpl(InliningOptions.ShortMethod)]
readonly get => Unsafe.As<Abgr32, uint>(ref Unsafe.AsRef(this));
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Abgr32, uint>(ref this) = value;
}
/// <inheritdoc/>
public uint PackedValue
{
[MethodImpl(InliningOptions.ShortMethod)]
readonly get => this.Abgr;
[MethodImpl(InliningOptions.ShortMethod)]
set => this.Abgr = value;
}
/// <summary>
/// Converts an <see cref="Abgr32"/> to <see cref="Color"/>.
/// </summary>
/// <param name="source">The <see cref="Abgr32"/>.</param>
/// <returns>The <see cref="Color"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Color(Abgr32 source) => new(source);
/// <summary>
/// Converts a <see cref="Color"/> to <see cref="Abgr32"/>.
/// </summary>
/// <param name="color">The <see cref="Color"/>.</param>
/// <returns>The <see cref="Abgr32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Abgr32(Color color) => color.ToAbgr32();
/// <summary>
/// Compares two <see cref="Argb32"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Abgr32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Abgr32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Abgr32 left, Abgr32 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Abgr32"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Abgr32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Abgr32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right);
/// <inheritdoc />
public readonly PixelOperations<Abgr32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.Pack(ref vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this = source;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source)
{
// We can assign the Bgr24 value directly to last three bytes of this instance.
ref byte thisRef = ref Unsafe.As<Abgr32, byte>(ref this);
ref byte thisRefFromB = ref Unsafe.AddByteOffset(ref thisRef, new IntPtr(1));
Unsafe.As<byte, Bgr24>(ref thisRefFromB) = source;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source)
{
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source)
{
this.R = source.L;
this.G = source.L;
this.B = source.L;
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source)
{
this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R);
this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G);
this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B);
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source)
{
this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R);
this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G);
this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B);
this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A);
}
/// <inheritdoc/>
public override readonly bool Equals(object obj) => obj is Abgr32 abgr32 && this.Equals(abgr32);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(Abgr32 other) => this.Abgr == other.Abgr;
/// <summary>
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
public override readonly string ToString() => $"Abgr({this.A}, {this.B}, {this.G}, {this.R})";
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.Abgr.GetHashCode();
/// <summary>
/// Packs the four floats into a color.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(float x, float y, float z, float w)
{
var value = new Vector4(x, y, z, w);
this.Pack(ref value);
}
/// <summary>
/// Packs a <see cref="Vector3"/> into a uint.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector3 vector)
{
var value = new Vector4(vector, 1);
this.Pack(ref value);
}
/// <summary>
/// Packs a <see cref="Vector4"/> into a color.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X;
this.G = (byte)vector.Y;
this.B = (byte)vector.Z;
this.A = (byte)vector.W;
}
}
}

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

@ -230,6 +230,16 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source)

10
src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs

@ -185,6 +185,16 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = source.B;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
// We can assign this instances value directly to last three bytes of the Abgr32.
ref byte sourceRef = ref Unsafe.As<Abgr32, byte>(ref source);
ref byte sourceRefFromB = ref Unsafe.AddByteOffset(ref sourceRef, new IntPtr(1));
this = Unsafe.As<byte, Bgr24>(ref sourceRefFromB);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this = source.Bgr;

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

@ -99,6 +99,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromVector4(source.ToVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -165,6 +165,16 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source)

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

@ -102,6 +102,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -124,6 +124,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());

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

@ -124,6 +124,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());

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

@ -88,6 +88,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -99,6 +99,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -104,6 +104,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

7
src/ImageSharp/PixelFormats/PixelImplementations/L16.cs

@ -91,6 +91,13 @@ namespace SixLabors.ImageSharp.PixelFormats
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -83,6 +83,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -112,6 +112,14 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -127,6 +127,18 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -107,6 +107,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -109,6 +109,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -108,6 +108,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -110,6 +110,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

26
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs

@ -0,0 +1,26 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.Formats;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Abgr32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal partial class PixelOperations : PixelOperations<Abgr32>
{
private static readonly Lazy<PixelTypeInfo> LazyInfo =
new Lazy<PixelTypeInfo>(() => PixelTypeInfo.Create<Abgr32>(PixelAlphaRepresentation.Unassociated), true);
/// <inheritdoc />
public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value;
}
}
}

346
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs

@ -0,0 +1,346 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats.Utils;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Abgr32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal partial class PixelOperations : PixelOperations<Abgr32>
{
/// <inheritdoc />
public override void FromAbgr32(Configuration configuration, ReadOnlySpan<Abgr32> source, Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels));
source.CopyTo(destinationPixels.Slice(0, source.Length));
}
/// <inheritdoc />
public override void ToAbgr32(Configuration configuration, ReadOnlySpan<Abgr32> sourcePixels, Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length));
}
/// <inheritdoc />
public override void FromVector4Destructive(
Configuration configuration,
Span<Vector4> sourceVectors,
Span<Abgr32> destinationPixels,
PixelConversionModifiers modifiers)
{
Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale));
}
/// <inheritdoc />
public override void ToVector4(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Vector4> destVectors,
PixelConversionModifiers modifiers)
{
Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale));
}
/// <inheritdoc />
public override void ToRgba32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Rgba32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Rgba32, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToRgba32(source, dest);
}
/// <inheritdoc />
public override void FromRgba32(
Configuration configuration,
ReadOnlySpan<Rgba32> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Rgba32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromRgba32.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void ToArgb32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Argb32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Argb32, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToArgb32(source, dest);
}
/// <inheritdoc />
public override void FromArgb32(
Configuration configuration,
ReadOnlySpan<Argb32> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Argb32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromArgb32.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void ToBgra32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Bgra32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Bgra32, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToBgra32(source, dest);
}
/// <inheritdoc />
public override void FromBgra32(
Configuration configuration,
ReadOnlySpan<Bgra32> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Bgra32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromBgra32.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void ToRgb24(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Rgb24> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Rgb24, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToRgb24(source, dest);
}
/// <inheritdoc />
public override void FromRgb24(
Configuration configuration,
ReadOnlySpan<Rgb24> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Rgb24, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromRgb24.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Bgr24> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Bgr24, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToBgr24(source, dest);
}
/// <inheritdoc />
public override void FromBgr24(
Configuration configuration,
ReadOnlySpan<Bgr24> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Bgr24, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromBgr24.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void ToL8(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<L8> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
dp.FromAbgr32(sp);
}
}
/// <inheritdoc />
public override void ToL16(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<L16> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
dp.FromAbgr32(sp);
}
}
/// <inheritdoc />
public override void ToLa16(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<La16> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
dp.FromAbgr32(sp);
}
}
/// <inheritdoc />
public override void ToLa32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<La32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromAbgr32(sp);
}
}
/// <inheritdoc />
public override void ToRgb48(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Rgb48> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.FromAbgr32(sp);
}
}
/// <inheritdoc />
public override void ToRgba64(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Rgba64> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.FromAbgr32(sp);
}
}
/// <inheritdoc />
public override void ToBgra5551(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Bgra5551> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);
dp.FromAbgr32(sp);
}
}
/// <inheritdoc />
public override void From<TSourcePixel>(
Configuration configuration,
ReadOnlySpan<TSourcePixel> sourcePixels,
Span<Abgr32> destinationPixels)
{
PixelOperations<TSourcePixel>.Instance.ToAbgr32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length));
}
}
}
}

18
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.tt

@ -0,0 +1,18 @@
<#@include file="_Common.ttinclude" #>
<#@ output extension=".cs" #>
namespace SixLabors.ImageSharp.PixelFormats
{
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Abgr32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal partial class PixelOperations : PixelOperations<Abgr32>
{
<# GenerateAllDefaultConversionMethods("Abgr32"); #>
}
}
}

41
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs

@ -85,6 +85,33 @@ namespace SixLabors.ImageSharp.PixelFormats
PixelConverter.FromRgba32.ToArgb32(source, dest);
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Argb32> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Argb32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromArgb32.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void FromAbgr32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Argb32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Argb32, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToArgb32(source, dest);
}
/// <inheritdoc />
public override void ToBgra32(
Configuration configuration,
ReadOnlySpan<Argb32> sourcePixels,
@ -177,7 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -197,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -217,7 +244,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -237,7 +264,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -257,7 +284,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -277,7 +304,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -297,7 +324,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

41
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs

@ -112,6 +112,33 @@ namespace SixLabors.ImageSharp.PixelFormats
PixelConverter.FromArgb32.ToBgr24(source, dest);
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Bgr24> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Bgr24, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromBgr24.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void FromAbgr32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Bgr24> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Bgr24, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToBgr24(source, dest);
}
/// <inheritdoc />
public override void ToBgra32(
Configuration configuration,
ReadOnlySpan<Bgr24> sourcePixels,
@ -177,7 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -197,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -217,7 +244,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -237,7 +264,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -257,7 +284,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -277,7 +304,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -297,7 +324,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

41
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs

@ -112,6 +112,33 @@ namespace SixLabors.ImageSharp.PixelFormats
PixelConverter.FromArgb32.ToBgra32(source, dest);
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Bgra32> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Bgra32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromBgra32.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void FromAbgr32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Bgra32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Bgra32, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToBgra32(source, dest);
}
/// <inheritdoc />
public override void ToRgb24(
Configuration configuration,
ReadOnlySpan<Bgra32> sourcePixels,
@ -177,7 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -197,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -217,7 +244,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -237,7 +264,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -257,7 +284,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -277,7 +304,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -297,7 +324,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

42
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Bgra5551> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromBgra5551(sp);
}
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<Bgra5551> sourcePixels,
@ -70,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
@ -90,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
@ -110,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -130,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -170,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -190,7 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
@ -230,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -250,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);

42
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<L16> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromL16(sp);
}
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<L16> sourcePixels,
@ -70,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
@ -90,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
@ -110,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -130,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -170,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
@ -190,7 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -230,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -250,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

42
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<L8> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromL8(sp);
}
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<L8> sourcePixels,
@ -70,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
@ -90,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
@ -110,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -130,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -170,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
@ -190,7 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -230,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -250,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref L8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

42
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<La16> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromLa16(sp);
}
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<La16> sourcePixels,
@ -70,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
@ -90,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
@ -110,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -130,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -170,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
@ -190,7 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -230,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -250,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

42
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<La32> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromLa32(sp);
}
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<La32> sourcePixels,
@ -70,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
@ -90,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
@ -110,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -130,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -170,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
@ -190,7 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -230,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -250,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref La32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

41
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs

@ -112,6 +112,33 @@ namespace SixLabors.ImageSharp.PixelFormats
PixelConverter.FromArgb32.ToRgb24(source, dest);
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Rgb24> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Rgb24, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromRgb24.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void FromAbgr32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Rgb24> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Rgb24, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToRgb24(source, dest);
}
/// <inheritdoc />
public override void ToBgra32(
Configuration configuration,
ReadOnlySpan<Rgb24> sourcePixels,
@ -177,7 +204,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -197,7 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -217,7 +244,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -237,7 +264,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -257,7 +284,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -277,7 +304,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -297,7 +324,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

42
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Rgb48> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromRgb48(sp);
}
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<Rgb48> sourcePixels,
@ -70,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
@ -90,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
@ -110,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -130,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -170,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -190,7 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
@ -230,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -250,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

41
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs

@ -66,6 +66,33 @@ namespace SixLabors.ImageSharp.PixelFormats
PixelConverter.FromArgb32.ToRgba32(source, dest);
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Rgba32> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Rgba32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Abgr32, byte>(destinationPixels);
PixelConverter.FromRgba32.ToAbgr32(source, dest);
}
/// <inheritdoc />
public override void FromAbgr32(
Configuration configuration,
ReadOnlySpan<Abgr32> sourcePixels,
Span<Rgba32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ReadOnlySpan<byte> source = MemoryMarshal.Cast<Abgr32, byte>(sourcePixels);
Span<byte> dest = MemoryMarshal.Cast<Rgba32, byte>(destinationPixels);
PixelConverter.FromAbgr32.ToRgba32(source, dest);
}
/// <inheritdoc />
public override void ToBgra32(
Configuration configuration,
ReadOnlySpan<Rgba32> sourcePixels,
@ -158,7 +185,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -178,7 +205,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -198,7 +225,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -218,7 +245,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -238,7 +265,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -258,7 +285,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
@ -278,7 +305,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

42
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
@ -59,6 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <inheritdoc />
public override void ToAbgr32(
Configuration configuration,
ReadOnlySpan<Rgba64> sourcePixels,
Span<Abgr32> destinationPixels)
{
Guard.NotNull(configuration, nameof(configuration));
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destRef, i);
dp.FromRgba64(sp);
}
}
/// <inheritdoc />
public override void ToBgr24(
Configuration configuration,
ReadOnlySpan<Rgba64> sourcePixels,
@ -70,7 +90,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
@ -90,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
@ -110,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref L8 dp = ref Unsafe.Add(ref destRef, i);
@ -130,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref L16 dp = ref Unsafe.Add(ref destRef, i);
@ -150,7 +170,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref La16 dp = ref Unsafe.Add(ref destRef, i);
@ -170,7 +190,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref La32 dp = ref Unsafe.Add(ref destRef, i);
@ -190,7 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
@ -210,7 +230,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
@ -230,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
@ -250,7 +270,7 @@ namespace SixLabors.ImageSharp.PixelFormats
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i);

5
src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude

@ -17,6 +17,7 @@ using SixLabors.ImageSharp.PixelFormats.Utils;
private static readonly string[] CommonPixelTypes =
{
"Argb32",
"Abgr32",
"Bgr24",
"Bgra32",
"L8",
@ -34,6 +35,7 @@ using SixLabors.ImageSharp.PixelFormats.Utils;
{
"Rgba32",
"Argb32",
"Abgr32",
"Bgra32",
"Rgb24",
"Bgr24"
@ -43,6 +45,7 @@ using SixLabors.ImageSharp.PixelFormats.Utils;
private static readonly string[] Rgba32CompatibleTypes =
{
"Argb32",
"Abgr32",
"Bgra32",
"Rgb24",
"Bgr24"
@ -101,7 +104,7 @@ using SixLabors.ImageSharp.PixelFormats.Utils;
ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
for (nint i = 0; i < sourcePixels.Length; i++)
{
ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i);

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

@ -93,6 +93,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

9
src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs

@ -153,6 +153,15 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = source.B;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source)

9
src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs

@ -186,6 +186,15 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R);
this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G);
this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)

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

@ -96,6 +96,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -333,6 +333,16 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -94,6 +94,19 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="source">A structure of 4 bytes in ABGR byte order.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba64(Abgr32 source)
{
this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R);
this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G);
this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B);
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
@ -250,6 +263,16 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R);
this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G);
this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B);
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
@ -380,6 +403,20 @@ namespace SixLabors.ImageSharp.PixelFormats
return new Argb32(r, g, b, a);
}
/// <summary>
/// Convert to <see cref="Abgr32"/>.
/// </summary>
/// <returns>The <see cref="Abgr32"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Abgr32 ToAbgr32()
{
byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R);
byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G);
byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B);
byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A);
return new Abgr32(r, g, b, a);
}
/// <summary>
/// Convert to <see cref="Rgb24"/>.
/// </summary>

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

@ -134,6 +134,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -111,6 +111,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

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

@ -116,6 +116,10 @@ namespace SixLabors.ImageSharp.PixelFormats
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());

72
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs

@ -82,6 +82,78 @@ namespace SixLabors.ImageSharp.PixelFormats
this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Argb32>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Abgr32"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations.</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Abgr32"/> data.</param>
/// <param name="destinationPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
public virtual void FromAbgr32(Configuration configuration, ReadOnlySpan<Abgr32> source, Span<TPixel> destinationPixels)
{
Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels));
ref Abgr32 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < source.Length; i++)
{
ref Abgr32 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.FromAbgr32(sp);
}
}
/// <summary>
/// A helper for <see cref="FromAbgr32(Configuration, ReadOnlySpan{Abgr32}, Span{TPixel})"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Abgr32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations.</param>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destinationPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromAbgr32Bytes(Configuration configuration, ReadOnlySpan<byte> sourceBytes, Span<TPixel> destinationPixels, int count)
{
this.FromAbgr32(configuration, MemoryMarshal.Cast<byte, Abgr32>(sourceBytes).Slice(0, count), destinationPixels);
}
/// <summary>
/// Converts all pixels of the 'sourcePixels` span to a span of <see cref="Abgr32"/>-s.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destinationPixels">The destination span of <see cref="Abgr32"/> data.</param>
public virtual void ToAbgr32(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<Abgr32> destinationPixels)
{
Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels));
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Abgr32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels);
for (int i = 0; i < sourcePixels.Length; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Abgr32 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.FromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="ToAbgr32(Configuration, ReadOnlySpan{TPixel}, Span{Abgr32})"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Abgr32"/> layout.
/// </summary>
/// <param name="configuration">A <see cref="Configuration"/> to configure internal operations</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToAbgr32Bytes(Configuration configuration, ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToAbgr32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast<byte, Abgr32>(destBytes));
}
/// <summary>
/// Converts all pixels in 'source` span of <see cref="Bgr24"/> into a span of <typeparamref name="TPixel"/>-s.
/// </summary>

3
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt

@ -112,6 +112,9 @@ namespace SixLabors.ImageSharp.PixelFormats
GenerateFromMethods("Argb32");
GenerateToDestFormatMethods("Argb32");
GenerateFromMethods("Abgr32");
GenerateToDestFormatMethods("Abgr32");
GenerateFromMethods("Bgr24");
GenerateToDestFormatMethods("Bgr24");

125
src/ImageSharp/PixelFormats/Utils/PixelConverter.cs

@ -18,8 +18,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
/// </remarks>
internal static class PixelConverter
{
/// <summary>
/// Optimized converters from <see cref="Rgba32"/>.
/// </summary>
public static class FromRgba32
{
// Input pixels have: X = R, Y = G, Z = B and W = A.
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Rgba32"/> pixels to a <see cref="Span{Byte}"/> representing
@ -38,6 +43,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
public static void ToBgra32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<ZYXWShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Argb32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Abgr32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToAbgr32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<WZYXShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Rgba32"/> pixels to a <see cref="Span{Byte}"/> representing
@ -57,8 +71,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
=> SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(3, 0, 1, 2));
}
/// <summary>
/// Optimized converters from <see cref="Argb32"/>.
/// </summary>
public static class FromArgb32
{
// Input pixels have: X = A, Y = R, Z = G and W = B.
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Argb32"/> pixels to a <see cref="Span{Byte}"/> representing
@ -77,6 +96,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
public static void ToBgra32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<WZYXShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Argb32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Abgr32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToAbgr32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<XWZYShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Argb32"/> pixels to a <see cref="Span{Byte}"/> representing
@ -96,8 +124,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
=> SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 1, 2, 3));
}
/// <summary>
/// Optimized converters from <see cref="Bgra32"/>.
/// </summary>
public static class FromBgra32
{
// Input pixels have: X = B, Y = G, Z = R and W = A.
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Bgra32"/> pixels to a <see cref="Span{Byte}"/> representing
@ -110,12 +143,21 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Bgra32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Bgra32"/> pixels.
/// a collection of <see cref="Rgba32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToRgba32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<ZYXWShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Bgra32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Abgr32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToAbgr32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<WXYZShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Argb32"/> pixels to a <see cref="Span{Byte}"/> representing
@ -135,8 +177,66 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
=> SimdUtils.Shuffle4Slice3<XYZWShuffle4Slice3>(source, dest, default);
}
/// <summary>
/// Optimized converters from <see cref="Abgr32"/>.
/// </summary>
public static class FromAbgr32
{
// Input pixels have: X = A, Y = B, Z = G and W = R.
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Abgr32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Argb32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToArgb32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<XWZYShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Abgr32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Bgra32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToRgba32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<WZYXShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Abgr32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Bgra32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToBgra32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4<YZWXShuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Abgr32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Rgb24"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToRgb24(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 1, 2, 3));
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Abgr32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Bgr24"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToBgr24(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Shuffle4Slice3(source, dest, new DefaultShuffle4Slice3(0, 3, 2, 1));
}
/// <summary>
/// Optimized converters from <see cref="Rgb24"/>.
/// </summary>
public static class FromRgb24
{
// Input pixels have: X = R, Y = G and Z = B.
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Rgb24"/> pixels to a <see cref="Span{Byte}"/> representing
@ -164,6 +264,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
public static void ToBgra32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(3, 0, 1, 2));
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Rgba32"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Bgra32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToAbgr32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(0, 1, 2, 3));
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Rgb24"/> pixels to a <see cref="Span{Byte}"/> representing
@ -174,8 +283,13 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
=> SimdUtils.Shuffle3(source, dest, new DefaultShuffle3(0, 1, 2));
}
/// <summary>
/// Optimized converters from <see cref="Bgr24"/>.
/// </summary>
public static class FromBgr24
{
// Input pixels have: X = B, Y = G and Z = R.
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Bgr24"/> pixels to a <see cref="Span{Byte}"/> representing
@ -203,6 +317,15 @@ namespace SixLabors.ImageSharp.PixelFormats.Utils
public static void ToBgra32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Pad3Shuffle4<XYZWPad3Shuffle4>(source, dest, default);
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Bgr24"/> pixels to a <see cref="Span{Byte}"/> representing
/// a collection of <see cref="Abgr32"/> pixels.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static void ToAbgr32(ReadOnlySpan<byte> source, Span<byte> dest)
=> SimdUtils.Pad3Shuffle4(source, dest, new DefaultPad3Shuffle4(2, 1, 0, 3));
/// <summary>
/// Converts a <see cref="ReadOnlySpan{Byte}"/> representing a collection of
/// <see cref="Bgr24"/> pixels to a <see cref="Span{Byte}"/> representing

1
tests/Directory.Build.targets

@ -33,6 +33,7 @@
<PackageReference Update="SharpZipLib" Version="1.3.2" />
<PackageReference Update="SkiaSharp" Version="2.80.2" />
<PackageReference Update="System.Drawing.Common" Version="5.0.2" />
<PackageReference Update="System.IO.Compression" Version="4.3.0" />
</ItemGroup>
</Project>

46
tests/ImageSharp.Benchmarks/General/Buffer2D_DangerousGetRowSpan.cs

@ -0,0 +1,46 @@
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General
{
public class Buffer2D_DangerousGetRowSpan
{
private const int Height = 1024;
[Params(0.5, 2.0, 10.0)] public double SizeMegaBytes { get; set; }
private Buffer2D<Rgba32> buffer;
[GlobalSetup]
public unsafe void Setup()
{
int totalElements = (int)(1024 * 1024 * this.SizeMegaBytes) / sizeof(Rgba32);
int width = totalElements / Height;
MemoryAllocator allocator = Configuration.Default.MemoryAllocator;
this.buffer = allocator.Allocate2D<Rgba32>(width, Height);
}
[GlobalCleanup]
public void Cleanup() => this.buffer.Dispose();
[Benchmark]
public int DangerousGetRowSpan() =>
this.buffer.DangerousGetRowSpan(1).Length +
this.buffer.DangerousGetRowSpan(Height - 1).Length;
// BenchmarkDotNet=v0.13.0, OS=Windows 10.0.19044
// Intel Core i9-10900X CPU 3.70GHz, 1 CPU, 20 logical and 10 physical cores
//
// | Method | SizeMegaBytes | Mean | Error | StdDev |
// |-------------------- |-------------- |----------:|----------:|----------:|
// | DangerousGetRowSpan | 0.5 | 7.498 ns | 0.1784 ns | 0.3394 ns |
// | DangerousGetRowSpan | 2 | 6.542 ns | 0.1565 ns | 0.3659 ns |
// | DangerousGetRowSpan | 10 | 38.556 ns | 0.6604 ns | 0.8587 ns |
}
}

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

Loading…
Cancel
Save