Browse Source

Merge pull request #2645 from SixLabors/js/pixelsformats

Modernize and optimize pixel format operations across platforms.
pull/2657/head
James Jackson-South 2 years ago
committed by GitHub
parent
commit
2d979f90dd
No known key found for this signature in database GPG Key ID: B5690EEEBB952194
  1. 2
      .editorconfig
  2. 2
      shared-infrastructure
  3. 4
      src/ImageSharp.ruleset
  4. 21
      src/ImageSharp/Color/Color.cs
  5. 37
      src/ImageSharp/Common/Helpers/ColorNumerics.cs
  6. 7
      src/ImageSharp/Common/Helpers/Numerics.cs
  7. 194
      src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs
  8. 28
      src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs
  9. 20
      src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs
  10. 178
      src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs
  11. 30
      src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs
  12. 466
      src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs
  13. 125
      src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs
  14. 176
      src/ImageSharp/Common/Helpers/Vector128Utilities.cs
  15. 78
      src/ImageSharp/Common/Helpers/Vector256Utilities.cs
  16. 80
      src/ImageSharp/Common/Helpers/Vector512Utilities.cs
  17. 210
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  18. 10
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  19. 7
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  20. 9
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  21. 119
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
  22. 14
      src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs
  23. 100
      src/ImageSharp/Formats/Tga/TgaDecoderCore.cs
  24. 10
      src/ImageSharp/Formats/Tga/TgaEncoderCore.cs
  25. 140
      src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs
  26. 10
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs
  27. 6
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs
  28. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs
  29. 11
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs
  30. 13
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs
  31. 25
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs
  32. 13
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs
  33. 11
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs
  34. 10
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs
  35. 8
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs
  36. 13
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs
  37. 15
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs
  38. 22
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs
  39. 20
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs
  40. 20
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs
  41. 20
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs
  42. 21
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs
  43. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs
  44. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs
  45. 13
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs
  46. 8
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs
  47. 23
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs
  48. 34
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs
  49. 33
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs
  50. 32
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs
  51. 33
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs
  52. 34
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs
  53. 5
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs
  54. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs
  55. 18
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs
  56. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs
  57. 14
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs
  58. 7
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs
  59. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs
  60. 11
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs
  61. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32TiffColor{TPixel}.cs
  62. 25
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs
  63. 8
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs
  64. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs
  65. 12
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs
  66. 11
      src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs
  67. 6
      src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs
  68. 120
      src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs
  69. 176
      src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs
  70. 1
      src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs
  71. 1
      src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs
  72. 2
      src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs
  73. 2
      src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs
  74. 1
      src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs
  75. 1
      src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs
  76. 4
      src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs
  77. 2
      src/ImageSharp/Formats/Webp/RiffHelper.cs
  78. 2
      src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs
  79. 127
      src/ImageSharp/PixelFormats/IPixel.cs
  80. 432
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
  81. 4
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt
  82. 432
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
  83. 4
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt
  84. 8
      src/ImageSharp/PixelFormats/PixelConversionModifiers.cs
  85. 102
      src/ImageSharp/PixelFormats/PixelImplementations/A8.cs
  86. 246
      src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs
  87. 259
      src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs
  88. 180
      src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs
  89. 135
      src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs
  90. 210
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs
  91. 122
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs
  92. 118
      src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs
  93. 139
      src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs
  94. 118
      src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs
  95. 132
      src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs
  96. 134
      src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs
  97. 140
      src/ImageSharp/PixelFormats/PixelImplementations/L16.cs
  98. 133
      src/ImageSharp/PixelFormats/PixelImplementations/L8.cs
  99. 198
      src/ImageSharp/PixelFormats/PixelImplementations/La16.cs
  100. 221
      src/ImageSharp/PixelFormats/PixelImplementations/La32.cs

2
.editorconfig

@ -172,6 +172,8 @@ dotnet_diagnostic.IDE0063.severity = suggestion
csharp_using_directive_placement = outside_namespace:warning
# Modifier preferences
csharp_prefer_static_local_function = true:warning
# Primary constructor preferences
csharp_style_prefer_primary_constructors = false:none
##########################################
# Unnecessary Code Rules

2
shared-infrastructure

@ -1 +1 @@
Subproject commit d65232bbbfe55a9a153b4058139dda5230e6eb4f
Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f

4
src/ImageSharp.ruleset

@ -1,6 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="ImageSharp" ToolsVersion="17.0">
<Include Path="..\shared-infrastructure\sixlabors.ruleset" Action="Default" />
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
</Rules>
</RuleSet>
</RuleSet>

21
src/ImageSharp/Color/Color.cs

@ -98,10 +98,8 @@ public readonly partial struct Color : IEquatable<Color>
{
return new(pixel.ToScaledVector4());
}
else
{
return new(pixel);
}
return new(pixel);
}
/// <summary>
@ -250,15 +248,12 @@ public readonly partial struct Color : IEquatable<Color>
[MethodImpl(InliningOptions.ShortMethod)]
public string ToHex()
{
Rgba32 rgba = default;
if (this.boxedHighPrecisionPixel is not null)
{
this.boxedHighPrecisionPixel.ToRgba32(ref rgba);
return rgba.ToHex();
return this.boxedHighPrecisionPixel.ToRgba32().ToHex();
}
rgba.FromScaledVector4(this.data);
return rgba.ToHex();
return Rgba32.FromScaledVector4(this.data).ToHex();
}
/// <inheritdoc />
@ -280,14 +275,10 @@ public readonly partial struct Color : IEquatable<Color>
if (this.boxedHighPrecisionPixel is null)
{
pixel = default;
pixel.FromScaledVector4(this.data);
return pixel;
return TPixel.FromScaledVector4(this.data);
}
pixel = default;
pixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
return pixel;
return TPixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4());
}
/// <summary>

37
src/ImageSharp/Common/Helpers/ColorNumerics.cs

@ -41,6 +41,34 @@ internal static class ColorNumerics
public static byte Get8BitBT709Luminance(byte r, byte g, byte b)
=> (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F);
/// <summary>
/// Gets the luminance from the rgb components using the formula
/// as specified by ITU-R Recommendation BT.709.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <returns>The <see cref="byte"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte Get8BitBT709Luminance(ushort r, ushort g, ushort b)
=> (byte)((From16BitTo8Bit(r) * .2126F) +
(From16BitTo8Bit(g) * .7152F) +
(From16BitTo8Bit(b) * .0722F) + 0.5F);
/// <summary>
/// Gets the luminance from the rgb components using the formula as
/// specified by ITU-R Recommendation BT.709.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <returns>The <see cref="ushort"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort Get16BitBT709Luminance(byte r, byte g, byte b)
=> (ushort)((From8BitTo16Bit(r) * .2126F) +
(From8BitTo16Bit(g) * .7152F) +
(From8BitTo16Bit(b) * .0722F) + 0.5F);
/// <summary>
/// Gets the luminance from the rgb components using the formula as
/// specified by ITU-R Recommendation BT.709.
@ -72,8 +100,8 @@ internal static class ColorNumerics
/// <param name="component">The 8 bit component value.</param>
/// <returns>The <see cref="byte"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static byte DownScaleFrom16BitTo8Bit(ushort component)
{
public static byte From16BitTo8Bit(ushort component) =>
// To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is:
//
// (V * 255) / 65535
@ -102,8 +130,7 @@ internal static class ColorNumerics
// An alternative arithmetic calculation which also gives no errors is:
//
// (V * 255 + 32895) >> 16
return (byte)(((component * 255) + 32895) >> 16);
}
(byte)(((component * 255) + 32895) >> 16);
/// <summary>
/// Scales a value from an 8 bit <see cref="byte"/> to
@ -112,7 +139,7 @@ internal static class ColorNumerics
/// <param name="component">The 8 bit component value.</param>
/// <returns>The <see cref="ushort"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort UpscaleFrom8BitTo16Bit(byte component)
public static ushort From8BitTo16Bit(byte component)
=> (ushort)(component * 257);
/// <summary>

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

@ -5,7 +5,6 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp;
@ -61,6 +60,12 @@ internal static class Numerics
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nint Modulo4(nint x) => x & 3;
/// <summary>
/// Calculates <paramref name="x"/> % 4
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static nuint Modulo4(nuint x) => x & 3;
/// <summary>
/// Calculates <paramref name="x"/> % 8
/// </summary>

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

@ -1,12 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
// The JIT can detect and optimize rotation idioms ROTL (Rotate Left)
// and ROTR (Rotate Right) emitting efficient CPU instructions:
// https://github.com/dotnet/coreclr/pull/1830
@ -19,190 +13,24 @@ namespace SixLabors.ImageSharp;
internal interface IComponentShuffle
{
/// <summary>
/// Shuffles then slices 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// Shuffles then slices 8-bit integers in <paramref name="source"/>
/// using a byte control and store the results in <paramref name="destination"/>.
/// If successful, this method will reduce the length of <paramref name="source"/> length
/// by the shuffle amount.
/// </summary>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest);
/// <param name="destination">The destination span of bytes.</param>
void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination);
/// <summary>
/// Shuffle 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// Shuffle 8-bit integers in <paramref name="source"/>
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <remarks>
/// Implementation can assume that source.Length is less or equal than dest.Length.
/// Implementation can assume that source.Length is less or equal than destination.Length.
/// Loops should iterate using source.Length.
/// </remarks>
void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest);
}
/// <inheritdoc/>
internal interface IShuffle4 : IComponentShuffle
{
}
internal readonly struct DefaultShuffle4 : IShuffle4
{
public DefaultShuffle4(byte control)
=> this.Control = control;
public byte Control { get; }
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref dest, this.Control);
[MethodImpl(InliningOptions.ShortMethod)]
public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest);
Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
for (nuint i = 0; i < (uint)source.Length; i += 4)
{
Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i);
Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i);
Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i);
}
}
}
internal readonly struct WXYZShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle2103);
[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));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// ROTL(8, packed) = [Z Y X W]
Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24);
}
}
}
internal readonly struct WZYXShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0123);
[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));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// REVERSE(packedArgb) = [X Y Z W]
Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed);
}
}
}
internal readonly struct YZWXShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0321);
[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));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// ROTR(8, packedArgb) = [Y Z W X]
Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8);
}
}
}
internal readonly struct ZYXWShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3012);
[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));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// tmp1 = [W 0 Y 0]
// tmp2 = [0 Z 0 X]
// tmp3=ROTL(16, tmp2) = [0 X 0 Z]
// tmp1 + tmp3 = [W X Y Z]
uint tmp1 = packed & 0xFF00FF00;
uint tmp2 = packed & 0x00FF00FF;
uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}
}
}
internal readonly struct XWZYShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle1230);
[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));
uint n = (uint)source.Length / 4;
for (nuint 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 = BitOperations.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}
}
void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination);
}

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

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
@ -12,24 +13,23 @@ internal interface IPad3Shuffle4 : IComponentShuffle
{
}
internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4
internal readonly struct DefaultPad3Shuffle4([ConstantExpected] byte control) : IPad3Shuffle4
{
public DefaultPad3Shuffle4(byte control)
=> this.Control = control;
public byte Control { get; }
public byte Control { get; } = control;
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, this.Control);
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
#pragma warning disable CA1857 // A constant is expected for the parameter
=> HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, this.Control);
#pragma warning restore CA1857 // A constant is expected for the parameter
[MethodImpl(InliningOptions.ShortMethod)]
public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest);
ref byte dBase = ref MemoryMarshal.GetReference(destination);
Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
Span<byte> temp = stackalloc byte[4];
ref byte t = ref MemoryMarshal.GetReference(temp);
@ -51,14 +51,14 @@ internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4
internal readonly struct XYZWPad3Shuffle4 : IPad3Shuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3210);
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
=> HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210);
[MethodImpl(InliningOptions.ShortMethod)]
public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest);
ref byte dBase = ref MemoryMarshal.GetReference(destination);
ref byte sEnd = ref Unsafe.Add(ref sBase, (uint)source.Length);
ref byte sLoopEnd = ref Unsafe.Subtract(ref sEnd, 4);

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

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
@ -12,24 +13,23 @@ internal interface IShuffle3 : IComponentShuffle
{
}
internal readonly struct DefaultShuffle3 : IShuffle3
internal readonly struct DefaultShuffle3([ConstantExpected] byte control) : IShuffle3
{
public DefaultShuffle3(byte control)
=> this.Control = control;
public byte Control { get; }
public byte Control { get; } = control;
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle3Reduce(ref source, ref dest, this.Control);
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
#pragma warning disable CA1857 // A constant is expected for the parameter
=> HwIntrinsics.Shuffle3Reduce(ref source, ref destination, this.Control);
#pragma warning restore CA1857 // A constant is expected for the parameter
[MethodImpl(InliningOptions.ShortMethod)]
public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest);
ref byte dBase = ref MemoryMarshal.GetReference(destination);
Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
for (nuint i = 0; i < (uint)source.Length; i += 3)
{

178
src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs

@ -0,0 +1,178 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
namespace SixLabors.ImageSharp;
/// <inheritdoc/>
internal interface IShuffle4 : IComponentShuffle
{
}
internal readonly struct DefaultShuffle4([ConstantExpected] byte control) : IShuffle4
{
public byte Control { get; } = control;
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
#pragma warning disable CA1857 // A constant is expected for the parameter
=> HwIntrinsics.Shuffle4Reduce(ref source, ref destination, this.Control);
#pragma warning restore CA1857 // A constant is expected for the parameter
[MethodImpl(InliningOptions.ShortMethod)]
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(destination);
SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0);
for (nuint i = 0; i < (uint)source.Length; i += 4)
{
Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i);
Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i);
Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i);
}
}
}
internal readonly struct WXYZShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle2103);
[MethodImpl(InliningOptions.ShortMethod)]
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(destination));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// ROTL(8, packed) = [Z Y X W]
Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24);
}
}
}
internal readonly struct WZYXShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0123);
[MethodImpl(InliningOptions.ShortMethod)]
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(destination));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// REVERSE(packedArgb) = [X Y Z W]
Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed);
}
}
}
internal readonly struct YZWXShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0321);
[MethodImpl(InliningOptions.ShortMethod)]
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(destination));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// ROTR(8, packedArgb) = [Y Z W X]
Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8);
}
}
}
internal readonly struct ZYXWShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3012);
[MethodImpl(InliningOptions.ShortMethod)]
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(destination));
uint n = (uint)source.Length / 4;
for (nuint i = 0; i < n; i++)
{
uint packed = Unsafe.Add(ref sBase, i);
// packed = [W Z Y X]
// tmp1 = [W 0 Y 0]
// tmp2 = [0 Z 0 X]
// tmp3=ROTL(16, tmp2) = [0 X 0 Z]
// tmp1 + tmp3 = [W X Y Z]
uint tmp1 = packed & 0xFF00FF00;
uint tmp2 = packed & 0x00FF00FF;
uint tmp3 = BitOperations.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}
}
}
internal readonly struct XWZYShuffle4 : IShuffle4
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
=> HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle1230);
[MethodImpl(InliningOptions.ShortMethod)]
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref uint dBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(destination));
uint n = (uint)source.Length / 4;
for (nuint 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 = BitOperations.RotateLeft(tmp2, 16);
Unsafe.Add(ref dBase, i) = tmp1 + tmp3;
}
}
}

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

@ -1,6 +1,7 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using static SixLabors.ImageSharp.SimdUtils;
@ -12,26 +13,25 @@ internal interface IShuffle4Slice3 : IComponentShuffle
{
}
internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3
internal readonly struct DefaultShuffle4Slice3([ConstantExpected] byte control) : IShuffle4Slice3
{
public DefaultShuffle4Slice3(byte control)
=> this.Control = control;
public byte Control { get; }
public byte Control { get; } = control;
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, this.Control);
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
#pragma warning disable CA1857 // A constant is expected for the parameter
=> HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, this.Control);
#pragma warning restore CA1857 // A constant is expected for the parameter
[MethodImpl(InliningOptions.ShortMethod)]
public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest);
ref byte dBase = ref MemoryMarshal.GetReference(destination);
Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0);
for (nuint i = 0, j = 0; i < (uint)dest.Length; i += 3, j += 4)
for (nuint i = 0, j = 0; i < (uint)destination.Length; i += 3, j += 4)
{
Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + j);
Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + j);
@ -43,14 +43,14 @@ internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3
internal readonly struct XYZWShuffle4Slice3 : IShuffle4Slice3
{
[MethodImpl(InliningOptions.ShortMethod)]
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> dest)
=> HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, Shuffle.MMShuffle3210);
public void ShuffleReduce(ref ReadOnlySpan<byte> source, ref Span<byte> destination)
=> HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210);
[MethodImpl(InliningOptions.ShortMethod)]
public void RunFallbackShuffle(ReadOnlySpan<byte> source, Span<byte> dest)
public void Shuffle(ReadOnlySpan<byte> source, Span<byte> destination)
{
ref uint sBase = ref Unsafe.As<byte, uint>(ref MemoryMarshal.GetReference(source));
ref Byte3 dBase = ref Unsafe.As<byte, Byte3>(ref MemoryMarshal.GetReference(dest));
ref Byte3 dBase = ref Unsafe.As<byte, Byte3>(ref MemoryMarshal.GetReference(destination));
nint n = (nint)(uint)source.Length / 4;
nint m = Numerics.Modulo4(n);

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

@ -8,6 +8,7 @@ using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp;
@ -51,22 +52,34 @@ internal static partial class SimdUtils
/// <summary>
/// Shuffle single-precision (32-bit) floating-point elements in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <param name="source">The source span of floats.</param>
/// <param name="dest">The destination span of floats.</param>
/// <param name="destination">The destination span of floats.</param>
/// <param name="control">The byte control.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle4Reduce(
ref ReadOnlySpan<float> source,
ref Span<float> dest,
ref Span<float> destination,
[ConstantExpected] byte control)
{
if (Avx.IsSupported || Sse.IsSupported)
if ((Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleFloat) ||
(Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleFloat) ||
(Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleFloat))
{
int remainder = Avx.IsSupported
? Numerics.ModuloP2(source.Length, Vector256<float>.Count)
: Numerics.ModuloP2(source.Length, Vector128<float>.Count);
int remainder = 0;
if (Vector512.IsHardwareAccelerated)
{
remainder = Numerics.ModuloP2(source.Length, Vector512<float>.Count);
}
else if (Vector256.IsHardwareAccelerated)
{
remainder = Numerics.ModuloP2(source.Length, Vector256<float>.Count);
}
else if (Vector128.IsHardwareAccelerated)
{
remainder = Numerics.ModuloP2(source.Length, Vector128<float>.Count);
}
int adjustedCount = source.Length - remainder;
@ -74,33 +87,45 @@ internal static partial class SimdUtils
{
Shuffle4(
source[..adjustedCount],
dest[..adjustedCount],
destination[..adjustedCount],
control);
source = source[adjustedCount..];
dest = dest[adjustedCount..];
destination = destination[adjustedCount..];
}
}
}
/// <summary>
/// Shuffle 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// Shuffle 8-bit integers <paramref name="source"/>
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="control">The byte control.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle4Reduce(
ref ReadOnlySpan<byte> source,
ref Span<byte> dest,
byte control)
ref Span<byte> destination,
[ConstantExpected] byte control)
{
if (Avx2.IsSupported || Ssse3.IsSupported)
if ((Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleByte) ||
(Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleByte) ||
(Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte))
{
int remainder = Avx2.IsSupported
? Numerics.ModuloP2(source.Length, Vector256<byte>.Count)
: Numerics.ModuloP2(source.Length, Vector128<byte>.Count);
int remainder = 0;
if (Vector512.IsHardwareAccelerated)
{
remainder = Numerics.ModuloP2(source.Length, Vector512<byte>.Count);
}
else if (Vector256.IsHardwareAccelerated)
{
remainder = Numerics.ModuloP2(source.Length, Vector256<byte>.Count);
}
else if (Vector128.IsHardwareAccelerated)
{
remainder = Numerics.ModuloP2(source.Length, Vector128<byte>.Count);
}
int adjustedCount = source.Length - remainder;
@ -108,29 +133,29 @@ internal static partial class SimdUtils
{
Shuffle4(
source[..adjustedCount],
dest[..adjustedCount],
destination[..adjustedCount],
control);
source = source[adjustedCount..];
dest = dest[adjustedCount..];
destination = destination[adjustedCount..];
}
}
}
/// <summary>
/// Shuffles 8-bit integer triplets within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// Shuffles 8-bit integer triplets in <paramref name="source"/>
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="control">The byte control.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle3Reduce(
ref ReadOnlySpan<byte> source,
ref Span<byte> dest,
byte control)
ref Span<byte> destination,
[ConstantExpected] byte control)
{
if (Ssse3.IsSupported)
if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsRightAlign)
{
int remainder = source.Length % (Vector128<byte>.Count * 3);
@ -140,77 +165,77 @@ internal static partial class SimdUtils
{
Shuffle3(
source[..adjustedCount],
dest[..adjustedCount],
destination[..adjustedCount],
control);
source = source[adjustedCount..];
dest = dest[adjustedCount..];
destination = destination[adjustedCount..];
}
}
}
/// <summary>
/// Pads then shuffles 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// Pads then shuffles 8-bit integers in <paramref name="source"/>
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="control">The byte control.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Pad3Shuffle4Reduce(
ref ReadOnlySpan<byte> source,
ref Span<byte> dest,
byte control)
ref Span<byte> destination,
[ConstantExpected] byte control)
{
if (Ssse3.IsSupported)
if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte)
{
int remainder = source.Length % (Vector128<byte>.Count * 3);
int sourceCount = source.Length - remainder;
int destCount = (int)((uint)sourceCount * 4 / 3);
int destinationCount = (int)((uint)sourceCount * 4 / 3);
if (sourceCount > 0)
{
Pad3Shuffle4(
source[..sourceCount],
dest[..destCount],
destination[..destinationCount],
control);
source = source[sourceCount..];
dest = dest[destCount..];
destination = destination[destinationCount..];
}
}
}
/// <summary>
/// Shuffles then slices 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// Shuffles then slices 8-bit integers in <paramref name="source"/>
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="control">The byte control.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle4Slice3Reduce(
ref ReadOnlySpan<byte> source,
ref Span<byte> dest,
byte control)
ref Span<byte> destination,
[ConstantExpected] byte control)
{
if (Ssse3.IsSupported)
if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte)
{
int remainder = source.Length & ((Vector128<byte>.Count * 4) - 1); // bit-hack for modulo
int sourceCount = source.Length - remainder;
int destCount = (int)((uint)sourceCount * 3 / 4);
int destinationCount = (int)((uint)sourceCount * 3 / 4);
if (sourceCount > 0)
{
Shuffle4Slice3(
source[..sourceCount],
dest[..destCount],
destination[..destinationCount],
control);
source = source[sourceCount..];
dest = dest[destCount..];
destination = destination[destinationCount..];
}
}
}
@ -218,76 +243,90 @@ internal static partial class SimdUtils
[MethodImpl(InliningOptions.ShortMethod)]
private static void Shuffle4(
ReadOnlySpan<float> source,
Span<float> dest,
Span<float> destination,
[ConstantExpected] byte control)
{
if (Avx.IsSupported)
if (Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleFloat)
{
ref Vector256<float> sourceBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source));
ref Vector512<float> sourceBase = ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(source));
ref Vector512<float> destinationBase = ref Unsafe.As<float, Vector512<float>>(ref MemoryMarshal.GetReference(destination));
ref Vector256<float> destBase =
ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(dest));
nuint n = (uint)destination.Length / (uint)Vector512<float>.Count;
nuint m = Numerics.Modulo4(n);
nuint u = n - m;
nint n = (nint)dest.Vector256Count<float>();
nint m = Numerics.Modulo4(n);
nint u = n - m;
for (nint i = 0; i < u; i += 4)
for (nuint i = 0; i < u; i += 4)
{
ref Vector256<float> vd0 = ref Unsafe.Add(ref destBase, i);
ref Vector256<float> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector512<float> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector512<float> vd0 = ref Unsafe.Add(ref destinationBase, i);
vd0 = Avx.Permute(vs0, control);
Unsafe.Add(ref vd0, 1) = Avx.Permute(Unsafe.Add(ref vs0, 1), control);
Unsafe.Add(ref vd0, 2) = Avx.Permute(Unsafe.Add(ref vs0, 2), control);
Unsafe.Add(ref vd0, 3) = Avx.Permute(Unsafe.Add(ref vs0, 3), control);
vd0 = Vector512Utilities.Shuffle(vs0, control);
Unsafe.Add(ref vd0, (nuint)1) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control);
Unsafe.Add(ref vd0, (nuint)2) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control);
Unsafe.Add(ref vd0, (nuint)3) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control);
}
if (m > 0)
{
for (nint i = u; i < n; i++)
for (nuint i = u; i < n; i++)
{
Unsafe.Add(ref destBase, i) = Avx.Permute(Unsafe.Add(ref sourceBase, i), control);
Unsafe.Add(ref destinationBase, i) = Vector512Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control);
}
}
}
else
else if (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleFloat)
{
// Sse
ref Vector128<float> sourceBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(source));
ref Vector256<float> sourceBase = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(source));
ref Vector256<float> destinationBase = ref Unsafe.As<float, Vector256<float>>(ref MemoryMarshal.GetReference(destination));
ref Vector128<float> destBase =
ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(dest));
nuint n = (uint)destination.Length / (uint)Vector256<float>.Count;
nuint m = Numerics.Modulo4(n);
nuint u = n - m;
nint n = (nint)((uint)dest.Length / (uint)Vector128<float>.Count);
nint m = Numerics.Modulo4(n);
nint u = n - m;
for (nint i = 0; i < u; i += 4)
for (nuint i = 0; i < u; i += 4)
{
ref Vector128<float> vd0 = ref Unsafe.Add(ref destBase, i);
ref Vector128<float> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector256<float> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector256<float> vd0 = ref Unsafe.Add(ref destinationBase, i);
vd0 = Vector256Utilities.Shuffle(vs0, control);
Unsafe.Add(ref vd0, (nuint)1) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control);
Unsafe.Add(ref vd0, (nuint)2) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control);
Unsafe.Add(ref vd0, (nuint)3) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control);
}
vd0 = Sse.Shuffle(vs0, vs0, control);
if (m > 0)
{
for (nuint i = u; i < n; i++)
{
Unsafe.Add(ref destinationBase, i) = Vector256Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control);
}
}
}
else if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleFloat)
{
ref Vector128<float> sourceBase = ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(source));
ref Vector128<float> destinationBase = ref Unsafe.As<float, Vector128<float>>(ref MemoryMarshal.GetReference(destination));
Vector128<float> vs1 = Unsafe.Add(ref vs0, 1);
Unsafe.Add(ref vd0, 1) = Sse.Shuffle(vs1, vs1, control);
nuint n = (uint)destination.Length / (uint)Vector128<float>.Count;
nuint m = Numerics.Modulo4(n);
nuint u = n - m;
Vector128<float> vs2 = Unsafe.Add(ref vs0, 2);
Unsafe.Add(ref vd0, 2) = Sse.Shuffle(vs2, vs2, control);
for (nuint i = 0; i < u; i += 4)
{
ref Vector128<float> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector128<float> vd0 = ref Unsafe.Add(ref destinationBase, i);
Vector128<float> vs3 = Unsafe.Add(ref vs0, 3);
Unsafe.Add(ref vd0, 3) = Sse.Shuffle(vs3, vs3, control);
vd0 = Vector128Utilities.Shuffle(vs0, control);
Unsafe.Add(ref vd0, (nuint)1) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control);
Unsafe.Add(ref vd0, (nuint)2) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control);
Unsafe.Add(ref vd0, (nuint)3) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control);
}
if (m > 0)
{
for (nint i = u; i < n; i++)
for (nuint i = u; i < n; i++)
{
Vector128<float> vs = Unsafe.Add(ref sourceBase, i);
Unsafe.Add(ref destBase, i) = Sse.Shuffle(vs, vs, control);
Unsafe.Add(ref destinationBase, i) = Vector128Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control);
}
}
}
@ -296,80 +335,102 @@ internal static partial class SimdUtils
[MethodImpl(InliningOptions.ShortMethod)]
private static void Shuffle4(
ReadOnlySpan<byte> source,
Span<byte> dest,
byte control)
Span<byte> destination,
[ConstantExpected] byte control)
{
if (Avx2.IsSupported)
if (Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleByte)
{
// I've chosen to do this for convenience while we determine what
// shuffle controls to add to the library.
// We can add static ROS instances if need be in the future.
Span<byte> bytes = stackalloc byte[Vector256<byte>.Count];
Shuffle.MMShuffleSpan(ref bytes, control);
Vector256<byte> vshuffle = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(bytes));
Span<byte> temp = stackalloc byte[Vector512<byte>.Count];
Shuffle.MMShuffleSpan(ref temp, control);
Vector512<byte> mask = Unsafe.As<byte, Vector512<byte>>(ref MemoryMarshal.GetReference(temp));
ref Vector256<byte> sourceBase =
ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector512<byte> sourceBase = ref Unsafe.As<byte, Vector512<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector512<byte> destinationBase = ref Unsafe.As<byte, Vector512<byte>>(ref MemoryMarshal.GetReference(destination));
ref Vector256<byte> destBase =
ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(dest));
nuint n = (uint)destination.Length / (uint)Vector512<byte>.Count;
nuint m = Numerics.Modulo4(n);
nuint u = n - m;
for (nuint i = 0; i < u; i += 4)
{
ref Vector512<byte> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector512<byte> vd0 = ref Unsafe.Add(ref destinationBase, i);
vd0 = Vector512Utilities.Shuffle(vs0, mask);
Unsafe.Add(ref vd0, (nuint)1) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask);
Unsafe.Add(ref vd0, (nuint)2) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask);
Unsafe.Add(ref vd0, (nuint)3) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask);
}
if (m > 0)
{
for (nuint i = u; i < n; i++)
{
Unsafe.Add(ref destinationBase, i) = Vector512Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask);
}
}
}
else if (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleByte)
{
Span<byte> temp = stackalloc byte[Vector256<byte>.Count];
Shuffle.MMShuffleSpan(ref temp, control);
Vector256<byte> mask = Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(temp));
ref Vector256<byte> sourceBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector256<byte> destinationBase = ref Unsafe.As<byte, Vector256<byte>>(ref MemoryMarshal.GetReference(destination));
nint n = (nint)((uint)dest.Length / (uint)Vector256<byte>.Count);
nint m = Numerics.Modulo4(n);
nint u = n - m;
nuint n = (uint)destination.Length / (uint)Vector256<byte>.Count;
nuint m = Numerics.Modulo4(n);
nuint u = n - m;
for (nint i = 0; i < u; i += 4)
for (nuint i = 0; i < u; i += 4)
{
ref Vector256<byte> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector256<byte> vd0 = ref Unsafe.Add(ref destBase, i);
ref Vector256<byte> vd0 = ref Unsafe.Add(ref destinationBase, i);
vd0 = Avx2.Shuffle(vs0, vshuffle);
Unsafe.Add(ref vd0, 1) = Avx2.Shuffle(Unsafe.Add(ref vs0, 1), vshuffle);
Unsafe.Add(ref vd0, 2) = Avx2.Shuffle(Unsafe.Add(ref vs0, 2), vshuffle);
Unsafe.Add(ref vd0, 3) = Avx2.Shuffle(Unsafe.Add(ref vs0, 3), vshuffle);
vd0 = Vector256Utilities.Shuffle(vs0, mask);
Unsafe.Add(ref vd0, (nuint)1) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask);
Unsafe.Add(ref vd0, (nuint)2) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask);
Unsafe.Add(ref vd0, (nuint)3) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask);
}
if (m > 0)
{
for (nint i = u; i < n; i++)
for (nuint i = u; i < n; i++)
{
Unsafe.Add(ref destBase, i) = Avx2.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle);
Unsafe.Add(ref destinationBase, i) = Vector256Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask);
}
}
}
else
else if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte)
{
// Ssse3
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
Shuffle.MMShuffleSpan(ref bytes, control);
Vector128<byte> vshuffle = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(bytes));
ref Vector128<byte> sourceBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(source));
Span<byte> temp = stackalloc byte[Vector128<byte>.Count];
Shuffle.MMShuffleSpan(ref temp, control);
Vector128<byte> mask = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(temp));
ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
ref Vector128<byte> sourceBase = ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector128<byte> destinationBase = ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(destination));
nint n = (nint)((uint)dest.Length / (uint)Vector128<byte>.Count);
nint m = Numerics.Modulo4(n);
nint u = n - m;
nuint n = (uint)destination.Length / (uint)Vector128<byte>.Count;
nuint m = Numerics.Modulo4(n);
nuint u = n - m;
for (nint i = 0; i < u; i += 4)
for (nuint i = 0; i < u; i += 4)
{
ref Vector128<byte> vs0 = ref Unsafe.Add(ref sourceBase, i);
ref Vector128<byte> vd0 = ref Unsafe.Add(ref destBase, i);
ref Vector128<byte> vd0 = ref Unsafe.Add(ref destinationBase, i);
vd0 = Ssse3.Shuffle(vs0, vshuffle);
Unsafe.Add(ref vd0, 1) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 1), vshuffle);
Unsafe.Add(ref vd0, 2) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 2), vshuffle);
Unsafe.Add(ref vd0, 3) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 3), vshuffle);
vd0 = Vector128Utilities.Shuffle(vs0, mask);
Unsafe.Add(ref vd0, (nuint)1) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask);
Unsafe.Add(ref vd0, (nuint)2) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask);
Unsafe.Add(ref vd0, (nuint)3) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask);
}
if (m > 0)
{
for (nint i = u; i < n; i++)
for (nuint i = u; i < n; i++)
{
Unsafe.Add(ref destBase, i) = Ssse3.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle);
Unsafe.Add(ref destinationBase, i) = Vector128Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask);
}
}
}
@ -378,24 +439,21 @@ internal static partial class SimdUtils
[MethodImpl(InliningOptions.ShortMethod)]
private static void Shuffle3(
ReadOnlySpan<byte> source,
Span<byte> dest,
byte control)
Span<byte> destination,
[ConstantExpected] byte control)
{
if (Ssse3.IsSupported)
if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsRightAlign)
{
Vector128<byte> vmask = ShuffleMaskPad4Nx16();
Vector128<byte> vmasko = ShuffleMaskSlice4Nx16();
Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12);
Vector128<byte> maskPad4Nx16 = ShuffleMaskPad4Nx16();
Vector128<byte> maskSlice4Nx16 = ShuffleMaskSlice4Nx16();
Vector128<byte> maskE = Vector128Utilities.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12);
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
Shuffle.MMShuffleSpan(ref bytes, control);
Vector128<byte> vshuffle = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(bytes));
Vector128<byte> mask = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(bytes));
ref Vector128<byte> sourceBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
ref Vector128<byte> sourceBase = ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector128<byte> destinationBase = ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(destination));
nuint n = source.Vector128Count<byte>();
@ -404,36 +462,36 @@ internal static partial class SimdUtils
ref Vector128<byte> vs = ref Unsafe.Add(ref sourceBase, i);
Vector128<byte> v0 = vs;
Vector128<byte> v1 = Unsafe.Add(ref vs, 1);
Vector128<byte> v2 = Unsafe.Add(ref vs, 2);
Vector128<byte> v3 = Sse2.ShiftRightLogical128BitLane(v2, 4);
Vector128<byte> v1 = Unsafe.Add(ref vs, (nuint)1);
Vector128<byte> v2 = Unsafe.Add(ref vs, (nuint)2);
Vector128<byte> v3 = Vector128Utilities.ShiftRightBytesInVector(v2, 4);
v2 = Ssse3.AlignRight(v2, v1, 8);
v1 = Ssse3.AlignRight(v1, v0, 12);
v2 = Vector128Utilities.AlignRight(v2, v1, 8);
v1 = Vector128Utilities.AlignRight(v1, v0, 12);
v0 = Ssse3.Shuffle(Ssse3.Shuffle(v0, vmask), vshuffle);
v1 = Ssse3.Shuffle(Ssse3.Shuffle(v1, vmask), vshuffle);
v2 = Ssse3.Shuffle(Ssse3.Shuffle(v2, vmask), vshuffle);
v3 = Ssse3.Shuffle(Ssse3.Shuffle(v3, vmask), vshuffle);
v0 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, maskPad4Nx16), mask);
v1 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, maskPad4Nx16), mask);
v2 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, maskPad4Nx16), mask);
v3 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, maskPad4Nx16), mask);
v0 = Ssse3.Shuffle(v0, vmaske);
v1 = Ssse3.Shuffle(v1, vmasko);
v2 = Ssse3.Shuffle(v2, vmaske);
v3 = Ssse3.Shuffle(v3, vmasko);
v0 = Vector128Utilities.Shuffle(v0, maskE);
v1 = Vector128Utilities.Shuffle(v1, maskSlice4Nx16);
v2 = Vector128Utilities.Shuffle(v2, maskE);
v3 = Vector128Utilities.Shuffle(v3, maskSlice4Nx16);
v0 = Ssse3.AlignRight(v1, v0, 4);
v3 = Ssse3.AlignRight(v3, v2, 12);
v0 = Vector128Utilities.AlignRight(v1, v0, 4);
v3 = Vector128Utilities.AlignRight(v3, v2, 12);
v1 = Sse2.ShiftLeftLogical128BitLane(v1, 4);
v2 = Sse2.ShiftRightLogical128BitLane(v2, 4);
v1 = Vector128Utilities.ShiftLeftBytesInVector(v1, 4);
v2 = Vector128Utilities.ShiftRightBytesInVector(v2, 4);
v1 = Ssse3.AlignRight(v2, v1, 8);
v1 = Vector128Utilities.AlignRight(v2, v1, 8);
ref Vector128<byte> vd = ref Unsafe.Add(ref destBase, i);
ref Vector128<byte> vd = ref Unsafe.Add(ref destinationBase, i);
vd = v0;
Unsafe.Add(ref vd, 1) = v1;
Unsafe.Add(ref vd, 2) = v3;
Unsafe.Add(ref vd, (nuint)1) = v1;
Unsafe.Add(ref vd, (nuint)2) = v3;
}
}
}
@ -441,23 +499,23 @@ internal static partial class SimdUtils
[MethodImpl(InliningOptions.ShortMethod)]
private static void Pad3Shuffle4(
ReadOnlySpan<byte> source,
Span<byte> dest,
byte control)
Span<byte> destination,
[ConstantExpected] byte control)
{
if (Ssse3.IsSupported)
if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte)
{
Vector128<byte> vmask = ShuffleMaskPad4Nx16();
Vector128<byte> vfill = Vector128.Create(0xff000000ff000000ul).AsByte();
Vector128<byte> maskPad4Nx16 = ShuffleMaskPad4Nx16();
Vector128<byte> fill = Vector128.Create(0xff000000ff000000ul).AsByte();
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
Shuffle.MMShuffleSpan(ref bytes, control);
Vector128<byte> vshuffle = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(bytes));
Span<byte> temp = stackalloc byte[Vector128<byte>.Count];
Shuffle.MMShuffleSpan(ref temp, control);
Vector128<byte> mask = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(temp));
ref Vector128<byte> sourceBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
ref Vector128<byte> destinationBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(destination));
nuint n = source.Vector128Count<byte>();
@ -466,17 +524,17 @@ internal static partial class SimdUtils
ref Vector128<byte> v0 = ref Unsafe.Add(ref sourceBase, i);
Vector128<byte> v1 = Unsafe.Add(ref v0, 1);
Vector128<byte> v2 = Unsafe.Add(ref v0, 2);
Vector128<byte> v3 = Sse2.ShiftRightLogical128BitLane(v2, 4);
Vector128<byte> v3 = Vector128Utilities.ShiftRightBytesInVector(v2, 4);
v2 = Ssse3.AlignRight(v2, v1, 8);
v1 = Ssse3.AlignRight(v1, v0, 12);
v2 = Vector128Utilities.AlignRight(v2, v1, 8);
v1 = Vector128Utilities.AlignRight(v1, v0, 12);
ref Vector128<byte> vd = ref Unsafe.Add(ref destBase, j);
ref Vector128<byte> vd = ref Unsafe.Add(ref destinationBase, j);
vd = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v0, vmask), vfill), vshuffle);
Unsafe.Add(ref vd, 1) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v1, vmask), vfill), vshuffle);
Unsafe.Add(ref vd, 2) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v2, vmask), vfill), vshuffle);
Unsafe.Add(ref vd, 3) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v3, vmask), vfill), vshuffle);
vd = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, maskPad4Nx16) | fill, mask);
Unsafe.Add(ref vd, 1) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, maskPad4Nx16) | fill, mask);
Unsafe.Add(ref vd, 2) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, maskPad4Nx16) | fill, mask);
Unsafe.Add(ref vd, 3) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, maskPad4Nx16) | fill, mask);
}
}
}
@ -484,23 +542,23 @@ internal static partial class SimdUtils
[MethodImpl(InliningOptions.ShortMethod)]
private static void Shuffle4Slice3(
ReadOnlySpan<byte> source,
Span<byte> dest,
byte control)
Span<byte> destination,
[ConstantExpected] byte control)
{
if (Ssse3.IsSupported)
if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte)
{
Vector128<byte> vmasko = ShuffleMaskSlice4Nx16();
Vector128<byte> vmaske = Ssse3.AlignRight(vmasko, vmasko, 12);
Vector128<byte> maskSlice4Nx16 = ShuffleMaskSlice4Nx16();
Vector128<byte> maskE = Vector128Utilities.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12);
Span<byte> bytes = stackalloc byte[Vector128<byte>.Count];
Shuffle.MMShuffleSpan(ref bytes, control);
Vector128<byte> vshuffle = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(bytes));
Span<byte> temp = stackalloc byte[Vector128<byte>.Count];
Shuffle.MMShuffleSpan(ref temp, control);
Vector128<byte> mask = Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(temp));
ref Vector128<byte> sourceBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector128<byte> destBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(dest));
ref Vector128<byte> destinationBase =
ref Unsafe.As<byte, Vector128<byte>>(ref MemoryMarshal.GetReference(destination));
nuint n = source.Vector128Count<byte>();
@ -513,20 +571,20 @@ internal static partial class SimdUtils
Vector128<byte> v2 = Unsafe.Add(ref vs, 2);
Vector128<byte> v3 = Unsafe.Add(ref vs, 3);
v0 = Ssse3.Shuffle(Ssse3.Shuffle(v0, vshuffle), vmaske);
v1 = Ssse3.Shuffle(Ssse3.Shuffle(v1, vshuffle), vmasko);
v2 = Ssse3.Shuffle(Ssse3.Shuffle(v2, vshuffle), vmaske);
v3 = Ssse3.Shuffle(Ssse3.Shuffle(v3, vshuffle), vmasko);
v0 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, mask), maskE);
v1 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, mask), maskSlice4Nx16);
v2 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, mask), maskE);
v3 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, mask), maskSlice4Nx16);
v0 = Ssse3.AlignRight(v1, v0, 4);
v3 = Ssse3.AlignRight(v3, v2, 12);
v0 = Vector128Utilities.AlignRight(v1, v0, 4);
v3 = Vector128Utilities.AlignRight(v3, v2, 12);
v1 = Sse2.ShiftLeftLogical128BitLane(v1, 4);
v2 = Sse2.ShiftRightLogical128BitLane(v2, 4);
v1 = Vector128Utilities.ShiftLeftBytesInVector(v1, 4);
v2 = Vector128Utilities.ShiftRightBytesInVector(v2, 4);
v1 = Ssse3.AlignRight(v2, v1, 8);
v1 = Vector128Utilities.AlignRight(v2, v1, 8);
ref Vector128<byte> vd = ref Unsafe.Add(ref destBase, j);
ref Vector128<byte> vd = ref Unsafe.Add(ref destinationBase, j);
vd = v0;
Unsafe.Add(ref vd, 1) = v1;

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

@ -12,140 +12,140 @@ internal static partial class SimdUtils
{
/// <summary>
/// Shuffle single-precision (32-bit) floating-point elements in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <param name="source">The source span of floats.</param>
/// <param name="dest">The destination span of floats.</param>
/// <param name="destination">The destination span of floats.</param>
/// <param name="control">The byte control.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle4(
ReadOnlySpan<float> source,
Span<float> dest,
Span<float> destination,
[ConstantExpected] byte control)
{
VerifyShuffle4SpanInput(source, dest);
VerifyShuffle4SpanInput(source, destination);
HwIntrinsics.Shuffle4Reduce(ref source, ref dest, control);
HwIntrinsics.Shuffle4Reduce(ref source, ref destination, control);
// Deal with the remainder:
if (source.Length > 0)
{
Shuffle4Remainder(source, dest, control);
Shuffle4Remainder(source, destination, control);
}
}
/// <summary>
/// Shuffle 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <typeparam name="TShuffle">The type of shuffle struct.</typeparam>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="shuffle">The type of shuffle to perform.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle4<TShuffle>(
ReadOnlySpan<byte> source,
Span<byte> dest,
Span<byte> destination,
TShuffle shuffle)
where TShuffle : struct, IShuffle4
{
VerifyShuffle4SpanInput(source, dest);
VerifyShuffle4SpanInput(source, destination);
shuffle.ShuffleReduce(ref source, ref dest);
shuffle.ShuffleReduce(ref source, ref destination);
// Deal with the remainder:
if (source.Length > 0)
{
shuffle.RunFallbackShuffle(source, dest);
shuffle.Shuffle(source, destination);
}
}
/// <summary>
/// Shuffle 8-bit integer triplets within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <typeparam name="TShuffle">The type of shuffle struct.</typeparam>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="shuffle">The type of shuffle to perform.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle3<TShuffle>(
ReadOnlySpan<byte> source,
Span<byte> dest,
Span<byte> destination,
TShuffle shuffle)
where TShuffle : struct, IShuffle3
{
// Source length should be smaller than dest length, and divisible by 3.
VerifyShuffle3SpanInput(source, dest);
// Source length should be smaller than destination length, and divisible by 3.
VerifyShuffle3SpanInput(source, destination);
shuffle.ShuffleReduce(ref source, ref dest);
shuffle.ShuffleReduce(ref source, ref destination);
// Deal with the remainder:
if (source.Length > 0)
{
shuffle.RunFallbackShuffle(source, dest);
shuffle.Shuffle(source, destination);
}
}
/// <summary>
/// Pads then shuffles 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <typeparam name="TShuffle">The type of shuffle struct.</typeparam>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="shuffle">The type of shuffle to perform.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Pad3Shuffle4<TShuffle>(
ReadOnlySpan<byte> source,
Span<byte> dest,
Span<byte> destination,
TShuffle shuffle)
where TShuffle : struct, IPad3Shuffle4
{
VerifyPad3Shuffle4SpanInput(source, dest);
VerifyPad3Shuffle4SpanInput(source, destination);
shuffle.ShuffleReduce(ref source, ref dest);
shuffle.ShuffleReduce(ref source, ref destination);
// Deal with the remainder:
if (source.Length > 0)
{
shuffle.RunFallbackShuffle(source, dest);
shuffle.Shuffle(source, destination);
}
}
/// <summary>
/// Shuffles then slices 8-bit integers within 128-bit lanes in <paramref name="source"/>
/// using the control and store the results in <paramref name="dest"/>.
/// using the control and store the results in <paramref name="destination"/>.
/// </summary>
/// <typeparam name="TShuffle">The type of shuffle struct.</typeparam>
/// <param name="source">The source span of bytes.</param>
/// <param name="dest">The destination span of bytes.</param>
/// <param name="destination">The destination span of bytes.</param>
/// <param name="shuffle">The type of shuffle to perform.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public static void Shuffle4Slice3<TShuffle>(
ReadOnlySpan<byte> source,
Span<byte> dest,
Span<byte> destination,
TShuffle shuffle)
where TShuffle : struct, IShuffle4Slice3
{
VerifyShuffle4Slice3SpanInput(source, dest);
VerifyShuffle4Slice3SpanInput(source, destination);
shuffle.ShuffleReduce(ref source, ref dest);
shuffle.ShuffleReduce(ref source, ref destination);
// Deal with the remainder:
if (source.Length > 0)
{
shuffle.RunFallbackShuffle(source, dest);
shuffle.Shuffle(source, destination);
}
}
private static void Shuffle4Remainder(
ReadOnlySpan<float> source,
Span<float> dest,
Span<float> destination,
byte control)
{
ref float sBase = ref MemoryMarshal.GetReference(source);
ref float dBase = ref MemoryMarshal.GetReference(dest);
ref float dBase = ref MemoryMarshal.GetReference(destination);
Shuffle.InverseMMShuffle(control, out uint p3, out uint p2, out uint p1, out uint p0);
for (nuint i = 0; i < (uint)source.Length; i += 4)
@ -158,69 +158,69 @@ internal static partial class SimdUtils
}
[Conditional("DEBUG")]
internal static void VerifyShuffle4SpanInput<T>(ReadOnlySpan<T> source, Span<T> dest)
internal static void VerifyShuffle4SpanInput<T>(ReadOnlySpan<T> source, Span<T> destination)
where T : struct
{
DebugGuard.IsTrue(
source.Length == dest.Length,
source.Length == destination.Length,
nameof(source),
"Input spans must be of same length!");
DebugGuard.IsTrue(
source.Length % 4 == 0,
nameof(source),
"Input spans must be divisable by 4!");
"Input spans must be divisible by 4!");
}
[Conditional("DEBUG")]
private static void VerifyShuffle3SpanInput<T>(ReadOnlySpan<T> source, Span<T> dest)
private static void VerifyShuffle3SpanInput<T>(ReadOnlySpan<T> source, Span<T> destination)
where T : struct
{
DebugGuard.IsTrue(
source.Length <= dest.Length,
source.Length <= destination.Length,
nameof(source),
"Source should fit into dest!");
"Source should fit into destination!");
DebugGuard.IsTrue(
source.Length % 3 == 0,
nameof(source),
"Input spans must be divisable by 3!");
"Input spans must be divisible by 3!");
}
[Conditional("DEBUG")]
private static void VerifyPad3Shuffle4SpanInput(ReadOnlySpan<byte> source, Span<byte> dest)
private static void VerifyPad3Shuffle4SpanInput(ReadOnlySpan<byte> source, Span<byte> destination)
{
DebugGuard.IsTrue(
source.Length % 3 == 0,
nameof(source),
"Input span must be divisable by 3!");
"Input span must be divisible by 3!");
DebugGuard.IsTrue(
dest.Length % 4 == 0,
nameof(dest),
"Output span must be divisable by 4!");
destination.Length % 4 == 0,
nameof(destination),
"Output span must be divisible by 4!");
DebugGuard.IsTrue(
source.Length == dest.Length * 3 / 4,
source.Length == destination.Length * 3 / 4,
nameof(source),
"Input span must be 3/4 the length of the output span!");
}
[Conditional("DEBUG")]
private static void VerifyShuffle4Slice3SpanInput(ReadOnlySpan<byte> source, Span<byte> dest)
private static void VerifyShuffle4Slice3SpanInput(ReadOnlySpan<byte> source, Span<byte> destination)
{
DebugGuard.IsTrue(
source.Length % 4 == 0,
nameof(source),
"Input span must be divisable by 4!");
"Input span must be divisible by 4!");
DebugGuard.IsTrue(
dest.Length % 3 == 0,
nameof(dest),
"Output span must be divisable by 3!");
destination.Length % 3 == 0,
nameof(destination),
"Output span must be divisible by 3!");
DebugGuard.IsTrue(
dest.Length >= source.Length * 3 / 4,
destination.Length >= source.Length * 3 / 4,
nameof(source),
"Output span must be at least 3/4 the length of the input span!");
}
@ -509,6 +509,27 @@ internal static partial class SimdUtils
}
}
[MethodImpl(InliningOptions.ShortMethod)]
public static void MMShuffleSpan(ref Span<int> span, byte control)
{
InverseMMShuffle(
control,
out uint p3,
out uint p2,
out uint p1,
out uint p0);
ref int spanBase = ref MemoryMarshal.GetReference(span);
for (nuint i = 0; i < (uint)span.Length; i += 4)
{
Unsafe.Add(ref spanBase, i + 0) = (int)(p0 + i);
Unsafe.Add(ref spanBase, i + 1) = (int)(p1 + i);
Unsafe.Add(ref spanBase, i + 2) = (int)(p2 + i);
Unsafe.Add(ref spanBase, i + 3) = (int)(p3 + i);
}
}
[MethodImpl(InliningOptions.ShortMethod)]
public static void InverseMMShuffle(
byte control,

176
src/ImageSharp/Common/Helpers/Vector128Utilities.cs

@ -0,0 +1,176 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.Common.Helpers;
/// <summary>
/// Defines utility methods for <see cref="Vector128{T}"/> that have either:
/// <list type="number">
/// <item>Not yet been normalized in the runtime.</item>
/// <item>Produce codegen that is poorly optimized by the runtime.</item>
/// </list>
/// Should only be used if the intrinsics are available.
/// </summary>
internal static class Vector128Utilities
{
/// <summary>
/// Gets a value indicating whether shuffle operations are supported.
/// </summary>
public static bool SupportsShuffleFloat
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Sse.IsSupported;
}
/// <summary>
/// Gets a value indicating whether shuffle operations are supported.
/// </summary>
public static bool SupportsShuffleByte
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Ssse3.IsSupported || AdvSimd.Arm64.IsSupported;
}
/// <summary>
/// Gets a value indicating whether right align operations are supported.
/// </summary>
public static bool SupportsRightAlign
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Ssse3.IsSupported || AdvSimd.IsSupported;
}
/// <summary>
/// Gets a value indicating whether right or left byte shift operations are supported.
/// </summary>
public static bool SupportsShiftByte
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Sse2.IsSupported || AdvSimd.IsSupported;
}
/// <summary>
/// Creates a new vector by selecting values from an input vector using the control.
/// </summary>
/// <param name="vector">The input vector from which values are selected.</param>
/// <param name="control">The shuffle control byte.</param>
/// <returns>The <see cref="Vector128{Single}"/>.</returns>
public static Vector128<float> Shuffle(Vector128<float> vector, [ConstantExpected] byte control)
{
if (Sse.IsSupported)
{
return Sse.Shuffle(vector, vector, control);
}
ThrowUnreachableException();
return default;
}
/// <summary>
/// Creates a new vector by selecting values from an input vector using a set of indices.
/// </summary>
/// <param name="vector">
/// The input vector from which values are selected.</param>
/// <param name="indices">
/// The per-element indices used to select a value from <paramref name="vector" />.
/// </param>
/// <returns>
/// A new vector containing the values from <paramref name="vector" /> selected by the given <paramref name="indices" />.
/// </returns>
public static Vector128<byte> Shuffle(Vector128<byte> vector, Vector128<byte> indices)
{
if (Ssse3.IsSupported)
{
return Ssse3.Shuffle(vector, indices);
}
if (AdvSimd.Arm64.IsSupported)
{
return AdvSimd.Arm64.VectorTableLookup(vector, indices);
}
ThrowUnreachableException();
return default;
}
/// <summary>
/// Shifts a 128-bit value right by a specified number of bytes while shifting in zeros.
/// </summary>
/// <param name="value">The value to shift.</param>
/// <param name="numBytes">The number of bytes to shift by.</param>
/// <returns>The <see cref="Vector128{Byte}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<byte> ShiftRightBytesInVector(Vector128<byte> value, [ConstantExpected(Max = (byte)15)] byte numBytes)
{
if (Sse2.IsSupported)
{
return Sse2.ShiftRightLogical128BitLane(value, numBytes);
}
if (AdvSimd.IsSupported)
{
return AdvSimd.ExtractVector128(value, Vector128<byte>.Zero, numBytes);
}
ThrowUnreachableException();
return default;
}
/// <summary>
/// Shifts a 128-bit value left by a specified number of bytes while shifting in zeros.
/// </summary>
/// <param name="value">The value to shift.</param>
/// <param name="numBytes">The number of bytes to shift by.</param>
/// <returns>The <see cref="Vector128{Byte}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector128<byte> ShiftLeftBytesInVector(Vector128<byte> value, [ConstantExpected(Max = (byte)15)] byte numBytes)
{
if (Sse2.IsSupported)
{
return Sse2.ShiftLeftLogical128BitLane(value, numBytes);
}
if (AdvSimd.IsSupported)
{
#pragma warning disable CA1857 // A constant is expected for the parameter
return AdvSimd.ExtractVector128(Vector128<byte>.Zero, value, (byte)(Vector128<byte>.Count - numBytes));
#pragma warning restore CA1857 // A constant is expected for the parameter
}
ThrowUnreachableException();
return default;
}
/// <summary>
/// Right aligns elements of two source 128-bit values depending on bits in a mask.
/// </summary>
/// <param name="left">The left hand source vector.</param>
/// <param name="right">The right hand source vector.</param>
/// <param name="mask">An 8-bit mask used for the operation.</param>
/// <returns>The <see cref="Vector128{Byte}"/>.</returns>
public static Vector128<byte> AlignRight(Vector128<byte> left, Vector128<byte> right, [ConstantExpected(Max = (byte)15)] byte mask)
{
if (Ssse3.IsSupported)
{
return Ssse3.AlignRight(left, right, mask);
}
if (AdvSimd.IsSupported)
{
return AdvSimd.ExtractVector128(right, left, mask);
}
ThrowUnreachableException();
return default;
}
[DoesNotReturn]
private static void ThrowUnreachableException() => throw new UnreachableException();
}

78
src/ImageSharp/Common/Helpers/Vector256Utilities.cs

@ -0,0 +1,78 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.Common.Helpers;
/// <summary>
/// Defines utility methods for <see cref="Vector256{T}"/> that have either:
/// <list type="number">
/// <item>Not yet been normalized in the runtime.</item>
/// <item>Produce codegen that is poorly optimized by the runtime.</item>
/// </list>
/// Should only be used if the intrinsics are available.
/// </summary>
internal static class Vector256Utilities
{
/// <summary>
/// Gets a value indicating whether shuffle byte operations are supported.
/// </summary>
public static bool SupportsShuffleFloat
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Avx.IsSupported;
}
/// <summary>
/// Gets a value indicating whether shuffle byte operations are supported.
/// </summary>
public static bool SupportsShuffleByte
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Avx2.IsSupported;
}
/// <summary>
/// Creates a new vector by selecting values from an input vector using a set of indices.
/// </summary>
/// <param name="vector">The input vector from which values are selected.</param>
/// <param name="control">The shuffle control byte.</param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
public static Vector256<float> Shuffle(Vector256<float> vector, [ConstantExpected] byte control)
{
if (Avx.IsSupported)
{
return Avx.Shuffle(vector, vector, control);
}
ThrowUnreachableException();
return default;
}
/// <summary>
/// Creates a new vector by selecting values from an input vector using a set of indices.</summary>
/// <param name="vector">
/// The input vector from which values are selected.</param>
/// <param name="indices">
/// The per-element indices used to select a value from <paramref name="vector" />.
/// </param>
/// <returns>The <see cref="Vector256{Single}"/>.</returns>
public static Vector256<byte> Shuffle(Vector256<byte> vector, Vector256<byte> indices)
{
if (Avx2.IsSupported)
{
return Avx2.Shuffle(vector, indices);
}
ThrowUnreachableException();
return default;
}
[DoesNotReturn]
private static void ThrowUnreachableException() => throw new UnreachableException();
}

80
src/ImageSharp/Common/Helpers/Vector512Utilities.cs

@ -0,0 +1,80 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.Common.Helpers;
/// <summary>
/// Defines utility methods for <see cref="Vector512{T}"/> that have either:
/// <list type="number">
/// <item>Not yet been normalized in the runtime.</item>
/// <item>Produce codegen that is poorly optimized by the runtime.</item>
/// </list>
/// Should only be used if the intrinsics are available.
/// </summary>
internal static class Vector512Utilities
{
/// <summary>
/// Gets a value indicating whether shuffle float operations are supported.
/// </summary>
public static bool SupportsShuffleFloat
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Avx512F.IsSupported;
}
/// <summary>
/// Gets a value indicating whether shuffle byte operations are supported.
/// </summary>
public static bool SupportsShuffleByte
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get => Avx512BW.IsSupported;
}
/// <summary>
/// Creates a new vector by selecting values from an input vector using the control.
/// </summary>
/// <param name="vector">The input vector from which values are selected.</param>
/// <param name="control">The shuffle control byte.</param>
/// <returns>The <see cref="Vector512{Single}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector512<float> Shuffle(Vector512<float> vector, [ConstantExpected] byte control)
{
if (Avx512F.IsSupported)
{
return Avx512F.Shuffle(vector, vector, control);
}
ThrowUnreachableException();
return default;
}
/// <summary>
/// Creates a new vector by selecting values from an input vector using a set of indices.
/// </summary>
/// <param name="vector">The input vector from which values are selected.</param>
/// <param name="indices">
/// The per-element indices used to select a value from <paramref name="vector" />.
/// </param>
/// <returns>The <see cref="Vector512{Byte}"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector512<byte> Shuffle(Vector512<byte> vector, Vector512<byte> indices)
{
if (Avx512BW.IsSupported)
{
return Avx512BW.Shuffle(vector, indices);
}
ThrowUnreachableException();
return default;
}
[DoesNotReturn]
private static void ThrowUnreachableException() => throw new UnreachableException();
}

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

@ -294,72 +294,60 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
private void ReadRle<TPixel>(BufferedReadStream stream, BmpCompression compression, Buffer2D<TPixel> pixels, byte[] colors, int width, int height, bool inverted)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height, AllocationOptions.Clean))
using (IMemoryOwner<bool> undefinedPixels = this.memoryAllocator.Allocate<bool>(width * height, AllocationOptions.Clean))
using (IMemoryOwner<bool> rowsWithUndefinedPixels = this.memoryAllocator.Allocate<bool>(height, AllocationOptions.Clean))
using IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height, AllocationOptions.Clean);
using IMemoryOwner<bool> undefinedPixels = this.memoryAllocator.Allocate<bool>(width * height, AllocationOptions.Clean);
using IMemoryOwner<bool> rowsWithUndefinedPixels = this.memoryAllocator.Allocate<bool>(height, AllocationOptions.Clean);
Span<bool> rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span;
Span<bool> undefinedPixelsSpan = undefinedPixels.Memory.Span;
Span<byte> bufferSpan = buffer.Memory.Span;
if (compression is BmpCompression.RLE8)
{
Span<bool> rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span;
Span<bool> undefinedPixelsSpan = undefinedPixels.Memory.Span;
Span<byte> bufferSpan = buffer.Memory.Span;
if (compression is BmpCompression.RLE8)
{
this.UncompressRle8(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
}
else
{
this.UncompressRle4(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
}
this.UncompressRle8(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
}
else
{
this.UncompressRle4(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
}
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
int rowStartIdx = y * width;
Span<byte> bufferRow = bufferSpan.Slice(rowStartIdx, width);
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
int rowStartIdx = y * width;
Span<byte> bufferRow = bufferSpan.Slice(rowStartIdx, width);
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
{
// Slow path with undefined pixels.
for (int x = 0; x < width; x++)
{
// Slow path with undefined pixels.
for (int x = 0; x < width; x++)
byte colorIdx = bufferRow[x];
if (undefinedPixelsSpan[rowStartIdx + x])
{
byte colorIdx = bufferRow[x];
if (undefinedPixelsSpan[rowStartIdx + x])
{
switch (this.rleSkippedPixelHandling)
{
case RleSkippedPixelHandling.FirstColorOfPalette:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIdx * 4]));
break;
case RleSkippedPixelHandling.Transparent:
color.FromScaledVector4(Vector4.Zero);
break;
// Default handling for skipped pixels is black (which is what System.Drawing is also doing).
default:
color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
break;
}
}
else
pixelRow[x] = this.rleSkippedPixelHandling switch
{
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIdx * 4]));
}
RleSkippedPixelHandling.FirstColorOfPalette => TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIdx * 4])),
RleSkippedPixelHandling.Transparent => TPixel.FromScaledVector4(Vector4.Zero),
pixelRow[x] = color;
// Default handling for skipped pixels is black (which is what System.Drawing is also doing).
_ => TPixel.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)),
};
}
}
else
{
// Fast path without any undefined pixels.
for (int x = 0; x < width; x++)
else
{
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[bufferRow[x] * 4]));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIdx * 4]));
}
}
}
else
{
// Fast path without any undefined pixels.
for (int x = 0; x < width; x++)
{
pixelRow[x] = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[bufferRow[x] * 4]));
}
}
}
}
@ -375,66 +363,54 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
private void ReadRle24<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> pixels, int width, int height, bool inverted)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
using (IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * 3, AllocationOptions.Clean))
using (IMemoryOwner<bool> undefinedPixels = this.memoryAllocator.Allocate<bool>(width * height, AllocationOptions.Clean))
using (IMemoryOwner<bool> rowsWithUndefinedPixels = this.memoryAllocator.Allocate<bool>(height, AllocationOptions.Clean))
{
Span<bool> rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span;
Span<bool> undefinedPixelsSpan = undefinedPixels.Memory.Span;
Span<byte> bufferSpan = buffer.GetSpan();
using IMemoryOwner<byte> buffer = this.memoryAllocator.Allocate<byte>(width * height * 3, AllocationOptions.Clean);
using IMemoryOwner<bool> undefinedPixels = this.memoryAllocator.Allocate<bool>(width * height, AllocationOptions.Clean);
using IMemoryOwner<bool> rowsWithUndefinedPixels = this.memoryAllocator.Allocate<bool>(height, AllocationOptions.Clean);
Span<bool> rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span;
Span<bool> undefinedPixelsSpan = undefinedPixels.Memory.Span;
Span<byte> bufferSpan = buffer.GetSpan();
this.UncompressRle24(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
for (int y = 0; y < height; y++)
this.UncompressRle24(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan);
for (int y = 0; y < height; y++)
{
int newY = Invert(y, height, inverted);
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
{
int newY = Invert(y, height, inverted);
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(newY);
bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y];
if (rowHasUndefinedPixels)
// Slow path with undefined pixels.
int yMulWidth = y * width;
int rowStartIdx = yMulWidth * 3;
for (int x = 0; x < width; x++)
{
// Slow path with undefined pixels.
int yMulWidth = y * width;
int rowStartIdx = yMulWidth * 3;
for (int x = 0; x < width; x++)
int idx = rowStartIdx + (x * 3);
if (undefinedPixelsSpan[yMulWidth + x])
{
int idx = rowStartIdx + (x * 3);
if (undefinedPixelsSpan[yMulWidth + x])
{
switch (this.rleSkippedPixelHandling)
{
case RleSkippedPixelHandling.FirstColorOfPalette:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
break;
case RleSkippedPixelHandling.Transparent:
color.FromScaledVector4(Vector4.Zero);
break;
// Default handling for skipped pixels is black (which is what System.Drawing is also doing).
default:
color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f));
break;
}
}
else
pixelRow[x] = this.rleSkippedPixelHandling switch
{
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
}
RleSkippedPixelHandling.FirstColorOfPalette => TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx])),
RleSkippedPixelHandling.Transparent => TPixel.FromScaledVector4(Vector4.Zero),
pixelRow[x] = color;
// Default handling for skipped pixels is black (which is what System.Drawing is also doing).
_ => TPixel.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)),
};
}
}
else
{
// Fast path without any undefined pixels.
int rowStartIdx = y * width * 3;
for (int x = 0; x < width; x++)
else
{
int idx = rowStartIdx + (x * 3);
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
}
}
}
else
{
// Fast path without any undefined pixels.
int rowStartIdx = y * width * 3;
for (int x = 0; x < width; x++)
{
int idx = rowStartIdx + (x * 3);
pixelRow[x] = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
}
}
}
}
@ -492,7 +468,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
int max = cmd[1];
int bytesToRead = (int)(((uint)max + 1) / 2);
Span<byte> run = bytesToRead <= 128 ? scratchBuffer.Slice(0, bytesToRead) : new byte[bytesToRead];
Span<byte> run = bytesToRead <= 128 ? scratchBuffer[..bytesToRead] : new byte[bytesToRead];
stream.Read(run);
@ -598,7 +574,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
// Take this number of bytes from the stream as uncompressed data.
int length = cmd[1];
Span<byte> run = length <= 128 ? scratchBuffer.Slice(0, length) : new byte[length];
Span<byte> run = length <= 128 ? scratchBuffer[..length] : new byte[length];
stream.Read(run);
@ -680,7 +656,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
int length = cmd[1];
int length3 = length * 3;
Span<byte> run = length3 <= 128 ? scratchBuffer.Slice(0, length3) : new byte[length3];
Span<byte> run = length3 <= 128 ? scratchBuffer[..length3] : new byte[length3];
stream.Read(run);
@ -835,7 +811,6 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
}
using IMemoryOwner<byte> row = this.memoryAllocator.Allocate<byte>(arrayWidth + padding, AllocationOptions.Clean);
TPixel color = default;
Span<byte> rowSpan = row.GetSpan();
for (int y = 0; y < height; y++)
@ -856,8 +831,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
{
int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry;
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIndex]));
pixelRow[newX] = color;
pixelRow[newX] = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIndex]));
}
offset++;
@ -882,8 +856,6 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
{
int padding = CalculatePadding(width, 2);
int stride = (width * 2) + padding;
TPixel color = default;
int rightShiftRedMask = CalculateRightShift((uint)redMask);
int rightShiftGreenMask = CalculateRightShift((uint)greenMask);
int rightShiftBlueMask = CalculateRightShift((uint)blueMask);
@ -917,8 +889,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask);
Rgb24 rgb = new((byte)r, (byte)g, (byte)b);
color.FromRgb24(rgb);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromRgb24(rgb);
offset += 2;
}
}
@ -1107,8 +1078,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
{
Bgra32 bgra = bgraRowSpan[x];
bgra.A = byte.MaxValue;
ref TPixel pixel = ref pixelSpan[x];
pixel.FromBgra32(bgra);
pixelSpan[x] = TPixel.FromBgra32(bgra);
}
}
}
@ -1129,7 +1099,6 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
private void ReadRgb32BitFields<TPixel>(BufferedReadStream stream, Buffer2D<TPixel> pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
int padding = CalculatePadding(width, 4);
int stride = (width * 4) + padding;
@ -1179,18 +1148,17 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
g * invMaxValueGreen,
b * invMaxValueBlue,
alpha);
color.FromScaledVector4(vector4);
pixelRow[x] = TPixel.FromScaledVector4(vector4);
}
else
{
byte r = (byte)((temp & redMask) >> rightShiftRedMask);
byte g = (byte)((temp & greenMask) >> rightShiftGreenMask);
byte b = (byte)((temp & blueMask) >> rightShiftBlueMask);
byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255;
color.FromRgba32(new Rgba32(r, g, b, a));
byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : byte.MaxValue;
pixelRow[x] = TPixel.FromRgba32(new(r, g, b, a));
}
pixelRow[x] = color;
offset += 4;
}
}
@ -1468,7 +1436,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals
colorMapSizeBytes = this.infoHeader.ClrUsed * bytesPerColorMapEntry;
}
palette = Array.Empty<byte>();
palette = [];
if (colorMapSizeBytes > 0)
{

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

@ -185,7 +185,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
{
uint frameCount = 0;
ImageFrameMetadata? previousFrame = null;
List<ImageFrameMetadata> framesMetadata = new();
List<ImageFrameMetadata> framesMetadata = [];
try
{
this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream);
@ -595,9 +595,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++)
{
int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x);
Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb);
Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]);
}
}
else
@ -613,9 +611,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals
}
int index = Numerics.Clamp(rawIndex, 0, colorTableMaxIdx);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x);
Rgb24 rgb = colorTable[index];
pixel.FromRgb24(rgb);
Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]);
}
}
}

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

@ -169,7 +169,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
this.EncodeFirstFrame(stream, frameMetadata, quantized);
// Capture the global palette for reuse on subsequent frames and cleanup the quantized frame.
TPixel[] globalPalette = image.Frames.Count == 1 ? Array.Empty<TPixel>() : quantized.Palette.ToArray();
TPixel[] globalPalette = image.Frames.Count == 1 ? [] : quantized.Palette.ToArray();
this.EncodeAdditionalFrames(stream, image, globalPalette, derivedTransparencyIndex, frameMetadata.DisposalMethod);
@ -488,8 +488,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
int index = -1;
if (quantized != null)
{
TPixel transparentPixel = default;
transparentPixel.FromScaledVector4(Vector4.Zero);
TPixel transparentPixel = TPixel.FromScaledVector4(Vector4.Zero);
ReadOnlySpan<TPixel> palette = quantized.Palette.Span;
// Transparent pixels are much more likely to be found at the end of a palette.
@ -693,7 +692,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals
}
IMemoryOwner<byte>? owner = null;
Span<byte> extensionBuffer = stackalloc byte[0]; // workaround compiler limitation
scoped Span<byte> extensionBuffer = []; // workaround compiler limitation
if (extensionSize > 128)
{
owner = this.memoryAllocator.Allocate<byte>(extensionSize + 3);

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

@ -328,18 +328,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable
=> clone.ProcessPixelRows(accessor =>
{
// TODO: We should be able to speed this up with SIMD and masking.
Rgba32 rgba32 = default;
Rgba32 transparent = Color.Transparent.ToPixel<Rgba32>();
for (int y = 0; y < accessor.Height; y++)
{
Span<TPixel> span = accessor.GetRowSpan(y);
for (int x = 0; x < accessor.Width; x++)
{
span[x].ToRgba32(ref rgba32);
if (rgba32.A is 0)
ref TPixel pixel = ref span[x];
Rgba32 rgba = pixel.ToRgba32();
if (rgba.A is 0)
{
span[x].FromRgba32(transparent);
pixel = TPixel.FromRgba32(transparent);
}
}
}

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

@ -42,7 +42,6 @@ internal static class PngScanlineProcessor
where TPixel : unmanaged, IPixel<TPixel>
{
uint offset = pixelOffset + frameControl.XOffset;
TPixel pixel = default;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
int scaleFactor = 255 / (ColorNumerics.GetColorCountForBitDepth(bitDepth) - 1);
@ -55,8 +54,7 @@ internal static class PngScanlineProcessor
for (nuint x = offset; x < frameControl.XMax; x += increment, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
pixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromL16(Unsafe.As<ushort, L16>(ref luminance));
}
}
else
@ -64,8 +62,7 @@ internal static class PngScanlineProcessor
for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
pixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromL8(Unsafe.As<byte, L8>(ref luminance));
}
}
@ -75,30 +72,22 @@ internal static class PngScanlineProcessor
if (bitDepth == 16)
{
L16 transparent = transparentColor.Value.ToPixel<L16>();
La32 source = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.L = luminance;
source.A = luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue;
pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
La32 source = new(luminance, luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue);
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa32(source);
}
}
else
{
byte transparent = (byte)(transparentColor.Value.ToPixel<L8>().PackedValue * scaleFactor);
La16 source = default;
for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
source.L = luminance;
source.A = luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue;
pixel.FromLa16(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
La16 source = new(luminance, luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue);
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa16(source);
}
}
}
@ -133,34 +122,28 @@ internal static class PngScanlineProcessor
where TPixel : unmanaged, IPixel<TPixel>
{
uint offset = pixelOffset + frameControl.XOffset;
TPixel pixel = default;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
if (bitDepth == 16)
{
La32 source = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += 4)
{
source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
ushort l = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2));
pixel.FromLa32(source);
Unsafe.Add(ref rowSpanRef, (uint)x) = pixel;
Unsafe.Add(ref rowSpanRef, (uint)x) = TPixel.FromLa32(new(l, a));
}
}
else
{
La16 source = default;
nuint offset2 = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment)
{
source.L = Unsafe.Add(ref scanlineSpanRef, offset2);
source.A = Unsafe.Add(ref scanlineSpanRef, offset2 + bytesPerSample);
pixel.FromLa16(source);
Unsafe.Add(ref rowSpanRef, x) = pixel;
byte l = Unsafe.Add(ref scanlineSpanRef, offset2);
byte a = Unsafe.Add(ref scanlineSpanRef, offset2 + bytesPerSample);
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa16(new(l, a));
offset2 += bytesPerPixel;
}
}
@ -194,7 +177,6 @@ internal static class PngScanlineProcessor
PngThrowHelper.ThrowMissingPalette();
}
TPixel pixel = default;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span);
@ -202,8 +184,7 @@ internal static class PngScanlineProcessor
for (nuint x = pixelOffset, o = 0; x < frameControl.XMax; x += increment, o++)
{
uint index = Unsafe.Add(ref scanlineSpanRef, o);
pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToPixel<Rgba32>());
Unsafe.Add(ref rowSpanRef, x) = pixel;
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToPixel<Rgba32>());
}
}
@ -243,8 +224,6 @@ internal static class PngScanlineProcessor
where TPixel : unmanaged, IPixel<TPixel>
{
uint offset = pixelOffset + frameControl.XOffset;
TPixel pixel = default;
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
@ -252,16 +231,13 @@ internal static class PngScanlineProcessor
{
if (bitDepth == 16)
{
Rgb48 rgb48 = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
{
rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
pixel.FromRgb48(rgb48);
Unsafe.Add(ref rowSpanRef, x) = pixel;
ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgb48(new(r, g, b));
}
}
else if (pixelOffset == 0 && increment == 1)
@ -274,16 +250,13 @@ internal static class PngScanlineProcessor
}
else
{
Rgb24 rgb = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
{
rgb.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgb.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgb.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
pixel.FromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel;
byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o);
byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgb24(new(r, g, b));
}
}
@ -293,27 +266,20 @@ internal static class PngScanlineProcessor
if (bitDepth == 16)
{
Rgb48 transparent = transparentColor.Value.ToPixel<Rgb48>();
Rgb48 rgb48 = default;
Rgba64 rgba64 = default;
Rgba64 rgba = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
{
rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
rgba64.Rgb = rgb48;
rgba64.A = rgb48.Equals(transparent) ? ushort.MinValue : ushort.MaxValue;
pixel.FromRgba64(rgba64);
Unsafe.Add(ref rowSpanRef, x) = pixel;
rgba.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgba.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
rgba.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
rgba.A = rgba.Rgb.Equals(transparent) ? ushort.MinValue : ushort.MaxValue;
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(rgba);
}
}
else
{
Rgb24 transparent = transparentColor.Value.ToPixel<Rgb24>();
Rgba32 rgba = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
@ -322,9 +288,7 @@ internal static class PngScanlineProcessor
rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
rgba.A = transparent.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue;
pixel.FromRgba32(rgba);
Unsafe.Add(ref rowSpanRef, x) = pixel;
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(rgba);
}
}
}
@ -362,22 +326,18 @@ internal static class PngScanlineProcessor
where TPixel : unmanaged, IPixel<TPixel>
{
uint offset = pixelOffset + frameControl.XOffset;
TPixel pixel = default;
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
if (bitDepth == 16)
{
Rgba64 rgba64 = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
{
rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample));
pixel.FromRgba64(rgba64);
Unsafe.Add(ref rowSpanRef, x) = pixel;
ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample));
ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample));
ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample));
ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(new(r, g, b, a));
}
}
else if (pixelOffset == 0 && increment == 1)
@ -391,17 +351,14 @@ internal static class PngScanlineProcessor
else
{
ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan);
Rgba32 rgba = default;
int o = 0;
for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel)
{
rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o);
rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
rgba.A = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample)));
pixel.FromRgba32(rgba);
Unsafe.Add(ref rowSpanRef, x) = pixel;
byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o);
byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample));
byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample)));
byte a = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample)));
Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(new(r, g, b, a));
}
}
}

14
src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs

@ -149,7 +149,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
Span<Rgba32> previouslySeenPixels = previouslySeenPixelsBuffer.GetSpan();
Rgba32 previousPixel = new(0, 0, 0, 255);
// We save the pixel to avoid loosing the fully opaque black pixel
// We save the pixel to avoid losing the fully opaque black pixel
// See https://github.com/phoboslab/qoi/issues/258
int pixelArrayPosition = GetArrayPosition(previousPixel);
previouslySeenPixels[pixelArrayPosition] = previousPixel;
@ -174,7 +174,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
}
readPixel.A = previousPixel.A;
pixel.FromRgba32(readPixel);
pixel = TPixel.FromRgba32(readPixel);
pixelArrayPosition = GetArrayPosition(readPixel);
previouslySeenPixels[pixelArrayPosition] = readPixel;
break;
@ -186,7 +186,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
ThrowInvalidImageContentException();
}
pixel.FromRgba32(readPixel);
pixel = TPixel.FromRgba32(readPixel);
pixelArrayPosition = GetArrayPosition(readPixel);
previouslySeenPixels[pixelArrayPosition] = readPixel;
break;
@ -197,7 +197,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
// Getting one pixel from previously seen pixels
case QoiChunk.QoiOpIndex:
readPixel = previouslySeenPixels[operationByte];
pixel.FromRgba32(readPixel);
pixel = TPixel.FromRgba32(readPixel);
break;
// Get one pixel from the difference (-2..1) of the previous pixel
@ -211,7 +211,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
G = (byte)Numerics.Modulo256(previousPixel.G + (greenDifference - 2)),
B = (byte)Numerics.Modulo256(previousPixel.B + (blueDifference - 2))
};
pixel.FromRgba32(readPixel);
pixel = TPixel.FromRgba32(readPixel);
pixelArrayPosition = GetArrayPosition(readPixel);
previouslySeenPixels[pixelArrayPosition] = readPixel;
break;
@ -227,7 +227,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
int currentRed = Numerics.Modulo256(diffRedDG - 8 + (diffGreen - 32) + previousPixel.R);
int currentBlue = Numerics.Modulo256(diffBlueDG - 8 + (diffGreen - 32) + previousPixel.B);
readPixel = previousPixel with { R = (byte)currentRed, B = (byte)currentBlue, G = (byte)currentGreen };
pixel.FromRgba32(readPixel);
pixel = TPixel.FromRgba32(readPixel);
pixelArrayPosition = GetArrayPosition(readPixel);
previouslySeenPixels[pixelArrayPosition] = readPixel;
break;
@ -241,7 +241,7 @@ internal class QoiDecoderCore : IImageDecoderInternals
}
readPixel = previousPixel;
pixel.FromRgba32(readPixel);
pixel = TPixel.FromRgba32(readPixel);
for (int k = -1; k < repetitions; k++, j++)
{
if (j == row.Length)

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

@ -222,7 +222,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
private void ReadPaletted<TPixel>(BufferedReadStream stream, int width, int height, Buffer2D<TPixel> pixels, Span<byte> palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
bool invertX = InvertX(origin);
for (int y = 0; y < height; y++)
@ -237,14 +236,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow);
}
}
@ -255,14 +254,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow);
}
}
@ -273,14 +272,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow);
}
}
else
{
for (int x = 0; x < width; x++)
{
ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow);
ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow);
}
}
@ -319,16 +318,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
switch (colorMapPixelSizeInBytes)
{
case 1:
color.FromL8(Unsafe.As<byte, L8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
color = TPixel.FromL8(Unsafe.As<byte, L8>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 2:
this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes, ref color);
color = this.ReadPalettedBgra16Pixel<TPixel>(palette, bufferSpan[idx], colorMapPixelSizeInBytes);
break;
case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
color = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
case 4:
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
color = TPixel.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes]));
break;
}
@ -350,17 +349,15 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
private void ReadMonoChrome<TPixel>(BufferedReadStream stream, int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
bool invertX = InvertX(origin);
if (invertX)
if (InvertX(origin))
{
TPixel color = default;
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = width - 1; x >= 0; x--)
{
ReadL8Pixel(stream, color, x, pixelSpan);
ReadL8Pixel(stream, x, pixelSpan);
}
}
@ -369,8 +366,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
using IMemoryOwner<byte> row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0);
Span<byte> rowSpan = row.GetSpan();
bool invertY = InvertY(origin);
if (invertY)
if (InvertY(origin))
{
for (int y = height - 1; y >= 0; y--)
{
@ -398,7 +394,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
private void ReadBgra16<TPixel>(BufferedReadStream stream, int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
bool invertX = InvertX(origin);
using IMemoryOwner<byte> row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0);
Span<byte> rowSpan = row.GetSpan();
@ -426,14 +421,12 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite)
{
color.FromLa16(Unsafe.As<byte, La16>(ref MemoryMarshal.GetReference(scratchBuffer)));
pixelSpan[x] = TPixel.FromLa16(Unsafe.As<byte, La16>(ref MemoryMarshal.GetReference(scratchBuffer)));
}
else
{
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref MemoryMarshal.GetReference(scratchBuffer)));
pixelSpan[x] = TPixel.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref MemoryMarshal.GetReference(scratchBuffer)));
}
pixelSpan[x] = color;
}
}
else
@ -477,18 +470,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
private void ReadBgr24<TPixel>(BufferedReadStream stream, int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
bool invertX = InvertX(origin);
if (invertX)
if (InvertX(origin))
{
Span<byte> scratchBuffer = stackalloc byte[4];
TPixel color = default;
for (int y = 0; y < height; y++)
{
int newY = InvertY(y, height, origin);
Span<TPixel> pixelSpan = pixels.DangerousGetRowSpan(newY);
for (int x = width - 1; x >= 0; x--)
{
ReadBgr24Pixel(stream, color, x, pixelSpan, scratchBuffer);
ReadBgr24Pixel(stream, x, pixelSpan, scratchBuffer);
}
}
@ -497,9 +488,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
using IMemoryOwner<byte> row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0);
Span<byte> rowSpan = row.GetSpan();
bool invertY = InvertY(origin);
if (invertY)
if (InvertY(origin))
{
for (int y = height - 1; y >= 0; y--)
{
@ -527,7 +517,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
private void ReadBgra32<TPixel>(BufferedReadStream stream, int width, int height, Buffer2D<TPixel> pixels, TgaImageOrigin origin)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
bool invertX = InvertX(origin);
Guard.NotNull(this.tgaMetadata);
@ -565,14 +554,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
{
for (int x = width - 1; x >= 0; x--)
{
this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
this.ReadBgra32Pixel(stream, x, pixelRow, scratchBuffer);
}
}
else
{
for (int x = 0; x < width; x++)
{
this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer);
this.ReadBgra32Pixel(stream, x, pixelRow, scratchBuffer);
}
}
}
@ -610,7 +599,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
switch (bytesPerPixel)
{
case 1:
color.FromL8(Unsafe.As<byte, L8>(ref bufferSpan[idx]));
color = TPixel.FromL8(Unsafe.As<byte, L8>(ref bufferSpan[idx]));
break;
case 2:
if (!this.hasAlpha)
@ -621,26 +610,26 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
if (this.fileHeader.ImageType == TgaImageType.RleBlackAndWhite)
{
color.FromLa16(Unsafe.As<byte, La16>(ref bufferSpan[idx]));
color = TPixel.FromLa16(Unsafe.As<byte, La16>(ref bufferSpan[idx]));
}
else
{
color.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx]));
color = TPixel.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref bufferSpan[idx]));
}
break;
case 3:
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
color = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref bufferSpan[idx]));
break;
case 4:
if (this.hasAlpha)
{
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref bufferSpan[idx]));
color = TPixel.FromBgra32(Unsafe.As<byte, Bgra32>(ref bufferSpan[idx]));
}
else
{
byte alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3];
color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], alpha));
color = TPixel.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], alpha));
}
break;
@ -677,16 +666,15 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ReadL8Pixel<TPixel>(BufferedReadStream stream, TPixel color, int x, Span<TPixel> pixelSpan)
private static void ReadL8Pixel<TPixel>(BufferedReadStream stream, int x, Span<TPixel> pixelSpan)
where TPixel : unmanaged, IPixel<TPixel>
{
byte pixelValue = (byte)stream.ReadByte();
color.FromL8(Unsafe.As<byte, L8>(ref pixelValue));
pixelSpan[x] = color;
pixelSpan[x] = TPixel.FromL8(Unsafe.As<byte, L8>(ref pixelValue));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ReadBgr24Pixel<TPixel>(BufferedReadStream stream, TPixel color, int x, Span<TPixel> pixelSpan, Span<byte> scratchBuffer)
private static void ReadBgr24Pixel<TPixel>(BufferedReadStream stream, int x, Span<TPixel> pixelSpan, Span<byte> scratchBuffer)
where TPixel : unmanaged, IPixel<TPixel>
{
int bytesRead = stream.Read(scratchBuffer, 0, 3);
@ -695,8 +683,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel");
}
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref MemoryMarshal.GetReference(scratchBuffer)));
pixelSpan[x] = color;
pixelSpan[x] = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref MemoryMarshal.GetReference(scratchBuffer)));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -714,7 +701,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadBgra32Pixel<TPixel>(BufferedReadStream stream, int x, TPixel color, Span<TPixel> pixelRow, Span<byte> scratchBuffer)
private void ReadBgra32Pixel<TPixel>(BufferedReadStream stream, int x, Span<TPixel> pixelRow, Span<byte> scratchBuffer)
where TPixel : unmanaged, IPixel<TPixel>
{
int bytesRead = stream.Read(scratchBuffer, 0, 4);
@ -726,8 +713,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
Guard.NotNull(this.tgaMetadata);
byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : scratchBuffer[3];
color.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
@ -745,7 +731,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(BufferedReadStream stream, Span<byte> palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
private void ReadPalettedBgra16Pixel<TPixel>(BufferedReadStream stream, Span<byte> palette, int colorMapPixelSizeInBytes, int x, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = stream.ReadByte();
@ -754,16 +740,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index");
}
this.ReadPalettedBgra16Pixel(palette, colorIndex, colorMapPixelSizeInBytes, ref color);
pixelRow[x] = color;
pixelRow[x] = this.ReadPalettedBgra16Pixel<TPixel>(palette, colorIndex, colorMapPixelSizeInBytes);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private void ReadPalettedBgra16Pixel<TPixel>(Span<byte> palette, int index, int colorMapPixelSizeInBytes, ref TPixel color)
private TPixel ReadPalettedBgra16Pixel<TPixel>(Span<byte> palette, int index, int colorMapPixelSizeInBytes)
where TPixel : unmanaged, IPixel<TPixel>
{
Bgra5551 bgra = default;
bgra.FromBgra5551(Unsafe.As<byte, Bgra5551>(ref palette[index * colorMapPixelSizeInBytes]));
Bgra5551 bgra = Unsafe.As<byte, Bgra5551>(ref palette[index * colorMapPixelSizeInBytes]);
if (!this.hasAlpha)
{
@ -771,11 +755,11 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000);
}
color.FromBgra5551(bgra);
return TPixel.FromBgra5551(bgra);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ReadPalettedBgr24Pixel<TPixel>(BufferedReadStream stream, Span<byte> palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
private static void ReadPalettedBgr24Pixel<TPixel>(BufferedReadStream stream, Span<byte> palette, int colorMapPixelSizeInBytes, int x, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = stream.ReadByte();
@ -784,12 +768,11 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index");
}
color.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromBgr24(Unsafe.As<byte, Bgr24>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static void ReadPalettedBgra32Pixel<TPixel>(BufferedReadStream stream, Span<byte> palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span<TPixel> pixelRow)
private static void ReadPalettedBgra32Pixel<TPixel>(BufferedReadStream stream, Span<byte> palette, int colorMapPixelSizeInBytes, int x, Span<TPixel> pixelRow)
where TPixel : unmanaged, IPixel<TPixel>
{
int colorIndex = stream.ReadByte();
@ -798,8 +781,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals
TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index");
}
color.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromBgra32(Unsafe.As<byte, Bgra32>(ref palette[colorIndex * colorMapPixelSizeInBytes]));
}
/// <summary>

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

@ -5,7 +5,6 @@ using System.Buffers;
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.PixelFormats;
@ -160,7 +159,6 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
private void WriteRunLengthEncodedImage<TPixel>(Stream stream, ImageFrame<TPixel> image)
where TPixel : unmanaged, IPixel<TPixel>
{
Rgba32 color = default;
Buffer2D<TPixel> pixels = image.PixelBuffer;
for (int y = 0; y < image.Height; y++)
{
@ -168,14 +166,13 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
for (int x = 0; x < image.Width;)
{
TPixel currentPixel = pixelRow[x];
currentPixel.ToRgba32(ref color);
byte equalPixelCount = FindEqualPixels(pixelRow, x);
if (equalPixelCount > 0)
{
// Write the number of equal pixels, with the high bit set, indicating ist a compressed pixel run.
stream.WriteByte((byte)(equalPixelCount | 128));
this.WritePixel(stream, currentPixel, color);
this.WritePixel(stream, currentPixel, currentPixel.ToRgba32());
x += equalPixelCount + 1;
}
else
@ -183,13 +180,12 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals
// Write Raw Packet (i.e., Non-Run-Length Encoded):
byte unEqualPixelCount = FindUnEqualPixels(pixelRow, x);
stream.WriteByte(unEqualPixelCount);
this.WritePixel(stream, currentPixel, color);
this.WritePixel(stream, currentPixel, currentPixel.ToRgba32());
x++;
for (int i = 0; i < unEqualPixelCount; i++)
{
currentPixel = pixelRow[x];
currentPixel.ToRgba32(ref color);
this.WritePixel(stream, currentPixel, color);
this.WritePixel(stream, currentPixel, currentPixel.ToRgba32());
x++;
}
}

140
src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs

@ -102,8 +102,7 @@ internal static class HorizontalPredictor
byte r = (byte)(rowRgb[x].R - rowRgb[x - 1].R);
byte g = (byte)(rowRgb[x].G - rowRgb[x - 1].G);
byte b = (byte)(rowRgb[x].B - rowRgb[x - 1].B);
var rgb = new Rgb24(r, g, b);
rowRgb[x].FromRgb24(rgb);
rowRgb[x] = new Rgb24(r, g, b);
}
}
}
@ -128,8 +127,7 @@ internal static class HorizontalPredictor
for (int x = rowL16.Length - 1; x >= 1; x--)
{
ushort val = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue);
rowL16[x].PackedValue = val;
rowL16[x].PackedValue = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue);
}
}
}
@ -181,13 +179,13 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
ushort pixelValue = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
ushort diff = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort diff = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
pixelValue += diff;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, pixelValue);
offset += 2;
@ -200,13 +198,13 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
ushort pixelValue = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
ushort diff = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort diff = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
pixelValue += diff;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, pixelValue);
offset += 2;
@ -225,13 +223,13 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
uint pixelValue = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
uint diff = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint diff = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
pixelValue += diff;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue);
offset += 4;
@ -244,13 +242,13 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
uint pixelValue = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
uint diff = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint diff = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
pixelValue += diff;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue);
offset += 4;
@ -278,8 +276,7 @@ internal static class HorizontalPredictor
r += pixel.R;
g += pixel.G;
b += pixel.B;
var rgb = new Rgb24(r, g, b);
pixel.FromRgb24(rgb);
pixel = new Rgb24(r, g, b);
}
}
}
@ -305,8 +302,7 @@ internal static class HorizontalPredictor
g += pixel.G;
b += pixel.B;
a += pixel.A;
var rgb = new Rgba32(r, g, b, a);
pixel.FromRgba32(rgb);
pixel = new Rgba32(r, g, b, a);
}
}
}
@ -321,29 +317,29 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
ushort r = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort g = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort b = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
ushort deltaR = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaG = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaB = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b);
offset += 2;
@ -356,29 +352,29 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
ushort r = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort g = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort b = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
ushort deltaR = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaG = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaB = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b);
offset += 2;
@ -397,37 +393,37 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
ushort r = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort g = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort b = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort a = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
ushort a = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2));
offset += 2;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
ushort deltaR = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaG = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaB = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaA = TiffUtils.ConvertToUShortBigEndian(rowSpan);
ushort deltaA = TiffUtilities.ConvertToUShortBigEndian(rowSpan);
a += deltaA;
BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a);
offset += 2;
@ -440,37 +436,37 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
ushort r = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort g = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort b = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
ushort a = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
ushort a = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2));
offset += 2;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 2);
ushort deltaR = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaG = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaB = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b);
offset += 2;
rowSpan = rowBytes.Slice(offset, 2);
ushort deltaA = TiffUtils.ConvertToUShortLittleEndian(rowSpan);
ushort deltaA = TiffUtilities.ConvertToUShortLittleEndian(rowSpan);
a += deltaA;
BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a);
offset += 2;
@ -489,29 +485,29 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
uint r = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint g = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint b = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
uint deltaR = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaG = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaB = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b);
offset += 4;
@ -524,29 +520,29 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
uint r = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint g = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint b = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
uint deltaR = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaG = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaB = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b);
offset += 4;
@ -565,37 +561,37 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
uint r = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint g = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint b = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint a = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
uint a = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4));
offset += 4;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
uint deltaR = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaG = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaB = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaA = TiffUtils.ConvertToUIntBigEndian(rowSpan);
uint deltaA = TiffUtilities.ConvertToUIntBigEndian(rowSpan);
a += deltaA;
BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a);
offset += 4;
@ -608,37 +604,37 @@ internal static class HorizontalPredictor
{
int offset = 0;
Span<byte> rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount);
uint r = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint g = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint b = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
uint a = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
uint a = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4));
offset += 4;
for (int x = 1; x < width; x++)
{
Span<byte> rowSpan = rowBytes.Slice(offset, 4);
uint deltaR = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
r += deltaR;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaG = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
g += deltaG;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaB = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
b += deltaB;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b);
offset += 4;
rowSpan = rowBytes.Slice(offset, 4);
uint deltaA = TiffUtils.ConvertToUIntLittleEndian(rowSpan);
uint deltaA = TiffUtilities.ConvertToUIntLittleEndian(rowSpan);
a += deltaA;
BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a);
offset += 4;

10
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs

@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation for 16-bit grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class BlackIsZero16TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -32,9 +33,8 @@ internal class BlackIsZero16TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
L16 l16 = TiffUtils.L16Default;
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
L16 l16 = TiffUtilities.L16Default;
TPixel color = TPixel.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
@ -44,10 +44,10 @@ internal class BlackIsZero16TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ushort intensity = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort intensity = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color);
pixelRow[x] = TPixel.FromL16(new(intensity));
}
}
else

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

@ -19,11 +19,9 @@ internal class BlackIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
nuint offset = 0;
TPixel colorBlack = default;
TPixel colorWhite = default;
TPixel colorBlack = TPixel.FromRgba32(Color.Black.ToPixel<Rgba32>());
TPixel colorWhite = TPixel.FromRgba32(Color.White.ToPixel<Rgba32>());
colorBlack.FromRgba32(Color.Black.ToPixel<Rgba32>());
colorWhite.FromRgba32(Color.White.ToPixel<Rgba32>());
ref byte dataRef = ref MemoryMarshal.GetReference(data);
for (nuint y = (uint)top; y < (uint)(top + height); y++)
{

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation for 24-bit grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class BlackIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -25,8 +25,6 @@ internal class BlackIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
@ -40,10 +38,10 @@ internal class BlackIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong intensity = TiffUtils.ConvertToUIntBigEndian(buffer);
uint intensity = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(intensity);
}
}
else
@ -51,10 +49,10 @@ internal class BlackIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong intensity = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint intensity = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(intensity);
}
}
}

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

@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation for 32-bit float grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -24,8 +25,6 @@ internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
TPixel color = default;
color.FromScaledVector4(Vector4.Zero);
Span<byte> buffer = stackalloc byte[4];
int offset = 0;
@ -41,9 +40,7 @@ internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
float intensity = BitConverter.ToSingle(buffer);
offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f));
}
}
else
@ -53,9 +50,7 @@ internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
float intensity = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f));
}
}
}

13
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation for 32-bit grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class BlackIsZero32TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -25,9 +25,6 @@ internal class BlackIsZero32TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -36,20 +33,20 @@ internal class BlackIsZero32TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong intensity = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint intensity = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(intensity);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong intensity = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint intensity = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(intensity);
}
}
}

25
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs

@ -9,47 +9,30 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation (optimized for 4-bit grayscale images).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class BlackIsZero4TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
int offset = 0;
bool isOddWidth = (width & 1) == 1;
var l8 = default(L8);
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan(y);
for (int x = left; x < left + width - 1;)
{
byte byteData = data[offset++];
byte intensity1 = (byte)(((byteData & 0xF0) >> 4) * 17);
l8.PackedValue = intensity1;
color.FromL8(l8);
pixelRowSpan[x++] = color;
byte intensity2 = (byte)((byteData & 0x0F) * 17);
l8.PackedValue = intensity2;
color.FromL8(l8);
pixelRowSpan[x++] = color;
pixelRowSpan[x++] = TPixel.FromL8(new((byte)(((byteData & 0xF0) >> 4) * 17)));
pixelRowSpan[x++] = TPixel.FromL8(new((byte)((byteData & 0x0F) * 17)));
}
if (isOddWidth)
{
byte byteData = data[offset++];
byte intensity1 = (byte)(((byteData & 0xF0) >> 4) * 17);
l8.PackedValue = intensity1;
color.FromL8(l8);
pixelRowSpan[left + width - 1] = color;
pixelRowSpan[left + width - 1] = TPixel.FromL8(new((byte)(((byteData & 0xF0) >> 4) * 17)));
}
}
}

13
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,25 +10,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'BlackIsZero' photometric interpretation (for all bit depths).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class BlackIsZeroTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly ushort bitsPerSample0;
private readonly float factor;
public BlackIsZeroTiffColor(TiffBitsPerSample bitsPerSample)
{
this.bitsPerSample0 = bitsPerSample.Channel0;
this.factor = (1 << this.bitsPerSample0) - 1.0f;
this.factor = (1 << this.bitsPerSample0) - 1f;
}
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
var bitReader = new BitReader(data);
BitReader bitReader = new(data);
for (int y = top; y < top + height; y++)
{
@ -38,9 +35,7 @@ internal class BlackIsZeroTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
int value = bitReader.ReadBits(this.bitsPerSample0);
float intensity = value / this.factor;
color.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(intensity, intensity, intensity, 1f));
}
bitReader.NextRow();

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

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Memory;
@ -13,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements decoding pixel data with photometric interpretation of type 'CieLab' with the planar configuration.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class CieLabPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -23,11 +23,10 @@ internal class CieLabPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
Span<byte> l = data[0].GetSpan();
Span<byte> a = data[1].GetSpan();
Span<byte> b = data[2].GetSpan();
Span<byte> a = data[1].GetSpan();
Span<byte> l = data[0].GetSpan();
TPixel color = default;
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -36,9 +35,7 @@ internal class CieLabPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
{
CieLab lab = new((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]);
Rgb rgb = ColorSpaceConverter.ToRgb(lab);
color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1.0f));
offset++;
}

10
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Memory;
@ -12,17 +11,16 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements decoding pixel data with photometric interpretation of type 'CieLab'.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class CieLabTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private static readonly ColorSpaceConverter ColorSpaceConverter = new();
private const float Inv255 = 1.0f / 255.0f;
private const float Inv255 = 1f / 255f;
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
TPixel color = default;
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -33,9 +31,7 @@ internal class CieLabTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float l = (data[offset] & 0xFF) * 100f * Inv255;
CieLab lab = new(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]);
Rgb rgb = ColorSpaceConverter.ToRgb(lab);
color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1f));
offset += 3;
}

8
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.ColorSpaces;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.Memory;
@ -12,12 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
internal class CmykTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private const float Inv255 = 1 / 255.0f;
private const float Inv255 = 1f / 255f;
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
TPixel color = default;
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -26,9 +24,7 @@ internal class CmykTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
Cmyk cmyk = new(data[offset] * Inv255, data[offset + 1] * Inv255, data[offset + 2] * Inv255, data[offset + 3] * Inv255);
Rgb rgb = ColorSpaceConverter.ToRgb(in cmyk);
color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1.0f));
offset += 4;
}

13
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'PaletteTiffColor' photometric interpretation (for all bit depths).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class PaletteTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -18,8 +18,11 @@ internal class PaletteTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
private readonly TPixel[] palette;
private const float InvMax = 1.0f / 65535F;
private const float InvMax = 1f / 65535f;
/// <summary>
/// Initializes a new instance of the <see cref="PaletteTiffColor{TPixel}"/> class.
/// </summary>
/// <param name="bitsPerSample">The number of bits per sample for each pixel.</param>
/// <param name="colorMap">The RGB color lookup table to use for decoding the image.</param>
public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap)
@ -32,7 +35,7 @@ internal class PaletteTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var bitReader = new BitReader(data);
BitReader bitReader = new(data);
for (int y = top; y < top + height; y++)
{
@ -49,7 +52,7 @@ internal class PaletteTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
private static TPixel[] GeneratePalette(ushort[] colorMap, int colorCount)
{
var palette = new TPixel[colorCount];
TPixel[] palette = new TPixel[colorCount];
const int rOffset = 0;
int gOffset = colorCount;
@ -60,7 +63,7 @@ internal class PaletteTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float r = colorMap[rOffset + i] * InvMax;
float g = colorMap[gOffset + i] * InvMax;
float b = colorMap[bOffset + i] * InvMax;
palette[i].FromScaledVector4(new Vector4(r, g, b, 1.0f));
palette[i] = TPixel.FromScaledVector4(new(r, g, b, 1f));
}
return palette;

15
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,11 +10,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 16 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgb161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
private readonly Configuration configuration;
/// <summary>
@ -32,10 +31,6 @@ internal class Rgb161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
@ -46,14 +41,14 @@ internal class Rgb161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
pixelRow[x] = TPixel.FromRgb48(new(r, g, b));
}
}
else

22
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 16 bit.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgb16PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -26,10 +26,6 @@ internal class Rgb16PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Span<byte> blueData = data[2].GetSpan();
@ -42,26 +38,26 @@ internal class Rgb16PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortBigEndian(redData.Slice(offset, 2));
ulong g = TiffUtils.ConvertToUShortBigEndian(greenData.Slice(offset, 2));
ulong b = TiffUtils.ConvertToUShortBigEndian(blueData.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortBigEndian(redData.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(greenData.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(blueData.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
pixelRow[x] = TPixel.FromRgb48(new(r, g, b));
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortLittleEndian(redData.Slice(offset, 2));
ulong g = TiffUtils.ConvertToUShortLittleEndian(greenData.Slice(offset, 2));
ulong b = TiffUtils.ConvertToUShortLittleEndian(blueData.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortLittleEndian(redData.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortLittleEndian(greenData.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortLittleEndian(blueData.Slice(offset, 2));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color);
pixelRow[x] = TPixel.FromRgb48(new(r, g, b));
}
}
}

20
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 24 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgb242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -25,8 +25,6 @@ internal class Rgb242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
@ -41,18 +39,18 @@ internal class Rgb242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntBigEndian(buffer);
uint r = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntBigEndian(buffer);
uint g = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntBigEndian(buffer);
uint b = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b);
}
}
else
@ -60,18 +58,18 @@ internal class Rgb242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b);
}
}
}

20
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 24 bit.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgb24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -26,8 +26,6 @@ internal class Rgb24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
@ -45,15 +43,15 @@ internal class Rgb24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
redData.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntBigEndian(buffer);
uint r = TiffUtilities.ConvertToUIntBigEndian(buffer);
greenData.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntBigEndian(buffer);
uint g = TiffUtilities.ConvertToUIntBigEndian(buffer);
blueData.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntBigEndian(buffer);
uint b = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b);
}
}
else
@ -61,15 +59,15 @@ internal class Rgb24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
redData.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer);
greenData.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer);
blueData.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b);
}
}
}

20
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 32 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgb323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -25,8 +25,6 @@ internal class Rgb323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
@ -37,32 +35,32 @@ internal class Rgb323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b);
}
}
}

21
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 32 bit.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgb32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -26,9 +26,6 @@ internal class Rgb32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Span<byte> blueData = data[2].GetSpan();
@ -41,26 +38,26 @@ internal class Rgb32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntBigEndian(redData.Slice(offset, 4));
ulong g = TiffUtils.ConvertToUIntBigEndian(greenData.Slice(offset, 4));
ulong b = TiffUtils.ConvertToUIntBigEndian(blueData.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntBigEndian(redData.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntBigEndian(greenData.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntBigEndian(blueData.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntLittleEndian(redData.Slice(offset, 4));
ulong g = TiffUtils.ConvertToUIntLittleEndian(greenData.Slice(offset, 4));
ulong b = TiffUtils.ConvertToUIntLittleEndian(blueData.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntLittleEndian(redData.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntLittleEndian(greenData.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntLittleEndian(blueData.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b);
}
}
}

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

@ -9,17 +9,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation for 4 bits per color channel images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgb444TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
int offset = 0;
var bgra = default(Bgra4444);
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y);
@ -31,9 +29,8 @@ internal class Rgb444TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
offset++;
byte b = (byte)((data[offset] & 0xF0) >> 4);
bgra.PackedValue = ToBgraPackedValue(b, g, r);
color.FromScaledVector4(bgra.ToScaledVector4());
pixelRow[x] = color;
Bgra4444 bgra = new() { PackedValue = ToBgraPackedValue(b, g, r) };
pixelRow[x] = TPixel.FromScaledVector4(bgra.ToScaledVector4());
if (x + 1 >= pixelRow.Length)
{
offset++;
@ -47,8 +44,7 @@ internal class Rgb444TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
offset++;
bgra.PackedValue = ToBgraPackedValue(b, g, r);
color.FromScaledVector4(bgra.ToScaledVector4());
pixelRow[x + 1] = color;
pixelRow[x + 1] = TPixel.FromScaledVector4(bgra.ToScaledVector4());
}
}
}

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -10,6 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 32 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -24,8 +24,6 @@ internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
Span<byte> buffer = stackalloc byte[4];
@ -52,9 +50,7 @@ internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float b = BitConverter.ToSingle(buffer);
offset += 4;
var colorVector = new Vector4(r, g, b, 1.0f);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f));
}
}
else
@ -70,9 +66,7 @@ internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float b = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
var colorVector = new Vector4(r, g, b, 1.0f);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f));
}
}
}

13
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with 'Planar' layout (for all bit depths).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class RgbPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -49,11 +49,9 @@ internal class RgbPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
/// <param name="height">The height of the image block.</param>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
var rBitReader = new BitReader(data[0].GetSpan());
var gBitReader = new BitReader(data[1].GetSpan());
var bBitReader = new BitReader(data[2].GetSpan());
BitReader rBitReader = new(data[0].GetSpan());
BitReader gBitReader = new(data[1].GetSpan());
BitReader bBitReader = new(data[2].GetSpan());
for (int y = top; y < top + height; y++)
{
@ -64,8 +62,7 @@ internal class RgbPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
float g = gBitReader.ReadBits(this.bitsPerSampleG) / this.gFactor;
float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
color.FromScaledVector4(new Vector4(r, g, b, 1.0f));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f));
}
rBitReader.NextRow();

8
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs

@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation (for all bit depths).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class RgbTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -40,9 +41,7 @@ internal class RgbTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
var bitReader = new BitReader(data);
BitReader bitReader = new(data);
for (int y = top; y < top + height; y++)
{
@ -53,8 +52,7 @@ internal class RgbTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float g = bitReader.ReadBits(this.bitsPerSampleG) / this.gFactor;
float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
color.FromScaledVector4(new Vector4(r, g, b, 1.0f));
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new Vector4(r, g, b, 1f));
}
bitReader.NextRow();

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

@ -13,6 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and with 16 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgba16161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -29,8 +30,8 @@ internal class Rgba16161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// </summary>
/// <param name="configuration">The configuration.</param>
/// <param name="memoryAllocator">The memory allocator.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
/// <param name="extraSamplesType">The type of the extra samples.</param>
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memoryAllocator, TiffExtraSampleType? extraSamplesType, bool isBigEndian)
{
this.configuration = configuration;
@ -42,15 +43,11 @@ internal class Rgba16161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
using IMemoryOwner<Vector4> vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate<Vector4>(width) : null;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span<Vector4>.Empty;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : [];
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
@ -59,18 +56,18 @@ internal class Rgba16161616TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
ulong a = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2));
ushort a = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2));
offset += 2;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) :
TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorFromRgba64Premultiplied<TPixel>(r, g, b, a)
: TPixel.FromRgba64(new(r, g, b, a));
}
}
else

34
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout for each color channel with 16 bit.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgba16PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -33,10 +33,6 @@ internal class Rgba16PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
Rgba64 rgba = TiffUtils.Rgba64Default;
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Span<byte> blueData = data[2].GetSpan();
@ -51,32 +47,32 @@ internal class Rgba16PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortBigEndian(redData.Slice(offset, 2));
ulong g = TiffUtils.ConvertToUShortBigEndian(greenData.Slice(offset, 2));
ulong b = TiffUtils.ConvertToUShortBigEndian(blueData.Slice(offset, 2));
ulong a = TiffUtils.ConvertToUShortBigEndian(alphaData.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortBigEndian(redData.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortBigEndian(greenData.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortBigEndian(blueData.Slice(offset, 2));
ushort a = TiffUtilities.ConvertToUShortBigEndian(alphaData.Slice(offset, 2));
offset += 2;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) :
TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorFromRgba64Premultiplied<TPixel>(r, g, b, a)
: TPixel.FromRgba64(new(r, g, b, a));
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUShortLittleEndian(redData.Slice(offset, 2));
ulong g = TiffUtils.ConvertToUShortLittleEndian(greenData.Slice(offset, 2));
ulong b = TiffUtils.ConvertToUShortLittleEndian(blueData.Slice(offset, 2));
ulong a = TiffUtils.ConvertToUShortLittleEndian(alphaData.Slice(offset, 2));
ushort r = TiffUtilities.ConvertToUShortLittleEndian(redData.Slice(offset, 2));
ushort g = TiffUtilities.ConvertToUShortLittleEndian(greenData.Slice(offset, 2));
ushort b = TiffUtilities.ConvertToUShortLittleEndian(blueData.Slice(offset, 2));
ushort a = TiffUtilities.ConvertToUShortLittleEndian(alphaData.Slice(offset, 2));
offset += 2;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) :
TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorFromRgba64Premultiplied<TPixel>(r, g, b, a)
: TPixel.FromRgba64(new(r, g, b, a));
}
}
}

33
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and with 24 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgba24242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -32,9 +32,6 @@ internal class Rgba24242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
@ -51,24 +48,24 @@ internal class Rgba24242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntBigEndian(buffer);
uint r = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntBigEndian(buffer);
uint g = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntBigEndian(buffer);
uint b = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntBigEndian(buffer);
uint a = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo24BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b, a);
}
}
else
@ -76,24 +73,24 @@ internal class Rgba24242424TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint a = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo24BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b, a);
}
}
}

32
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout for each color channel with 24 bit.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgba24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -33,8 +33,6 @@ internal class Rgba24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
@ -54,19 +52,19 @@ internal class Rgba24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
for (int x = 0; x < pixelRow.Length; x++)
{
redData.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntBigEndian(buffer);
uint r = TiffUtilities.ConvertToUIntBigEndian(buffer);
greenData.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntBigEndian(buffer);
uint g = TiffUtilities.ConvertToUIntBigEndian(buffer);
blueData.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntBigEndian(buffer);
uint b = TiffUtilities.ConvertToUIntBigEndian(buffer);
alphaData.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntBigEndian(buffer);
uint a = TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo24BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b, a);
}
}
else
@ -74,19 +72,19 @@ internal class Rgba24PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
for (int x = 0; x < pixelRow.Length; x++)
{
redData.Slice(offset, 3).CopyTo(bufferSpan);
ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer);
greenData.Slice(offset, 3).CopyTo(bufferSpan);
ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer);
blueData.Slice(offset, 3).CopyTo(bufferSpan);
ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer);
alphaData.Slice(offset, 3).CopyTo(bufferSpan);
ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer);
uint a = TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo24Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo24BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo24Bit<TPixel>(r, g, b, a);
}
}
}

33
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgba32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -32,9 +32,6 @@ internal class Rgba32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
int offset = 0;
@ -46,42 +43,42 @@ internal class Rgba32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
ulong a = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint a = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo32BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b, a);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
ulong a = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint a = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo32BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b, a);
}
}
}

34
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers;
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -12,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and a 'Planar' layout for each color channel with 32 bit.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgba32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly bool isBigEndian;
private readonly TiffExtraSampleType? extraSamplesType;
/// <summary>
@ -33,9 +32,6 @@ internal class Rgba32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
/// <inheritdoc/>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> redData = data[0].GetSpan();
Span<byte> greenData = data[1].GetSpan();
Span<byte> blueData = data[2].GetSpan();
@ -50,32 +46,32 @@ internal class Rgba32PlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntBigEndian(redData.Slice(offset, 4));
ulong g = TiffUtils.ConvertToUIntBigEndian(greenData.Slice(offset, 4));
ulong b = TiffUtils.ConvertToUIntBigEndian(blueData.Slice(offset, 4));
ulong a = TiffUtils.ConvertToUIntBigEndian(alphaData.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntBigEndian(redData.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntBigEndian(greenData.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntBigEndian(blueData.Slice(offset, 4));
uint a = TiffUtilities.ConvertToUIntBigEndian(alphaData.Slice(offset, 4));
offset += 4;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo32BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b, a);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong r = TiffUtils.ConvertToUIntLittleEndian(redData.Slice(offset, 4));
ulong g = TiffUtils.ConvertToUIntLittleEndian(greenData.Slice(offset, 4));
ulong b = TiffUtils.ConvertToUIntLittleEndian(blueData.Slice(offset, 4));
ulong a = TiffUtils.ConvertToUIntLittleEndian(alphaData.Slice(offset, 4));
uint r = TiffUtilities.ConvertToUIntLittleEndian(redData.Slice(offset, 4));
uint g = TiffUtilities.ConvertToUIntLittleEndian(greenData.Slice(offset, 4));
uint b = TiffUtilities.ConvertToUIntLittleEndian(blueData.Slice(offset, 4));
uint a = TiffUtilities.ConvertToUIntLittleEndian(alphaData.Slice(offset, 4));
offset += 4;
pixelRow[x] = hasAssociatedAlpha ?
TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) :
TiffUtils.ColorScaleTo32Bit(r, g, b, a, color);
pixelRow[x] = hasAssociatedAlpha
? TiffUtilities.ColorScaleTo32BitPremultiplied<TPixel>(r, g, b, a)
: TiffUtilities.ColorScaleTo32Bit<TPixel>(r, g, b, a);
}
}
}

5
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs

@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and 8 bits per channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class Rgba8888TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -34,10 +35,8 @@ internal class Rgba8888TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
int offset = 0;
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
using IMemoryOwner<Vector4> vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate<Vector4>(width) : null;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span<Vector4>.Empty;
Span<Vector4> vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : [];
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -10,6 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -24,8 +24,6 @@ internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
Span<byte> buffer = stackalloc byte[4];
@ -57,9 +55,7 @@ internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float a = BitConverter.ToSingle(buffer);
offset += 4;
var colorVector = new Vector4(r, g, b, a);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, a));
}
}
else
@ -78,9 +74,7 @@ internal class RgbaFloat32323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float a = BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
var colorVector = new Vector4(r, g, b, a);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, a));
}
}
}

18
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs

@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout (for all bit depths).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class RgbaPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -59,13 +60,12 @@ internal class RgbaPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
/// <param name="height">The height of the image block.</param>
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
bool hasAssociatedAlpha = this.extraSampleType.HasValue && this.extraSampleType == TiffExtraSampleType.AssociatedAlphaData;
var rBitReader = new BitReader(data[0].GetSpan());
var gBitReader = new BitReader(data[1].GetSpan());
var bBitReader = new BitReader(data[2].GetSpan());
var aBitReader = new BitReader(data[3].GetSpan());
BitReader rBitReader = new(data[0].GetSpan());
BitReader gBitReader = new(data[1].GetSpan());
BitReader bBitReader = new(data[2].GetSpan());
BitReader aBitReader = new(data[3].GetSpan());
for (int y = top; y < top + height; y++)
{
@ -77,17 +77,15 @@ internal class RgbaPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
float a = aBitReader.ReadBits(this.bitsPerSampleA) / this.aFactor;
var vec = new Vector4(r, g, b, a);
Vector4 vector = new(r, g, b, a);
if (hasAssociatedAlpha)
{
color = TiffUtils.UnPremultiply(ref vec, color);
pixelRow[x] = TiffUtilities.UnPremultiply<TPixel>(ref vector);
}
else
{
color.FromScaledVector4(vec);
pixelRow[x] = TPixel.FromScaledVector4(vector);
}
pixelRow[x] = color;
}
rBitReader.NextRow();

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

@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'RGB' photometric interpretation with alpha channel (for all bit depths).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class RgbaTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -50,9 +51,7 @@ internal class RgbaTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
var bitReader = new BitReader(data);
BitReader bitReader = new(data);
bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData;
@ -66,15 +65,14 @@ internal class RgbaTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor;
float a = bitReader.ReadBits(this.bitsPerSampleB) / this.aFactor;
var vec = new Vector4(r, g, b, a);
Vector4 vector = new(r, g, b, a);
if (hasAssociatedAlpha)
{
pixelRow[x] = TiffUtils.UnPremultiply(ref vec, color);
pixelRow[x] = TiffUtilities.UnPremultiply<TPixel>(ref vector);
}
else
{
color.FromScaledVector4(vec);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(vector);
}
}

14
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation for 16-bit grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZero16TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -25,10 +25,6 @@ internal class WhiteIsZero16TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
L16 l16 = TiffUtils.L16Default;
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
int offset = 0;
for (int y = top; y < top + height; y++)
{
@ -37,20 +33,20 @@ internal class WhiteIsZero16TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ushort intensity = (ushort)(ushort.MaxValue - TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)));
ushort intensity = (ushort)(ushort.MaxValue - TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color);
pixelRow[x] = TPixel.FromL16(new(intensity));
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ushort intensity = (ushort)(ushort.MaxValue - TiffUtils.ConvertToUShortLittleEndian(data.Slice(offset, 2)));
ushort intensity = (ushort)(ushort.MaxValue - TiffUtilities.ConvertToUShortLittleEndian(data.Slice(offset, 2)));
offset += 2;
pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color);
pixelRow[x] = TPixel.FromL16(new(intensity));
}
}
}

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

@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (optimized for bilevel images).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -18,11 +19,9 @@ internal class WhiteIsZero1TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
nuint offset = 0;
var colorBlack = default(TPixel);
var colorWhite = default(TPixel);
TPixel colorBlack = TPixel.FromRgba32(Color.Black.ToPixel<Rgba32>());
TPixel colorWhite = TPixel.FromRgba32(Color.White.ToPixel<Rgba32>());
colorBlack.FromRgba32(Color.Black.ToPixel<Rgba32>());
colorWhite.FromRgba32(Color.White.ToPixel<Rgba32>());
ref byte dataRef = ref MemoryMarshal.GetReference(data);
for (nuint y = (uint)top; y < (uint)(top + height); y++)
{

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation for 24-bit grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -25,8 +25,6 @@ internal class WhiteIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> buffer = stackalloc byte[4];
int bufferStartIdx = this.isBigEndian ? 1 : 0;
const uint maxValue = 0xFFFFFF;
@ -41,10 +39,10 @@ internal class WhiteIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong intensity = maxValue - TiffUtils.ConvertToUIntBigEndian(buffer);
uint intensity = maxValue - TiffUtilities.ConvertToUIntBigEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(intensity);
}
}
else
@ -52,10 +50,10 @@ internal class WhiteIsZero24TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
data.Slice(offset, 3).CopyTo(bufferSpan);
ulong intensity = maxValue - TiffUtils.ConvertToUIntLittleEndian(buffer);
uint intensity = maxValue - TiffUtilities.ConvertToUIntLittleEndian(buffer);
offset += 3;
pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo24Bit<TPixel>(intensity);
}
}
}

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

@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation for 32-bit float grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -24,8 +25,6 @@ internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
Span<byte> buffer = stackalloc byte[4];
int offset = 0;
@ -41,9 +40,7 @@ internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
float intensity = 1.0f - BitConverter.ToSingle(buffer);
offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new(intensity, intensity, intensity, 1f));
}
}
else
@ -53,9 +50,7 @@ internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel
float intensity = 1.0f - BitConverter.ToSingle(data.Slice(offset, 4));
offset += 4;
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f);
color.FromScaledVector4(colorVector);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f));
}
}
}

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

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation for 32-bit grayscale images.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZero32TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -25,8 +25,6 @@ internal class WhiteIsZero32TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
color.FromScaledVector4(Vector4.Zero);
const uint maxValue = 0xFFFFFFFF;
int offset = 0;
@ -37,20 +35,20 @@ internal class WhiteIsZero32TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong intensity = maxValue - TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4));
uint intensity = maxValue - TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(intensity);
}
}
else
{
for (int x = 0; x < pixelRow.Length; x++)
{
ulong intensity = maxValue - TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4));
uint intensity = maxValue - TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4));
offset += 4;
pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color);
pixelRow[x] = TiffUtilities.ColorScaleTo32Bit<TPixel>(intensity);
}
}
}

25
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs

@ -9,47 +9,30 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (optimized for 4-bit grayscale images).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZero4TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
int offset = 0;
bool isOddWidth = (width & 1) == 1;
var l8 = default(L8);
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRowSpan = pixels.DangerousGetRowSpan(y);
for (int x = left; x < left + width - 1;)
{
byte byteData = data[offset++];
byte intensity1 = (byte)((15 - ((byteData & 0xF0) >> 4)) * 17);
l8.PackedValue = intensity1;
color.FromL8(l8);
pixelRowSpan[x++] = color;
byte intensity2 = (byte)((15 - (byteData & 0x0F)) * 17);
l8.PackedValue = intensity2;
color.FromL8(l8);
pixelRowSpan[x++] = color;
pixelRowSpan[x++] = TPixel.FromL8(new((byte)((15 - ((byteData & 0xF0) >> 4)) * 17)));
pixelRowSpan[x++] = TPixel.FromL8(new((byte)((15 - (byteData & 0x0F)) * 17)));
}
if (isOddWidth)
{
byte byteData = data[offset++];
byte intensity1 = (byte)((15 - ((byteData & 0xF0) >> 4)) * 17);
l8.PackedValue = intensity1;
color.FromL8(l8);
pixelRowSpan[left + width - 1] = color;
pixelRowSpan[left + width - 1] = TPixel.FromL8(new((byte)((15 - ((byteData & 0xF0) >> 4)) * 17)));
}
}
}

8
src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Formats.Tiff.Utils;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -10,24 +9,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (optimized for 8-bit grayscale images).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZero8TiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
int offset = 0;
var l8 = default(L8);
for (int y = top; y < top + height; y++)
{
Span<TPixel> pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width);
for (int x = 0; x < pixelRow.Length; x++)
{
byte intensity = (byte)(byte.MaxValue - data[offset++]);
pixelRow[x] = TiffUtils.ColorFromL8(l8, intensity, color);
pixelRow[x] = TPixel.FromL8(new(intensity));
}
}
}

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

@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements the 'WhiteIsZero' photometric interpretation (for all bit depths).
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class WhiteIsZeroTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly ushort bitsPerSample0;
private readonly float factor;
public WhiteIsZeroTiffColor(TiffBitsPerSample bitsPerSample)
@ -27,9 +27,7 @@ internal class WhiteIsZeroTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
/// <inheritdoc/>
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height)
{
var color = default(TPixel);
var bitReader = new BitReader(data);
BitReader bitReader = new(data);
for (int y = top; y < top + height; y++)
{
@ -37,10 +35,8 @@ internal class WhiteIsZeroTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
int value = bitReader.ReadBits(this.bitsPerSample0);
float intensity = 1.0f - (value / this.factor);
color.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f));
pixelRow[x] = color;
float intensity = 1f - (value / this.factor);
pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f));
}
bitReader.NextRow();

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

@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements decoding pixel data with photometric interpretation of type 'YCbCr' with the planar configuration.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class YCbCrPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
private readonly YCbCrConverter converter;
private readonly ushort[] ycbcrSubSampling;
public YCbCrPlanarTiffColor(Rational[] referenceBlackAndWhite, Rational[] coefficients, ushort[] ycbcrSubSampling)
@ -36,13 +36,12 @@ internal class YCbCrPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], cbData, crData);
}
var color = default(TPixel);
int offset = 0;
int widthPadding = 0;
if (this.ycbcrSubSampling != null)
{
// Round to the next integer multiple of horizontalSubSampling.
widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]);
widthPadding = TiffUtilities.PaddingToNextInteger(width, this.ycbcrSubSampling[0]);
}
for (int y = top; y < top + height; y++)
@ -51,8 +50,7 @@ internal class YCbCrPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
Rgba32 rgba = this.converter.ConvertToRgba32(yData[offset], cbData[offset], crData[offset]);
color.FromRgba32(rgba);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromRgba32(rgba);
offset++;
}
@ -64,8 +62,8 @@ internal class YCbCrPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel>
{
// If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively,
// then the source data will be padded.
width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling);
height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling);
width += TiffUtilities.PaddingToNextInteger(width, horizontalSubSampling);
height += TiffUtilities.PaddingToNextInteger(height, verticalSubSampling);
for (int row = height - 1; row >= 0; row--)
{

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

@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation;
/// <summary>
/// Implements decoding pixel data with photometric interpretation of type 'YCbCr'.
/// </summary>
/// <typeparam name="TPixel">The type of pixel format.</typeparam>
internal class YCbCrTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
where TPixel : unmanaged, IPixel<TPixel>
{
@ -50,13 +51,12 @@ internal class YCbCrTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
private void DecodeYCbCrData(Buffer2D<TPixel> pixels, int left, int top, int width, int height, ReadOnlySpan<byte> ycbcrData)
{
var color = default(TPixel);
int offset = 0;
int widthPadding = 0;
if (this.ycbcrSubSampling != null)
{
// Round to the next integer multiple of horizontalSubSampling.
widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]);
widthPadding = TiffUtilities.PaddingToNextInteger(width, this.ycbcrSubSampling[0]);
}
for (int y = top; y < top + height; y++)
@ -65,8 +65,7 @@ internal class YCbCrTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
for (int x = 0; x < pixelRow.Length; x++)
{
Rgba32 rgba = this.converter.ConvertToRgba32(ycbcrData[offset], ycbcrData[offset + 1], ycbcrData[offset + 2]);
color.FromRgba32(rgba);
pixelRow[x] = color;
pixelRow[x] = TPixel.FromRgba32(rgba);
offset += 3;
}
@ -78,8 +77,8 @@ internal class YCbCrTiffColor<TPixel> : TiffBaseColorDecoder<TPixel>
{
// If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively,
// then the source data will be padded.
width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling);
height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling);
width += TiffUtilities.PaddingToNextInteger(width, horizontalSubSampling);
height += TiffUtilities.PaddingToNextInteger(height, verticalSubSampling);
int blockWidth = width / horizontalSubSampling;
int blockHeight = height / verticalSubSampling;
int cbCrOffsetInBlock = horizontalSubSampling * verticalSubSampling;

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

@ -163,8 +163,8 @@ internal class TiffDecoderCore : IImageDecoderInternals
public Image<TPixel> Decode<TPixel>(BufferedReadStream stream, CancellationToken cancellationToken)
where TPixel : unmanaged, IPixel<TPixel>
{
List<ImageFrame<TPixel>> frames = new();
List<ImageFrameMetadata> framesMetadata = new();
List<ImageFrame<TPixel>> frames = [];
List<ImageFrameMetadata> framesMetadata = [];
try
{
this.inputStream = stream;
@ -221,7 +221,7 @@ internal class TiffDecoderCore : IImageDecoderInternals
DirectoryReader reader = new(stream, this.configuration.MemoryAllocator);
IList<ExifProfile> directories = reader.Read();
List<ImageFrameMetadata> framesMetadata = new();
List<ImageFrameMetadata> framesMetadata = [];
foreach (ExifProfile dir in directories)
{
framesMetadata.Add(this.CreateFrameMetadata(dir));

120
src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs

@ -0,0 +1,120 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.Utils;
/// <summary>
/// Helper methods for TIFF decoding.
/// </summary>
internal static class TiffUtilities
{
private const float Scale24Bit = 1f / 0xFFFFFF;
private static readonly Vector4 Scale24BitVector = Vector128.Create(Scale24Bit, Scale24Bit, Scale24Bit, 1f).AsVector4();
private const float Scale32Bit = 1f / 0xFFFFFFFF;
private static readonly Vector4 Scale32BitVector = Vector128.Create(Scale32Bit, Scale32Bit, Scale32Bit, 1f).AsVector4();
public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0);
public static L16 L16Default { get; } = new(0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ConvertToUShortBigEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt16BigEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ConvertToUShortLittleEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ConvertToUIntBigEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt32BigEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ConvertToUIntLittleEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt32LittleEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromRgba64Premultiplied<TPixel>(ushort r, ushort g, ushort b, ushort a)
where TPixel : unmanaged, IPixel<TPixel>
{
if (a == 0)
{
return TPixel.FromRgba64(default);
}
return TPixel.FromRgba64(new((ushort)(r / a), (ushort)(g / a), (ushort)(b / a), a));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(uint r, uint g, uint b)
where TPixel : unmanaged, IPixel<TPixel>
=> TPixel.FromScaledVector4(new Vector4(r, g, b, 1f) * Scale24BitVector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(uint r, uint g, uint b, uint a)
where TPixel : unmanaged, IPixel<TPixel>
=> TPixel.FromScaledVector4(new Vector4(r, g, b, a) * Scale24Bit);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24BitPremultiplied<TPixel>(uint r, uint g, uint b, uint a)
where TPixel : unmanaged, IPixel<TPixel>
{
Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit;
return UnPremultiply<TPixel>(ref colorVector);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(uint r, uint g, uint b)
where TPixel : unmanaged, IPixel<TPixel>
=> TPixel.FromScaledVector4(new Vector4(r, g, b, 1f) * Scale32BitVector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(uint r, uint g, uint b, uint a)
where TPixel : unmanaged, IPixel<TPixel>
=> TPixel.FromScaledVector4(new Vector4(r, g, b, a) * Scale32Bit);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32BitPremultiplied<TPixel>(uint r, uint g, uint b, uint a)
where TPixel : unmanaged, IPixel<TPixel>
{
Vector4 vector = new Vector4(r, g, b, a) * Scale32Bit;
return UnPremultiply<TPixel>(ref vector);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(uint intensity)
where TPixel : unmanaged, IPixel<TPixel>
=> TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f) * Scale24BitVector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(uint intensity)
where TPixel : unmanaged, IPixel<TPixel>
=> TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f) * Scale32BitVector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel UnPremultiply<TPixel>(ref Vector4 vector)
where TPixel : unmanaged, IPixel<TPixel>
{
Numerics.UnPremultiply(ref vector);
return TPixel.FromScaledVector4(vector);
}
/// <summary>
/// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value.
/// </summary>
/// <param name="valueToRoundUp">The width or height to round up.</param>
/// <param name="subSampling">The sub sampling.</param>
/// <returns>The padding.</returns>
public static int PaddingToNextInteger(int valueToRoundUp, int subSampling)
{
if (valueToRoundUp % subSampling == 0)
{
return 0;
}
return subSampling - (valueToRoundUp % subSampling);
}
}

176
src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs

@ -1,176 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
using System.Numerics;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Formats.Tiff.Utils;
/// <summary>
/// Helper methods for TIFF decoding.
/// </summary>
internal static class TiffUtils
{
private const float Scale24Bit = 1.0f / 0xFFFFFF;
private const float Scale32Bit = 1.0f / 0xFFFFFFFF;
public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0);
public static L16 L16Default { get; } = new(0);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ConvertToUShortBigEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt16BigEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static ushort ConvertToUShortLittleEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ConvertToUIntBigEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt32BigEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static uint ConvertToUIntLittleEndian(ReadOnlySpan<byte> buffer) => BinaryPrimitives.ReadUInt32LittleEndian(buffer);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromL8<TPixel>(L8 l8, byte intensity, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
l8.PackedValue = intensity;
color.FromL8(l8);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromRgb64<TPixel>(Rgba64 rgba, ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
rgba.PackedValue = r | (g << 16) | (b << 32) | (0xfffful << 48);
color.FromRgba64(rgba);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromRgba64<TPixel>(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48);
color.FromRgba64(rgba);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromRgba64Premultiplied<TPixel>(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48);
var vec = rgba.ToVector4();
return UnPremultiply(ref vec, color);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
var colorVector = new Vector4(r * Scale24Bit, g * Scale24Bit, b * Scale24Bit, 1.0f);
color.FromScaledVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit;
color.FromScaledVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24BitPremultiplied<TPixel>(ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit;
return UnPremultiply(ref colorVector, color);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(ulong r, ulong g, ulong b, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
var colorVector = new Vector4(r * Scale32Bit, g * Scale32Bit, b * Scale32Bit, 1.0f);
color.FromScaledVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Vector4 colorVector = new Vector4(r, g, b, a) * Scale32Bit;
color.FromScaledVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32BitPremultiplied<TPixel>(ulong r, ulong g, ulong b, ulong a, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Vector4 colorVector = new Vector4(r, g, b, a) * Scale32Bit;
return UnPremultiply(ref colorVector, color);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorFromL16<TPixel>(L16 l16, ushort intensity, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
l16.PackedValue = intensity;
color.FromL16(l16);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo24Bit<TPixel>(ulong intensity, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
var colorVector = new Vector4(intensity * Scale24Bit, intensity * Scale24Bit, intensity * Scale24Bit, 1.0f);
color.FromScaledVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel ColorScaleTo32Bit<TPixel>(ulong intensity, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
var colorVector = new Vector4(intensity * Scale32Bit, intensity * Scale32Bit, intensity * Scale32Bit, 1.0f);
color.FromScaledVector4(colorVector);
return color;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel UnPremultiply<TPixel>(ref Vector4 vector, TPixel color)
where TPixel : unmanaged, IPixel<TPixel>
{
Numerics.UnPremultiply(ref vector);
color.FromScaledVector4(vector);
return color;
}
/// <summary>
/// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value.
/// </summary>
/// <param name="valueToRoundUp">The width or height to round up.</param>
/// <param name="subSampling">The sub sampling.</param>
/// <returns>The padding.</returns>
public static int PaddingToNextInteger(int valueToRoundUp, int subSampling)
{
if (valueToRoundUp % subSampling == 0)
{
return 0;
}
return subSampling - (valueToRoundUp % subSampling);
}
}

1
src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Webp.Chunks;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.Metadata.Profiles.Icc;

1
src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs

@ -2,7 +2,6 @@
// Licensed under the Six Labors Split License.
using System.Buffers.Binary;
using SixLabors.ImageSharp.Common.Helpers;
namespace SixLabors.ImageSharp.Formats.Webp.Chunks;

2
src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Common.Helpers;
namespace SixLabors.ImageSharp.Formats.Webp.Chunks;
internal readonly struct WebpFrameData

2
src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs

@ -1,8 +1,6 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.Common.Helpers;
namespace SixLabors.ImageSharp.Formats.Webp.Chunks;
internal readonly struct WebpVp8X

1
src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs

@ -6,7 +6,6 @@ using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Webp.BitWriter;
using SixLabors.ImageSharp.Formats.Webp.Chunks;
using SixLabors.ImageSharp.Memory;

1
src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs

@ -4,7 +4,6 @@
using System.Buffers;
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.Common.Helpers;
using SixLabors.ImageSharp.Formats.Webp.BitWriter;
using SixLabors.ImageSharp.Formats.Webp.Chunks;
using SixLabors.ImageSharp.Memory;

4
src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs

@ -140,7 +140,6 @@ internal sealed class WebpLossyDecoder
private static void DecodePixelValues<TPixel>(int width, int height, Span<byte> pixelData, Buffer2D<TPixel> decodedPixels, IMemoryOwner<byte> alpha)
where TPixel : unmanaged, IPixel<TPixel>
{
TPixel color = default;
Span<byte> alphaSpan = alpha.Memory.Span;
Span<Bgr24> pixelsBgr = MemoryMarshal.Cast<byte, Bgr24>(pixelData);
for (int y = 0; y < height; y++)
@ -151,8 +150,7 @@ internal sealed class WebpLossyDecoder
{
int offset = yMulWidth + x;
Bgr24 bgr = pixelsBgr[offset];
color.FromBgra32(new Bgra32(bgr.R, bgr.G, bgr.B, alphaSpan[offset]));
decodedPixelRow[x] = color;
decodedPixelRow[x] = TPixel.FromBgra32(new(bgr.R, bgr.G, bgr.B, alphaSpan[offset]));
}
}
}

2
src/ImageSharp/Common/Helpers/RiffHelper.cs → src/ImageSharp/Formats/Webp/RiffHelper.cs

@ -4,7 +4,7 @@
using System.Buffers.Binary;
using System.Text;
namespace SixLabors.ImageSharp.Common.Helpers;
namespace SixLabors.ImageSharp.Formats.Webp;
internal static class RiffHelper
{

2
src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.PixelFormats;

127
src/ImageSharp/PixelFormats/IPixel.cs

@ -14,135 +14,150 @@ namespace SixLabors.ImageSharp.PixelFormats;
public interface IPixel<TSelf> : IPixel, IEquatable<TSelf>
where TSelf : unmanaged, IPixel<TSelf>
{
/// <summary>
/// Gets the pixel type information.
/// </summary>
/// <returns>The <see cref="PixelTypeInfo"/>.</returns>
#pragma warning disable CA1000
static abstract PixelTypeInfo GetPixelTypeInfo();
#pragma warning restore CA1000
#pragma warning disable CA1000 // Do not declare static members on generic types
/// <summary>
/// Creates a <see cref="PixelOperations{TPixel}"/> instance for this pixel type.
/// This method is not intended to be consumed directly. Use <see cref="PixelOperations{TPixel}.Instance"/> instead.
/// </summary>
/// <returns>The <see cref="PixelOperations{TPixel}"/> instance.</returns>
PixelOperations<TSelf> CreatePixelOperations();
}
static abstract PixelOperations<TSelf> CreatePixelOperations();
/// <summary>
/// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type.
/// </summary>
public interface IPixel
{
/// <summary>
/// Initializes the pixel instance from a generic ("scaled") <see cref="Vector4"/>.
/// Initializes the pixel instance from a generic scaled <see cref="Vector4"/>.
/// </summary>
/// <param name="vector">The vector to load the pixel from.</param>
void FromScaledVector4(Vector4 vector);
/// <summary>
/// Expands the pixel into a generic ("scaled") <see cref="Vector4"/> representation
/// with values scaled and clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToScaledVector4();
/// <param name="source">The vector to load the pixel from.</param>
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromScaledVector4(Vector4 source);
/// <summary>
/// Initializes the pixel instance from a <see cref="Vector4"/> which is specific to the current pixel type.
/// </summary>
/// <param name="vector">The vector to load the pixel from.</param>
void FromVector4(Vector4 vector);
/// <param name="source">The vector to load the pixel from.</param>
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromVector4(Vector4 source);
/// <summary>
/// Expands the pixel into a <see cref="Vector4"/> which is specific to the current pixel type.
/// The vector components are typically expanded in least to greatest significance order.
/// Initializes the pixel instance from an <see cref="Abgr32"/> value.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToVector4();
/// <param name="source">The <see cref="Abgr32"/> value.</param>
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromAbgr32(Abgr32 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Argb32"/> value.
/// </summary>
/// <param name="source">The <see cref="Argb32"/> value.</param>
void FromArgb32(Argb32 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromArgb32(Argb32 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Bgra5551"/> value.
/// </summary>
/// <param name="source">The <see cref="Bgra5551"/> value.</param>
void FromBgra5551(Bgra5551 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromBgra5551(Bgra5551 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Bgr24"/> value.
/// </summary>
/// <param name="source">The <see cref="Bgr24"/> value.</param>
void FromBgr24(Bgr24 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromBgr24(Bgr24 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Bgra32"/> value.
/// </summary>
/// <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);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromBgra32(Bgra32 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="L8"/> value.
/// </summary>
/// <param name="source">The <see cref="L8"/> value.</param>
void FromL8(L8 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromL8(L8 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="L16"/> value.
/// </summary>
/// <param name="source">The <see cref="L16"/> value.</param>
void FromL16(L16 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromL16(L16 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="La16"/> value.
/// </summary>
/// <param name="source">The <see cref="La16"/> value.</param>
void FromLa16(La16 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromLa16(La16 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="La32"/> value.
/// </summary>
/// <param name="source">The <see cref="La32"/> value.</param>
void FromLa32(La32 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromLa32(La32 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Rgb24"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgb24"/> value.</param>
void FromRgb24(Rgb24 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromRgb24(Rgb24 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Rgba32"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgba32"/> value.</param>
void FromRgba32(Rgba32 source);
/// <summary>
/// Convert the pixel instance into <see cref="Rgba32"/> representation.
/// </summary>
/// <param name="dest">The reference to the destination <see cref="Rgba32"/> pixel</param>
void ToRgba32(ref Rgba32 dest);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromRgba32(Rgba32 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Rgb48"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgb48"/> value.</param>
void FromRgb48(Rgb48 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromRgb48(Rgb48 source);
/// <summary>
/// Initializes the pixel instance from an <see cref="Rgba64"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgba64"/> value.</param>
void FromRgba64(Rgba64 source);
/// <returns>The <typeparamref name="TSelf"/>.</returns>
static abstract TSelf FromRgba64(Rgba64 source);
#pragma warning restore CA1000 // Do not declare static members on generic types
}
/// <summary>
/// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type.
/// </summary>
public interface IPixel
{
/// <summary>
/// Gets the pixel type information.
/// </summary>
/// <returns>The <see cref="PixelTypeInfo"/>.</returns>
static abstract PixelTypeInfo GetPixelTypeInfo();
/// <summary>
/// Convert the pixel instance into <see cref="Rgba32"/> representation.
/// </summary>
/// <returns>The <see cref="Rgba32"/></returns>
Rgba32 ToRgba32();
/// <summary>
/// Expands the pixel into a generic ("scaled") <see cref="Vector4"/> representation
/// with values scaled and clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToScaledVector4();
/// <summary>
/// Expands the pixel into a <see cref="Vector4"/> which is specific to the current pixel type.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToVector4();
}

432
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs

File diff suppressed because it is too large

4
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt

@ -81,9 +81,7 @@ var blenders = new []{
/// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount)
{
TPixel dest = default;
dest.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1)));
return dest;
return TPixel.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1)));
}
/// <inheritdoc />

432
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs

File diff suppressed because it is too large

4
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt

@ -368,9 +368,7 @@ internal static partial class PorterDuffFunctions
where TPixel : unmanaged, IPixel<TPixel>
{
opacity = Numerics.Clamp(opacity, 0, 1);
TPixel dest = default;
dest.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity));
return dest;
return TPixel.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity));
}
<# } #>
<#

8
src/ImageSharp/PixelFormats/PixelConversionModifiers.cs

@ -1,4 +1,4 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.ColorSpaces.Companding;
@ -7,9 +7,9 @@ namespace SixLabors.ImageSharp.PixelFormats;
/// <summary>
/// Flags responsible to select additional operations which could be efficiently applied in
/// <see cref="PixelOperations{TPixel}.ToVector4(SixLabors.ImageSharp.Configuration,System.ReadOnlySpan{TPixel},System.Span{System.Numerics.Vector4},SixLabors.ImageSharp.PixelFormats.PixelConversionModifiers)"/>
/// <see cref="PixelOperations{TPixel}.ToVector4(Configuration,ReadOnlySpan{TPixel},Span{System.Numerics.Vector4},PixelConversionModifiers)"/>
/// or
/// <see cref="PixelOperations{TPixel}.FromVector4Destructive(SixLabors.ImageSharp.Configuration,System.Span{System.Numerics.Vector4},System.Span{TPixel},SixLabors.ImageSharp.PixelFormats.PixelConversionModifiers)"/>
/// <see cref="PixelOperations{TPixel}.FromVector4Destructive(Configuration,Span{System.Numerics.Vector4},Span{TPixel},PixelConversionModifiers)"/>
/// knowing the pixel type.
/// </summary>
[Flags]
@ -21,7 +21,7 @@ public enum PixelConversionModifiers
None = 0,
/// <summary>
/// Select <see cref="IPixel.ToScaledVector4"/> and <see cref="IPixel.FromScaledVector4"/> instead the standard (non scaled) variants.
/// Select <see cref="IPixel.ToScaledVector4"/> and <see cref="IPixel{T}.FromScaledVector4"/> instead the standard (non scaled) variants.
/// </summary>
Scale = 1 << 0,

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

@ -41,7 +41,7 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(A8 left, A8 right) => left.Equals(right);
/// <summary>
@ -52,9 +52,21 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(A8 left, A8 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => new() { A = this.PackedValue };
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new(0, 0, 0, this.PackedValue / 255f);
/// <inheritdoc/>
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<A8>(
@ -63,83 +75,67 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public readonly PixelOperations<A8> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector);
public static PixelOperations<A8> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new(0, 0, 0, this.PackedValue / 255F);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromVector4(Vector4 source) => new(Pack(source.W));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.PackedValue = source.A;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromAbgr32(Abgr32 source) => new(source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromArgb32(Argb32 source) => new(source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.PackedValue = source.A;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.PackedValue = source.A;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromBgr24(Bgr24 source) => new(byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromBgra32(Bgra32 source) => new(source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.PackedValue = byte.MaxValue;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromL8(L8 source) => new(byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.PackedValue = byte.MaxValue;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromL16(L16 source) => new(byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.PackedValue = source.A;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromLa16(La16 source) => new(source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.A));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue;
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.PackedValue = source.A;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromRgb24(Rgb24 source) => new(byte.MaxValue);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)
{
dest = default;
dest.A = this.PackedValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromRgba32(Rgba32 source) => new(source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromRgb48(Rgb48 source) => new(byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static A8 FromRgba64(Rgba64 source) => new(ColorNumerics.From16BitTo8Bit(source.A));
/// <summary>
/// Compares an object with the packed vector.
@ -153,7 +149,6 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
/// </summary>
/// <param name="other">The A8 packed vector to compare.</param>
/// <returns>True if the packed vectors are equal.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(A8 other) => this.PackedValue.Equals(other.PackedValue);
/// <summary>
@ -163,7 +158,6 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
public override readonly string ToString() => $"A8({this.PackedValue})";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
@ -171,6 +165,6 @@ public partial struct A8 : IPixel<A8>, IPackedVector<byte>
/// </summary>
/// <param name="alpha">The float containing the value to pack.</param>
/// <returns>The <see cref="byte"/> containing the packed values.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static byte Pack(float alpha) => (byte)Math.Round(Numerics.Clamp(alpha, 0, 1F) * 255F);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte Pack(float alpha) => (byte)Math.Round(Numerics.Clamp(alpha, 0, 1f) * 255f);
}

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

@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp.PixelFormats;
@ -44,12 +45,12 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new(255);
private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4();
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new(0.5F);
private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4();
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
@ -57,7 +58,7 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Abgr32(byte r, byte g, byte b)
{
this.R = r;
@ -73,7 +74,7 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Abgr32(byte r, byte g, byte b, byte a)
{
this.R = r;
@ -89,9 +90,11 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Abgr32(float r, float g, float b, float a = 1)
: this() => this.Pack(r, g, b, a);
: this(new Vector4(r, g, b, a))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
@ -99,9 +102,11 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Abgr32(Vector3 vector)
: this() => this.Pack(ref vector);
: this(new Vector4(vector, 1f))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
@ -109,9 +114,9 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Abgr32(Vector4 vector)
: this() => this.Pack(ref vector);
: this() => this = Pack(vector);
/// <summary>
/// Initializes a new instance of the <see cref="Abgr32"/> struct.
@ -119,29 +124,29 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <param name="packed">
/// The packed value.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Abgr32(uint packed)
: this() => this.Abgr = packed;
/// <summary>
/// Gets or sets the packed representation of the Abgrb32 struct.
/// Gets or sets the packed representation of the Abgr struct.
/// </summary>
public uint Abgr
{
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => Unsafe.As<Abgr32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => Unsafe.As<Abgr32, uint>(ref this) = value;
}
/// <inheritdoc/>
public uint PackedValue
{
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => this.Abgr;
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => this.Abgr = value;
}
@ -153,7 +158,7 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Abgr32 left, Abgr32 right) => left.Equals(right);
/// <summary>
@ -164,9 +169,21 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromAbgr32(this);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Abgr32>(
@ -175,160 +192,94 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public readonly PixelOperations<Abgr32> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<Abgr32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromVector4(Vector4 source) => Pack(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.Pack(ref vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromAbgr32(Abgr32 source) => new() { PackedValue = source.PackedValue };
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this = source;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B);
/// <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, 1);
Unsafe.As<byte, Bgr24>(ref thisRefFromB) = source;
this.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A);
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromL16(L16 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue);
return new(rgb, rgb, rgb);
}
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromLa32(La32 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = byte.MaxValue;
byte rgb = ColorNumerics.From16BitTo8Bit(source.L);
return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A));
}
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B);
/// <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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, 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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromRgb48(Rgb48 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B),
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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Abgr32 FromRgba64(Rgba64 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B),
A = ColorNumerics.From16BitTo8Bit(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>
@ -338,7 +289,6 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
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>
@ -348,38 +298,28 @@ public partial struct Abgr32 : IPixel<Abgr32>, IPackedVector<uint>
/// <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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Abgr32 Pack(float x, float y, float z, float w) => Pack(new Vector4(x, y, z, w));
/// <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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Abgr32 Pack(Vector3 vector) => Pack(new Vector4(vector, 1));
/// <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)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Abgr32 Pack(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;
Vector128<byte> result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte();
return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12));
}
}

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

@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp.PixelFormats;
@ -41,15 +42,8 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// </summary>
public byte B;
/// <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);
private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4();
private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4();
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -57,7 +51,7 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(byte r, byte g, byte b)
{
this.R = r;
@ -73,7 +67,7 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(byte r, byte g, byte b, byte a)
{
this.R = r;
@ -89,9 +83,11 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(float r, float g, float b, float a = 1)
: this() => this.Pack(r, g, b, a);
: this(new Vector4(r, g, b, a))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -99,9 +95,11 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(Vector3 vector)
: this() => this.Pack(ref vector);
: this(new Vector4(vector, 1f))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -109,9 +107,9 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(Vector4 vector)
: this() => this.Pack(ref vector);
: this() => this = Pack(vector);
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -119,7 +117,7 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <param name="packed">
/// The packed value.
/// </param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32(uint packed)
: this() => this.Argb = packed;
@ -128,20 +126,20 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// </summary>
public uint Argb
{
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => Unsafe.As<Argb32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => Unsafe.As<Argb32, uint>(ref this) = value;
}
/// <inheritdoc/>
public uint PackedValue
{
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => this.Argb;
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => this.Argb = value;
}
@ -153,7 +151,7 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right);
/// <summary>
@ -164,9 +162,21 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromArgb32(this);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Argb32>(
@ -175,159 +185,94 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public readonly PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromVector4(Vector4 source) => Pack(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.Pack(ref vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromArgb32(Argb32 source) => new() { PackedValue = source.PackedValue };
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.PackedValue = source.PackedValue;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, 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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromL16(L16 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue);
return new(rgb, rgb, rgb);
}
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromLa32(La32 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = byte.MaxValue;
byte rgb = ColorNumerics.From16BitTo8Bit(source.L);
return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A));
}
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B);
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.A);
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromRgb48(Rgb48 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B),
A = byte.MaxValue
};
/// <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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Argb32 FromRgba64(Rgba64 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B),
A = ColorNumerics.From16BitTo8Bit(source.A)
};
/// <inheritdoc/>
public override readonly bool Equals(object? obj) => obj is Argb32 argb32 && this.Equals(argb32);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(Argb32 other) => this.Argb == other.Argb;
/// <summary>
@ -337,48 +282,20 @@ public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
public override readonly string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})";
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.Argb.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)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Argb32 Pack(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;
Vector128<byte> result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte();
return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12));
}
}

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

@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp.PixelFormats;
@ -35,13 +36,16 @@ public partial struct Bgr24 : IPixel<Bgr24>
[FieldOffset(2)]
public byte R;
private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4();
private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4();
/// <summary>
/// Initializes a new instance of the <see cref="Bgr24"/> 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)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgr24(byte r, byte g, byte b)
{
this.R = r;
@ -57,7 +61,7 @@ public partial struct Bgr24 : IPixel<Bgr24>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right);
/// <summary>
@ -68,9 +72,21 @@ public partial struct Bgr24 : IPixel<Bgr24>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromBgr24(this);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, byte.MaxValue) / MaxBytes;
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Bgr24>(
@ -79,146 +95,97 @@ public partial struct Bgr24 : IPixel<Bgr24>
PixelAlphaRepresentation.None);
/// <inheritdoc/>
public readonly PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector);
public static PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromVector4(Vector4 source)
{
Rgba32 rgba = default;
rgba.FromVector4(vector);
this.FromRgba32(rgba);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4();
source *= MaxBytes;
source += Half;
source = Numerics.Clamp(source, Vector4.Zero, MaxBytes);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
Vector128<byte> result = Vector128.ConvertToInt32(source.AsVector128()).AsByte();
return new(result.GetElement(0), result.GetElement(4), result.GetElement(8));
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source)
{
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source)
{
this.R = source.L;
this.G = source.L;
this.B = source.L;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromL16(L16 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L);
this.R = rgb;
this.G = rgb;
this.B = rgb;
byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue);
return new(rgb, rgb, rgb);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromLa16(La16 source) => new(source.L, source.L, source.L);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromLa32(La32 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, 1);
this = Unsafe.As<byte, Bgr24>(ref sourceRefFromB);
byte rgb = ColorNumerics.From16BitTo8Bit(source.L);
return new(rgb, rgb, rgb);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this = source.Bgr;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B);
/// <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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromRgb48(Rgb48 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B)
};
/// <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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr24 FromRgba64(Rgba64 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B)
};
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
/// <inheritdoc/>
@ -228,6 +195,5 @@ public partial struct Bgr24 : IPixel<Bgr24>
public override readonly string ToString() => $"Bgr24({this.B}, {this.G}, {this.R})";
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => HashCode.Combine(this.R, this.B, this.G);
}

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

@ -13,7 +13,13 @@ namespace SixLabors.ImageSharp.PixelFormats;
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public partial struct Bgr565 : IPixel<Bgr565>, IPackedVector<ushort>
/// <remarks>
/// Initializes a new instance of the <see cref="Bgr565"/> struct.
/// </remarks>
/// <param name="vector">
/// The vector containing the components for the packed value.
/// </param>
public partial struct Bgr565(Vector3 vector) : IPixel<Bgr565>, IPackedVector<ushort>
{
/// <summary>
/// Initializes a new instance of the <see cref="Bgr565"/> struct.
@ -26,16 +32,8 @@ public partial struct Bgr565 : IPixel<Bgr565>, IPackedVector<ushort>
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Bgr565"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed value.
/// </param>
public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
public ushort PackedValue { get; set; } = Pack(vector);
/// <summary>
/// Compares two <see cref="Bgr565"/> objects for equality.
@ -45,7 +43,7 @@ public partial struct Bgr565 : IPixel<Bgr565>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right);
/// <summary>
@ -56,9 +54,17 @@ public partial struct Bgr565 : IPixel<Bgr565>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new(this.ToVector3(), 1F);
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Bgr565>(
@ -67,90 +73,77 @@ public partial struct Bgr565 : IPixel<Bgr565>, IPackedVector<ushort>
PixelAlphaRepresentation.None);
/// <inheritdoc />
public readonly PixelOperations<Bgr565> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<Bgr565> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector);
/// <inheritdoc />
public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector)
{
var vector3 = new Vector3(vector.X, vector.Y, vector.Z);
this.PackedValue = Pack(ref vector3);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector3(source.X, source.Y, source.Z)) };
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new(this.ToVector3(), 1F);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.FromVector4(source.ToVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromVector4(source.ToVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromVector4(source.ToVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromVector4(source.ToVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgr565 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4());
/// <summary>
/// Expands the packed representation into a <see cref="Vector3"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector3 ToVector3() => new(
((this.PackedValue >> 11) & 0x1F) * (1F / 31F),
((this.PackedValue >> 5) & 0x3F) * (1F / 63F),
@ -160,22 +153,20 @@ public partial struct Bgr565 : IPixel<Bgr565>, IPackedVector<ushort>
public override readonly bool Equals(object? obj) => obj is Bgr565 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString()
{
var vector = this.ToVector3();
Vector3 vector = this.ToVector3();
return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})");
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector3 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(Vector3 vector)
{
vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One);

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

@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp.PixelFormats;
@ -38,15 +39,8 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
/// </summary>
public byte A;
/// <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);
private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4();
private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4();
/// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct.
@ -54,7 +48,7 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32(byte r, byte g, byte b)
{
this.R = r;
@ -70,7 +64,7 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32(byte r, byte g, byte b, byte a)
{
this.R = r;
@ -84,10 +78,10 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
/// </summary>
public uint Bgra
{
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => Unsafe.As<Bgra32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => Unsafe.As<Bgra32, uint>(ref this) = value;
}
@ -106,7 +100,7 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right);
/// <summary>
@ -117,9 +111,21 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromBgra32(this);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Bgra32>(
@ -128,153 +134,89 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc/>
public readonly PixelOperations<Bgra32> 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();
public static PixelOperations<Bgra32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.Pack(vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromVector4(Vector4 source) => Pack(source);
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, 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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromBgra32(Bgra32 source) => new() { PackedValue = source.PackedValue };
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromL16(L16 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = byte.MaxValue;
byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue);
return new(rgb, rgb, rgb);
}
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromLa32(La32 source)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A);
byte rgb = ColorNumerics.From16BitTo8Bit(source.L);
return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A));
}
/// <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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B);
/// <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 ToRgba32(ref Rgba32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.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;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromRgb48(Rgb48 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B),
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);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra32 FromRgba64(Rgba64 source)
=> new()
{
R = ColorNumerics.From16BitTo8Bit(source.R),
G = ColorNumerics.From16BitTo8Bit(source.G),
B = ColorNumerics.From16BitTo8Bit(source.B),
A = ColorNumerics.From16BitTo8Bit(source.A)
};
/// <inheritdoc/>
public override readonly bool Equals(object? obj) => obj is Bgra32 other && this.Equals(other);
@ -292,16 +234,14 @@ public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
/// 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(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Bgra32 Pack(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;
Vector128<byte> result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte();
return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12));
}
}

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

@ -30,7 +30,7 @@ public partial struct Bgra4444 : IPixel<Bgra4444>, IPackedVector<ushort>
/// Initializes a new instance of the <see cref="Bgra4444"/> struct.
/// </summary>
/// <param name="vector">The vector containing the components for the packed vector.</param>
public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector);
public Bgra4444(Vector4 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
@ -43,7 +43,7 @@ public partial struct Bgra4444 : IPixel<Bgra4444>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right);
/// <summary>
@ -54,120 +54,118 @@ public partial struct Bgra4444 : IPixel<Bgra4444>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right);
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Bgra4444>(
PixelComponentInfo.Create<Bgra4444>(4, 4, 4, 4, 4),
PixelColorType.BGR | PixelColorType.Alpha,
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public readonly PixelOperations<Bgra4444> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4()
{
const float Max = 1 / 15F;
const float max = 1 / 15f;
return new Vector4(
(this.PackedValue >> 8) & 0x0F,
(this.PackedValue >> 4) & 0x0F,
this.PackedValue & 0x0F,
(this.PackedValue >> 12) & 0x0F) * Max;
(this.PackedValue >> 12) & 0x0F) * max;
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4());
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Bgra4444>(
PixelComponentInfo.Create<Bgra4444>(4, 4, 4, 4, 4),
PixelColorType.BGR | PixelColorType.Alpha,
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public static PixelOperations<Bgra4444> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) };
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra4444 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is Bgra4444 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString()
{
var vector = this.ToVector4();
Vector4 vector = this.ToVector4();
return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})");
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(Vector4 vector)
{
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One);
return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12)

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

@ -33,7 +33,7 @@ public partial struct Bgra5551 : IPixel<Bgra5551>, IPackedVector<ushort>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector);
public Bgra5551(Vector4 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
@ -46,7 +46,7 @@ public partial struct Bgra5551 : IPixel<Bgra5551>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right);
/// <summary>
@ -57,9 +57,25 @@ public partial struct Bgra5551 : IPixel<Bgra5551>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new(
((this.PackedValue >> 10) & 0x1F) / 31F,
((this.PackedValue >> 5) & 0x1F) / 31F,
((this.PackedValue >> 0) & 0x1F) / 31F,
(this.PackedValue >> 15) & 0x01);
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Bgra5551>(
@ -68,104 +84,86 @@ public partial struct Bgra5551 : IPixel<Bgra5551>, IPackedVector<ushort>
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public readonly PixelOperations<Bgra5551> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<Bgra5551> 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();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) };
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new(
((this.PackedValue >> 10) & 0x1F) / 31F,
((this.PackedValue >> 5) & 0x1F) / 31F,
((this.PackedValue >> 0) & 0x1F) / 31F,
(this.PackedValue >> 15) & 0x01);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Bgra5551 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object? obj) => obj is Bgra5551 other && this.Equals(other);
public override readonly bool Equals(object? obj) => obj is Bgra5551 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString()
{
var vector = this.ToVector4();
Vector4 vector = this.ToVector4();
return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})");
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(Vector4 vector)
{
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One);
return (ushort)(

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

@ -3,6 +3,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp.PixelFormats;
@ -14,13 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats;
/// </summary>
public partial struct Byte4 : IPixel<Byte4>, IPackedVector<uint>
{
/// <summary>
/// Initializes a new instance of the <see cref="Byte4"/> struct.
/// </summary>
/// <param name="vector">
/// A vector containing the initial values for the components of the Byte4 structure.
/// </param>
public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector);
private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4();
/// <summary>
/// Initializes a new instance of the <see cref="Byte4"/> struct.
@ -30,11 +25,18 @@ public partial struct Byte4 : IPixel<Byte4>, IPackedVector<uint>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
public Byte4(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{
var vector = new Vector4(x, y, z, w);
this.PackedValue = Pack(ref vector);
}
/// <summary>
/// Initializes a new instance of the <see cref="Byte4"/> struct.
/// </summary>
/// <param name="vector">
/// A vector containing the initial values for the components of the Byte4 structure.
/// </param>
public Byte4(Vector4 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public uint PackedValue { get; set; }
@ -46,7 +48,7 @@ public partial struct Byte4 : IPixel<Byte4>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right);
/// <summary>
@ -57,9 +59,25 @@ public partial struct Byte4 : IPixel<Byte4>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32() => new() { PackedValue = this.PackedValue };
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4() / 255f;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new(
this.PackedValue & 0xFF,
(this.PackedValue >> 8) & 0xFF,
(this.PackedValue >> 16) & 0xFF,
(this.PackedValue >> 24) & 0xFF);
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<Byte4>(
@ -68,99 +86,81 @@ public partial struct Byte4 : IPixel<Byte4>, IPackedVector<uint>
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public readonly PixelOperations<Byte4> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<Byte4> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector * 255F);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4() / 255F;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromScaledVector4(Vector4 source) => FromVector4(source * 255f);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) };
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new(
this.PackedValue & 0xFF,
(this.PackedValue >> 0x8) & 0xFF,
(this.PackedValue >> 0x10) & 0xFF,
(this.PackedValue >> 0x18) & 0xFF);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromRgba32(Rgba32 source) => new() { PackedValue = source.PackedValue };
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Byte4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is Byte4 byte4 && this.Equals(byte4);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc />
public override readonly string ToString()
{
var vector = this.ToVector4();
Vector4 vector = this.ToVector4();
return FormattableString.Invariant($"Byte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
@ -169,13 +169,10 @@ public partial struct Byte4 : IPixel<Byte4>, IPackedVector<uint>
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(ref Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(Vector4 vector)
{
const float Max = 255F;
// Clamp the value between min and max values
vector = Numerics.Clamp(vector, Vector4.Zero, new Vector4(Max));
vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes);
uint byte4 = (uint)Math.Round(vector.X) & 0xFF;
uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8;

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

@ -31,7 +31,7 @@ public partial struct HalfSingle : IPixel<HalfSingle>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right);
/// <summary>
@ -42,9 +42,26 @@ public partial struct HalfSingle : IPixel<HalfSingle>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4()
{
float single = this.ToSingle() + 1F;
single /= 2F;
return new Vector4(single, 0, 0, 1F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new(this.ToSingle(), 0, 0, 1F);
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<HalfSingle>(
@ -53,109 +70,90 @@ public partial struct HalfSingle : IPixel<HalfSingle>, IPackedVector<ushort>
PixelAlphaRepresentation.None);
/// <inheritdoc />
public PixelOperations<HalfSingle> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<HalfSingle> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromScaledVector4(Vector4 source)
{
float scaled = vector.X;
float scaled = source.X;
scaled *= 2F;
scaled--;
this.PackedValue = HalfTypeHelper.Pack(scaled);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4()
{
float single = this.ToSingle() + 1F;
single /= 2F;
return new Vector4(single, 0, 0, 1F);
return new() { PackedValue = HalfTypeHelper.Pack(scaled) };
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromVector4(Vector4 source) => new() { PackedValue = HalfTypeHelper.Pack(source.X) };
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4() => new(this.ToSingle(), 0, 0, 1F);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfSingle FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4());
/// <summary>
/// Expands the packed representation into a <see cref="float"/>.
/// </summary>
/// <returns>The <see cref="float"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue);
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is HalfSingle other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})");
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
}

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

@ -38,7 +38,7 @@ public partial struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right);
/// <summary>
@ -49,9 +49,31 @@ public partial struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4()
{
Vector2 scaled = this.ToVector2();
scaled += Vector2.One;
scaled /= 2F;
return new(scaled, 0F, 1F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4()
{
Vector2 vector = this.ToVector2();
return new(vector.X, vector.Y, 0F, 1F);
}
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<HalfVector2>(
@ -60,100 +82,78 @@ public partial struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint>
PixelAlphaRepresentation.None);
/// <inheritdoc />
public readonly PixelOperations<HalfVector2> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<HalfVector2> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromScaledVector4(Vector4 source)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
Vector2 scaled = new Vector2(source.X, source.Y) * 2F;
scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
scaled += Vector2.One;
scaled /= 2F;
return new Vector4(scaled, 0F, 1F);
return new() { PackedValue = Pack(scaled.X, scaled.Y) };
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromVector4(Vector4 source) => new() { PackedValue = Pack(source.X, source.Y) };
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4()
{
var vector = this.ToVector2();
return new Vector4(vector.X, vector.Y, 0F, 1F);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4());
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector2 ToVector2()
{
Vector2 vector;
@ -166,21 +166,19 @@ public partial struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint>
public override readonly bool Equals(object? obj) => obj is HalfVector2 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString()
{
var vector = this.ToVector2();
Vector2 vector = this.ToVector2();
return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})");
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y)
{
uint num2 = HalfTypeHelper.Pack(x);

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

@ -30,7 +30,7 @@ public partial struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
/// Initializes a new instance of the <see cref="HalfVector4"/> struct.
/// </summary>
/// <param name="vector">A vector containing the initial values for the components</param>
public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
public HalfVector4(Vector4 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public ulong PackedValue { get; set; }
@ -43,7 +43,7 @@ public partial struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right);
/// <summary>
@ -54,44 +54,25 @@ public partial struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right);
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<HalfVector4>(
PixelComponentInfo.Create<HalfVector4>(4, 16, 16, 16, 16),
PixelColorType.RGB | PixelColorType.Alpha,
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public readonly PixelOperations<HalfVector4> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector)
{
vector *= 2F;
vector -= Vector4.One;
this.FromVector4(vector);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
Vector4 scaled = this.ToVector4();
scaled += Vector4.One;
scaled /= 2F;
scaled /= 2f;
return scaled;
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4() => new(
HalfTypeHelper.Unpack((ushort)this.PackedValue),
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)),
@ -99,77 +80,94 @@ public partial struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30)));
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4());
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<HalfVector4>(
PixelComponentInfo.Create<HalfVector4>(4, 16, 16, 16, 16),
PixelColorType.RGB | PixelColorType.Alpha,
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc />
public static PixelOperations<HalfVector4> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromScaledVector4(Vector4 source)
{
source *= 2f;
source -= Vector4.One;
return FromVector4(source);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) };
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static HalfVector4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is HalfVector4 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString()
{
var vector = this.ToVector4();
Vector4 vector = this.ToVector4();
return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
@ -177,8 +175,8 @@ public partial struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static ulong Pack(ref Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Pack(Vector4 vector)
{
ulong num4 = HalfTypeHelper.Pack(vector.X);
ulong num3 = (ulong)HalfTypeHelper.Pack(vector.Y) << 0x10;

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

@ -33,7 +33,7 @@ public partial struct L16 : IPixel<L16>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(L16 left, L16 right) => left.Equals(right);
/// <summary>
@ -44,9 +44,29 @@ public partial struct L16 : IPixel<L16>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(L16 left, L16 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32()
{
byte rgb = ColorNumerics.From16BitTo8Bit(this.PackedValue);
return new(rgb, rgb, rgb);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4()
{
float scaled = this.PackedValue / Max;
return new Vector4(scaled, scaled, scaled, 1f);
}
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<L16>(
@ -55,130 +75,84 @@ public partial struct L16 : IPixel<L16>, IPackedVector<ushort>
PixelAlphaRepresentation.None);
/// <inheritdoc />
public readonly PixelOperations<L16> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
public static PixelOperations<L16> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4()
{
float scaled = this.PackedValue / Max;
return new Vector4(scaled, scaled, scaled, 1F);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) };
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromArgb32(Argb32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <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));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this.PackedValue = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue));
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromL16(L16 source) => new(source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.PackedValue = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromLa16(La16 source) => new(ColorNumerics.From8BitTo16Bit(source.L));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.PackedValue = source.L;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromLa32(La32 source) => new(source.L);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromRgb24(Rgb24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(this.PackedValue);
dest.R = rgb;
dest.G = rgb;
dest.B = rgb;
dest.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromRgba32(Rgba32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromRgb48(Rgb48 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L16 FromRgba64(Rgba64 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is L16 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(L16 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString() => $"L16({this.PackedValue})";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(Vector4 vector)
{
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
this.PackedValue = ColorNumerics.Get16BitBT709Luminance(
vector.X,
vector.Y,
vector.Z);
return ColorNumerics.Get16BitBT709Luminance(vector.X, vector.Y, vector.Z);
}
}

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

@ -3,6 +3,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp.PixelFormats;
@ -14,8 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats;
/// </summary>
public partial struct L8 : IPixel<L8>, IPackedVector<byte>
{
private static readonly Vector4 MaxBytes = new(255F);
private static readonly Vector4 Half = new(0.5F);
private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4();
private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4();
/// <summary>
/// Initializes a new instance of the <see cref="L8"/> struct.
@ -34,7 +35,7 @@ public partial struct L8 : IPixel<L8>, IPackedVector<byte>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(L8 left, L8 right) => left.Equals(right);
/// <summary>
@ -45,9 +46,29 @@ public partial struct L8 : IPixel<L8>, IPackedVector<byte>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(L8 left, L8 right) => !left.Equals(right);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32()
{
byte rgb = this.PackedValue;
return new(rgb, rgb, rgb);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4()
{
float rgb = this.PackedValue / 255f;
return new Vector4(rgb, rgb, rgb, 1f);
}
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<L8>(
@ -56,118 +77,88 @@ public partial struct L8 : IPixel<L8>, IPackedVector<byte>
PixelAlphaRepresentation.None);
/// <inheritdoc />
public readonly PixelOperations<L8> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<L8> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromScaledVector4(Vector4 source) => FromVector4(source);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4()
{
float rgb = this.PackedValue / 255F;
return new Vector4(rgb, rgb, rgb, 1F);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) };
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source) => this = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromL8(L8 source) => new(source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromL16(L16 source) => new(ColorNumerics.From16BitTo8Bit(source.PackedValue));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this.PackedValue = source.L;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromLa16(La16 source) => new(source.L);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.L));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromRgb24(Rgb24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)
{
dest.R = this.PackedValue;
dest.G = this.PackedValue;
dest.B = this.PackedValue;
dest.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromRgba32(Rgba32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source)
=> this.PackedValue = ColorNumerics.Get8BitBT709Luminance(
ColorNumerics.DownScaleFrom16BitTo8Bit(source.R),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.G),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.B));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromRgb48(Rgb48 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source)
=> this.PackedValue = ColorNumerics.Get8BitBT709Luminance(
ColorNumerics.DownScaleFrom16BitTo8Bit(source.R),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.G),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.B));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static L8 FromRgba64(Rgba64 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B));
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is L8 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(L8 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly string ToString() => $"L8({this.PackedValue})";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte Pack(Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes);
this.PackedValue = ColorNumerics.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z);
Vector128<byte> result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte();
return ColorNumerics.Get8BitBT709Luminance(result.GetElement(0), result.GetElement(4), result.GetElement(8));
}
}

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

@ -4,6 +4,7 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
namespace SixLabors.ImageSharp.PixelFormats;
@ -16,8 +17,15 @@ namespace SixLabors.ImageSharp.PixelFormats;
[StructLayout(LayoutKind.Explicit)]
public partial struct La16 : IPixel<La16>, IPackedVector<ushort>
{
private static readonly Vector4 MaxBytes = new(255F);
private static readonly Vector4 Half = new(0.5F);
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4();
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4();
/// <summary>
/// Gets or sets the luminance component.
@ -57,7 +65,7 @@ public partial struct La16 : IPixel<La16>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(La16 left, La16 right) => left.Equals(right);
/// <summary>
@ -68,174 +76,118 @@ public partial struct La16 : IPixel<La16>, IPackedVector<ushort>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(La16 left, La16 right) => !left.Equals(right);
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<La16>(
PixelComponentInfo.Create<La16>(2, 8, 8),
PixelColorType.Grayscale | PixelColorType.Alpha,
PixelAlphaRepresentation.Unassociated);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32() => new(this.L, this.L, this.L, this.A);
/// <inheritdoc/>
public readonly PixelOperations<La16> CreatePixelOperations() => new PixelOperations();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(La16 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is La16 other && this.Equals(other);
/// <inheritdoc />
public override readonly string ToString() => $"La16({this.L}, {this.A})";
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4()
{
const float max = 255f;
float rgb = this.L / max;
return new Vector4(rgb, rgb, rgb, this.A / max);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<La16>(
PixelComponentInfo.Create<La16>(2, 8, 8),
PixelColorType.Grayscale | PixelColorType.Alpha,
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
this.A = source.A;
}
public static PixelOperations<La16> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
this.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromScaledVector4(Vector4 source) => Pack(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
this.A = source.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromVector4(Vector4 source) => Pack(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromAbgr32(Abgr32 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
this.A = source.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4());
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source)
{
this.L = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source)
{
this.L = source.PackedValue;
this.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source) => this = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source)
{
this.L = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L);
this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromL16(L16 source) => new(ColorNumerics.From16BitTo8Bit(source.PackedValue), byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
this.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromL8(L8 source) => new(source.PackedValue, byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(
ColorNumerics.DownScaleFrom16BitTo8Bit(source.R),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.G),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.B));
this.A = byte.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromLa16(La16 source) => new(source.L, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B);
this.A = source.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.L), ColorNumerics.From16BitTo8Bit(source.A));
/// <inheritdoc/>
public void FromRgba64(Rgba64 source)
{
this.L = ColorNumerics.Get8BitBT709Luminance(
ColorNumerics.DownScaleFrom16BitTo8Bit(source.R),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.G),
ColorNumerics.DownScaleFrom16BitTo8Bit(source.B));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromRgb24(Rgb24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue);
this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromRgba32(Rgba32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La16 FromRgb48(Rgb48 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
public static La16 FromRgba64(Rgba64 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), ColorNumerics.From16BitTo8Bit(source.A));
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)
{
dest.R = this.L;
dest.G = this.L;
dest.B = this.L;
dest.A = this.A;
}
public override readonly bool Equals(object? obj) => obj is La16 other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
public readonly bool Equals(La16 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4()
{
const float Max = 255F;
float rgb = this.L / Max;
return new Vector4(rgb, rgb, rgb, this.A / Max);
}
/// <inheritdoc />
public override readonly string ToString() => $"La16({this.L}, {this.A})";
/// <inheritdoc />
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static La16 Pack(Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes);
this.L = ColorNumerics.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z);
this.A = (byte)vector.W;
Vector128<byte> result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte();
byte l = ColorNumerics.Get8BitBT709Luminance(result.GetElement(0), result.GetElement(4), result.GetElement(8));
byte a = result.GetElement(12);
return new(l, a);
}
}

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

@ -44,10 +44,10 @@ public partial struct La32 : IPixel<La32>, IPackedVector<uint>
/// <inheritdoc/>
public uint PackedValue
{
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
readonly get => Unsafe.As<La32, uint>(ref Unsafe.AsRef(in this));
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set => Unsafe.As<La32, uint>(ref this) = value;
}
@ -59,7 +59,7 @@ public partial struct La32 : IPixel<La32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(La32 left, La32 right) => left.Equals(right);
/// <summary>
@ -70,9 +70,29 @@ public partial struct La32 : IPixel<La32>, IPackedVector<uint>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(La32 left, La32 right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Rgba32 ToRgba32()
{
byte rgb = ColorNumerics.From16BitTo8Bit(this.L);
return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(this.A));
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public readonly Vector4 ToVector4()
{
float rgb = this.L / Max;
return new Vector4(rgb, rgb, rgb, this.A / Max);
}
/// <inheritdoc />
public static PixelTypeInfo GetPixelTypeInfo()
=> PixelTypeInfo.Create<La32>(
@ -81,182 +101,115 @@ public partial struct La32 : IPixel<La32>, IPackedVector<uint>
PixelAlphaRepresentation.Unassociated);
/// <inheritdoc/>
public readonly PixelOperations<La32> CreatePixelOperations() => new PixelOperations();
public static PixelOperations<La32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly bool Equals(La32 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is La32 other && this.Equals(other);
/// <inheritdoc />
public override readonly string ToString() => $"La32({this.L}, {this.A})";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromScaledVector4(Vector4 source) => Pack(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromArgb32(Argb32 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromVector4(Vector4 source) => Pack(source);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgr24(Bgr24 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromAbgr32(Abgr32 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
this.A = ushort.MaxValue;
ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
ushort a = ColorNumerics.From8BitTo16Bit(source.A);
return new(l, a);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromBgra32(Bgra32 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromArgb32(Argb32 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
ushort a = ColorNumerics.From8BitTo16Bit(source.A);
return new(l, 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());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL16(L16 source)
{
this.L = source.PackedValue;
this.A = ushort.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromL8(L8 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromBgra32(Bgra32 source)
{
this.L = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue);
this.A = ushort.MaxValue;
ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
ushort a = ColorNumerics.From8BitTo16Bit(source.A);
return new(l, a);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa16(La16 source)
{
this.L = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L);
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromL16(L16 source) => new(source.PackedValue, ushort.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromLa32(La32 source) => this = source;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue), ushort.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb24(Rgb24 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromLa16(La16 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
this.A = ushort.MaxValue;
ushort l = ColorNumerics.From8BitTo16Bit(source.L);
ushort a = ColorNumerics.From8BitTo16Bit(source.A);
return new(l, a);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgb48(Rgb48 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
this.A = ushort.MaxValue;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromLa32(La32 source) => new(source.L, source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba32(Rgba32 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(
ColorNumerics.UpscaleFrom8BitTo16Bit(source.R),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.G),
ColorNumerics.UpscaleFrom8BitTo16Bit(source.B));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromRgb24(Rgb24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue);
this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromRgb48(Rgb48 source)
{
ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
return new(l, ushort.MaxValue);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromRgba64(Rgba64 source)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromRgba32(Rgba32 source)
{
this.L = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
this.A = source.A;
ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B);
ushort a = ColorNumerics.From8BitTo16Bit(source.A);
return new(l, a);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static La32 FromRgba64(Rgba64 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), source.A);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector);
/// <inheritdoc />
public override readonly bool Equals(object? obj) => obj is La32 other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest)
{
byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(this.L);
dest.R = rgb;
dest.G = rgb;
dest.B = rgb;
dest.A = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A);
}
public readonly bool Equals(La32 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
public override readonly string ToString() => $"La32({this.L}, {this.A})";
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public readonly Vector4 ToVector4()
{
float scaled = this.L / Max;
return new Vector4(scaled, scaled, scaled, this.A / Max);
}
/// <inheritdoc />
public override readonly int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static La32 Pack(Vector4 vector)
{
vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
this.L = ColorNumerics.Get16BitBT709Luminance(
vector.X,
vector.Y,
vector.Z);
this.A = (ushort)MathF.Round(vector.W);
ushort l = ColorNumerics.Get16BitBT709Luminance(vector.X, vector.Y, vector.Z);
ushort a = (ushort)MathF.Round(vector.W);
return new(l, a);
}
}

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

Loading…
Cancel
Save