Browse Source

Merge branch 'master' into js/assignable-palette-quantizer

pull/741/head
James Jackson-South 8 years ago
parent
commit
5ab0799e50
  1. 232
      src/ImageSharp/Common/Extensions/SimdUtils.cs
  2. 107
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  3. 215
      src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
  4. 178
      src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
  5. 151
      src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
  6. 185
      src/ImageSharp/Common/Helpers/SimdUtils.cs
  7. 109
      src/ImageSharp/Common/Tuples/Octet.cs
  8. 12
      src/ImageSharp/Common/Tuples/Vector4Pair.cs
  9. 24
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  10. 4
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  11. 34
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  12. 34
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  13. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
  14. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
  15. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
  16. 116
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  17. 51
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
  18. 14
      src/ImageSharp/ImageFrame{TPixel}.cs
  19. 72
      src/ImageSharp/ImageSharp.csproj
  20. 171
      src/ImageSharp/PixelFormats/Alpha8.cs
  21. 253
      src/ImageSharp/PixelFormats/Argb32.cs
  22. 179
      src/ImageSharp/PixelFormats/Bgr24.cs
  23. 204
      src/ImageSharp/PixelFormats/Bgr565.cs
  24. 210
      src/ImageSharp/PixelFormats/Bgra32.cs
  25. 186
      src/ImageSharp/PixelFormats/Bgra4444.cs
  26. 194
      src/ImageSharp/PixelFormats/Bgra5551.cs
  27. 168
      src/ImageSharp/PixelFormats/Byte4.cs
  28. 177
      src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs
  29. 85
      src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt
  30. 177
      src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs
  31. 85
      src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt
  32. 177
      src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs
  33. 85
      src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt
  34. 177
      src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs
  35. 85
      src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt
  36. 177
      src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs
  37. 85
      src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt
  38. 621
      src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs
  39. 92
      src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt
  40. 177
      src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs
  41. 85
      src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt
  42. 177
      src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs
  43. 85
      src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt
  44. 124
      src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs
  45. 70
      src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt
  46. 177
      src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs
  47. 85
      src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt
  48. 177
      src/ImageSharp/PixelFormats/Gray16.cs
  49. 152
      src/ImageSharp/PixelFormats/Gray8.cs
  50. 202
      src/ImageSharp/PixelFormats/HalfSingle.cs
  51. 12
      src/ImageSharp/PixelFormats/HalfTypeHelper.cs
  52. 216
      src/ImageSharp/PixelFormats/HalfVector2.cs
  53. 188
      src/ImageSharp/PixelFormats/HalfVector4.cs
  54. 78
      src/ImageSharp/PixelFormats/IPixel.cs
  55. 253
      src/ImageSharp/PixelFormats/NormalizedByte2.cs
  56. 234
      src/ImageSharp/PixelFormats/NormalizedByte4.cs
  57. 239
      src/ImageSharp/PixelFormats/NormalizedShort2.cs
  58. 243
      src/ImageSharp/PixelFormats/NormalizedShort4.cs
  59. 54
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  60. 216
      src/ImageSharp/PixelFormats/Rg32.cs
  61. 186
      src/ImageSharp/PixelFormats/Rgb24.cs
  62. 189
      src/ImageSharp/PixelFormats/Rgb48.cs
  63. 208
      src/ImageSharp/PixelFormats/Rgba1010102.cs
  64. 160
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs
  65. 253
      src/ImageSharp/PixelFormats/Rgba32.cs
  66. 239
      src/ImageSharp/PixelFormats/Rgba64.cs
  67. 721
      src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs
  68. 18
      src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs
  69. 346
      src/ImageSharp/PixelFormats/RgbaVector.cs
  70. 238
      src/ImageSharp/PixelFormats/Short2.cs
  71. 236
      src/ImageSharp/PixelFormats/Short4.cs
  72. 11
      src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs
  73. 9
      src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs
  74. 9
      src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs
  75. 12
      src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs
  76. 15
      src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs
  77. 49
      src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs
  78. 48
      src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs
  79. 68
      tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs
  80. 166
      tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs
  81. 32
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs
  82. 14
      tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs
  83. 8
      tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs
  84. 70
      tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs
  85. 12
      tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs
  86. 23
      tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs
  87. 32
      tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs
  88. 3
      tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs
  89. 19
      tests/ImageSharp.Benchmarks/General/Modulus.cs
  90. 28
      tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs
  91. 81
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs
  92. 58
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs
  93. 61
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs
  94. 113
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs
  95. 83
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs
  96. 95
      tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs
  97. 89
      tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs
  98. 72
      tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs
  99. 113
      tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs
  100. 64
      tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs

232
src/ImageSharp/Common/Extensions/SimdUtils.cs

@ -1,232 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Various extension and utility methods for <see cref="Vector4"/> and <see cref="Vector{T}"/> utilizing SIMD capabilities
/// </summary>
internal static class SimdUtils
{
/// <summary>
/// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte.
/// </summary>
public static bool IsAvx2CompatibleArchitecture => Vector<float>.Count == 8 && Vector<int>.Count == 8;
internal static void GuardAvx2(string operation)
{
if (!IsAvx2CompatibleArchitecture)
{
throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!");
}
}
/// <summary>
/// Transform all scalars in 'v' in a way that converting them to <see cref="int"/> would have rounding semantics.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector4 PseudoRound(this Vector4 v)
{
var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1));
return v + (sign * 0.5f);
}
/// <summary>
/// Rounds all values in 'v' to the nearest integer following <see cref="MidpointRounding.ToEven"/> semantics.
/// Source:
/// <see>
/// <cref>https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110</cref>
/// </see>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector<float> FastRound(this Vector<float> x)
{
Vector<int> magic0 = new Vector<int>(int.MinValue); // 0x80000000
Vector<float> sgn0 = Vector.AsVectorSingle(magic0);
Vector<float> and0 = Vector.BitwiseAnd(sgn0, x);
Vector<float> or0 = Vector.BitwiseOr(and0, new Vector<float>(8388608.0f));
Vector<float> add0 = Vector.Add(x, or0);
Vector<float> sub0 = Vector.Subtract(add0, or0);
return sub0;
}
/// <summary>
/// Convert 'source.Length' <see cref="float"/> values normalized into [0..1] from 'source' into 'dest' buffer of <see cref="byte"/> values.
/// The values gonna be scaled up into [0-255] and rounded.
/// Based on:
/// <see>
/// <cref>http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions</cref>
/// </see>
/// </summary>
internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan<float> source, Span<byte> dest)
{
GuardAvx2(nameof(BulkConvertNormalizedFloatToByte));
DebugGuard.IsTrue((source.Length % Vector<float>.Count) == 0, nameof(source), "source.Length should be divisable by Vector<float>.Count!");
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
/// <summary>
/// Same as <see cref="BulkConvertNormalizedFloatToByte"/> but clamps overflown values before conversion.
/// </summary>
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan<float> source, Span<byte> dest)
{
GuardAvx2(nameof(BulkConvertNormalizedFloatToByte));
DebugGuard.IsTrue((source.Length % Vector<float>.Count) == 0, nameof(source), "source.Length should be divisable by Vector<float>.Count!");
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = Vector.Max(x, Vector<float>.Zero);
x = Vector.Min(x, Vector<float>.One);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
// TODO: Replace these with T4-d library level tuples!
internal static class Octet
{
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))]
public struct OfUInt32
{
[FieldOffset(0 * sizeof(uint))]
public uint V0;
[FieldOffset(1 * sizeof(uint))]
public uint V1;
[FieldOffset(2 * sizeof(uint))]
public uint V2;
[FieldOffset(3 * sizeof(uint))]
public uint V3;
[FieldOffset(4 * sizeof(uint))]
public uint V4;
[FieldOffset(5 * sizeof(uint))]
public uint V5;
[FieldOffset(6 * sizeof(uint))]
public uint V6;
[FieldOffset(7 * sizeof(uint))]
public uint V7;
public override string ToString()
{
return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]";
}
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct OfByte
{
[FieldOffset(0)]
public byte V0;
[FieldOffset(1)]
public byte V1;
[FieldOffset(2)]
public byte V2;
[FieldOffset(3)]
public byte V3;
[FieldOffset(4)]
public byte V4;
[FieldOffset(5)]
public byte V5;
[FieldOffset(6)]
public byte V6;
[FieldOffset(7)]
public byte V7;
public override string ToString()
{
return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]";
}
public void LoadFrom(ref OfUInt32 i)
{
this.V0 = (byte)i.V0;
this.V1 = (byte)i.V1;
this.V2 = (byte)i.V2;
this.V3 = (byte)i.V3;
this.V4 = (byte)i.V4;
this.V5 = (byte)i.V5;
this.V6 = (byte)i.V6;
this.V7 = (byte)i.V7;
}
}
}
}
}

107
src/ImageSharp/Common/Helpers/ImageMaths.cs

@ -14,6 +14,73 @@ namespace SixLabors.ImageSharp
/// </summary>
internal static class ImageMaths
{
/// <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(InliningOptions.ShortMethod)]
public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F));
/// <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(InliningOptions.ShortMethod)]
public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
/// <summary>
/// Scales a value from a 16 bit <see cref="ushort"/> to it's 8 bit <see cref="byte"/> equivalent.
/// </summary>
/// <param name="component">The 8 bit compoonent value.</param>
/// <returns>The <see cref="byte"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static byte DownScaleFrom16BitTo8Bit(ushort component)
{
// To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is:
//
// (V * 255) / 65535
//
// This reduces to round(V / 257), or floor((V + 128.5)/257)
//
// Represent V as the two byte value vhi.vlo. Make a guess that the
// result is the top byte of V, vhi, then the correction to this value
// is:
//
// error = floor(((V-vhi.vhi) + 128.5) / 257)
// = floor(((vlo-vhi) + 128.5) / 257)
//
// This can be approximated using integer arithmetic (and a signed
// shift):
//
// error = (vlo-vhi+128) >> 8;
//
// The approximate differs from the exact answer only when (vlo-vhi) is
// 128; it then gives a correction of +1 when the exact correction is
// 0. This gives 128 errors. The exact answer (correct for all 16-bit
// input values) is:
//
// error = (vlo-vhi+128)*65535 >> 24;
//
// An alternative arithmetic calculation which also gives no errors is:
//
// (V * 255 + 32895) >> 16
return (byte)(((component * 255) + 32895) >> 16);
}
/// <summary>
/// Scales a value from an 8 bit <see cref="byte"/> to it's 16 bit <see cref="ushort"/> equivalent.
/// </summary>
/// <param name="component">The 8 bit compoonent value.</param>
/// <returns>The <see cref="ushort"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257);
/// <summary>
/// Determine the Greatest CommonDivisor (GCD) of two numbers.
/// </summary>
@ -39,6 +106,28 @@ namespace SixLabors.ImageSharp
return (a / GreatestCommonDivisor(a, b)) * b;
}
/// <summary>
/// Calculates <paramref name="x"/> % 4
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static int Modulo4(int x) => x & 3;
/// <summary>
/// Calculates <paramref name="x"/> % 8
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static int Modulo8(int x) => x & 7;
/// <summary>
/// Fast (x mod m) calculator, with the restriction that
/// <paramref name="m"/> should be power of 2.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static int ModuloP2(int x, int m)
{
return x & (m - 1);
}
/// <summary>
/// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation.
/// </summary>
@ -46,7 +135,7 @@ namespace SixLabors.ImageSharp
/// A number that is greater than <see cref="int.MinValue"/>, but less than or equal to <see cref="int.MaxValue"/>
/// </param>
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static int FastAbs(int x)
{
int y = x >> 31;
@ -58,7 +147,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="x">A single-precision floating-point number</param>
/// <returns>The number <paramref name="x" /> raised to the power of 2.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static float Pow2(float x) => x * x;
/// <summary>
@ -66,7 +155,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="x">A single-precision floating-point number</param>
/// <returns>The number <paramref name="x" /> raised to the power of 3.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static float Pow3(float x) => x * x * x;
/// <summary>
@ -77,7 +166,7 @@ namespace SixLabors.ImageSharp
/// <returns>
/// The <see cref="int"/>
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2)));
/// <summary>
@ -85,7 +174,7 @@ namespace SixLabors.ImageSharp
/// </summary>
/// <param name="bitDepth">The bit depth.</param>
/// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth;
/// <summary>
@ -94,7 +183,7 @@ namespace SixLabors.ImageSharp
/// <param name="x">The x provided to G(x).</param>
/// <param name="sigma">The spread of the blur.</param>
/// <returns>The Gaussian G(x)</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static float Gaussian(float x, float sigma)
{
const float Numerator = 1.0f;
@ -117,7 +206,7 @@ namespace SixLabors.ImageSharp
/// <returns>
/// The sine cardinal of <paramref name="f" />.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static float SinC(float f)
{
if (MathF.Abs(f) > Constants.Epsilon)
@ -140,7 +229,7 @@ namespace SixLabors.ImageSharp
/// <returns>
/// The <see cref="float"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static float GetBcValue(float x, float b, float c)
{
if (x < 0F)
@ -176,7 +265,7 @@ namespace SixLabors.ImageSharp
/// <returns>
/// The bounding <see cref="Rectangle"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
/// <summary>

215
src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs

@ -0,0 +1,215 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Tuples;
// ReSharper disable MemberHidesStaticFromOuterClass
namespace SixLabors.ImageSharp
{
internal static partial class SimdUtils
{
/// <summary>
/// Implementation with 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen etc.)
/// </summary>
public static class BasicIntrinsics256
{
public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture;
/// <summary>
/// <see cref="BulkConvertByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloatReduce(
ref ReadOnlySpan<byte> source,
ref Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.Modulo8(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertByteToNormalizedFloat(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// <see cref="BulkConvertNormalizedFloatToByteClampOverflows"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce(
ref ReadOnlySpan<float> source,
ref Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.Modulo8(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// SIMD optimized implementation for <see cref="SimdUtils.BulkConvertByteToNormalizedFloat"/>.
/// Works only with span Length divisible by 8.
/// Implementation adapted from:
/// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions
/// http://stackoverflow.com/a/536278
/// </summary>
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
VerifyIsAvx2Compatible(nameof(BulkConvertByteToNormalizedFloat));
VerifySpanInput(source, dest, 8);
var bVec = new Vector<float>(256.0f / 255.0f);
var magicFloat = new Vector<float>(32768.0f);
var magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
var mask = new Vector<uint>(255);
ref Octet.OfByte sourceBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(source));
ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As<float, Octet.OfUInt32>(ref MemoryMarshal.GetReference(dest));
ref Vector<float> destBaseAsFloat = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref destBaseAsWideOctet);
int n = dest.Length / 8;
for (int i = 0; i < n; i++)
{
ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i);
ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i);
d.LoadFrom(ref s);
}
for (int i = 0; i < n; i++)
{
ref Vector<float> df = ref Unsafe.Add(ref destBaseAsFloat, i);
var vi = Vector.AsVectorUInt32(df);
vi &= mask;
vi |= magicInt;
var vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
df = vf;
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows"/> which is faster on older runtimes.
/// </summary>
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan<float> source, Span<byte> dest)
{
VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByteClampOverflows));
VerifySpanInput(source, dest, 8);
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = Vector.Max(x, Vector<float>.Zero);
x = Vector.Min(x, Vector<float>.One);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
/// <summary>
/// Convert all <see cref="float"/> values normalized into [0..1] from 'source'
/// into 'dest' buffer of <see cref="byte"/>. The values are scaled up into [0-255] and rounded.
/// This implementation is SIMD optimized and works only when span Length is divisible by 8.
/// Based on:
/// <see>
/// <cref>http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions</cref>
/// </see>
/// </summary>
internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan<float> source, Span<byte> dest)
{
VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByte));
VerifySpanInput(source, dest, 8);
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
}
}
}

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

@ -0,0 +1,178 @@
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable MemberHidesStaticFromOuterClass
namespace SixLabors.ImageSharp
{
internal static partial class SimdUtils
{
/// <summary>
/// Implementation methods based on newer <see cref="Vector{T}"/> API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*).
/// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+)
/// See:
/// https://github.com/dotnet/coreclr/pull/10662
/// API Proposal:
/// https://github.com/dotnet/corefx/issues/15957
/// </summary>
public static class ExtendedIntrinsics
{
public static bool IsAvailable { get; } =
#if NETCOREAPP2_1
// TODO: Also available in .NET 4.7.2, we need to add a build target!
Vector.IsHardwareAccelerated;
#else
false;
#endif
/// <summary>
/// <see cref="BulkConvertByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloatReduce(
ref ReadOnlySpan<byte> source,
ref Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.ModuloP2(source.Length, Vector<byte>.Count);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// <see cref="BulkConvertNormalizedFloatToByteClampOverflows"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce(
ref ReadOnlySpan<float> source,
ref Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.ModuloP2(source.Length, Vector<byte>.Count);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertNormalizedFloatToByteClampOverflows(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// Implementation <see cref="SimdUtils.BulkConvertByteToNormalizedFloat"/>, which is faster on new RyuJIT runtime.
/// </summary>
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
VerifySpanInput(source, dest, Vector<byte>.Count);
int n = dest.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dest));
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
Vector<float> f0 = ConvertToSingle(w0);
Vector<float> f1 = ConvertToSingle(w1);
Vector<float> f2 = ConvertToSingle(w2);
Vector<float> f3 = ConvertToSingle(w3);
ref Vector<float> d = ref Unsafe.Add(ref destBase, i * 4);
d = f0;
Unsafe.Add(ref d, 1) = f1;
Unsafe.Add(ref d, 2) = f2;
Unsafe.Add(ref d, 3) = f3;
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows"/>, which is faster on new .NET runtime.
/// </summary>
internal static void BulkConvertNormalizedFloatToByteClampOverflows(
ReadOnlySpan<float> source,
Span<byte> dest)
{
VerifySpanInput(source, dest, Vector<byte>.Count);
int n = dest.Length / Vector<byte>.Count;
ref Vector<float> sourceBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Vector<byte> destBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(dest));
for (int i = 0; i < n; i++)
{
ref Vector<float> s = ref Unsafe.Add(ref sourceBase, i * 4);
Vector<float> f0 = s;
Vector<float> f1 = Unsafe.Add(ref s, 1);
Vector<float> f2 = Unsafe.Add(ref s, 2);
Vector<float> f3 = Unsafe.Add(ref s, 3);
Vector<uint> w0 = ConvertToUInt32(f0);
Vector<uint> w1 = ConvertToUInt32(f1);
Vector<uint> w2 = ConvertToUInt32(f2);
Vector<uint> w3 = ConvertToUInt32(f3);
Vector<ushort> u0 = Vector.Narrow(w0, w1);
Vector<ushort> u1 = Vector.Narrow(w2, w3);
Vector<byte> b = Vector.Narrow(u0, u1);
Unsafe.Add(ref destBase, i) = b;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<uint> ConvertToUInt32(Vector<float> vf)
{
Vector<float> maxBytes = new Vector<float>(255f);
vf *= maxBytes;
vf += new Vector<float>(0.5f);
vf = Vector.Min(Vector.Max(vf, Vector<float>.Zero), maxBytes);
Vector<int> vi = Vector.ConvertToInt32(vf);
return Vector.AsVectorUInt32(vi);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> ConvertToSingle(Vector<uint> u)
{
Vector<int> vi = Vector.AsVectorInt32(u);
Vector<float> v = Vector.ConvertToSingle(vi);
v *= new Vector<float>(1f / 255f);
return v;
}
}
}
}

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

@ -0,0 +1,151 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable MemberHidesStaticFromOuterClass
namespace SixLabors.ImageSharp
{
internal static partial class SimdUtils
{
/// <summary>
/// Fallback implementation based on <see cref="Vector4"/> (128bit).
/// For <see cref="Vector4"/>, efficient software fallback implementations are present,
/// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P
/// </summary>
public static class FallbackIntrinsics128
{
/// <summary>
/// <see cref="BulkConvertByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloatReduce(
ref ReadOnlySpan<byte> source,
ref Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
int remainder = ImageMaths.Modulo4(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertByteToNormalizedFloat(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// <see cref="BulkConvertNormalizedFloatToByteClampOverflows"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce(
ref ReadOnlySpan<float> source,
ref Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
int remainder = ImageMaths.Modulo4(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertNormalizedFloatToByteClampOverflows(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertByteToNormalizedFloat"/> using <see cref="Vector4"/>.
/// </summary>
[MethodImpl(InliningOptions.ColdPath)]
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
VerifySpanInput(source, dest, 4);
int count = dest.Length / 4;
if (count == 0)
{
return;
}
ref ByteVector4 sBase = ref Unsafe.As<byte, ByteVector4>(ref MemoryMarshal.GetReference(source));
ref Vector4 dBase = ref Unsafe.As<float, Vector4>(ref MemoryMarshal.GetReference(dest));
const float Scale = 1f / 255f;
Vector4 d = default;
for (int i = 0; i < count; i++)
{
ref ByteVector4 s = ref Unsafe.Add(ref sBase, i);
d.X = s.X;
d.Y = s.Y;
d.Z = s.Z;
d.W = s.W;
d *= Scale;
Unsafe.Add(ref dBase, i) = d;
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows"/> using <see cref="Vector4"/>.
/// </summary>
[MethodImpl(InliningOptions.ColdPath)]
internal static void BulkConvertNormalizedFloatToByteClampOverflows(
ReadOnlySpan<float> source,
Span<byte> dest)
{
VerifySpanInput(source, dest, 4);
int count = source.Length / 4;
if (count == 0)
{
return;
}
ref Vector4 sBase = ref Unsafe.As<float, Vector4>(ref MemoryMarshal.GetReference(source));
ref ByteVector4 dBase = ref Unsafe.As<byte, ByteVector4>(ref MemoryMarshal.GetReference(dest));
var half = new Vector4(0.5f);
var maxBytes = new Vector4(255f);
for (int i = 0; i < count; i++)
{
Vector4 s = Unsafe.Add(ref sBase, i);
s *= maxBytes;
s += half;
// I'm not sure if Vector4.Clamp() is properly implemented with intrinsics.
s = Vector4.Max(Vector4.Zero, s);
s = Vector4.Min(maxBytes, s);
ref ByteVector4 d = ref Unsafe.Add(ref dBase, i);
d.X = (byte)s.X;
d.Y = (byte)s.Y;
d.Z = (byte)s.Z;
d.W = (byte)s.W;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct ByteVector4
{
public byte X;
public byte Y;
public byte Z;
public byte W;
}
}
}
}

185
src/ImageSharp/Common/Helpers/SimdUtils.cs

@ -0,0 +1,185 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Various extension and utility methods for <see cref="Vector4"/> and <see cref="Vector{T}"/> utilizing SIMD capabilities
/// </summary>
internal static partial class SimdUtils
{
/// <summary>
/// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte.
/// </summary>
public static bool IsAvx2CompatibleArchitecture { get; } =
Vector.IsHardwareAccelerated && Vector<float>.Count == 8 && Vector<int>.Count == 8;
/// <summary>
/// Transform all scalars in 'v' in a way that converting them to <see cref="int"/> would have rounding semantics.
/// </summary>
/// <param name="v">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector4 PseudoRound(this Vector4 v)
{
var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1));
return v + (sign * 0.5f);
}
/// <summary>
/// Rounds all values in 'v' to the nearest integer following <see cref="MidpointRounding.ToEven"/> semantics.
/// Source:
/// <see>
/// <cref>https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110</cref>
/// </see>
/// </summary>
/// <param name="v">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector<float> FastRound(this Vector<float> v)
{
Vector<int> magic0 = new Vector<int>(int.MinValue); // 0x80000000
Vector<float> sgn0 = Vector.AsVectorSingle(magic0);
Vector<float> and0 = Vector.BitwiseAnd(sgn0, v);
Vector<float> or0 = Vector.BitwiseOr(and0, new Vector<float>(8388608.0f));
Vector<float> add0 = Vector.Add(v, or0);
Vector<float> sub0 = Vector.Subtract(add0, or0);
return sub0;
}
/// <summary>
/// Converts all input <see cref="byte"/>-s to <see cref="float"/>-s normalized into [0..1].
/// <paramref name="source"/> should be the of the same size as <paramref name="dest"/>,
/// but there are no restrictions on the span's length.
/// </summary>
/// <param name="source">The source span of bytes</param>
/// <param name="dest">The destination span of floats</param>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if NETCOREAPP2_1
ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest);
#else
BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest);
#endif
FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest);
// Deal with the remainder:
if (source.Length > 0)
{
ConverByteToNormalizedFloatRemainder(source, dest);
}
}
/// <summary>
/// Convert all <see cref="float"/> values normalized into [0..1] from 'source' into 'dest' buffer of <see cref="byte"/>.
/// The values are scaled up into [0-255] and rounded, overflows are clamped.
/// <paramref name="source"/> should be the of the same size as <paramref name="dest"/>,
/// but there are no restrictions on the span's length.
/// </summary>
/// <param name="source">The source span of floats</param>
/// <param name="dest">The destination span of bytes</param>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan<float> source, Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if NETCOREAPP2_1
ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest);
#else
BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest);
#endif
FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest);
// Deal with the remainder:
if (source.Length > 0)
{
ConvertNormalizedFloatToByteRemainder(source, dest);
}
}
[MethodImpl(InliningOptions.ColdPath)]
private static void ConverByteToNormalizedFloatRemainder(ReadOnlySpan<byte> source, Span<float> dest)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref float dBase = ref MemoryMarshal.GetReference(dest);
// There are at most 3 elements at this point, having a for loop is overkill.
// Let's minimize the no. of instructions!
switch (source.Length)
{
case 3:
Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f;
goto case 2;
case 2:
Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f;
goto case 1;
case 1:
dBase = sBase / 255f;
break;
}
}
[MethodImpl(InliningOptions.ColdPath)]
private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan<float> source, Span<byte> dest)
{
ref float sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest);
switch (source.Length)
{
case 3:
Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2));
goto case 2;
case 2:
Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1));
goto case 1;
case 1:
dBase = ConvertToByte(sBase);
break;
}
}
[MethodImpl(InliningOptions.ShortMethod)]
private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f);
[Conditional("DEBUG")]
private static void VerifyIsAvx2Compatible(string operation)
{
if (!IsAvx2CompatibleArchitecture)
{
throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!");
}
}
[Conditional("DEBUG")]
private static void VerifySpanInput(ReadOnlySpan<byte> source, Span<float> dest, int shouldBeDivisibleBy)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
$"length should be divisable by {shouldBeDivisibleBy}!");
}
[Conditional("DEBUG")]
private static void VerifySpanInput(ReadOnlySpan<float> source, Span<byte> dest, int shouldBeDivisibleBy)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
$"length should be divisable by {shouldBeDivisibleBy}!");
}
}
}

109
src/ImageSharp/Common/Tuples/Octet.cs

@ -0,0 +1,109 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Tuples
{
/// <summary>
/// Contains 8 element value tuples of various types.
/// </summary>
internal static class Octet
{
/// <summary>
/// Value tuple of <see cref="uint"/>-s
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))]
public struct OfUInt32
{
[FieldOffset(0 * sizeof(uint))]
public uint V0;
[FieldOffset(1 * sizeof(uint))]
public uint V1;
[FieldOffset(2 * sizeof(uint))]
public uint V2;
[FieldOffset(3 * sizeof(uint))]
public uint V3;
[FieldOffset(4 * sizeof(uint))]
public uint V4;
[FieldOffset(5 * sizeof(uint))]
public uint V5;
[FieldOffset(6 * sizeof(uint))]
public uint V6;
[FieldOffset(7 * sizeof(uint))]
public uint V7;
public override string ToString()
{
return $"{nameof(Octet)}.{nameof(OfUInt32)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})";
}
[MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(ref OfByte src)
{
this.V0 = src.V0;
this.V1 = src.V1;
this.V2 = src.V2;
this.V3 = src.V3;
this.V4 = src.V4;
this.V5 = src.V5;
this.V6 = src.V6;
this.V7 = src.V7;
}
}
/// <summary>
/// Value tuple of <see cref="byte"/>-s
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct OfByte
{
[FieldOffset(0)]
public byte V0;
[FieldOffset(1)]
public byte V1;
[FieldOffset(2)]
public byte V2;
[FieldOffset(3)]
public byte V3;
[FieldOffset(4)]
public byte V4;
[FieldOffset(5)]
public byte V5;
[FieldOffset(6)]
public byte V6;
[FieldOffset(7)]
public byte V7;
public override string ToString()
{
return $"{nameof(Octet)}.{nameof(OfByte)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})";
}
[MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(ref OfUInt32 src)
{
this.V0 = (byte)src.V0;
this.V1 = (byte)src.V1;
this.V2 = (byte)src.V2;
this.V3 = (byte)src.V3;
this.V4 = (byte)src.V4;
this.V5 = (byte)src.V5;
this.V6 = (byte)src.V6;
this.V7 = (byte)src.V7;
}
}
}
}

12
src/ImageSharp/Common/Tuples/Vector4Pair.cs

@ -2,11 +2,12 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Common.Tuples
namespace SixLabors.ImageSharp.Tuples
{
/// <summary>
/// Its faster to process multiple Vector4-s together, so let's pair them!
/// On AVX2 this pair should be convertible to <see cref="Vector{T}"/> of <see cref="float"/>!
/// TODO: Investigate defining this as union with an Octet.OfSingle type.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
internal struct Vector4Pair
@ -15,8 +16,6 @@ namespace SixLabors.ImageSharp.Common.Tuples
public Vector4 B;
private static readonly Vector4 Scale = new Vector4(1 / 255f);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyInplace(float value)
{
@ -52,8 +51,9 @@ namespace SixLabors.ImageSharp.Common.Tuples
b = b.FastRound();
// Downscale by 1/255
this.A *= Scale;
this.B *= Scale;
var scale = new Vector4(1 / 255f);
this.A *= scale;
this.B *= scale;
}
/// <summary>
@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Common.Tuples
public override string ToString()
{
return $"{this.A}, {this.B}";
return $"{nameof(Vector4Pair)}({this.A}, {this.B})";
}
}
}

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

@ -219,8 +219,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : struct, IPixel<TPixel>
{
TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255);
using (Buffer2D<byte> buffer = this.memoryAllocator.Allocate2D<byte>(width, height, AllocationOptions.Clean))
{
this.UncompressRle8(width, buffer.GetSpan());
@ -233,8 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int x = 0; x < width; x++)
{
rgba.Bgr = Unsafe.As<byte, Bgr24>(ref colors[bufferRow[x] * 4]);
color.PackFromRgba32(rgba);
color.PackFromBgr24(Unsafe.As<byte, Bgr24>(ref colors[bufferRow[x] * 4]));
pixelRow[x] = color;
}
}
@ -352,8 +349,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean))
{
TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255);
Span<byte> rowSpan = row.GetSpan();
for (int y = 0; y < height; y++)
@ -363,7 +358,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int offset = 0;
Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
// TODO: Could use PixelOperations here!
for (int x = 0; x < arrayWidth; x++)
{
int colOffset = x * ppb;
@ -371,9 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4;
// Stored in b-> g-> r order.
rgba.Bgr = Unsafe.As<byte, Bgr24>(ref colors[colorIndex]);
color.PackFromRgba32(rgba);
color.PackFromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIndex]));
pixelRow[newX] = color;
}
@ -397,7 +389,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int padding = CalculatePadding(width, 2);
int stride = (width * 2) + padding;
TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255);
using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
{
@ -412,11 +403,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{
short temp = BitConverter.ToInt16(buffer.Array, offset);
rgba.R = GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10);
rgba.G = GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5);
rgba.B = GetBytesFrom5BitValue(temp & Rgb16BMask);
var rgb = new Rgb24(
GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10),
GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5),
GetBytesFrom5BitValue(temp & Rgb16BMask));
color.PackFromRgba32(rgba);
color.PackFromRgb24(rgb);
pixelRow[x] = color;
offset += 2;
}
@ -537,7 +529,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.metaData = meta;
short bitsPerPixel = this.infoHeader.BitsPerPixel;
var bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance);
BmpMetaData bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance);
// We can only encode at these bit rates so far.
if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24)

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

@ -101,9 +101,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var fileHeader = new BmpFileHeader(
type: 19778, // BM
offset: 54,
fileSize: 54 + infoHeader.ImageSize,
reserved: 0,
fileSize: 54 + infoHeader.ImageSize);
offset: 54);
#if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[40];

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

@ -481,22 +481,36 @@ namespace SixLabors.ImageSharp.Formats.Gif
}
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
var rgba = new Rgba32(0, 0, 0, 255);
bool transFlag = this.graphicsControlExtension.TransparencyFlag;
// #403 The left + width value can be larger than the image width
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
if (!transFlag)
{
int index = Unsafe.Add(ref indicesRef, i);
if (!this.graphicsControlExtension.TransparencyFlag
|| this.graphicsControlExtension.TransparencyIndex != index)
// #403 The left + width value can be larger than the image width
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
{
int index = Unsafe.Add(ref indicesRef, i);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
rgba.Rgb = colorTable[index];
pixel.PackFromRgba32(rgba);
Rgb24 rgb = colorTable[index];
pixel.PackFromRgb24(rgb);
i++;
}
}
else
{
byte transIndex = this.graphicsControlExtension.TransparencyIndex;
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
{
int index = Unsafe.Add(ref indicesRef, i);
if (transIndex != index)
{
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
Rgb24 rgb = colorTable[index];
pixel.PackFromRgb24(rgb);
}
i++;
i++;
}
}
}

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.IO;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -209,16 +210,20 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
// Transparent pixels are much more likely to be found at the end of a palette
int index = -1;
Rgba32 trans = default;
int length = quantized.Palette.Length;
ref TPixel paletteRef = ref MemoryMarshal.GetReference(quantized.Palette.AsSpan());
for (int i = quantized.Palette.Length - 1; i >= 0; i--)
using (IMemoryOwner<Rgba32> rgbaBuffer = this.memoryAllocator.Allocate<Rgba32>(length))
{
ref TPixel entry = ref Unsafe.Add(ref paletteRef, i);
entry.ToRgba32(ref trans);
if (trans.Equals(default))
Span<Rgba32> rgbaSpan = rgbaBuffer.GetSpan();
ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba32(quantized.Palette, rgbaSpan, length);
for (int i = quantized.Palette.Length - 1; i >= 0; i--)
{
index = i;
if (Unsafe.Add(ref paletteRef, i).Equals(default))
{
index = i;
}
}
}
@ -405,24 +410,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteColorTable<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel>
{
int pixelCount = image.Palette.Length;
// The maximium number of colors for the bit depth
int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3;
Rgb24 rgb = default;
int pixelCount = image.Palette.Length;
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
{
ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan());
ref Rgb24 rgb24Ref = ref Unsafe.As<byte, Rgb24>(ref MemoryMarshal.GetReference(colorTable.GetSpan()));
for (int i = 0; i < pixelCount; i++)
{
ref TPixel entry = ref Unsafe.Add(ref paletteRef, i);
entry.ToRgb24(ref rgb);
Unsafe.Add(ref rgb24Ref, i) = rgb;
}
// Write the palette to the stream
PixelOperations<TPixel>.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount);
stream.Write(colorTable.Array, 0, colorTableLength);
}
}

4
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs

@ -6,7 +6,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order:
ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i);
destination.Collect(ref r, ref g, ref b);
destination.Pack(ref r, ref g, ref b);
}
}
}

4
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs

@ -6,7 +6,7 @@ using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Tuples;
// ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order:
ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i);
destination.Collect(ref rr, ref gg, ref bb);
destination.Pack(ref rr, ref gg, ref bb);
}
}
}

6
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs

@ -6,8 +6,8 @@ using System.Collections.Generic;
using System.Linq;
using System.Numerics;
using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Tuples;
using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
@ -157,9 +157,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
public Vector4 V0, V1, V2, V3, V4, V5, V6, V7;
/// <summary>
/// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order.
/// Pack (r0,r1...r7) (g0,g1...g7) (b0,b1...b7) vector values as (r0,g0,b0,1), (r1,g1,b1,1) ...
/// </summary>
public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b)
public void Pack(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b)
{
this.V0.X = r.A.X;
this.V0.Y = g.A.X;

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Buffers.Binary;
using System.Collections.Generic;
using System.IO;
@ -312,11 +313,6 @@ namespace SixLabors.ImageSharp.Formats.Png
private void CollectGrayscaleBytes<TPixel>(ReadOnlySpan<TPixel> rowSpan)
where TPixel : struct, IPixel<TPixel>
{
// Use ITU-R recommendation 709 to match libpng.
const float RX = .2126F;
const float GX = .7152F;
const float BX = .0722F;
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
Span<byte> rawScanlineSpan = this.rawScanline.GetSpan();
ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan);
@ -327,12 +323,18 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.use16Bit)
{
// 16 bit grayscale
Rgb48 rgb = default;
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2)
using (IMemoryOwner<Gray16> luminanceBuffer = this.memoryAllocator.Allocate<Gray16>(rowSpan.Length))
{
Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb);
ushort luminance = (ushort)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B));
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance);
Span<Gray16> luminanceSpan = luminanceBuffer.GetSpan();
ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan);
PixelOperations<TPixel>.Instance.ToGray16(rowSpan, luminanceSpan, rowSpan.Length);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2)
{
Gray16 luminance = Unsafe.Add(ref luminanceRef, x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue);
}
}
}
else
@ -340,12 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.bitDepth == 8)
{
// 8 bit grayscale
Rgb24 rgb = default;
for (int x = 0; x < rowSpan.Length; x++)
{
Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb);
Unsafe.Add(ref rawScanlineSpanRef, x) = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B));
}
PixelOperations<TPixel>.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length);
}
else
{
@ -356,14 +353,9 @@ namespace SixLabors.ImageSharp.Formats.Png
Span<byte> tempSpan = temp.GetSpan();
ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan);
Rgb24 rgb = default;
for (int x = 0; x < rowSpan.Length; x++)
{
Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb);
float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor;
Unsafe.Add(ref tempSpanRef, x) = (byte)luminance;
this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth);
}
// We need to first create an array of luminance bytes then scale them down to the correct bit depth.
PixelOperations<TPixel>.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length);
this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor);
}
}
}
@ -373,23 +365,31 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.use16Bit)
{
// 16 bit grayscale + alpha
Rgba64 rgba = default;
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4)
// TODO: Should we consider in the future a GrayAlpha32 type.
using (IMemoryOwner<Rgba64> rgbaBuffer = this.memoryAllocator.Allocate<Rgba64>(rowSpan.Length))
{
Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba);
ushort luminance = (ushort)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B));
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A);
Span<Rgba64> rgbaSpan = rgbaBuffer.GetSpan();
ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4)
{
Rgba64 rgba = Unsafe.Add(ref rgbaRef, x);
ushort luminance = ImageMaths.Get16BitBT709Luminance(rgba.R, rgba.G, rgba.B);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A);
}
}
}
else
{
// 8 bit grayscale + alpha
Rgba32 rgba = default;
// TODO: Should we consider in the future a GrayAlpha16 type.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2)
{
Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba);
Unsafe.Add(ref rawScanlineSpanRef, o) = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B));
var rgba = Unsafe.Add(ref rowSpanRef, x).ToRgba32();
Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A;
}
}
@ -425,15 +425,21 @@ namespace SixLabors.ImageSharp.Formats.Png
case 8:
{
// 16 bit Rgba
Rgba64 rgba = default;
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8)
using (IMemoryOwner<Rgba64> rgbaBuffer = this.memoryAllocator.Allocate<Rgba64>(rowSpan.Length))
{
Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A);
Span<Rgba64> rgbaSpan = rgbaBuffer.GetSpan();
ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan);
PixelOperations<TPixel>.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8)
{
Rgba64 rgba = Unsafe.Add(ref rgbaRef, x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A);
}
}
break;
@ -442,14 +448,20 @@ namespace SixLabors.ImageSharp.Formats.Png
default:
{
// 16 bit Rgb
Rgb48 rgb = default;
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6)
using (IMemoryOwner<Rgb48> rgbBuffer = this.memoryAllocator.Allocate<Rgb48>(rowSpan.Length))
{
Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B);
Span<Rgb48> rgbSpan = rgbBuffer.GetSpan();
ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan);
PixelOperations<TPixel>.Instance.ToRgb48(rowSpan, rgbSpan, rowSpan.Length);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6)
{
Rgb48 rgb = Unsafe.Add(ref rgbRef, x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B);
}
}
break;
@ -624,7 +636,6 @@ namespace SixLabors.ImageSharp.Formats.Png
TPixel[] palette = quantized.Palette;
int paletteLength = Math.Min(palette.Length, 256);
int colorTableLength = paletteLength * 3;
Rgba32 rgba = default;
bool anyAlpha = false;
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
@ -639,7 +650,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (quantizedSpan.IndexOf((byte)i) > -1)
{
int offset = i * 3;
palette[i].ToRgba32(ref rgba);
var rgba = palette[i].ToRgba32();
byte alpha = rgba.A;
@ -851,7 +862,8 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="source">The source span in 8 bits.</param>
/// <param name="result">The resultant span in <paramref name="bits"/>.</param>
/// <param name="bits">The bit depth.</param>
private void ScaleDownFrom8BitArray(ReadOnlySpan<byte> source, Span<byte> result, int bits)
/// <param name="scale">The scaling factor.</param>
private void ScaleDownFrom8BitArray(ReadOnlySpan<byte> source, Span<byte> result, int bits, float scale = 1)
{
ref byte sourceRef = ref MemoryMarshal.GetReference(source);
ref byte resultRef = ref MemoryMarshal.GetReference(result);
@ -864,7 +876,7 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int i = 0; i < source.Length; i++)
{
int value = Unsafe.Add(ref sourceRef, i) & mask;
int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask;
v |= value << shift;
if (shift == 0)

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

@ -32,30 +32,19 @@ namespace SixLabors.ImageSharp.Formats.Png
{
if (header.BitDepth == 16)
{
Rgb48 rgb48 = default;
for (int x = 0, o = 0; x < header.Width; x++, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgb48.R = luminance;
rgb48.G = luminance;
rgb48.B = luminance;
pixel.PackFromRgb48(rgb48);
pixel.PackFromGray16(new Gray16(luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else
{
// TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method.
var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = 0; x < header.Width; x++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
pixel.PackFromRgba32(rgba32);
pixel.PackFromGray8(new Gray8(luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -116,30 +105,19 @@ namespace SixLabors.ImageSharp.Formats.Png
{
if (header.BitDepth == 16)
{
Rgb48 rgb48 = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2)
{
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgb48.R = luminance;
rgb48.G = luminance;
rgb48.B = luminance;
pixel.PackFromRgb48(rgb48);
pixel.PackFromGray16(new Gray16(luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
else
{
// TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method.
var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++)
{
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
rgba32.R = luminance;
rgba32.G = luminance;
rgba32.B = luminance;
pixel.PackFromRgba32(rgba32);
pixel.PackFromGray8(new Gray8(luminance));
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -311,14 +289,12 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
// TODO: We should have PackFromRgb24.
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = 0; x < header.Width; x++)
{
int index = Unsafe.Add(ref scanlineSpanRef, x);
rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index);
Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
pixel.PackFromRgba32(rgba);
pixel.PackFromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -358,13 +334,12 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++)
{
int index = Unsafe.Add(ref scanlineSpanRef, o);
rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index);
Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
pixel.PackFromRgba32(rgba);
pixel.PackFromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}
@ -511,14 +486,14 @@ namespace SixLabors.ImageSharp.Formats.Png
}
else
{
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
Rgb24 rgb = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel)
{
rgba.R = Unsafe.Add(ref scanlineSpanRef, o);
rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample);
rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample));
rgb.R = Unsafe.Add(ref scanlineSpanRef, o);
rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample);
rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample));
pixel.PackFromRgba32(rgba);
pixel.PackFromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel;
}
}

14
src/ImageSharp/ImageFrame{TPixel}.cs

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0.
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
@ -289,22 +287,16 @@ namespace SixLabors.ImageSharp
var target = new ImageFrame<TPixel2>(configuration, this.Width, this.Height, this.MetaData.DeepClone());
ParallelHelper.IterateRowsWithTempBuffer<Vector4>(
ParallelHelper.IterateRows(
this.Bounds(),
configuration,
(rows, tempRowBuffer) =>
(rows) =>
{
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> sourceRow = this.GetPixelRowSpan(y);
Span<TPixel2> targetRow = target.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span;
PixelOperations<TPixel>.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length);
PixelOperations<TPixel2>.Instance.PackFromScaledVector4(
tempRowSpan,
targetRow,
targetRow.Length);
PixelOperations<TPixel>.Instance.To(sourceRow, targetRow, sourceRow.Length);
}
});

72
src/ImageSharp/ImageSharp.csproj

@ -76,10 +76,42 @@
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>PixelOperations{TPixel}.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Argb32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Argb32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Bgr24.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Bgr24.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Bgra32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Bgra32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Gray8.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Gray8.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Gray16.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Gray16.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgb24.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgb24.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgb48.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgb48.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgba64.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba64.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.tt">
<LastGenOutput>PorterDuffFunctions.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator>
@ -110,11 +142,51 @@
<AutoGen>True</AutoGen>
<DependentUpon>PixelOperations{TPixel}.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Argb32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Argb32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Bgr24.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Bgr24.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Bgra32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Bgra32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Gray8.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Gray8.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Gray16.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Gray16.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgb24.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgb24.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgb48.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgb48.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgba64.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgba64.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>

171
src/ImageSharp/PixelFormats/Alpha8.cs

@ -18,11 +18,14 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Initializes a new instance of the <see cref="Alpha8"/> struct.
/// </summary>
/// <param name="alpha">The alpha component</param>
public Alpha8(float alpha)
{
this.PackedValue = Pack(alpha);
}
/// <param name="alpha">The alpha component.</param>
public Alpha8(byte alpha) => this.PackedValue = alpha;
/// <summary>
/// Initializes a new instance of the <see cref="Alpha8"/> struct.
/// </summary>
/// <param name="alpha">The alpha component.</param>
public Alpha8(float alpha) => this.PackedValue = Pack(alpha);
/// <inheritdoc />
public byte PackedValue { get; set; }
@ -39,11 +42,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Alpha8 left, Alpha8 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Alpha8"/> objects for equality.
@ -53,161 +53,91 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Alpha8 left, Alpha8 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Alpha8> CreatePixelOperations() => new PixelOperations<Alpha8>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(0, 0, 0, this.PackedValue / 255F);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackedValue = source.A;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackedValue = source.A;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackedValue = source.A;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
dest = default(Rgb24);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
dest.A = this.PackedValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
dest.A = this.PackedValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
dest = default(Bgr24);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
dest.A = this.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(0, 0, 0, this.PackedValue);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest)
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary>
/// Compares an object with the packed vector.
/// </summary>
/// <param name="obj">The object to compare.</param>
/// <returns>True if the object is equal to the packed vector.</returns>
public override bool Equals(object obj)
{
return obj is Alpha8 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is Alpha8 other && this.Equals(other);
/// <summary>
/// Compares another Alpha8 packed vector with the packed vector.
/// </summary>
/// <param name="other">The Alpha8 packed vector to compare.</param>
/// <returns>True if the packed vectors are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Alpha8 other)
{
return this.PackedValue == other.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue);
/// <summary>
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
public override string ToString()
{
return (this.PackedValue / 255F).ToString();
}
public override string ToString() => $"Alpha8({this.PackedValue})";
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
@ -215,10 +145,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
/// <param name="alpha">The float containing the value to pack.</param>
/// <returns>The <see cref="byte"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static byte Pack(float alpha)
{
return (byte)Math.Round(alpha.Clamp(0, 1) * 255F);
}
[MethodImpl(InliningOptions.ShortMethod)]
private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1F) * 255F);
}
}

253
src/ImageSharp/PixelFormats/Argb32.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// as it avoids the need to create new values for modification operations.
/// </remarks>
[StructLayout(LayoutKind.Sequential)]
public struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
{
/// <summary>
/// Gets or sets the alpha component.
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Argb32(byte r, byte g, byte b)
{
this.R = r;
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Argb32(byte r, byte g, byte b, byte a)
{
this.R = r;
@ -89,12 +89,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Argb32(float r, float g, float b, float a = 1)
: this()
{
this.Pack(r, g, b, a);
}
: this() => this.Pack(r, g, b, a);
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -102,12 +99,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Argb32(Vector3 vector)
: this()
{
this.Pack(ref vector);
}
: this() => this.Pack(ref vector);
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -115,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Argb32(Vector4 vector)
: this()
{
this.Pack(ref vector);
}
: this() => this.Pack(ref vector);
/// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -128,22 +119,19 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="packed">
/// The packed value.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Argb32(uint packed)
: this()
{
this.Argb = packed;
}
: this() => this.Argb = packed;
/// <summary>
/// Gets or sets the packed representation of the Argb32 struct.
/// </summary>
public uint Argb
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
get => Unsafe.As<Argb32, uint>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Argb32, uint>(ref this) = value;
}
@ -157,20 +145,13 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="Argb32"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Argb32"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Argb32"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Argb32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Argb32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Argb32 left, Argb32 right)
{
return left.Argb == right.Argb;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Argb32"/> objects for equality.
@ -180,62 +161,44 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Argb32 left, Argb32 right)
{
return left.Argb != right.Argb;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.Pack(ref vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc />
public PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations<Argb32>();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackedValue = source.PackedValue;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
this.R = source.R;
@ -244,136 +207,88 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = source.A;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
this.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
dest = this;
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
}
/// <summary>
/// Converts the pixel to <see cref="Rgba32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Bgra32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Argb32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32 ToArgb32() => this;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
this.A = (byte)(((source.A * 255) + 32895) >> 16);
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is Argb32 argb32 && this.Equals(argb32);
}
public override bool Equals(object obj) => obj is Argb32 argb32 && this.Equals(argb32);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Argb32 other)
{
return this.Argb == other.Argb;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Argb32 other) => this.Argb == other.Argb;
/// <summary>
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
public override string ToString()
{
return $"({this.R},{this.G},{this.B},{this.A})";
}
public override string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})";
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.Argb.GetHashCode();
/// <summary>
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1]
/// </summary>
/// <returns>A <see cref="Vector4"/> of values in [0, 255] </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Vector4 ToByteScaledVector4()
{
return new Vector4(this.R, this.G, this.B, this.A);
}
/// <summary>
/// Packs the four floats into a color.
/// </summary>
@ -381,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(float x, float y, float z, float w)
{
var value = new Vector4(x, y, z, w);
@ -392,7 +307,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packs a <see cref="Vector3"/> into a uint.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector3 vector)
{
var value = new Vector4(vector, 1);
@ -403,7 +318,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packs a <see cref="Vector4"/> into a color.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector4 vector)
{
vector *= MaxBytes;

179
src/ImageSharp/PixelFormats/Bgr24.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para>
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct Bgr24 : IPixel<Bgr24>
public partial struct Bgr24 : IPixel<Bgr24>
{
/// <summary>
/// The blue component.
@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Bgr24(byte r, byte g, byte b)
{
this.R = r;
@ -49,39 +49,54 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = b;
}
/// <summary>
/// Compares two <see cref="Bgr24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Bgr24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgr24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Bgr24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Bgr24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgr24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right);
/// <inheritdoc/>
public PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations<Bgr24>();
public PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Bgr24 other)
{
return this.R == other.R && this.G == other.G && this.B == other.B;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is Bgr24 other && this.Equals(other);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
Rgba32 rgba = default;
rgba.PackFromVector4(vector);
this.PackFromRgba32(rgba);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this = source.Bgr;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.R = source.R;
@ -90,7 +105,11 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this = source;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
this.R = source.R;
@ -99,109 +118,75 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source)
{
return this.ToVector4();
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source)
{
Rgba32 rgba = default;
rgba.PackFromVector4(vector);
this.PackFromRgba32(rgba);
byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
return new Rgba32(this.R, this.G, this.B, 255).ToVector4();
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
this.R = source.R;
this.G = source.G;
this.B = source.B;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this = source.Bgr;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue);
/// <inheritdoc/>
public void ToBgr24(ref Bgr24 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{
dest = this;
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
}
/// <inheritdoc/>
public void ToBgra32(ref Bgra32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgb48(Rgb48 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
public override bool Equals(object obj) => obj is Bgr24 other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
}
/// <inheritdoc />
public override string ToString() => $"Bgra({this.B}, {this.G}, {this.R})";
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override string ToString()
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
return $"({this.B},{this.G},{this.R})";
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
}
}
}

204
src/ImageSharp/PixelFormats/Bgr565.cs

@ -8,7 +8,8 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits.
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1.
/// The x and z components use 5 bits, and the y component uses 6 bits.
/// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
@ -22,8 +23,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
public Bgr565(float x, float y, float z)
: this(new Vector3(x, y, z))
{
this.PackedValue = Pack(x, y, z);
}
/// <summary>
@ -32,10 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector">
/// The vector containing the components for the packed value.
/// </param>
public Bgr565(Vector3 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z);
}
public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
@ -48,11 +46,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgr565 left, Bgr565 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Bgr565"/> objects for equality.
@ -62,183 +57,112 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgr565 left, Bgr565 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Bgr565> CreatePixelOperations() => new PixelOperations<Bgr565>();
/// <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(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3()
{
return new Vector3(
((this.PackedValue >> 11) & 0x1F) * (1F / 31F),
((this.PackedValue >> 5) & 0x3F) * (1F / 63F),
(this.PackedValue & 0x1F) * (1F / 31F));
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z);
var vector3 = new Vector3(vector.X, vector.Y, vector.Z);
this.PackedValue = Pack(ref vector3);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.ToVector3(), 1F);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.ToVector3(), 1F);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
/// <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)]
public Vector3 ToVector3()
{
return obj is Bgr565 other && this.Equals(other);
return new Vector3(
((this.PackedValue >> 11) & 0x1F) * (1F / 31F),
((this.PackedValue >> 5) & 0x3F) * (1F / 63F),
(this.PackedValue & 0x1F) * (1F / 31F));
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Bgr565 other)
{
return this.PackedValue == other.PackedValue;
}
public override bool Equals(object obj) => obj is Bgr565 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString()
{
return this.ToVector3().ToString();
var vector = this.ToVector3();
return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})");
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y, float z)
[MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector3 vector)
{
return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11)
| (((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5)
| ((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F));
vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One);
return (ushort)((((int)Math.Round(vector.X * 31F) & 0x1F) << 11)
| (((int)Math.Round(vector.Y * 63F) & 0x3F) << 5)
| ((int)Math.Round(vector.Z * 31F) & 0x1F));
}
}
}

210
src/ImageSharp/PixelFormats/Bgra32.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
{
/// <summary>
/// Gets or sets the blue component.
@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Bgra32(byte r, byte g, byte b)
{
this.R = r;
@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Bgra32(byte r, byte g, byte b, byte a)
{
this.R = r;
@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public uint Bgra
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
get => Unsafe.As<Bgra32, uint>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Bgra32, uint>(ref this) = value;
}
@ -98,62 +98,50 @@ namespace SixLabors.ImageSharp.PixelFormats
set => this.Bgra = value;
}
/// <inheritdoc/>
public PixelOperations<Bgra32> CreatePixelOperations() => new PixelOperations<Bgra32>();
/// <inheritdoc/>
public bool Equals(Bgra32 other)
{
return this.Bgra == other.Bgra;
}
/// <inheritdoc/>
public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other);
/// <inheritdoc/>
public override int GetHashCode() => this.Bgra.GetHashCode();
/// <summary>
/// Compares two <see cref="Bgra32"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Bgra32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgra32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right);
/// <summary>
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1]
/// Compares two <see cref="Bgra32"/> objects for equality.
/// </summary>
/// <returns>A <see cref="Vector4"/> of values in [0, 255] </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Vector4 ToByteScaledVector4()
{
return new Vector4(this.R, this.G, this.B, this.A);
}
/// <param name="left">The <see cref="Bgra32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgra32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
public PixelOperations<Bgra32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.Pack(ref vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.R = source.R;
this.G = source.G;
@ -162,113 +150,101 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackedValue = source.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this = source;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = source.A;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest) => dest = Unsafe.As<Bgra32, Bgr24>(ref this);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest) => dest = this;
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = byte.MaxValue;
}
/// <summary>
/// Converts the pixel to <see cref="Rgba32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Argb32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Bgra32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32 ToBgra32() => this;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
this.A = (byte)(((source.A * 255) + 32895) >> 16);
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other);
/// <inheritdoc/>
public bool Equals(Bgra32 other) => this.Bgra.Equals(other.Bgra);
/// <inheritdoc/>
public override int GetHashCode() => this.Bgra.GetHashCode();
/// <inheritdoc />
public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})";
/// <summary>
/// Packs a <see cref="Vector4"/> into a color.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector4 vector)
{
vector *= MaxBytes;
@ -280,11 +256,5 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = (byte)vector.Z;
this.A = (byte)vector.W;
}
/// <inheritdoc />
public override string ToString()
{
return $"({this.B},{this.G},{this.R},{this.A})";
}
}
}

186
src/ImageSharp/PixelFormats/Bgra4444.cs

@ -23,18 +23,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
public Bgra4444(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{
this.PackedValue = Pack(x, y, z, w);
}
/// <summary>
/// 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(vector.X, vector.Y, vector.Z, vector.W);
}
public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
@ -47,11 +44,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgra4444 left, Bgra4444 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Bgra4444"/> objects for equality.
@ -61,177 +55,103 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgra4444 left, Bgra4444 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Bgra4444> CreatePixelOperations() => new PixelOperations<Bgra4444>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
const float Max = 1 / 15F;
return new Vector4(
((this.PackedValue >> 8) & 0x0F) * Max,
((this.PackedValue >> 4) & 0x0F) * Max,
(this.PackedValue & 0x0F) * Max,
((this.PackedValue >> 12) & 0x0F) * Max);
(this.PackedValue >> 8) & 0x0F,
(this.PackedValue >> 4) & 0x0F,
this.PackedValue & 0x0F,
(this.PackedValue >> 12) & 0x0F) * Max;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Bgra4444 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Bgra4444 other)
{
return this.PackedValue == other.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString()
{
return this.ToVector4().ToString();
var vector = this.ToVector4();
return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})");
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
/// </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>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y, float z, float w)
[MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector4 vector)
{
return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) |
(((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) |
(((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) |
((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F));
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One);
return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12)
| (((int)Math.Round(vector.X * 15F) & 0x0F) << 8)
| (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4)
| ((int)Math.Round(vector.Z * 15F) & 0x0F));
}
}
}
}

194
src/ImageSharp/PixelFormats/Bgra5551.cs

@ -8,7 +8,8 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit.
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1.
/// The x , y and z components use 5 bits, and the w component uses 1 bit.
/// <para>
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para>
@ -23,8 +24,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
public Bgra5551(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{
this.PackedValue = Pack(x, y, z, w);
}
/// <summary>
@ -33,10 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
public Bgra5551(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
@ -49,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Bgra5551 left, Bgra5551 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Bgra5551"/> objects for equality.
@ -63,31 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Bgra5551 left, Bgra5551 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Bgra5551> CreatePixelOperations() => new PixelOperations<Bgra5551>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
return new Vector4(
@ -98,150 +88,72 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Bgra5551 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Bgra5551 other)
{
return this.PackedValue == other.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue);
/// <summary>
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
/// <inheritdoc />
public override string ToString()
{
return this.ToVector4().ToString();
var vector = this.ToVector4();
return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})");
}
/// <summary>
/// Gets a hash code of the packed vector.
/// </summary>
/// <returns>The hash code for the packed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
/// </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>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y, float z, float w)
[MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(ref Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One);
return (ushort)(
(((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 10)
| (((int)Math.Round(y.Clamp(0, 1) * 31F) & 0x1F) << 5)
| (((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0)
| (((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15));
(((int)Math.Round(vector.X * 31F) & 0x1F) << 10)
| (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5)
| (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0)
| (((int)Math.Round(vector.W) & 0x1) << 15));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4() => this.ToVector4() * 255f;
}
}
}

168
src/ImageSharp/PixelFormats/Byte4.cs

@ -21,10 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <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);
}
public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <summary>
/// Initializes a new instance of the <see cref="Byte4"/> struct.
@ -50,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Byte4 left, Byte4 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Byte4"/> objects for equality.
@ -64,38 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Byte4 left, Byte4 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Byte4> CreatePixelOperations() => new PixelOperations<Byte4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector * 255F);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector * 255F);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4() / 255F;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4() / 255F;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(ref vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
return new Vector4(
@ -106,119 +88,61 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToByteScaledVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToByteScaledVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToByteScaledVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Byte4 byte4 && this.Equals(byte4);
}
public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Byte4 other)
{
return this == other;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Returns a string representation of the current instance.
/// </summary>
/// <returns>String that represents the object.</returns>
/// <inheritdoc />
public override string ToString()
{
return this.PackedValue.ToString("x8");
var vector = this.ToVector4();
return FormattableString.Invariant($"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
/// <summary>
@ -226,18 +150,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(ref Vector4 vector)
{
const float Max = 255F;
const float Min = 0F;
// Clamp the value between min and max values
// TODO: Use Vector4.Clamp() here!
uint byte4 = (uint)Math.Round(vector.X.Clamp(Min, Max)) & 0xFF;
uint byte3 = ((uint)Math.Round(vector.Y.Clamp(Min, Max)) & 0xFF) << 0x8;
uint byte2 = ((uint)Math.Round(vector.Z.Clamp(Min, Max)) & 0xFF) << 0x10;
uint byte1 = ((uint)Math.Round(vector.W.Clamp(Min, Max)) & 0xFF) << 0x18;
vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max));
uint byte4 = (uint)Math.Round(vector.X) & 0xFF;
uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8;
uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10;
uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18;
return byte4 | byte3 | byte2 | byte1;
}

177
src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Argb32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Argb32>
{
/// <inheritdoc />
internal override void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<Argb32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Argb32> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Argb32> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Argb32> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Argb32> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Argb32> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Argb32> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Argb32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Argb32> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Argb32> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Argb32> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Argb32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Argb32>
{
/// <inheritdoc />
internal override void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<Argb32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Argb32> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgr24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgr24>
{
/// <inheritdoc />
internal override void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<Bgr24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Bgr24> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Bgr24> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Bgr24> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Bgr24> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgr24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgr24>
{
/// <inheritdoc />
internal override void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<Bgr24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgra32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgra32>
{
/// <inheritdoc />
internal override void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<Bgra32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Bgra32> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Bgra32> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Bgra32> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Bgra32> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgra32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgra32>
{
/// <inheritdoc />
internal override void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<Bgra32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray16
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray16>
{
/// <inheritdoc />
internal override void PackFromGray16(ReadOnlySpan<Gray16> source, Span<Gray16> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray16> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Gray16> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Gray16> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Gray16> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray16> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Gray16> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Gray16> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Gray16> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Gray16> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Gray16> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray16
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray16>
{
/// <inheritdoc />
internal override void PackFromGray16(ReadOnlySpan<Gray16> source, Span<Gray16> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray16> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray8
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray8>
{
/// <inheritdoc />
internal override void PackFromGray8(ReadOnlySpan<Gray8> source, Span<Gray8> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray8> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Gray8> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Gray8> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Gray8> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray8> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Gray8> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Gray8> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Gray8> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Gray8> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Gray8> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray8
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray8>
{
/// <inheritdoc />
internal override void PackFromGray8(ReadOnlySpan<Gray8> source, Span<Gray8> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray8> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

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

@ -10,296 +10,357 @@ namespace SixLabors.ImageSharp.PixelFormats
public partial class PixelOperations<TPixel>
{
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgba64"/> data to a span of <typeparamref name="TPixel"/>-s.
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Argb32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba64"/> data.</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Argb32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<TPixel> destPixels, int count)
internal virtual void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba64>.Black;
ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
temp = Unsafe.Add(ref sourceRef, i);
dp.PackFromRgba64(temp);
ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromArgb32(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromRgba64(ReadOnlySpan{Rgba64}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba64"/> layout.
/// <summary>
/// A helper for <see cref="PackFromArgb32(ReadOnlySpan{Argb32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Argb32"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgba64Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void PackFromArgb32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromRgba64(MemoryMarshal.Cast<byte, Rgba64>(sourceBytes), destPixels, count);
this.PackFromArgb32(MemoryMarshal.Cast<byte, Argb32>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba64"/>-s.
/// Bulk version of <see cref="IPixel.ToRgba64(ref Rgba64)"/>.
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Argb32"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgba64"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="Argb32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgba64(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba64> dest, int count)
internal virtual void ToArgb32(ReadOnlySpan<TPixel> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest);
ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgba64(ref dp);
ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="ToRgba64(ReadOnlySpan{TPixel}, Span{Rgba64}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba64"/> layout.
/// <summary>
/// A helper for <see cref="ToArgb32(ReadOnlySpan{TPixel}, Span{Argb32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Argb32"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba64Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToArgb32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgba64(sourceColors, MemoryMarshal.Cast<byte, Rgba64>(destBytes), count);
this.ToArgb32(sourcePixels, MemoryMarshal.Cast<byte, Argb32>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgb48"/> data to a span of <typeparamref name="TPixel"/>-s.
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Bgr24"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb48"/> data.</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<TPixel> destPixels, int count)
internal virtual void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgb48>.Black;
ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
temp = Unsafe.Add(ref sourceRef, i);
dp.PackFromRgb48(temp);
ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromBgr24(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromRgb48(ReadOnlySpan{Rgb48}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb48"/> layout.
/// <summary>
/// A helper for <see cref="PackFromBgr24(ReadOnlySpan{Bgr24}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgb48Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void PackFromBgr24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromRgb48(MemoryMarshal.Cast<byte, Rgb48>(sourceBytes), destPixels, count);
this.PackFromBgr24(MemoryMarshal.Cast<byte, Bgr24>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb48"/>-s.
/// Bulk version of <see cref="IPixel.ToRgb48(ref Rgb48)"/>.
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgr24"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgb48"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="Bgr24"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgb48(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb48> dest, int count)
internal virtual void ToBgr24(ReadOnlySpan<TPixel> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(dest);
ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgb48(ref dp);
ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="ToRgb48(ReadOnlySpan{TPixel}, Span{Rgb48}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb48"/> layout.
/// <summary>
/// A helper for <see cref="ToBgr24(ReadOnlySpan{TPixel}, Span{Bgr24}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb48Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgr24Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgb48(sourceColors, MemoryMarshal.Cast<byte, Rgb48>(destBytes), count);
this.ToBgr24(sourcePixels, MemoryMarshal.Cast<byte, Bgr24>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgba32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Bgra32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<TPixel> destPixels, int count)
internal virtual void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba32>.Black;
ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
temp = Unsafe.Add(ref sourceRef, i);
dp.PackFromRgba32(temp);
ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromBgra32(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromRgba32(ReadOnlySpan{Rgba32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout.
/// <summary>
/// A helper for <see cref="PackFromBgra32(ReadOnlySpan{Bgra32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgba32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void PackFromBgra32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromRgba32(MemoryMarshal.Cast<byte, Rgba32>(sourceBytes), destPixels, count);
this.PackFromBgra32(MemoryMarshal.Cast<byte, Bgra32>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba32"/>-s.
/// Bulk version of <see cref="IPixel.ToRgba32(ref Rgba32)"/>.
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgra32"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgba32"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="Bgra32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgba32(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba32> dest, int count)
internal virtual void ToBgra32(ReadOnlySpan<TPixel> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(dest);
ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgba32(ref dp);
ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="ToRgba32(ReadOnlySpan{TPixel}, Span{Rgba32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout.
/// <summary>
/// A helper for <see cref="ToBgra32(ReadOnlySpan{TPixel}, Span{Bgra32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgra32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgba32(sourceColors, MemoryMarshal.Cast<byte, Rgba32>(destBytes), count);
this.ToBgra32(sourcePixels, MemoryMarshal.Cast<byte, Bgra32>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Bgra32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Gray8"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Gray8"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<TPixel> destPixels, int count)
internal virtual void PackFromGray8(ReadOnlySpan<Gray8> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Bgra32>.Black;
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromGray8(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromGray8(ReadOnlySpan{Gray8}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Gray8"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromGray8Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromGray8(MemoryMarshal.Cast<byte, Gray8>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Gray8"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Gray8"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToGray8(ReadOnlySpan<TPixel> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
temp = Unsafe.Add(ref sourceRef, i);
dp.PackFromBgra32(temp);
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="PackFromBgra32(ReadOnlySpan{Bgra32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout.
/// <summary>
/// A helper for <see cref="ToGray8(ReadOnlySpan{TPixel}, Span{Gray8}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Gray8"/> layout.
/// </summary>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToGray8Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToGray8(sourcePixels, MemoryMarshal.Cast<byte, Gray8>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Gray16"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Gray16"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromGray16(ReadOnlySpan<Gray16> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromGray16(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromGray16(ReadOnlySpan{Gray16}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Gray16"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromBgra32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void PackFromGray16Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromBgra32(MemoryMarshal.Cast<byte, Bgra32>(sourceBytes), destPixels, count);
this.PackFromGray16(MemoryMarshal.Cast<byte, Gray16>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgra32"/>-s.
/// Bulk version of <see cref="IPixel.ToBgra32(ref Bgra32)"/>.
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Gray16"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Bgra32"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="Gray16"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToBgra32(ReadOnlySpan<TPixel> sourcePixels, Span<Bgra32> dest, int count)
internal virtual void ToGray16(ReadOnlySpan<TPixel> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(dest);
ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToBgra32(ref dp);
ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="ToBgra32(ReadOnlySpan{TPixel}, Span{Bgra32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout.
/// <summary>
/// A helper for <see cref="ToGray16(ReadOnlySpan{TPixel}, Span{Gray16}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Gray16"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgra32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToGray16Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToBgra32(sourceColors, MemoryMarshal.Cast<byte, Bgra32>(destBytes), count);
this.ToGray16(sourcePixels, MemoryMarshal.Cast<byte, Gray16>(destBytes), count);
}
/// <summary>
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgb24"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb24"/> data.</param>
@ -307,23 +368,21 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba32>.Black;
ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
temp.Rgb = Unsafe.Add(ref sourceRef, i);
dp.PackFromRgba32(temp);
ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgb24(sp);
}
}
/// <summary>
/// <summary>
/// A helper for <see cref="PackFromRgb24(ReadOnlySpan{Rgb24}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary>
@ -335,186 +394,250 @@ namespace SixLabors.ImageSharp.PixelFormats
{
this.PackFromRgb24(MemoryMarshal.Cast<byte, Rgb24>(sourceBytes), destPixels, count);
}
/// <summary>
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb24"/>-s.
/// Bulk version of <see cref="IPixel.ToRgb24(ref Rgb24)"/>.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgb24"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="Rgb24"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgb24(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb24> dest, int count)
internal virtual void ToRgb24(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(dest);
ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgb24(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// <summary>
/// A helper for <see cref="ToRgb24(ReadOnlySpan{TPixel}, Span{Rgb24}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb24Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb24Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgb24(sourceColors, MemoryMarshal.Cast<byte, Rgb24>(destBytes), count);
this.ToRgb24(sourcePixels, MemoryMarshal.Cast<byte, Rgb24>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Bgr24"/> data to a span of <typeparamref name="TPixel"/>-s.
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgba32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<TPixel> destPixels, int count)
internal virtual void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba32>.Black;
ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
temp.Bgr = Unsafe.Add(ref sourceRef, i);
dp.PackFromRgba32(temp);
ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgba32(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromBgr24(ReadOnlySpan{Bgr24}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout.
/// <summary>
/// A helper for <see cref="PackFromRgba32(ReadOnlySpan{Rgba32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromBgr24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void PackFromRgba32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromBgr24(MemoryMarshal.Cast<byte, Bgr24>(sourceBytes), destPixels, count);
this.PackFromRgba32(MemoryMarshal.Cast<byte, Rgba32>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgr24"/>-s.
/// Bulk version of <see cref="IPixel.ToBgr24(ref Bgr24)"/>.
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba32"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Bgr24"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="Rgba32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToBgr24(ReadOnlySpan<TPixel> sourcePixels, Span<Bgr24> dest, int count)
internal virtual void ToRgba32(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(dest);
ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToBgr24(ref dp);
ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="ToBgr24(ReadOnlySpan{TPixel}, Span{Bgr24}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout.
/// <summary>
/// A helper for <see cref="ToRgba32(ReadOnlySpan{TPixel}, Span{Rgba32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgr24Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToBgr24(sourceColors, MemoryMarshal.Cast<byte, Bgr24>(destBytes), count);
this.ToRgba32(sourcePixels, MemoryMarshal.Cast<byte, Rgba32>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Argb32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgb48"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Argb32"/> data.</param>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb48"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<TPixel> destPixels, int count)
internal virtual void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Argb32>.Black;
ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
temp = Unsafe.Add(ref sourceRef, i);
dp.PackFromArgb32(temp);
ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgb48(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromArgb32(ReadOnlySpan{Argb32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Argb32"/> layout.
/// <summary>
/// A helper for <see cref="PackFromRgb48(ReadOnlySpan{Rgb48}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb48"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromArgb32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
internal void PackFromRgb48Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromArgb32(MemoryMarshal.Cast<byte, Argb32>(sourceBytes), destPixels, count);
this.PackFromRgb48(MemoryMarshal.Cast<byte, Rgb48>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Argb32"/>-s.
/// Bulk version of <see cref="IPixel.ToArgb32(ref Argb32)"/>.
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb48"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Argb32"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="Rgb48"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToArgb32(ReadOnlySpan<TPixel> sourcePixels, Span<Argb32> dest, int count)
internal virtual void ToRgb48(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(dest);
ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToArgb32(ref dp);
ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// A helper for <see cref="ToArgb32(ReadOnlySpan{TPixel}, Span{Argb32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Argb32"/> layout.
/// <summary>
/// A helper for <see cref="ToRgb48(ReadOnlySpan{TPixel}, Span{Rgb48}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb48"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToArgb32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb48Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgb48(sourcePixels, MemoryMarshal.Cast<byte, Rgb48>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgba64"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba64"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgba64(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromRgba64(ReadOnlySpan{Rgba64}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba64"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgba64Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromRgba64(MemoryMarshal.Cast<byte, Rgba64>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba64"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Rgba64"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgba64(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba64> destPixels, int count)
{
this.ToArgb32(sourceColors, MemoryMarshal.Cast<byte, Argb32>(destBytes), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
}
/// <summary>
/// A helper for <see cref="ToRgba64(ReadOnlySpan{TPixel}, Span{Rgba64}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba64"/> layout.
/// </summary>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba64Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgba64(sourcePixels, MemoryMarshal.Cast<byte, Rgba64>(destBytes), count);
}
}
}

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

@ -11,11 +11,11 @@
<#@ output extension=".cs" #>
<#
void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode)
void GeneratePackFromMethods(string pixelType)
{
#>
/// <summary>
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="<#=pixelType#>"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="<#=pixelType#>"/> data.</param>
@ -23,23 +23,21 @@
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<<#=tempPixelType#>>.Black;
ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel dp = ref Unsafe.Add(ref destRef, i);
<#=assignToTempCode#>
dp.PackFrom<#=tempPixelType#>(temp);
ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFrom<#=pixelType#>(sp);
}
}
/// <summary>
/// <summary>
/// A helper for <see cref="PackFrom<#=pixelType#>(ReadOnlySpan{<#=pixelType#>}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary>
@ -51,48 +49,48 @@
{
this.PackFrom<#=pixelType#>(MemoryMarshal.Cast<byte, <#=pixelType#>>(sourceBytes), destPixels, count);
}
<#
<#
}
void GenerateToDestFormatMethods(string pixelType)
{
#>
/// <summary>
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="<#=pixelType#>"/>-s.
/// Bulk version of <see cref="IPixel.To<#=pixelType#>(ref <#=pixelType#>)"/>.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="<#=pixelType#>"/> data.</param>
/// <param name="destPixels">The destination span of <see cref="<#=pixelType#>"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void To<#=pixelType#>(ReadOnlySpan<TPixel> sourcePixels, Span<<#=pixelType#>> dest, int count)
internal virtual void To<#=pixelType#>(ReadOnlySpan<TPixel> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest);
ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i);
sp.To<#=pixelType#>(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// <summary>
/// A helper for <see cref="To<#=pixelType#>(ReadOnlySpan{TPixel}, Span{<#=pixelType#>}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void To<#=pixelType#>Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count)
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void To<#=pixelType#>Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast<byte, <#=pixelType#>>(destBytes), count);
this.To<#=pixelType#>(sourcePixels, MemoryMarshal.Cast<byte, <#=pixelType#>>(destBytes), count);
}
<#
<#
}
#>
@ -107,30 +105,34 @@ namespace SixLabors.ImageSharp.PixelFormats
using System.Runtime.InteropServices;
public partial class PixelOperations<TPixel>
{
<#
GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);");
GenerateToDestFormatMethods("Rgba64");
{<#
GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);");
GenerateToDestFormatMethods("Rgb48");
GeneratePackFromMethods("Argb32");
GenerateToDestFormatMethods("Argb32");
GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);");
GenerateToDestFormatMethods("Rgba32");
GeneratePackFromMethods("Bgr24");
GenerateToDestFormatMethods("Bgr24");
GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);");
GeneratePackFromMethods("Bgra32");
GenerateToDestFormatMethods("Bgra32");
GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);");
GeneratePackFromMethods("Gray8");
GenerateToDestFormatMethods("Gray8");
GeneratePackFromMethods("Gray16");
GenerateToDestFormatMethods("Gray16");
GeneratePackFromMethods("Rgb24");
GenerateToDestFormatMethods("Rgb24");
GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);");
GenerateToDestFormatMethods("Bgr24");
GeneratePackFromMethods("Rgba32");
GenerateToDestFormatMethods("Rgba32");
GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);");
GenerateToDestFormatMethods("Argb32");
#>
GeneratePackFromMethods("Rgb48");
GenerateToDestFormatMethods("Rgb48");
}
GeneratePackFromMethods("Rgba64");
GenerateToDestFormatMethods("Rgba64");
#> }
}

177
src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb24>
{
/// <inheritdoc />
internal override void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgb24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgb24> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgb24> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgb24> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgb24> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgb24> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgb24> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb24>
{
/// <inheritdoc />
internal override void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgb24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb48
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb48>
{
/// <inheritdoc />
internal override void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<Rgb48> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgb48> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgb48> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgb48> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgb48> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgb48> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgb48> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb48
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb48>
{
/// <inheritdoc />
internal override void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<Rgb48> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

124
src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs

@ -13,134 +13,162 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </content>
public partial struct Rgba32
{
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
internal partial class PixelOperations
{
/// <inheritdoc />
internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgba32> destPixels, int count)
internal override void ToArgb32(ReadOnlySpan<Rgba32> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
Unsafe.As<Rgba32, Rgb24>(ref dp) = sp; dp.A = 255;
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb24> dest, int count)
internal override void ToBgr24(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(dest);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp = Unsafe.As<Rgba32, Rgb24>(ref sp);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}
/// <inheritdoc />
internal override void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<Rgba32> destPixels, int count)
internal override void ToBgra32(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.Bgr = sp; dp.A = 255;
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgr24> dest, int count)
internal override void ToGray8(ReadOnlySpan<Rgba32> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(dest);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.Bgr;
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}
/// <inheritdoc />
internal override void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<Rgba32> destPixels, int count)
internal override void ToGray16(ReadOnlySpan<Rgba32> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToRgba32();
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> dest, int count)
internal override void ToRgb24(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(dest);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToBgra32();
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}
/// <inheritdoc />
internal override void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<Rgba32> destPixels, int count)
internal override void ToRgb48(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToRgba32();
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgba32> sourcePixels, Span<Argb32> dest, int count)
internal override void ToRgba64(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(dest);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToArgb32();
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba32(sp);
}
}

70
src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt

@ -9,45 +9,24 @@
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GeneratePackFromMethod(string pixelType, string converterCode)
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<Rgba32> destPixels, int count)
internal override void To<#=pixelType#>(ReadOnlySpan<Rgba32> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
<#=converterCode#>
}
}
<#
}
void GenerateConvertToMethod(string pixelType, string converterCode)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgba32> sourcePixels, Span<<#=pixelType#>> dest, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(dest);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
<#=converterCode#>
dp.PackFromRgba32(sp);
}
}
<#
@ -68,20 +47,37 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </content>
public partial struct Rgba32
{
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
internal partial class PixelOperations
{
<#
GeneratePackFromMethod("Rgb24", "Unsafe.As<Rgba32, Rgb24>(ref dp) = sp; dp.A = 255;");
GenerateConvertToMethod("Rgb24", "dp = Unsafe.As<Rgba32, Rgb24>(ref sp);");
/// <inheritdoc />
internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;");
GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;");
GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();");
GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();");
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
GeneratePackFromMethod("Argb32", "dp = sp.ToRgba32();");
GenerateConvertToMethod("Argb32", "dp = sp.ToArgb32();");
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}

177
src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgba64
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgba64>
{
/// <inheritdoc />
internal override void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<Rgba64> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgba64> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgba64> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgba64> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgba64> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgba64> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgba64> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgba64
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgba64>
{
/// <inheritdoc />
internal override void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<Rgba64> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Gray16.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Packed pixel type containing a single 16 bit normalized gray values.
/// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public partial struct Gray16 : IPixel<Gray16>, IPackedVector<ushort>
{
private const float Max = ushort.MaxValue;
private const float Average = 1 / 3F;
/// <summary>
/// Initializes a new instance of the <see cref="Gray16"/> struct.
/// </summary>
/// <param name="luminance">The luminance component</param>
public Gray16(ushort luminance) => this.PackedValue = luminance;
/// <inheritdoc />
public ushort PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="Gray16"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray16"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray16"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Gray16 left, Gray16 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Gray16"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray16"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray16"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Gray16> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average;
this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
float scaled = this.PackedValue / Max;
return new Vector4(scaled, scaled, scaled, 1F);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue;
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32()
{
byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue);
return new Rgba32(rgb, rgb, rgb, byte.MaxValue);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Gray16 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString() => $"Gray16({this.PackedValue})";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
(ushort)MathF.Round(vector.X),
(ushort)MathF.Round(vector.Y),
(ushort)MathF.Round(vector.Z));
}
}
}

152
src/ImageSharp/PixelFormats/Gray8.cs

@ -0,0 +1,152 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Packed pixel type containing a single 8 bit normalized gray values.
/// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public partial struct Gray8 : IPixel<Gray8>, IPackedVector<byte>
{
private static readonly Vector4 MaxBytes = new Vector4(255F);
private static readonly Vector4 Half = new Vector4(0.5F);
private const float Average = 1 / 3F;
/// <summary>
/// Initializes a new instance of the <see cref="Gray8"/> struct.
/// </summary>
/// <param name="luminance">The luminance component.</param>
public Gray8(byte luminance) => this.PackedValue = luminance;
/// <inheritdoc />
public byte PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="Gray8"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray8"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray8"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Gray8 left, Gray8 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Gray8"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray8"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray8"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Gray8> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes) * Average;
this.PackedValue = (byte)(vector.X + vector.Y + vector.Z);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
float rgb = this.PackedValue / 255F;
return new Vector4(rgb, rgb, rgb, 1F);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.PackedValue, this.PackedValue, this.PackedValue, byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
=> this.PackedValue = ImageMaths.Get8BitBT709Luminance(
ImageMaths.DownScaleFrom16BitTo8Bit(source.R),
ImageMaths.DownScaleFrom16BitTo8Bit(source.G),
ImageMaths.DownScaleFrom16BitTo8Bit(source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
=> this.PackedValue = ImageMaths.Get8BitBT709Luminance(
ImageMaths.DownScaleFrom16BitTo8Bit(source.R),
ImageMaths.DownScaleFrom16BitTo8Bit(source.G),
ImageMaths.DownScaleFrom16BitTo8Bit(source.B));
/// <inheritdoc />
public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString() => $"Gray8({this.PackedValue}";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z);
}
}
}

202
src/ImageSharp/PixelFormats/HalfSingle.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -14,24 +15,11 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct HalfSingle : IPixel<HalfSingle>, IPackedVector<ushort>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="HalfSingle"/> struct.
/// </summary>
/// <param name="single">The single component.</param>
public HalfSingle(float single)
{
this.PackedValue = HalfTypeHelper.Pack(single);
}
public HalfSingle(float single) => this.PackedValue = HalfTypeHelper.Pack(single);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
@ -39,206 +27,114 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="HalfSingle"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="HalfSingle"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="HalfSingle"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="HalfSingle"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HalfSingle"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(HalfSingle left, HalfSingle right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="HalfSingle"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="HalfSingle"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="HalfSingle"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="HalfSingle"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HalfSingle"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HalfSingle left, HalfSingle right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<HalfSingle> CreatePixelOperations() => new PixelOperations<HalfSingle>();
/// <summary>
/// Expands the packed representation into a <see cref="float"/>.
/// </summary>
/// <returns>The <see cref="float"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float ToSingle()
{
return HalfTypeHelper.Unpack(this.PackedValue);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
float scaled = vector.X;
scaled *= 2F;
scaled -= 1F;
scaled--;
this.PackedValue = HalfTypeHelper.Pack(scaled);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
float single = this.ToSingle() + 1F;
single /= 2F;
return new Vector4(single, 0, 0, 1);
return new Vector4(single, 0, 0, 1F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = HalfTypeHelper.Pack(vector.X);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.ToSingle(), 0, 0, 1);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.ToSingle(), 0, 0, 1F);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary>
/// Expands the packed representation into a <see cref="float"/>.
/// </summary>
/// <returns>The <see cref="float"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue);
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is HalfSingle other && this.Equals(other);
}
public override bool Equals(object obj) => obj is HalfSingle other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(HalfSingle other)
{
return this.PackedValue == other.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString()
{
return this.ToSingle().ToString();
}
public override string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})");
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
}
}

12
src/ImageSharp/PixelFormats/HalfTypeHelper.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Helper methods for packing and unpacking floating point values
/// </summary>
internal class HalfTypeHelper
internal static class HalfTypeHelper
{
/// <summary>
/// Packs a <see cref="float"/> into an <see cref="ushort"/>
@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats
return (ushort)s;
}
m = m | 0x00800000;
m |= 0x00800000;
int t = 14 - e;
int a = (1 << (t - 1)) - 1;
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.PixelFormats
if ((m & 0x00800000) != 0)
{
m = 0;
e += 1;
e++;
}
if (e > 30)
@ -97,11 +97,11 @@ namespace SixLabors.ImageSharp.PixelFormats
while ((mantissa & 1024) == 0)
{
exponent--;
mantissa = mantissa << 1;
mantissa <<= 1;
}
mantissa &= 0xfffffbff;
result = ((uint)((((uint)value & 0x8000) << 16) | ((exponent + 127) << 23))) | (mantissa << 13);
result = (((uint)value & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13);
}
else
{
@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
else
{
result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13);
result = (((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23) | (mantissa << 13);
}
var uif = new Uif { U = result };

216
src/ImageSharp/PixelFormats/HalfVector2.cs

@ -15,34 +15,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="HalfVector2"/> struct.
/// </summary>
/// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param>
public HalfVector2(float x, float y)
{
this.PackedValue = Pack(x, y);
}
public HalfVector2(float x, float y) => this.PackedValue = Pack(x, y);
/// <summary>
/// Initializes a new instance of the <see cref="HalfVector2"/> struct.
/// </summary>
/// <param name="vector">A vector containing the initial values for the components.</param>
public HalfVector2(Vector2 vector)
{
this.PackedValue = Pack(vector.X, vector.Y);
}
public HalfVector2(Vector2 vector) => this.PackedValue = Pack(vector.X, vector.Y);
/// <inheritdoc/>
public uint PackedValue { get; set; }
@ -50,57 +34,30 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="HalfVector2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="HalfVector2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HalfVector2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(HalfVector2 left, HalfVector2 right)
{
return left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="HalfVector2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="HalfVector2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HalfVector2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HalfVector2 left, HalfVector2 right)
{
return !left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<HalfVector2> CreatePixelOperations() => new PixelOperations<HalfVector2>();
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 ToVector2()
{
Vector2 vector;
vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue);
vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10));
return vector;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
@ -109,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
@ -119,14 +76,11 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
var vector = this.ToVector2();
@ -134,140 +88,82 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override string ToString()
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2()
{
return this.ToVector2().ToString();
Vector2 vector;
vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue);
vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10));
return vector;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
public override bool Equals(object obj) => obj is HalfVector2 other && this.Equals(other);
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is HalfVector2 other && this.Equals(other);
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(HalfVector2 other)
public override string ToString()
{
return this.PackedValue.Equals(other.PackedValue);
var vector = this.ToVector2();
return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})");
}
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(float x, float y)
{
uint num2 = HalfTypeHelper.Pack(x);
uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10);
return num2 | num;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
}
}

188
src/ImageSharp/PixelFormats/HalfVector4.cs

@ -15,16 +15,6 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="HalfVector4"/> struct.
/// </summary>
@ -33,64 +23,46 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param>
public HalfVector4(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="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(ref vector);
/// <inheritdoc/>
public ulong PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality.
/// Compares two <see cref="HalfVector4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="HalfVector2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="HalfVector4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HalfVector4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(HalfVector4 left, HalfVector4 right)
{
return left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality.
/// Compares two <see cref="HalfVector4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="HalfVector2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="HalfVector4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HalfVector4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HalfVector4 left, HalfVector4 right)
{
return !left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<HalfVector4> CreatePixelOperations() => new PixelOperations<HalfVector4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 2F;
@ -99,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
@ -109,14 +81,11 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(ref vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
return new Vector4(
@ -127,124 +96,69 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override string ToString()
{
return this.ToVector4().ToString();
}
public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override bool Equals(object obj)
public override string ToString()
{
return obj is HalfVector4 other && this.Equals(other);
var vector = this.ToVector4();
return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(HalfVector4 other)
{
return this.PackedValue.Equals(other.PackedValue);
}
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Packs a <see cref="Vector4"/> into a <see cref="ulong"/>.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private static ulong Pack(ref Vector4 vector)
{
ulong num4 = HalfTypeHelper.Pack(vector.X);
@ -253,15 +167,5 @@ namespace SixLabors.ImageSharp.PixelFormats
ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30;
return num4 | num3 | num2 | num1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
}
}

78
src/ImageSharp/PixelFormats/IPixel.cs

@ -28,12 +28,6 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public interface IPixel
{
/// <summary>
/// Sets the packed representation from a <see cref="Vector4"/>.
/// </summary>
/// <param name="vector">The vector to create the packed representation from.</param>
void PackFromVector4(Vector4 vector);
/// <summary>
/// Sets the packed representation from a scaled <see cref="Vector4"/>.
/// </summary>
@ -48,6 +42,12 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToScaledVector4();
/// <summary>
/// Sets the packed representation from a <see cref="Vector4"/>.
/// </summary>
/// <param name="vector">The vector to create the packed representation from.</param>
void PackFromVector4(Vector4 vector);
/// <summary>
/// Expands the packed representation into a <see cref="Vector4"/>.
/// The vector components are typically expanded in least to greatest significance order.
@ -55,30 +55,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToVector4();
/// <summary>
/// Packs the pixel from an <see cref="Rgba32"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgba32"/> value.</param>
void PackFromRgba32(Rgba32 source);
/// <summary>
/// Packs the pixel from an <see cref="Rgb48"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgb48"/> value.</param>
void PackFromRgb48(Rgb48 source);
/// <summary>
/// Packs the pixel from an <see cref="Rgba64"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgba64"/> value.</param>
void PackFromRgba64(Rgba64 source);
/// <summary>
/// Packs the pixel from an <see cref="Argb32"/> value.
/// </summary>
/// <param name="source">The <see cref="Argb32"/> value.</param>
void PackFromArgb32(Argb32 source);
/// <summary>
/// Packs the pixel from an <see cref="Bgr24"/> value.
/// </summary>
/// <param name="source">The <see cref="Bgr24"/> value.</param>
void PackFromBgr24(Bgr24 source);
/// <summary>
/// Packs the pixel from an <see cref="Bgra32"/> value.
/// </summary>
@ -86,45 +74,45 @@ namespace SixLabors.ImageSharp.PixelFormats
void PackFromBgra32(Bgra32 source);
/// <summary>
/// Converts the pixel to <see cref="Rgb24"/> format.
/// Packs the Pixel from an <see cref="Gray8"/> value.
/// </summary>
/// <param name="dest">The destination pixel to write to</param>
void ToRgb24(ref Rgb24 dest);
/// <param name="source">The <see cref="Gray8"/> value.</param>
void PackFromGray8(Gray8 source);
/// <summary>
/// Converts the pixel to <see cref="Rgba32"/> format.
/// Packs the Pixel from an <see cref="Gray16"/> value.
/// </summary>
/// <param name="dest">The destination pixel to write to</param>
void ToRgba32(ref Rgba32 dest);
/// <param name="source">The <see cref="Gray16"/> value.</param>
void PackFromGray16(Gray16 source);
/// <summary>
/// Converts the pixel to <see cref="Rgb48"/> format.
/// Packs the pixel from an <see cref="Rgb24"/> value.
/// </summary>
/// <param name="dest">The destination pixel to write to</param>
void ToRgb48(ref Rgb48 dest);
/// <param name="source">The <see cref="Rgb24"/> value.</param>
void PackFromRgb24(Rgb24 source);
/// <summary>
/// Converts the pixel to <see cref="Rgba64"/> format.
/// Packs the pixel from an <see cref="Rgba32"/> value.
/// </summary>
/// <param name="dest">The destination pixel to write to</param>
void ToRgba64(ref Rgba64 dest);
/// <param name="source">The <see cref="Rgba32"/> value.</param>
void PackFromRgba32(Rgba32 source);
/// <summary>
/// Converts the pixel to <see cref="Argb32"/> format.
/// Expands the packed representation into an <see cref="Rgba32"/>.
/// </summary>
/// <param name="dest">The destination pixel to write to</param>
void ToArgb32(ref Argb32 dest);
/// <returns>The <see cref="Rgba32"/>.</returns>
Rgba32 ToRgba32();
/// <summary>
/// Converts the pixel to <see cref="Bgr24"/> format.
/// Packs the pixel from an <see cref="Rgb48"/> value.
/// </summary>
/// <param name="dest">The destination pixel to write to</param>
void ToBgr24(ref Bgr24 dest);
/// <param name="source">The <see cref="Rgb48"/> value.</param>
void PackFromRgb48(Rgb48 source);
/// <summary>
/// Converts the pixel to <see cref="Bgra32"/> format.
/// Packs the pixel from an <see cref="Rgba64"/> value.
/// </summary>
/// <param name="dest">The destination pixel to write to</param>
void ToBgra32(ref Bgra32 dest);
/// <param name="source">The <see cref="Rgba64"/> value.</param>
void PackFromRgba64(Rgba64 source);
}
}

253
src/ImageSharp/PixelFormats/NormalizedByte2.cs

@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct NormalizedByte2 : IPixel<NormalizedByte2>, IPackedVector<ushort>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
private static readonly Vector2 Half = new Vector2(127);
private static readonly Vector2 MinusOne = new Vector2(-1F);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte2"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedByte2(Vector2 vector)
/// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param>
public NormalizedByte2(float x, float y)
: this(new Vector2(x, y))
{
this.PackedValue = Pack(vector.X, vector.Y);
}
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte2"/> struct.
/// </summary>
/// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param>
public NormalizedByte2(float x, float y)
{
this.PackedValue = Pack(x, y);
}
/// <param name="vector">The vector containing the component values.</param>
public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public ushort PackedValue { get; set; }
@ -55,66 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="NormalizedByte2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedByte2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedByte2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedByte2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="NormalizedByte2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedByte2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedByte2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedByte2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<NormalizedByte2> CreatePixelOperations() => new PixelOperations<NormalizedByte2>();
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 ToVector2()
{
return new Vector2(
(sbyte)((this.PackedValue >> 0) & 0xFF) / 127F,
(sbyte)((this.PackedValue >> 8) & 0xFF) / 127F);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y);
this.PackedValue = Pack(scaled);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
@ -124,172 +82,97 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y);
var vector2 = new Vector2(vector.X, vector.Y);
this.PackedValue = Pack(vector2);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.ToVector2(), 0F, 1F);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2()
{
return obj is NormalizedByte2 other && this.Equals(other);
return new Vector2(
(sbyte)((this.PackedValue >> 0) & 0xFF) / 127F,
(sbyte)((this.PackedValue >> 8) & 0xFF) / 127F);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(NormalizedByte2 other)
{
return this.PackedValue == other.PackedValue;
}
public override bool Equals(object obj) => obj is NormalizedByte2 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc />
public override string ToString()
{
return this.PackedValue.ToString("X");
var vector = this.ToVector2();
return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})");
}
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y)
[MethodImpl(InliningOptions.ShortMethod)]
private static ushort Pack(Vector2 vector)
{
int byte2 = ((ushort)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0;
int byte1 = ((ushort)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8;
vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half;
return (ushort)(byte2 | byte1);
}
int byte2 = ((ushort)Math.Round(vector.X) & 0xFF) << 0;
int byte1 = ((ushort)Math.Round(vector.Y) & 0xFF) << 8;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
return (ushort)(byte2 | byte1);
}
}
}

234
src/ImageSharp/PixelFormats/NormalizedByte4.cs

@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct NormalizedByte4 : IPixel<NormalizedByte4>, IPackedVector<uint>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedByte4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
private static readonly Vector4 MinusOne = new Vector4(-1F);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param>
public NormalizedByte4(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{
this.PackedValue = Pack(x, y, z, w);
}
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public uint PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="NormalizedByte4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedByte4"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte4"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedByte4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedByte4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="NormalizedByte4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedByte4"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte4"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedByte4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedByte4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<NormalizedByte4> CreatePixelOperations() => new PixelOperations<NormalizedByte4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 2F;
@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
return new Vector4(
@ -131,162 +99,74 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is NormalizedByte4 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(NormalizedByte4 other)
{
return this.PackedValue == other.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc />
public override string ToString()
{
return this.PackedValue.ToString("X");
var vector = this.ToVector4();
return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
/// </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>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y, float z, float w)
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(ref Vector4 vector)
{
uint byte4 = ((uint)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0;
uint byte3 = ((uint)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8;
uint byte2 = ((uint)Math.Round(z.Clamp(-1F, 1F) * 127F) & 0xFF) << 16;
uint byte1 = ((uint)Math.Round(w.Clamp(-1F, 1F) * 127F) & 0xFF) << 24;
vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half;
return byte4 | byte3 | byte2 | byte1;
}
uint byte4 = ((uint)Math.Round(vector.X) & 0xFF) << 0;
uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 8;
uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 16;
uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 24;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
return byte4 | byte3 | byte2 | byte1;
}
}
}

239
src/ImageSharp/PixelFormats/NormalizedShort2.cs

@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct NormalizedShort2 : IPixel<NormalizedShort2>, IPackedVector<uint>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
private static readonly Vector2 Max = new Vector2(0x7FFF);
private static readonly Vector2 Min = Vector2.Negate(Max);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort2"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedShort2(Vector2 vector)
/// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param>
public NormalizedShort2(float x, float y)
: this(new Vector2(x, y))
{
this.PackedValue = Pack(vector.X, vector.Y);
}
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort2"/> struct.
/// </summary>
/// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param>
public NormalizedShort2(float x, float y)
{
this.PackedValue = Pack(x, y);
}
/// <param name="vector">The vector containing the component values.</param>
public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public uint PackedValue { get; set; }
@ -55,53 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="NormalizedShort2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedShort2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedShort2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedShort2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right)
{
return left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="NormalizedShort2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedShort2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedShort2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedShort2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right)
{
return !left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<NormalizedShort2> CreatePixelOperations() => new PixelOperations<NormalizedShort2>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y);
this.PackedValue = Pack(scaled);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
@ -111,130 +82,63 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y);
var vector2 = new Vector2(vector.X, vector.Y);
this.PackedValue = Pack(vector2);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.ToVector2(), 0, 1);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2()
{
const float MaxVal = 0x7FFF;
@ -245,61 +149,34 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is NormalizedShort2 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is NormalizedShort2 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(NormalizedShort2 other)
{
return this.PackedValue.Equals(other.PackedValue);
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.PackedValue.GetHashCode();
}
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc />
public override string ToString()
{
return this.PackedValue.ToString("X");
var vector = this.ToVector2();
return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})");
}
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y)
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(Vector2 vector)
{
const float MaxPos = 0x7FFF;
const float MinNeg = -MaxPos;
vector *= Max;
vector = Vector2.Clamp(vector, Min, Max);
// Clamp the value between min and max values
// Round rather than truncate.
uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF);
uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10);
uint word2 = (uint)((int)MathF.Round(vector.X) & 0xFFFF);
uint word1 = (uint)(((int)MathF.Round(vector.Y) & 0xFFFF) << 0x10);
return word2 | word1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
}
}

243
src/ImageSharp/PixelFormats/NormalizedShort4.cs

@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct NormalizedShort4 : IPixel<NormalizedShort4>, IPackedVector<ulong>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedShort4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
private static readonly Vector4 Max = new Vector4(0x7FFF);
private static readonly Vector4 Min = Vector4.Negate(Max);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param>
public NormalizedShort4(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{
this.PackedValue = Pack(x, y, z, w);
}
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public ulong PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="NormalizedShort4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedShort4"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort4"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedShort4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedShort4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right)
{
return left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="NormalizedShort4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="NormalizedShort4"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort4"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="NormalizedShort4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="NormalizedShort4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right)
{
return !left.Equals(right);
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<NormalizedShort4> CreatePixelOperations() => new PixelOperations<NormalizedShort4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 2F;
@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
const float MaxVal = 0x7FFF;
@ -133,169 +101,76 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is NormalizedShort4 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(NormalizedShort4 other)
{
return this.PackedValue.Equals(other.PackedValue);
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.PackedValue.GetHashCode();
}
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc />
public override string ToString()
{
return this.PackedValue.ToString("X");
var vector = this.ToVector4();
return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ulong"/>.
/// </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>
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Pack(float x, float y, float z, float w)
[MethodImpl(InliningOptions.ShortMethod)]
private static ulong Pack(ref Vector4 vector)
{
const float MaxPos = 0x7FFF;
const float MinNeg = -MaxPos;
vector *= Max;
vector = Vector4.Clamp(vector, Min, Max);
// Clamp the value between min and max values
ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00;
ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10;
ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20;
ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30;
// Round rather than truncate.
ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00;
ulong word3 = ((ulong)MathF.Round(vector.Y) & 0xFFFF) << 0x10;
ulong word2 = ((ulong)MathF.Round(vector.Z) & 0xFFFF) << 0x20;
ulong word1 = ((ulong)MathF.Round(vector.W) & 0xFFFF) << 0x30;
return word4 | word3 | word2 | word1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
}
}
}

54
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

@ -105,6 +105,60 @@ namespace SixLabors.ImageSharp.PixelFormats
}
}
/// <summary>
/// Performs a bulk conversion of a collection of one pixel format into another.
/// </summary>
/// <typeparam name="TPixel2">The pixel format.</typeparam>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destinationColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void To<TPixel2>(ReadOnlySpan<TPixel> sourceColors, Span<TPixel2> destinationColors, int count)
where TPixel2 : struct, IPixel<TPixel2>
{
GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count);
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
// Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the
// standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm.
// One of the requirements of PackFromScaledVector4/ToScaledVector4 is that it unaware of this and
// packs/unpacks the pixel without and conversion so we employ custom methods do do this.
if (typeof(TPixel2).Equals(typeof(Gray16)))
{
ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<TPixel2, Gray16>(destinationColors));
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref gray16Ref, i);
dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4());
}
return;
}
if (typeof(TPixel2).Equals(typeof(Gray8)))
{
ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<TPixel2, Gray8>(destinationColors));
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref gray8Ref, i);
dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4());
}
return;
}
// Normal converson
ref TPixel2 destRef = ref MemoryMarshal.GetReference(destinationColors);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref TPixel2 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary>
/// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size.
/// Throwing an <see cref="ArgumentException"/> if the condition is not met.

216
src/ImageSharp/PixelFormats/Rg32.cs

@ -15,24 +15,23 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct Rg32 : IPixel<Rg32>, IPackedVector<uint>
{
private static readonly Vector2 Max = new Vector2(ushort.MaxValue);
/// <summary>
/// Initializes a new instance of the <see cref="Rg32"/> struct.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
public Rg32(float x, float y)
: this(new Vector2(x, y))
{
this.PackedValue = Pack(x, y);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rg32"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public Rg32(Vector2 vector)
{
this.PackedValue = Pack(vector.X, vector.Y);
}
public Rg32(Vector2 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public uint PackedValue { get; set; }
@ -40,214 +39,119 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="Rg32"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Rg32"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rg32"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Rg32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rg32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Rg32 left, Rg32 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rg32"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Rg32"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rg32"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Rg32"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rg32"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Rg32 left, Rg32 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Rg32> CreatePixelOperations() => new PixelOperations<Rg32>();
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 ToVector2()
{
return new Vector2(
(this.PackedValue & 0xFFFF) / 65535F,
((this.PackedValue >> 16) & 0xFFFF) / 65535F);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y);
var vector2 = new Vector2(vector.X, vector.Y);
this.PackedValue = Pack(vector2);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.ToVector2(), 0F, 1F);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max;
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Rg32 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is Rg32 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rg32 other)
{
return this.PackedValue == other.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString()
{
return this.ToVector2().ToString();
var vector = this.ToVector2();
return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})");
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.PackedValue.GetHashCode();
}
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y)
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(Vector2 vector)
{
return (uint)(
((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) |
(((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16));
vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max;
return (uint)(((int)Math.Round(vector.X) & 0xFFFF) | (((int)Math.Round(vector.Y) & 0xFFFF) << 16));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F;
}
}
}

186
src/ImageSharp/PixelFormats/Rgb24.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
@ -16,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para>
/// </summary>
[StructLayout(LayoutKind.Explicit)]
public struct Rgb24 : IPixel<Rgb24>
public partial struct Rgb24 : IPixel<Rgb24>
{
/// <summary>
/// The red component.
@ -36,13 +35,16 @@ namespace SixLabors.ImageSharp.PixelFormats
[FieldOffset(2)]
public byte B;
private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue);
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="Rgb24"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgb24(byte r, byte g, byte b)
{
this.R = r;
@ -56,48 +58,59 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
/// <param name="color">The instance of <see cref="ColorSpaces.Rgb"/> to convert.</param>
/// <returns>An instance of <see cref="Rgb24"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgb24(ColorSpaces.Rgb color)
{
var vector = new Vector4(color.ToVector3(), 1);
var vector = new Vector4(color.ToVector3(), 1F);
Rgb24 rgb = default;
rgb.PackFromScaledVector4(vector);
return rgb;
}
/// <summary>
/// Compares two <see cref="Rgb24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Rgb24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rgb24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Rgb24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right);
/// <inheritdoc/>
public PixelOperations<Rgb24> CreatePixelOperations() => new PixelOperations<Rgb24>();
public PixelOperations<Rgb24> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rgb24 other)
{
return this.R == other.R && this.G == other.G && this.B == other.B;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is Rgb24 other && this.Equals(other);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this = Unsafe.As<Rgba32, Rgb24>(ref source);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.R = source.R;
@ -106,8 +119,8 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.R = source.R;
this.G = source.G;
@ -115,102 +128,95 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
return this.ToVector4();
this.R = source.R;
this.G = source.G;
this.B = source.B;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source)
{
Rgba32 rgba = default;
rgba.PackFromVector4(vector);
this.PackFromRgba32(rgba);
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source)
{
return new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4();
byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest) => dest = this;
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this = source;
/// <inheritdoc/>
public void ToRgba32(ref Rgba32 dest)
{
dest.Rgb = this;
dest.A = byte.MaxValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this = source.Rgb;
/// <inheritdoc/>
public void ToArgb32(ref Argb32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue);
/// <inheritdoc/>
public void ToBgr24(ref Bgr24 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
}
/// <inheritdoc/>
public void ToBgra32(ref Bgra32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgb48(Rgb48 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
}
public override bool Equals(object obj) => obj is Rgb24 other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source)
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
public override string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})";
/// <inheritdoc/>
public override string ToString()
/// <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)
{
return $"({this.R},{this.G},{this.B})";
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X;
this.G = (byte)vector.Y;
this.B = (byte)vector.Z;
}
}
}

189
src/ImageSharp/PixelFormats/Rgb48.cs

@ -15,9 +15,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Rgb48 : IPixel<Rgb48>
public partial struct Rgb48 : IPixel<Rgb48>
{
private const float Max = 65535F;
private const float Max = ushort.MaxValue;
/// <summary>
/// Gets or sets the red component.
@ -48,29 +48,6 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgb48"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
public Rgb48(float r, float g, float b)
: this()
{
this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max);
this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max);
this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgb48"/> struct.
/// </summary>
/// <param name="vector">The vector containing the components values.</param>
public Rgb48(Vector3 vector)
: this(vector.X, vector.Y, vector.Z)
{
}
/// <summary>
/// Compares two <see cref="Rgb48"/> objects for equality.
/// </summary>
@ -79,13 +56,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Rgb48 left, Rgb48 right)
{
return left.R == right.R
&& left.G == right.G
&& left.B == right.B;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rgb48"/> objects for equality.
@ -95,40 +67,22 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Rgb48 left, Rgb48 right)
{
return left.R != right.R
|| left.G != right.G
|| left.B != right.B;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Rgb48> CreatePixelOperations() => new PixelOperations<Rgb48>();
public PixelOperations<Rgb48> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.R / Max, this.G / Max, this.B / Max, 1);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
@ -138,114 +92,103 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.R / Max, this.G / Max, this.B / Max, 1F);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.PackFromVector4(source.ToVector4());
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this = source.Rgb;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source)
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source)
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
dest.A = 255;
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
dest.A = 255;
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source)
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32()
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
dest.A = 255;
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
return new Rgba32(r, g, b, byte.MaxValue);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this = source;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest = this;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest)
{
dest.Rgb = this;
dest.A = ushort.MaxValue;
}
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Rgb48 rgb48 && this.Equals(rgb48);
}
public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rgb48 other)
{
return this.R == other.R
&& this.G == other.G
&& this.B == other.B;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
/// <inheritdoc />
public override string ToString() => this.ToVector4().ToString();
public override string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})";
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode()
{
return HashHelpers.Combine(

208
src/ImageSharp/PixelFormats/Rgba1010102.cs

@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct Rgba1010102 : IPixel<Rgba1010102>, IPackedVector<uint>
{
private static readonly Vector4 Multiplier = new Vector4(1023F, 1023F, 1023F, 3F);
/// <summary>
/// Initializes a new instance of the <see cref="Rgba1010102"/> struct.
/// </summary>
@ -24,18 +26,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
public Rgba1010102(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{
this.PackedValue = Pack(x, y, z, w);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba1010102"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public Rgba1010102(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public uint PackedValue { get; set; }
@ -43,206 +42,119 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="Rgba1010102"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Rgba1010102"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rgba1010102"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Rgba1010102"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgba1010102"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Rgba1010102 left, Rgba1010102 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rgba1010102"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Rgba1010102"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rgba1010102"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Rgba1010102"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgba1010102"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Rgba1010102 left, Rgba1010102 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Rgba1010102> CreatePixelOperations() => new PixelOperations<Rgba1010102>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(
((this.PackedValue >> 0) & 0x03FF) / 1023F,
((this.PackedValue >> 10) & 0x03FF) / 1023F,
((this.PackedValue >> 20) & 0x03FF) / 1023F,
((this.PackedValue >> 30) & 0x03) / 3F);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
return new Vector4(
(this.PackedValue >> 0) & 0x03FF,
(this.PackedValue >> 10) & 0x03FF,
(this.PackedValue >> 20) & 0x03FF,
(this.PackedValue >> 30) & 0x03) / Multiplier;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Rgba1010102 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rgba1010102 other)
{
return this.PackedValue == other.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue;
/// <inheritdoc />
public override string ToString()
{
return this.ToVector4().ToString();
var vector = this.ToVector4();
return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
{
return this.PackedValue.GetHashCode();
}
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
/// </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>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y, float z, float w)
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(ref Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier;
return (uint)(
(((int)Math.Round(x.Clamp(0, 1) * 1023F) & 0x03FF) << 0) |
(((int)Math.Round(y.Clamp(0, 1) * 1023F) & 0x03FF) << 10) |
(((int)Math.Round(z.Clamp(0, 1) * 1023F) & 0x03FF) << 20) |
(((int)Math.Round(w.Clamp(0, 1) * 3F) & 0x03) << 30));
(((int)Math.Round(vector.X) & 0x03FF) << 0)
| (((int)Math.Round(vector.Y) & 0x03FF) << 10)
| (((int)Math.Round(vector.Z) & 0x03FF) << 20)
| (((int)Math.Round(vector.W) & 0x03) << 30));
}
}
}

160
src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

@ -3,7 +3,6 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.Memory;
@ -19,100 +18,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
internal partial class PixelOperations : PixelOperations<Rgba32>
{
/// <summary>
/// SIMD optimized bulk implementation of <see cref="IPixel.PackFromVector4(Vector4)"/>
/// that works only with `count` divisible by <see cref="Vector{UInt32}.Count"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="Span{T}"/> to the dstination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
/// <remarks>
/// Implementation adapted from:
/// <see>
/// <cref>http://stackoverflow.com/a/5362789</cref>
/// </see>
/// TODO: We can replace this implementation in the future using new Vector API-s:
/// <see>
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see>
/// </remarks>
internal static void ToVector4SimdAligned(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destVectors, int count)
{
if (!Vector.IsHardwareAccelerated)
{
throw new InvalidOperationException(
"Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
}
DebugGuard.IsTrue(
count % Vector<uint>.Count == 0,
nameof(count),
"Argument 'count' should divisible by Vector<uint>.Count!");
var bVec = new Vector<float>(256.0f / 255.0f);
var magicFloat = new Vector<float>(32768.0f);
var magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
var mask = new Vector<uint>(255);
int unpackedRawCount = count * 4;
ref uint sourceBase = ref Unsafe.As<Rgba32, uint>(ref MemoryMarshal.GetReference(sourceColors));
ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As<Vector4, UnpackedRGBA>(ref MemoryMarshal.GetReference(destVectors));
ref Vector<uint> destBaseAsUInt = ref Unsafe.As<UnpackedRGBA, Vector<uint>>(ref destBaseAsUnpacked);
ref Vector<float> destBaseAsFloat = ref Unsafe.As<UnpackedRGBA, Vector<float>>(ref destBaseAsUnpacked);
for (int i = 0; i < count; i++)
{
uint sVal = Unsafe.Add(ref sourceBase, i);
ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i);
// This call is the bottleneck now:
dst.Load(sVal);
}
int numOfVectors = unpackedRawCount / Vector<uint>.Count;
for (int i = 0; i < numOfVectors; i++)
{
Vector<uint> vi = Unsafe.Add(ref destBaseAsUInt, i);
vi &= mask;
vi |= magicInt;
var vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
Unsafe.Add(ref destBaseAsFloat, i) = vf;
}
}
/// <inheritdoc />
internal override void ToVector4(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destinationVectors, int count)
{
Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors));
Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors));
if (count < 256 || !Vector.IsHardwareAccelerated)
{
// Doesn't worth to bother with SIMD:
base.ToVector4(sourceColors, destinationVectors, count);
return;
}
sourceColors = sourceColors.Slice(0, count);
destinationVectors = destinationVectors.Slice(0, count);
int remainder = count % Vector<uint>.Count;
int alignedCount = count - remainder;
if (alignedCount > 0)
{
ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount);
}
if (remainder > 0)
{
sourceColors = sourceColors.Slice(alignedCount);
destinationVectors = destinationVectors.Slice(alignedCount);
base.ToVector4(sourceColors, destinationVectors, remainder);
}
SimdUtils.BulkConvertByteToNormalizedFloat(
MemoryMarshal.Cast<Rgba32, byte>(sourceColors),
MemoryMarshal.Cast<Vector4, float>(destinationVectors));
}
/// <inheritdoc />
@ -120,29 +37,12 @@ namespace SixLabors.ImageSharp.PixelFormats
{
GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count);
if (!SimdUtils.IsAvx2CompatibleArchitecture)
{
base.PackFromVector4(sourceVectors, destinationColors, count);
return;
}
int remainder = count % 2;
int alignedCount = count - remainder;
if (alignedCount > 0)
{
ReadOnlySpan<float> flatSrc = MemoryMarshal.Cast<Vector4, float>(sourceVectors.Slice(0, alignedCount));
Span<byte> flatDest = MemoryMarshal.Cast<Rgba32, byte>(destinationColors);
sourceVectors = sourceVectors.Slice(0, count);
destinationColors = destinationColors.Slice(0, count);
SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest);
}
if (remainder > 0)
{
// actually: remainder == 1
int lastIdx = count - 1;
destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]);
}
SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(
MemoryMarshal.Cast<Vector4, float>(sourceVectors),
MemoryMarshal.Cast<Rgba32, byte>(destinationColors));
}
/// <inheritdoc />
@ -156,46 +56,6 @@ namespace SixLabors.ImageSharp.PixelFormats
{
this.PackFromVector4(sourceVectors, destinationColors, count);
}
/// <inheritdoc />
internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> dest, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
sourcePixels.Slice(0, count).CopyTo(dest);
}
/// <summary>
/// Value type to store <see cref="Rgba32"/>-s unpacked into multiple <see cref="uint"/>-s.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct UnpackedRGBA
{
private uint r;
private uint g;
private uint b;
private uint a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Load(uint p)
{
this.r = p;
this.g = p >> GreenShift;
this.b = p >> BlueShift;
this.a = p >> AlphaShift;
}
}
}
}
}

253
src/ImageSharp/PixelFormats/Rgba32.cs

@ -41,34 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public byte A;
/// <summary>
/// The shift count for the red component
/// </summary>
private const int RedShift = 0;
/// <summary>
/// The shift count for the green component
/// </summary>
private const int GreenShift = 8;
/// <summary>
/// The shift count for the blue component
/// </summary>
private const int BlueShift = 16;
/// <summary>
/// The shift count for the alpha component
/// </summary>
private const int AlphaShift = 24;
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue);
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
@ -77,7 +50,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32(byte r, byte g, byte b)
{
this.R = r;
@ -93,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32(byte r, byte g, byte b, byte a)
{
this.R = r;
@ -109,7 +82,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32(float r, float g, float b, float a = 1)
: this() => this.Pack(r, g, b, a);
@ -119,7 +92,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32(Vector3 vector)
: this() => this.Pack(ref vector);
@ -129,7 +102,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32(Vector4 vector)
: this() => this = PackNew(ref vector);
@ -139,7 +112,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="packed">
/// The packed value.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32(uint packed)
: this() => this.Rgba = packed;
@ -148,10 +121,10 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public uint Rgba
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
get => Unsafe.As<Rgba32, uint>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Rgba32, uint>(ref this) = value;
}
@ -160,10 +133,12 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public Rgb24 Rgb
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
// If this is changed to ShortMethod then several jpeg encoding tests fail
// on 32 bit Net 4.6.2 and NET 4.7.1
[MethodImpl(InliningOptions.ColdPath)]
get => Unsafe.As<Rgba32, Rgb24>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Rgba32, Rgb24>(ref this) = value;
}
@ -172,10 +147,10 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public Bgr24 Bgr
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
get => new Bgr24(this.R, this.G, this.B);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set
{
this.R = value.R;
@ -187,10 +162,10 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc/>
public uint PackedValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
get => this.Rgba;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set => this.Rgba = value;
}
@ -200,10 +175,11 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
/// <param name="color">The instance of <see cref="ColorSpaces.Rgb"/> to convert.</param>
/// <returns>An instance of <see cref="Rgba32"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgba32(ColorSpaces.Rgb color)
{
var vector = new Vector4(color.ToVector3(), 1);
var vector = new Vector4(color.ToVector3(), 1F);
Rgba32 rgba = default;
rgba.PackFromScaledVector4(vector);
return rgba;
@ -217,8 +193,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Rgba32 left, Rgba32 right) => left.Rgba == right.Rgba;
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgba32 left, Rgba32 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rgba32"/> objects for equality.
@ -228,8 +204,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Rgba32 left, Rgba32 right) => left.Rgba != right.Rgba;
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right);
/// <summary>
/// Creates a new instance of the <see cref="Rgba32"/> struct.
@ -247,11 +223,23 @@ namespace SixLabors.ImageSharp.PixelFormats
public PixelOperations<Rgba32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source) => this = source;
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.R = source.R;
@ -261,7 +249,15 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.Bgr = source;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
this.R = source.R;
@ -270,148 +266,93 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = source.A;
}
/// <summary>
/// Converts the value of this instance to a hexadecimal string.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
public string ToHex()
{
uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24);
return hexOrder.ToString("X8");
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest) => dest = Unsafe.As<Rgba32, Rgb24>(ref this);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest) => dest = this;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
this.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = byte.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
this.Rgb = source;
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <summary>
/// Gets the value of this struct as <see cref="Bgra32"/>.
/// Useful for changing the component order.
/// </summary>
/// <returns>A <see cref="Bgra32"/> value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A);
/// <summary>
/// Gets the value of this struct as <see cref="Argb32"/>.
/// Useful for changing the component order.
/// </summary>
/// <returns>A <see cref="Argb32"/> value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A);
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this = source;
/// <summary>
/// Converts the pixel to <see cref="Rgba32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => this;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
{
// Taken from libpng pngtran.c line: 2419
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
this.A = (byte)(((source.A * 255) + 32895) >> 16);
this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary>
/// Converts the value of this instance to a hexadecimal string.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
public string ToHex()
{
uint hexOrder = (uint)(this.A << 0 | this.B << 8 | this.G << 16 | this.R << 24);
return hexOrder.ToString("X8");
}
/// <inheritdoc/>
public override bool Equals(object obj) => obj is Rgba32 rgba32 && this.Equals(rgba32);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rgba32 other) => this.Rgba == other.Rgba;
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgba32 other) => this.Rgba.Equals(other.Rgba);
/// <inheritdoc/>
public override string ToString() => $"({this.R},{this.G},{this.B},{this.A})";
public override string ToString() => $"Rgba32({this.R}, {this.G}, {this.B}, {this.A})";
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.Rgba.GetHashCode();
/// <summary>
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1]
/// </summary>
/// <returns>A <see cref="Vector4"/> of values in [0, 255] </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A);
/// <summary>
/// Packs a <see cref="Vector4"/> into a color returning a new instance as a result.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="Rgba32"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private static Rgba32 PackNew(ref Vector4 vector)
{
vector *= MaxBytes;
@ -428,7 +369,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(float x, float y, float z, float w)
{
var value = new Vector4(x, y, z, w);
@ -439,10 +380,10 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packs a <see cref="Vector3"/> into a uint.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector3 vector)
{
var value = new Vector4(vector, 1);
var value = new Vector4(vector, 1F);
this.Pack(ref value);
}
@ -450,7 +391,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packs a <see cref="Vector4"/> into a color.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector4 vector)
{
vector *= MaxBytes;

239
src/ImageSharp/PixelFormats/Rgba64.cs

@ -15,9 +15,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public struct Rgba64 : IPixel<Rgba64>, IPackedVector<ulong>
public partial struct Rgba64 : IPixel<Rgba64>, IPackedVector<ulong>
{
private const float Max = 65535F;
private const float Max = ushort.MaxValue;
/// <summary>
/// Gets or sets the red component.
@ -47,7 +47,6 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
public Rgba64(ushort r, ushort g, ushort b, ushort a)
: this()
{
this.R = r;
this.G = g;
@ -55,126 +54,63 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = a;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
public Rgba64(float r, float g, float b, float a)
: this()
{
this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max);
this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max);
this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max);
this.A = (ushort)MathF.Round(a.Clamp(0, 1) * Max);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="vector">The vector containing the components values.</param>
public Rgba64(Vector4 vector)
: this(vector.X, vector.Y, vector.Z, vector.W)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgba64"/> struct.
/// </summary>
/// <param name="packed">The packed value.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba64(ulong packed)
: this()
{
this.PackedValue = packed;
}
/// <summary>
/// Gets or sets the RGB components of this struct as <see cref="Rgb48"/>
/// </summary>
public Rgb48 Rgb
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
get => Unsafe.As<Rgba64, Rgb48>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Rgba64, Rgb48>(ref this) = value;
}
/// <inheritdoc/>
public ulong PackedValue
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
get => Unsafe.As<Rgba64, ulong>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Rgba64, ulong>(ref this) = value;
}
/// <summary>
/// Compares two <see cref="Rgba64"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Rgba64"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rgba64"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Rgba64"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgba64"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Rgba64 left, Rgba64 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgba64 left, Rgba64 right) => left.PackedValue == right.PackedValue;
/// <summary>
/// Compares two <see cref="Rgba64"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Rgba64"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Rgba64"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Rgba64"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgba64"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Rgba64 left, Rgba64 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue;
/// <inheritdoc />
public PixelOperations<Rgba64> CreatePixelOperations() => new PixelOperations<Rgba64>();
public PixelOperations<Rgba64> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.R, this.G, this.B, this.A) / Max;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
@ -185,116 +121,115 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.PackFromVector4(source.ToVector4());
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.PackFromVector4(source.ToVector4());
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ushort.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this = source;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source)
{
// Taken from libpng pngtran.c line: 2419
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
dest.A = (byte)(((this.A * 255) + 32895) >> 16);
ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
this.A = ushort.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgb48(Rgb48 source)
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source)
{
this.Rgb = source;
this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
this.A = ushort.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest = this.Rgb;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest = this;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
dest.A = (byte)(((this.A * 255) + 32895) >> 16);
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ushort.MaxValue;
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source)
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
this.A = ImageMaths.UpscaleFrom8BitTo16Bit(source.A);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32()
{
dest.R = (byte)(((this.R * 255) + 32895) >> 16);
dest.G = (byte)(((this.G * 255) + 32895) >> 16);
dest.B = (byte)(((this.B * 255) + 32895) >> 16);
dest.A = (byte)(((this.A * 255) + 32895) >> 16);
byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
byte a = ImageMaths.DownScaleFrom16BitTo8Bit(this.A);
return new Rgba32(r, g, b, a);
}
/// <inheritdoc />
public override bool Equals(object obj)
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{
return obj is Rgba64 rgba64 && this.Equals(rgba64);
this.Rgb = source;
this.A = ushort.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this = source;
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rgba64 other)
{
return this.PackedValue == other.PackedValue;
}
public override bool Equals(object obj) => obj is Rgba64 rgba64 && this.Equals(rgba64);
/// <inheritdoc />
public override string ToString()
{
return $"({this.R},{this.G},{this.B},{this.A})";
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgba64 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString() => $"Rgba64({this.R}, {this.G}, {this.B}, {this.A})";
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
}
}

721
src/ImageSharp/PixelFormats/RgbaVector.Definitions.cs

@ -1,721 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.PixelFormats
{
/// <content>
/// Provides operators and composition algorithms.
/// </content>
public partial struct RgbaVector
{
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F0F8FF.
/// </summary>
public static readonly RgbaVector AliceBlue = NamedColors<RgbaVector>.AliceBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FAEBD7.
/// </summary>
public static readonly RgbaVector AntiqueWhite = NamedColors<RgbaVector>.AntiqueWhite;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly RgbaVector Aqua = NamedColors<RgbaVector>.Aqua;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #7FFFD4.
/// </summary>
public static readonly RgbaVector Aquamarine = NamedColors<RgbaVector>.Aquamarine;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F0FFFF.
/// </summary>
public static readonly RgbaVector Azure = NamedColors<RgbaVector>.Azure;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F5F5DC.
/// </summary>
public static readonly RgbaVector Beige = NamedColors<RgbaVector>.Beige;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFE4C4.
/// </summary>
public static readonly RgbaVector Bisque = NamedColors<RgbaVector>.Bisque;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #000000.
/// </summary>
public static readonly RgbaVector Black = NamedColors<RgbaVector>.Black;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFEBCD.
/// </summary>
public static readonly RgbaVector BlanchedAlmond = NamedColors<RgbaVector>.BlanchedAlmond;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #0000FF.
/// </summary>
public static readonly RgbaVector Blue = NamedColors<RgbaVector>.Blue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #8A2BE2.
/// </summary>
public static readonly RgbaVector BlueViolet = NamedColors<RgbaVector>.BlueViolet;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #A52A2A.
/// </summary>
public static readonly RgbaVector Brown = NamedColors<RgbaVector>.Brown;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #DEB887.
/// </summary>
public static readonly RgbaVector BurlyWood = NamedColors<RgbaVector>.BurlyWood;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #5F9EA0.
/// </summary>
public static readonly RgbaVector CadetBlue = NamedColors<RgbaVector>.CadetBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #7FFF00.
/// </summary>
public static readonly RgbaVector Chartreuse = NamedColors<RgbaVector>.Chartreuse;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #D2691E.
/// </summary>
public static readonly RgbaVector Chocolate = NamedColors<RgbaVector>.Chocolate;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF7F50.
/// </summary>
public static readonly RgbaVector Coral = NamedColors<RgbaVector>.Coral;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #6495ED.
/// </summary>
public static readonly RgbaVector CornflowerBlue = NamedColors<RgbaVector>.CornflowerBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFF8DC.
/// </summary>
public static readonly RgbaVector Cornsilk = NamedColors<RgbaVector>.Cornsilk;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #DC143C.
/// </summary>
public static readonly RgbaVector Crimson = NamedColors<RgbaVector>.Crimson;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00FFFF.
/// </summary>
public static readonly RgbaVector Cyan = NamedColors<RgbaVector>.Cyan;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00008B.
/// </summary>
public static readonly RgbaVector DarkBlue = NamedColors<RgbaVector>.DarkBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #008B8B.
/// </summary>
public static readonly RgbaVector DarkCyan = NamedColors<RgbaVector>.DarkCyan;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #B8860B.
/// </summary>
public static readonly RgbaVector DarkGoldenrod = NamedColors<RgbaVector>.DarkGoldenrod;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #A9A9A9.
/// </summary>
public static readonly RgbaVector DarkGray = NamedColors<RgbaVector>.DarkGray;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #006400.
/// </summary>
public static readonly RgbaVector DarkGreen = NamedColors<RgbaVector>.DarkGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #BDB76B.
/// </summary>
public static readonly RgbaVector DarkKhaki = NamedColors<RgbaVector>.DarkKhaki;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #8B008B.
/// </summary>
public static readonly RgbaVector DarkMagenta = NamedColors<RgbaVector>.DarkMagenta;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #556B2F.
/// </summary>
public static readonly RgbaVector DarkOliveGreen = NamedColors<RgbaVector>.DarkOliveGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF8C00.
/// </summary>
public static readonly RgbaVector DarkOrange = NamedColors<RgbaVector>.DarkOrange;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #9932CC.
/// </summary>
public static readonly RgbaVector DarkOrchid = NamedColors<RgbaVector>.DarkOrchid;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #8B0000.
/// </summary>
public static readonly RgbaVector DarkRed = NamedColors<RgbaVector>.DarkRed;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #E9967A.
/// </summary>
public static readonly RgbaVector DarkSalmon = NamedColors<RgbaVector>.DarkSalmon;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #8FBC8B.
/// </summary>
public static readonly RgbaVector DarkSeaGreen = NamedColors<RgbaVector>.DarkSeaGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #483D8B.
/// </summary>
public static readonly RgbaVector DarkSlateBlue = NamedColors<RgbaVector>.DarkSlateBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #2F4F4F.
/// </summary>
public static readonly RgbaVector DarkSlateGray = NamedColors<RgbaVector>.DarkSlateGray;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00CED1.
/// </summary>
public static readonly RgbaVector DarkTurquoise = NamedColors<RgbaVector>.DarkTurquoise;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #9400D3.
/// </summary>
public static readonly RgbaVector DarkViolet = NamedColors<RgbaVector>.DarkViolet;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF1493.
/// </summary>
public static readonly RgbaVector DeepPink = NamedColors<RgbaVector>.DeepPink;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00BFFF.
/// </summary>
public static readonly RgbaVector DeepSkyBlue = NamedColors<RgbaVector>.DeepSkyBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #696969.
/// </summary>
public static readonly RgbaVector DimGray = NamedColors<RgbaVector>.DimGray;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #1E90FF.
/// </summary>
public static readonly RgbaVector DodgerBlue = NamedColors<RgbaVector>.DodgerBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #B22222.
/// </summary>
public static readonly RgbaVector Firebrick = NamedColors<RgbaVector>.Firebrick;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFAF0.
/// </summary>
public static readonly RgbaVector FloralWhite = NamedColors<RgbaVector>.FloralWhite;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #228B22.
/// </summary>
public static readonly RgbaVector ForestGreen = NamedColors<RgbaVector>.ForestGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly RgbaVector Fuchsia = NamedColors<RgbaVector>.Fuchsia;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #DCDCDC.
/// </summary>
public static readonly RgbaVector Gainsboro = NamedColors<RgbaVector>.Gainsboro;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F8F8FF.
/// </summary>
public static readonly RgbaVector GhostWhite = NamedColors<RgbaVector>.GhostWhite;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFD700.
/// </summary>
public static readonly RgbaVector Gold = NamedColors<RgbaVector>.Gold;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #DAA520.
/// </summary>
public static readonly RgbaVector Goldenrod = NamedColors<RgbaVector>.Goldenrod;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #808080.
/// </summary>
public static readonly RgbaVector Gray = NamedColors<RgbaVector>.Gray;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #008000.
/// </summary>
public static readonly RgbaVector Green = NamedColors<RgbaVector>.Green;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #ADFF2F.
/// </summary>
public static readonly RgbaVector GreenYellow = NamedColors<RgbaVector>.GreenYellow;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F0FFF0.
/// </summary>
public static readonly RgbaVector Honeydew = NamedColors<RgbaVector>.Honeydew;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF69B4.
/// </summary>
public static readonly RgbaVector HotPink = NamedColors<RgbaVector>.HotPink;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #CD5C5C.
/// </summary>
public static readonly RgbaVector IndianRed = NamedColors<RgbaVector>.IndianRed;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #4B0082.
/// </summary>
public static readonly RgbaVector Indigo = NamedColors<RgbaVector>.Indigo;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFFF0.
/// </summary>
public static readonly RgbaVector Ivory = NamedColors<RgbaVector>.Ivory;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F0E68C.
/// </summary>
public static readonly RgbaVector Khaki = NamedColors<RgbaVector>.Khaki;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #E6E6FA.
/// </summary>
public static readonly RgbaVector Lavender = NamedColors<RgbaVector>.Lavender;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFF0F5.
/// </summary>
public static readonly RgbaVector LavenderBlush = NamedColors<RgbaVector>.LavenderBlush;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #7CFC00.
/// </summary>
public static readonly RgbaVector LawnGreen = NamedColors<RgbaVector>.LawnGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFACD.
/// </summary>
public static readonly RgbaVector LemonChiffon = NamedColors<RgbaVector>.LemonChiffon;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #ADD8E6.
/// </summary>
public static readonly RgbaVector LightBlue = NamedColors<RgbaVector>.LightBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F08080.
/// </summary>
public static readonly RgbaVector LightCoral = NamedColors<RgbaVector>.LightCoral;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #E0FFFF.
/// </summary>
public static readonly RgbaVector LightCyan = NamedColors<RgbaVector>.LightCyan;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FAFAD2.
/// </summary>
public static readonly RgbaVector LightGoldenrodYellow = NamedColors<RgbaVector>.LightGoldenrodYellow;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #D3D3D3.
/// </summary>
public static readonly RgbaVector LightGray = NamedColors<RgbaVector>.LightGray;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #90EE90.
/// </summary>
public static readonly RgbaVector LightGreen = NamedColors<RgbaVector>.LightGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFB6C1.
/// </summary>
public static readonly RgbaVector LightPink = NamedColors<RgbaVector>.LightPink;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFA07A.
/// </summary>
public static readonly RgbaVector LightSalmon = NamedColors<RgbaVector>.LightSalmon;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #20B2AA.
/// </summary>
public static readonly RgbaVector LightSeaGreen = NamedColors<RgbaVector>.LightSeaGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #87CEFA.
/// </summary>
public static readonly RgbaVector LightSkyBlue = NamedColors<RgbaVector>.LightSkyBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #778899.
/// </summary>
public static readonly RgbaVector LightSlateGray = NamedColors<RgbaVector>.LightSlateGray;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #B0C4DE.
/// </summary>
public static readonly RgbaVector LightSteelBlue = NamedColors<RgbaVector>.LightSteelBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFFE0.
/// </summary>
public static readonly RgbaVector LightYellow = NamedColors<RgbaVector>.LightYellow;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00FF00.
/// </summary>
public static readonly RgbaVector Lime = NamedColors<RgbaVector>.Lime;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #32CD32.
/// </summary>
public static readonly RgbaVector LimeGreen = NamedColors<RgbaVector>.LimeGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FAF0E6.
/// </summary>
public static readonly RgbaVector Linen = NamedColors<RgbaVector>.Linen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF00FF.
/// </summary>
public static readonly RgbaVector Magenta = NamedColors<RgbaVector>.Magenta;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #800000.
/// </summary>
public static readonly RgbaVector Maroon = NamedColors<RgbaVector>.Maroon;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #66CDAA.
/// </summary>
public static readonly RgbaVector MediumAquamarine = NamedColors<RgbaVector>.MediumAquamarine;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #0000CD.
/// </summary>
public static readonly RgbaVector MediumBlue = NamedColors<RgbaVector>.MediumBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #BA55D3.
/// </summary>
public static readonly RgbaVector MediumOrchid = NamedColors<RgbaVector>.MediumOrchid;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #9370DB.
/// </summary>
public static readonly RgbaVector MediumPurple = NamedColors<RgbaVector>.MediumPurple;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #3CB371.
/// </summary>
public static readonly RgbaVector MediumSeaGreen = NamedColors<RgbaVector>.MediumSeaGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #7B68EE.
/// </summary>
public static readonly RgbaVector MediumSlateBlue = NamedColors<RgbaVector>.MediumSlateBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00FA9A.
/// </summary>
public static readonly RgbaVector MediumSpringGreen = NamedColors<RgbaVector>.MediumSpringGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #48D1CC.
/// </summary>
public static readonly RgbaVector MediumTurquoise = NamedColors<RgbaVector>.MediumTurquoise;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #C71585.
/// </summary>
public static readonly RgbaVector MediumVioletRed = NamedColors<RgbaVector>.MediumVioletRed;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #191970.
/// </summary>
public static readonly RgbaVector MidnightBlue = NamedColors<RgbaVector>.MidnightBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F5FFFA.
/// </summary>
public static readonly RgbaVector MintCream = NamedColors<RgbaVector>.MintCream;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFE4E1.
/// </summary>
public static readonly RgbaVector MistyRose = NamedColors<RgbaVector>.MistyRose;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFE4B5.
/// </summary>
public static readonly RgbaVector Moccasin = NamedColors<RgbaVector>.Moccasin;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFDEAD.
/// </summary>
public static readonly RgbaVector NavajoWhite = NamedColors<RgbaVector>.NavajoWhite;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #000080.
/// </summary>
public static readonly RgbaVector Navy = NamedColors<RgbaVector>.Navy;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FDF5E6.
/// </summary>
public static readonly RgbaVector OldLace = NamedColors<RgbaVector>.OldLace;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #808000.
/// </summary>
public static readonly RgbaVector Olive = NamedColors<RgbaVector>.Olive;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #6B8E23.
/// </summary>
public static readonly RgbaVector OliveDrab = NamedColors<RgbaVector>.OliveDrab;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFA500.
/// </summary>
public static readonly RgbaVector Orange = NamedColors<RgbaVector>.Orange;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF4500.
/// </summary>
public static readonly RgbaVector OrangeRed = NamedColors<RgbaVector>.OrangeRed;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #DA70D6.
/// </summary>
public static readonly RgbaVector Orchid = NamedColors<RgbaVector>.Orchid;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #EEE8AA.
/// </summary>
public static readonly RgbaVector PaleGoldenrod = NamedColors<RgbaVector>.PaleGoldenrod;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #98FB98.
/// </summary>
public static readonly RgbaVector PaleGreen = NamedColors<RgbaVector>.PaleGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #AFEEEE.
/// </summary>
public static readonly RgbaVector PaleTurquoise = NamedColors<RgbaVector>.PaleTurquoise;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #DB7093.
/// </summary>
public static readonly RgbaVector PaleVioletRed = NamedColors<RgbaVector>.PaleVioletRed;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFEFD5.
/// </summary>
public static readonly RgbaVector PapayaWhip = NamedColors<RgbaVector>.PapayaWhip;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFDAB9.
/// </summary>
public static readonly RgbaVector PeachPuff = NamedColors<RgbaVector>.PeachPuff;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #CD853F.
/// </summary>
public static readonly RgbaVector Peru = NamedColors<RgbaVector>.Peru;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFC0CB.
/// </summary>
public static readonly RgbaVector Pink = NamedColors<RgbaVector>.Pink;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #DDA0DD.
/// </summary>
public static readonly RgbaVector Plum = NamedColors<RgbaVector>.Plum;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #B0E0E6.
/// </summary>
public static readonly RgbaVector PowderBlue = NamedColors<RgbaVector>.PowderBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #800080.
/// </summary>
public static readonly RgbaVector Purple = NamedColors<RgbaVector>.Purple;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #663399.
/// </summary>
public static readonly RgbaVector RebeccaPurple = NamedColors<RgbaVector>.RebeccaPurple;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF0000.
/// </summary>
public static readonly RgbaVector Red = NamedColors<RgbaVector>.Red;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #BC8F8F.
/// </summary>
public static readonly RgbaVector RosyBrown = NamedColors<RgbaVector>.RosyBrown;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #4169E1.
/// </summary>
public static readonly RgbaVector RoyalBlue = NamedColors<RgbaVector>.RoyalBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #8B4513.
/// </summary>
public static readonly RgbaVector SaddleBrown = NamedColors<RgbaVector>.SaddleBrown;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FA8072.
/// </summary>
public static readonly RgbaVector Salmon = NamedColors<RgbaVector>.Salmon;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F4A460.
/// </summary>
public static readonly RgbaVector SandyBrown = NamedColors<RgbaVector>.SandyBrown;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #2E8B57.
/// </summary>
public static readonly RgbaVector SeaGreen = NamedColors<RgbaVector>.SeaGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFF5EE.
/// </summary>
public static readonly RgbaVector SeaShell = NamedColors<RgbaVector>.SeaShell;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #A0522D.
/// </summary>
public static readonly RgbaVector Sienna = NamedColors<RgbaVector>.Sienna;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #C0C0C0.
/// </summary>
public static readonly RgbaVector Silver = NamedColors<RgbaVector>.Silver;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #87CEEB.
/// </summary>
public static readonly RgbaVector SkyBlue = NamedColors<RgbaVector>.SkyBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #6A5ACD.
/// </summary>
public static readonly RgbaVector SlateBlue = NamedColors<RgbaVector>.SlateBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #708090.
/// </summary>
public static readonly RgbaVector SlateGray = NamedColors<RgbaVector>.SlateGray;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFAFA.
/// </summary>
public static readonly RgbaVector Snow = NamedColors<RgbaVector>.Snow;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #00FF7F.
/// </summary>
public static readonly RgbaVector SpringGreen = NamedColors<RgbaVector>.SpringGreen;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #4682B4.
/// </summary>
public static readonly RgbaVector SteelBlue = NamedColors<RgbaVector>.SteelBlue;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #D2B48C.
/// </summary>
public static readonly RgbaVector Tan = NamedColors<RgbaVector>.Tan;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #008080.
/// </summary>
public static readonly RgbaVector Teal = NamedColors<RgbaVector>.Teal;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #D8BFD8.
/// </summary>
public static readonly RgbaVector Thistle = NamedColors<RgbaVector>.Thistle;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FF6347.
/// </summary>
public static readonly RgbaVector Tomato = NamedColors<RgbaVector>.Tomato;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly RgbaVector Transparent = NamedColors<RgbaVector>.Transparent;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #40E0D0.
/// </summary>
public static readonly RgbaVector Turquoise = NamedColors<RgbaVector>.Turquoise;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #EE82EE.
/// </summary>
public static readonly RgbaVector Violet = NamedColors<RgbaVector>.Violet;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F5DEB3.
/// </summary>
public static readonly RgbaVector Wheat = NamedColors<RgbaVector>.Wheat;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFFFF.
/// </summary>
public static readonly RgbaVector White = NamedColors<RgbaVector>.White;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #F5F5F5.
/// </summary>
public static readonly RgbaVector WhiteSmoke = NamedColors<RgbaVector>.WhiteSmoke;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #FFFF00.
/// </summary>
public static readonly RgbaVector Yellow = NamedColors<RgbaVector>.Yellow;
/// <summary>
/// Represents a <see cref="RgbaVector"/> matching the W3C definition that has an hex value of #9ACD32.
/// </summary>
public static readonly RgbaVector YellowGreen = NamedColors<RgbaVector>.YellowGreen;
}
}

18
src/ImageSharp/PixelFormats/RgbaVector.PixelOperations.cs

@ -18,11 +18,23 @@ namespace SixLabors.ImageSharp.PixelFormats
internal class PixelOperations : PixelOperations<RgbaVector>
{
/// <inheritdoc />
internal override unsafe void ToVector4(ReadOnlySpan<RgbaVector> sourceColors, Span<Vector4> destVectors, int count)
internal override void PackFromScaledVector4(ReadOnlySpan<Vector4> sourceVectors, Span<RgbaVector> destinationColors, int count)
{
GuardSpans(sourceColors, nameof(sourceColors), destVectors, nameof(destVectors), count);
GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count);
MemoryMarshal.Cast<RgbaVector, Vector4>(sourceColors).Slice(0, count).CopyTo(destVectors);
MemoryMarshal.Cast<Vector4, RgbaVector>(sourceVectors).Slice(0, count).CopyTo(destinationColors);
}
/// <inheritdoc />
internal override void ToScaledVector4(ReadOnlySpan<RgbaVector> sourceColors, Span<Vector4> destinationVectors, int count)
=> this.ToVector4(sourceColors, destinationVectors, count);
/// <inheritdoc />
internal override void ToVector4(ReadOnlySpan<RgbaVector> sourceColors, Span<Vector4> destinationVectors, int count)
{
GuardSpans(sourceColors, nameof(sourceColors), destinationVectors, nameof(destinationVectors), count);
MemoryMarshal.Cast<RgbaVector, Vector4>(sourceColors).Slice(0, count).CopyTo(destinationVectors);
}
}
}

346
src/ImageSharp/PixelFormats/RgbaVector.cs

@ -4,6 +4,7 @@
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.PixelFormats
{
@ -18,36 +19,32 @@ namespace SixLabors.ImageSharp.PixelFormats
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
/// as it avoids the need to create new values for modification operations.
/// </remarks>
[StructLayout(LayoutKind.Sequential)]
public partial struct RgbaVector : IPixel<RgbaVector>
{
/// <summary>
/// The maximum byte value.
/// Gets or sets the red component.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
public float R;
/// <summary>
/// The half vector value.
/// Gets or sets the green component.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
public float G;
/// <summary>
/// The backing vector for SIMD support.
/// Gets or sets the blue component.
/// </summary>
private Vector4 backingVector;
public float B;
/// <summary>
/// Initializes a new instance of the <see cref="RgbaVector"/> struct.
/// Gets or sets the alpha component.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RgbaVector(byte r, byte g, byte b, byte a = 255)
: this()
{
this.backingVector = new Vector4(r, g, b, a) / MaxBytes;
}
public float A;
private const float MaxBytes = byte.MaxValue;
private static readonly Vector4 Max = new Vector4(MaxBytes);
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary>
/// Initializes a new instance of the <see cref="RgbaVector"/> struct.
@ -56,128 +53,25 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public RgbaVector(float r, float g, float b, float a = 1)
: this()
{
this.backingVector = new Vector4(r, g, b, a);
}
/// <summary>
/// Initializes a new instance of the <see cref="RgbaVector"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RgbaVector(Vector3 vector)
: this()
{
this.backingVector = new Vector4(vector, 1);
}
/// <summary>
/// Initializes a new instance of the <see cref="RgbaVector"/> struct.
/// </summary>
/// <param name="vector">
/// The vector containing the components for the packed vector.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public RgbaVector(Vector4 vector)
: this()
{
this.backingVector = vector;
}
/// <summary>
/// Gets or sets the red component.
/// </summary>
public float R
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.X;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.X = value;
}
}
/// <summary>
/// Gets or sets the green component.
/// </summary>
public float G
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.Y;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.Y = value;
}
}
/// <summary>
/// Gets or sets the blue component.
/// </summary>
public float B
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.Z;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.Z = value;
}
}
/// <summary>
/// Gets or sets the alpha component.
/// </summary>
public float A
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.backingVector.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
set
{
this.backingVector.W = value;
}
this.R = r;
this.G = g;
this.B = b;
this.A = a;
}
/// <summary>
/// Compares two <see cref="RgbaVector"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="RgbaVector"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="RgbaVector"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="RgbaVector"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="RgbaVector"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(RgbaVector left, RgbaVector right)
{
return left.backingVector == right.backingVector;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="RgbaVector"/> objects for equality.
@ -187,11 +81,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(RgbaVector left, RgbaVector right)
{
return left.backingVector != right.backingVector;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right);
/// <summary>
/// Creates a new instance of the <see cref="RgbaVector"/> struct.
@ -203,174 +94,111 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>
/// The <see cref="RgbaVector"/>.
/// </returns>
public static RgbaVector FromHex(string hex)
{
return ColorBuilder<RgbaVector>.FromHex(hex);
}
public static RgbaVector FromHex(string hex) => ColorBuilder<RgbaVector>.FromHex(hex);
/// <inheritdoc />
public PixelOperations<RgbaVector> CreatePixelOperations() => new RgbaVector.PixelOperations();
public PixelOperations<RgbaVector> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.backingVector = source.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.backingVector = source.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
this.backingVector = source.ToVector4();
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One);
this.R = vector.X;
this.G = vector.Y;
this.B = vector.Z;
this.A = vector.W;
}
/// <summary>
/// Converts the value of this instance to a hexadecimal string.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
public string ToHex()
{
// Hex is RRGGBBAA
Vector4 vector = this.backingVector * MaxBytes;
vector += Half;
uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24);
return hexOrder.ToString("X8");
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{
return this.ToVector4();
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
/// <summary>
/// Converts the value of this instance to a hexadecimal string.
/// </summary>
/// <returns>A hexadecimal string representation of the value.</returns>
public string ToHex()
{
this.backingVector = vector;
// Hex is RRGGBBAA
Vector4 vector = this.ToVector4() * Max;
vector += Half;
uint hexOrder = (uint)((byte)vector.W | (byte)vector.Z << 8 | (byte)vector.Y << 16 | (byte)vector.X << 24);
return hexOrder.ToString("X8");
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return this.backingVector;
}
public override bool Equals(object obj) => obj is RgbaVector other && this.Equals(other);
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is RgbaVector other && this.Equals(other);
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(RgbaVector other) =>
this.R.Equals(other.R)
&& this.G.Equals(other.G)
&& this.B.Equals(other.B)
&& this.A.Equals(other.A);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(RgbaVector other)
{
return this.backingVector == other.backingVector;
}
/// <summary>
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
public override string ToString()
{
return this.ToVector4().ToString();
var vector = this.ToVector4();
return FormattableString.Invariant($"RgbaVector({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})");
}
/// <inheritdoc/>
public override int GetHashCode()
{
return this.backingVector.GetHashCode();
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
hash = HashHelpers.Combine(hash, this.B.GetHashCode());
return HashHelpers.Combine(hash, this.A.GetHashCode());
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4() => Vector4.Clamp(this.backingVector, Vector4.Zero, Vector4.One) * MaxBytes;
}
}

238
src/ImageSharp/PixelFormats/Short2.cs

@ -15,39 +15,30 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct Short2 : IPixel<Short2>, IPackedVector<uint>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector2 MaxBytes = new Vector2(255);
// Largest two byte positive number 0xFFFF >> 1;
private const float MaxPos = 0x7FFF;
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector2 Half = new Vector2(127);
// Two's complement
private const float MinNeg = ~(int)MaxPos;
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector2 Round = new Vector2(.5F);
private static readonly Vector2 Max = new Vector2(MaxPos);
private static readonly Vector2 Min = new Vector2(MinNeg);
/// <summary>
/// Initializes a new instance of the <see cref="Short2"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public Short2(Vector2 vector)
/// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param>
public Short2(float x, float y)
: this(new Vector2(x, y))
{
this.PackedValue = Pack(vector.X, vector.Y);
}
/// <summary>
/// Initializes a new instance of the <see cref="Short2"/> struct.
/// </summary>
/// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param>
public Short2(float x, float y)
{
this.PackedValue = Pack(x, y);
}
/// <param name="vector">The vector containing the component values.</param>
public Short2(Vector2 vector) => this.PackedValue = Pack(vector);
/// <inheritdoc/>
public uint PackedValue { get; set; }
@ -55,53 +46,39 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary>
/// Compares two <see cref="Short2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Short2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Short2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Short2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Short2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Short2 left, Short2 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Short2 left, Short2 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Short2"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Short2"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Short2"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Short2"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Short2"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Short2 left, Short2 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Short2> CreatePixelOperations() => new PixelOperations<Short2>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F;
scaled -= new Vector2(32767F);
this.PackedValue = Pack(scaled.X, scaled.Y);
this.PackedValue = Pack(scaled);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector2();
@ -111,182 +88,91 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y);
var vector2 = new Vector2(vector.X, vector.Y);
this.PackedValue = Pack(vector2);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() => new Vector4((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
Vector2 vector = new Vector2(source.R, source.G) / 255;
vector *= 65534;
vector -= new Vector2(32767);
this.PackedValue = Pack(vector.X, vector.Y);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
Vector2 vector = new Vector2(source.R, source.G) / 255;
vector *= 65534;
vector -= new Vector2(32767);
this.PackedValue = Pack(vector.X, vector.Y);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
Vector2 vector = new Vector2(source.R, source.G) / 255;
vector *= 65534;
vector -= new Vector2(32767);
this.PackedValue = Pack(vector.X, vector.Y);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector2 vector = this.ToByteScaledVector2();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 ToVector2()
{
return new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10));
}
[MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2() => new Vector2((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10));
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Short2 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is Short2 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Short2 other)
{
return this == other;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Short2 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc />
public override string ToString()
{
return this.PackedValue.ToString("x8");
var vector = this.ToVector2();
return FormattableString.Invariant($"Short2({vector.X:#0.##}, {vector.Y:#0.##})");
}
/// <summary>
/// Packs the <see cref="float"/> components into a <see cref="uint"/>.
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y)
[MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(Vector2 vector)
{
// Largest two byte positive number 0xFFFF >> 1;
const float MaxPos = 0x7FFF;
const float MinNeg = ~(int)MaxPos;
// Clamp the value between min and max values
uint word2 = (uint)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF;
uint word1 = ((uint)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10;
vector = Vector2.Clamp(vector, Min, Max);
uint word2 = (uint)Math.Round(vector.X) & 0xFFFF;
uint word1 = ((uint)Math.Round(vector.Y) & 0xFFFF) << 0x10;
return word2 | word1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector2 ToByteScaledVector2()
{
var vector = this.ToVector2();
vector /= 65534;
vector *= 255;
vector += Half;
vector += Round;
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
return vector;
}
}
}

236
src/ImageSharp/PixelFormats/Short4.cs

@ -15,29 +15,14 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary>
public struct Short4 : IPixel<Short4>, IPackedVector<ulong>
{
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
// Largest two byte positive number 0xFFFF >> 1;
private const float MaxPos = 0x7FFF;
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
// Two's complement
private const float MinNeg = ~(int)MaxPos;
/// <summary>
/// Initializes a new instance of the <see cref="Short4"/> struct.
/// </summary>
/// <param name="vector">A vector containing the initial values for the components.</param>
public Short4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
private static readonly Vector4 Max = new Vector4(MaxPos);
private static readonly Vector4 Min = new Vector4(MinNeg);
/// <summary>
/// Initializes a new instance of the <see cref="Short4"/> struct.
@ -47,54 +32,46 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param>
public Short4(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{
this.PackedValue = Pack(x, y, z, w);
}
/// <summary>
/// Initializes a new instance of the <see cref="Short4"/> struct.
/// </summary>
/// <param name="vector">A vector containing the initial values for the components.</param>
public Short4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/>
public ulong PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="Short4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Short4"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Short4"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Short4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Short4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Short4 left, Short4 right)
{
return left.PackedValue == right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Short4 left, Short4 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Short4"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Short4"/> on the left side of the operand.
/// </param>
/// <param name="right">
/// The <see cref="Short4"/> on the right side of the operand.
/// </param>
/// <param name="left">The <see cref="Short4"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Short4"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Short4 left, Short4 right)
{
return left.PackedValue != right.PackedValue;
}
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Short4> CreatePixelOperations() => new PixelOperations<Short4>();
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector)
{
vector *= 65534F;
@ -103,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4()
{
var scaled = this.ToVector4();
@ -113,14 +90,11 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
return new Vector4(
@ -131,168 +105,78 @@ namespace SixLabors.ImageSharp.PixelFormats
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
var vector = source.ToVector4();
vector *= 65534;
vector -= new Vector4(32767);
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
var vector = source.ToVector4();
vector *= 65534;
vector -= new Vector4(32767);
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
var vector = source.ToVector4();
vector *= 65534;
vector -= new Vector4(32767);
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba32(ref Rgba32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToArgb32(ref Argb32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgr24(ref Bgr24 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToBgra32(ref Bgra32 dest)
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc />
public override bool Equals(object obj)
{
return obj is Short4 other && this.Equals(other);
}
public override bool Equals(object obj) => obj is Short4 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Short4 other)
{
return this == other;
}
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Short4 other) => this.PackedValue.Equals(other);
/// <summary>
/// Gets the hash code for the current instance.
/// </summary>
/// <returns>Hash code for the instance.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary>
/// Returns a string representation of the current instance.
/// </summary>
/// <returns>String that represents the object.</returns>
/// <inheritdoc />
public override string ToString()
{
return this.PackedValue.ToString("x16");
var vector = this.ToVector4();
return FormattableString.Invariant($"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
}
/// <summary>
/// Packs the components into a <see cref="ulong"/>.
/// </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>
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Pack(float x, float y, float z, float w)
[MethodImpl(InliningOptions.ShortMethod)]
private static ulong Pack(ref Vector4 vector)
{
// Largest two byte positive number 0xFFFF >> 1;
const float MaxPos = 0x7FFF;
// Two's complement
const float MinNeg = ~(int)MaxPos;
vector = Vector4.Clamp(vector, Min, Max);
// Clamp the value between min and max values
ulong word4 = ((ulong)Math.Round(x.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x00;
ulong word3 = ((ulong)Math.Round(y.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x10;
ulong word2 = ((ulong)Math.Round(z.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x20;
ulong word1 = ((ulong)Math.Round(w.Clamp(MinNeg, MaxPos)) & 0xFFFF) << 0x30;
ulong word4 = ((ulong)Math.Round(vector.X) & 0xFFFF) << 0x00;
ulong word3 = ((ulong)Math.Round(vector.Y) & 0xFFFF) << 0x10;
ulong word2 = ((ulong)Math.Round(vector.Z) & 0xFFFF) << 0x20;
ulong word1 = ((ulong)Math.Round(vector.W) & 0xFFFF) << 0x30;
return word4 | word3 | word2 | word1;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector /= 65534;
vector *= 255;
vector += Half;
vector += Round;
return Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
}
}
}

11
src/ImageSharp/Processing/Processors/Binarization/BinaryErrorDiffusionProcessor.cs

@ -76,8 +76,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
float threshold = this.Threshold * 255F;
Rgba32 rgba = default;
byte threshold = (byte)MathF.Round(this.Threshold * 255F);
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
@ -89,10 +88,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
sourcePixel.ToRgba32(ref rgba);
var rgba = sourcePixel.ToRgba32();
// Convert to grayscale using ITU-R Recommendation BT.709 if required
float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
for (int y = startY; y < endY; y++)
{
@ -106,8 +105,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
rgba = sourcePixel.ToRgba32();
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;

9
src/ImageSharp/Processing/Processors/Binarization/BinaryOrderedDitherProcessor.cs

@ -56,7 +56,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
Rgba32 rgba = default;
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
@ -68,10 +67,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
// Collect the values before looping so we can reduce our calculation count for identical sibling pixels
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
sourcePixel.ToRgba32(ref rgba);
var rgba = sourcePixel.ToRgba32();
// Convert to grayscale using ITU-R Recommendation BT.709 if required
float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
for (int y = startY; y < endY; y++)
{
@ -85,8 +84,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
// rather than calculating it again. This is an inexpensive optimization.
if (!previousPixel.Equals(sourcePixel))
{
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
rgba = sourcePixel.ToRgba32();
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;

9
src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs

@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
Rectangle sourceRectangle,
Configuration configuration)
{
float threshold = this.Threshold * 255F;
byte threshold = (byte)MathF.Round(this.Threshold * 255F);
TPixel upper = this.UpperColor;
TPixel lower = this.LowerColor;
@ -83,17 +83,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization
for (int y = rows.Min; y < rows.Max; y++)
{
Span<TPixel> row = source.GetPixelRowSpan(y);
Rgba32 rgba = default;
for (int x = startX; x < endX; x++)
{
ref TPixel color = ref row[x];
color.ToRgba32(ref rgba);
var rgba = color.ToRgba32();
// Convert to grayscale using ITU-R Recommendation BT.709 if required
float luminance = isAlphaOnly
? rgba.A
: (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
color = luminance >= threshold ? upper : lower;
}
}

12
src/ImageSharp/Processing/Processors/Dithering/ErrorDiffusionPaletteProcessor.cs

@ -4,7 +4,6 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
@ -64,8 +63,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
float threshold = this.Threshold * 255F;
Rgba32 rgba = default;
byte threshold = (byte)MathF.Round(this.Threshold * 255F);
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
@ -78,10 +76,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
PixelPair<TPixel> pair = this.GetClosestPixelPair(ref sourcePixel);
sourcePixel.ToRgba32(ref rgba);
var rgba = sourcePixel.ToRgba32();
// Convert to grayscale using ITU-R Recommendation BT.709 if required
float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
for (int y = startY; y < endY; y++)
{
@ -103,8 +101,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
continue;
}
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
rgba = sourcePixel.ToRgba32();
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;

15
src/ImageSharp/Processing/Processors/Dithering/OrderedDitherPaletteProcessor.cs

@ -4,7 +4,6 @@
using System;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Processing.Processors.Dithering;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors.Dithering
@ -32,10 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
/// <param name="dither">The ordered ditherer.</param>
/// <param name="palette">The palette to select substitute colors from.</param>
public OrderedDitherPaletteProcessor(IOrderedDither dither, TPixel[] palette)
: base(palette)
{
this.Dither = dither ?? throw new ArgumentNullException(nameof(dither));
}
: base(palette) => this.Dither = dither ?? throw new ArgumentNullException(nameof(dither));
/// <summary>
/// Gets the ditherer.
@ -45,7 +41,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
/// <inheritdoc/>
protected override void OnFrameApply(ImageFrame<TPixel> source, Rectangle sourceRectangle, Configuration configuration)
{
Rgba32 rgba = default;
bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8);
var interest = Rectangle.Intersect(sourceRectangle, source.Bounds());
@ -58,10 +53,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
TPixel sourcePixel = source[startX, startY];
TPixel previousPixel = sourcePixel;
PixelPair<TPixel> pair = this.GetClosestPixelPair(ref sourcePixel);
sourcePixel.ToRgba32(ref rgba);
var rgba = sourcePixel.ToRgba32();
// Convert to grayscale using ITU-R Recommendation BT.709 if required
float luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
byte luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
for (int y = startY; y < endY; y++)
{
@ -83,8 +78,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Dithering
continue;
}
sourcePixel.ToRgba32(ref rgba);
luminance = isAlphaOnly ? rgba.A : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B);
rgba = sourcePixel.ToRgba32();
luminance = isAlphaOnly ? rgba.A : ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
// Setup the previous pointer
previousPixel = sourcePixel;

49
src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs

@ -73,14 +73,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row);
// And loop through each column
Rgba32 rgba = default;
for (int x = 0; x < width; x++)
{
ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x);
pixel.ToRgba32(ref rgba);
// Add the color to the Octree
this.octree.AddColor(ref pixel, ref rgba);
this.octree.AddColor(ref pixel);
}
}
}
@ -97,9 +95,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
// pass of the algorithm by avoiding transforming rows of identical color.
TPixel sourcePixel = source[0, 0];
TPixel previousPixel = sourcePixel;
Rgba32 rgba = default;
this.transparentIndex = this.GetTransparentIndex();
byte pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba);
byte pixelValue = this.QuantizePixel(ref sourcePixel);
TPixel transformedPixel = palette[pixelValue];
for (int y = 0; y < height; y++)
@ -117,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
if (!previousPixel.Equals(sourcePixel))
{
// Quantize the pixel
pixelValue = this.QuantizePixel(ref sourcePixel, ref rgba);
pixelValue = this.QuantizePixel(ref sourcePixel);
// And setup the previous pointer
previousPixel = sourcePixel;
@ -146,10 +143,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Process the pixel in the second pass of the algorithm.
/// </summary>
/// <param name="pixel">The pixel to quantize.</param>
/// <param name="rgba">The color to compare against.</param>
/// <returns>The <see cref="byte"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private byte QuantizePixel(ref TPixel pixel, ref Rgba32 rgba)
private byte QuantizePixel(ref TPixel pixel)
{
if (this.Dither)
{
@ -158,13 +154,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
return this.GetClosestPixel(ref pixel);
}
pixel.ToRgba32(ref rgba);
var rgba = pixel.ToRgba32();
if (rgba.Equals(default))
{
return this.transparentIndex;
}
return (byte)this.octree.GetPaletteIndex(ref pixel, ref rgba);
return (byte)this.octree.GetPaletteIndex(ref pixel);
}
/// <summary>
@ -239,8 +235,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Add a given color value to the Octree
/// </summary>
/// <param name="pixel">The pixel data.</param>
/// <param name="rgba">The color.</param>
public void AddColor(ref TPixel pixel, ref Rgba32 rgba)
public void AddColor(ref TPixel pixel)
{
// Check if this request is for the same color as the last
if (this.previousColor.Equals(pixel))
@ -250,18 +245,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
if (this.previousNode is null)
{
this.previousColor = pixel;
this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba);
this.root.AddColor(ref pixel, this.maxColorBits, 0, this);
}
else
{
// Just update the previous node
this.previousNode.Increment(ref pixel, ref rgba);
this.previousNode.Increment(ref pixel);
}
}
else
{
this.previousColor = pixel;
this.root.AddColor(ref pixel, this.maxColorBits, 0, this, ref rgba);
this.root.AddColor(ref pixel, this.maxColorBits, 0, this);
}
}
@ -294,12 +289,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Get the palette index for the passed color
/// </summary>
/// <param name="pixel">The pixel data.</param>
/// <param name="rgba">The color to map to.</param>
/// <returns>
/// The <see cref="int"/>.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public int GetPaletteIndex(ref TPixel pixel, ref Rgba32 rgba) => this.root.GetPaletteIndex(ref pixel, 0, ref rgba);
public int GetPaletteIndex(ref TPixel pixel) => this.root.GetPaletteIndex(ref pixel, 0);
/// <summary>
/// Keep track of the previous node that was quantized
@ -426,13 +420,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// <param name="colorBits">The number of significant color bits</param>
/// <param name="level">The level in the tree</param>
/// <param name="octree">The tree to which this node belongs</param>
/// <param name="rgba">The color to map to.</param>
public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree, ref Rgba32 rgba)
public void AddColor(ref TPixel pixel, int colorBits, int level, Octree octree)
{
// Update the color information if this is a leaf
if (this.leaf)
{
this.Increment(ref pixel, ref rgba);
this.Increment(ref pixel);
// Setup the previous node
octree.TrackPrevious(this);
@ -441,7 +434,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
{
// Go to the next level down in the tree
int shift = 7 - level;
pixel.ToRgba32(ref rgba);
var rgba = pixel.ToRgba32();
int index = ((rgba.B & Mask[level]) >> (shift - 2))
| ((rgba.G & Mask[level]) >> (shift - 1))
@ -456,7 +449,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
// Add the color to the child node
child.AddColor(ref pixel, colorBits, level + 1, octree, ref rgba);
child.AddColor(ref pixel, colorBits, level + 1, octree);
}
}
@ -525,19 +518,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// </summary>
/// <param name="pixel">The pixel data.</param>
/// <param name="level">The level.</param>
/// <param name="rgba">The color to map to.</param>
/// <returns>
/// The <see cref="int"/> representing the index of the pixel in the palette.
/// </returns>
[MethodImpl(MethodImplOptions.NoInlining)]
public int GetPaletteIndex(ref TPixel pixel, int level, ref Rgba32 rgba)
public int GetPaletteIndex(ref TPixel pixel, int level)
{
int index = this.paletteIndex;
if (!this.leaf)
{
int shift = 7 - level;
pixel.ToRgba32(ref rgba);
var rgba = pixel.ToRgba32();
int pixelIndex = ((rgba.B & Mask[level]) >> (shift - 2))
| ((rgba.G & Mask[level]) >> (shift - 1))
@ -546,7 +538,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
OctreeNode child = this.children[pixelIndex];
if (child != null)
{
index = child.GetPaletteIndex(ref pixel, level + 1, ref rgba);
index = child.GetPaletteIndex(ref pixel, level + 1);
}
else
{
@ -561,11 +553,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
/// Increment the pixel count and add to the color information
/// </summary>
/// <param name="pixel">The pixel to add.</param>
/// <param name="rgba">The color to map to.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Increment(ref TPixel pixel, ref Rgba32 rgba)
public void Increment(ref TPixel pixel)
{
pixel.ToRgba32(ref rgba);
var rgba = pixel.ToRgba32();
this.pixelCount++;
this.red += rgba.R;
this.green += rgba.G;

48
src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs

@ -442,33 +442,36 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
// Build up the 3-D color histogram
// Loop through each row
for (int y = 0; y < height; y++)
using (IMemoryOwner<Rgba32> rgbaBuffer = source.MemoryAllocator.Allocate<Rgba32>(source.Width))
{
Span<TPixel> row = source.GetPixelRowSpan(y);
ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row);
// And loop through each column
Rgba32 rgba = default;
for (int x = 0; x < width; x++)
for (int y = 0; y < height; y++)
{
ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x);
pixel.ToRgba32(ref rgba);
Span<TPixel> row = source.GetPixelRowSpan(y);
Span<Rgba32> rgbaSpan = rgbaBuffer.GetSpan();
PixelOperations<TPixel>.Instance.ToRgba32(row, rgbaSpan, source.Width);
ref Rgba32 scanBaseRef = ref MemoryMarshal.GetReference(rgbaSpan);
// And loop through each column
for (int x = 0; x < width; x++)
{
ref Rgba32 rgba = ref Unsafe.Add(ref scanBaseRef, x);
int r = rgba.R >> (8 - IndexBits);
int g = rgba.G >> (8 - IndexBits);
int b = rgba.B >> (8 - IndexBits);
int a = rgba.A >> (8 - IndexAlphaBits);
int r = rgba.R >> (8 - IndexBits);
int g = rgba.G >> (8 - IndexBits);
int b = rgba.B >> (8 - IndexBits);
int a = rgba.A >> (8 - IndexAlphaBits);
int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1);
vwtSpan[index]++;
vmrSpan[index] += rgba.R;
vmgSpan[index] += rgba.G;
vmbSpan[index] += rgba.B;
vmaSpan[index] += rgba.A;
vwtSpan[index]++;
vmrSpan[index] += rgba.R;
vmgSpan[index] += rgba.G;
vmbSpan[index] += rgba.B;
vmaSpan[index] += rgba.A;
var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A);
m2Span[index] += Vector4.Dot(vector, vector);
var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A);
m2Span[index] += Vector4.Dot(vector, vector);
}
}
}
}
@ -876,8 +879,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization
}
// Expected order r->g->b->a
Rgba32 rgba = default;
pixel.ToRgba32(ref rgba);
var rgba = pixel.ToRgba32();
int r = rgba.R >> (8 - IndexBits);
int g = rgba.G >> (8 - IndexBits);

68
tests/ImageSharp.Benchmarks/Color/Bulk/PackFromVector4.cs

@ -3,6 +3,7 @@
// ReSharper disable InconsistentNaming
using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices;
@ -19,11 +20,14 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
public abstract class PackFromVector4<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private IMemoryOwner<Vector4> source;
protected IMemoryOwner<Vector4> source;
private IMemoryOwner<TPixel> destination;
protected IMemoryOwner<TPixel> destination;
[Params(16, 128, 512)]
[Params(
64,
2048
)]
public int Count { get; set; }
[GlobalSetup]
@ -40,7 +44,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
this.source.Dispose();
}
[Benchmark(Baseline = true)]
//[Benchmark]
public void PerElement()
{
ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan());
@ -53,13 +57,13 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
}
[Benchmark]
public void CommonBulk()
public void PixelOperations_Base()
{
new PixelOperations<TPixel>().PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
public void PixelOperations_Specialized()
{
PixelOperations<TPixel>.Instance.PackFromVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
@ -67,6 +71,58 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
public class PackFromVector4_Rgba32 : PackFromVector4<Rgba32>
{
[Benchmark]
public void FallbackIntrinsics128()
{
Span<float> sBytes = MemoryMarshal.Cast<Vector4, float>(this.source.GetSpan());
Span<byte> dFloats = MemoryMarshal.Cast<Rgba32, byte>(this.destination.GetSpan());
SimdUtils.FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats);
}
[Benchmark(Baseline = true)]
public void BasicIntrinsics256()
{
Span<float> sBytes = MemoryMarshal.Cast<Vector4, float>(this.source.GetSpan());
Span<byte> dFloats = MemoryMarshal.Cast<Rgba32, byte>(this.destination.GetSpan());
SimdUtils.BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats);
}
[Benchmark]
public void ExtendedIntrinsic()
{
Span<float> sBytes = MemoryMarshal.Cast<Vector4, float>(this.source.GetSpan());
Span<byte> dFloats = MemoryMarshal.Cast<Rgba32, byte>(this.destination.GetSpan());
SimdUtils.ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflows(sBytes, dFloats);
}
// RESULTS (2018 October):
// Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
// ---------------------------- |-------- |------ |-------------:|-------------:|------------:|-------:|---------:|-------:|----------:|
// FallbackIntrinsics128 | Clr | 64 | 340.38 ns | 22.319 ns | 1.2611 ns | 1.41 | 0.01 | - | 0 B |
// BasicIntrinsics256 | Clr | 64 | 240.79 ns | 11.421 ns | 0.6453 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsic | Clr | 64 | 199.09 ns | 124.239 ns | 7.0198 ns | 0.83 | 0.02 | - | 0 B |
// PixelOperations_Base | Clr | 64 | 647.99 ns | 24.003 ns | 1.3562 ns | 2.69 | 0.01 | 0.0067 | 24 B |
// PixelOperations_Specialized | Clr | 64 | 259.79 ns | 13.391 ns | 0.7566 ns | 1.08 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized!
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 64 | 234.64 ns | 12.320 ns | 0.6961 ns | 1.58 | 0.00 | - | 0 B |
// BasicIntrinsics256 | Core | 64 | 148.87 ns | 2.794 ns | 0.1579 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsic | Core | 64 | 94.06 ns | 10.015 ns | 0.5659 ns | 0.63 | 0.00 | - | 0 B |
// PixelOperations_Base | Core | 64 | 573.52 ns | 31.865 ns | 1.8004 ns | 3.85 | 0.01 | 0.0067 | 24 B |
// PixelOperations_Specialized | Core | 64 | 117.21 ns | 13.264 ns | 0.7494 ns | 0.79 | 0.00 | - | 0 B |
// | | | | | | | | | |
// FallbackIntrinsics128 | Clr | 2048 | 6,735.93 ns | 2,139.340 ns | 120.8767 ns | 1.71 | 0.03 | - | 0 B |
// BasicIntrinsics256 | Clr | 2048 | 3,929.29 ns | 334.027 ns | 18.8731 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsic | Clr | 2048 | 2,226.01 ns | 130.525 ns | 7.3749 ns |!! 0.57 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Clr | 2048 | 16,760.84 ns | 367.800 ns | 20.7814 ns | 4.27 | 0.02 | - | 24 B | <--- Extra copies using "Vector4 TPixel.ToVector4()"
// PixelOperations_Specialized | Clr | 2048 | 3,986.03 ns | 237.238 ns | 13.4044 ns | 1.01 | 0.00 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :(
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 2048 | 6,644.65 ns | 2,677.090 ns | 151.2605 ns | 1.69 | 0.05 | - | 0 B |
// BasicIntrinsics256 | Core | 2048 | 3,923.70 ns | 1,971.760 ns | 111.4081 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsic | Core | 2048 | 2,092.32 ns | 375.657 ns | 21.2253 ns |!! 0.53 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Core | 2048 | 16,875.73 ns | 1,271.957 ns | 71.8679 ns | 4.30 | 0.10 | - | 24 B |
// PixelOperations_Specialized | Core | 2048 | 2,129.92 ns | 262.888 ns | 14.8537 ns |!! 0.54 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock!
}
}

166
tests/ImageSharp.Benchmarks/Color/Bulk/ToVector4.cs

@ -6,8 +6,14 @@
using System.Buffers;
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Jobs;
using BenchmarkDotNet.Configs;
using BenchmarkDotNet.Environments;
using BenchmarkDotNet.Jobs;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -17,11 +23,17 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
public abstract class ToVector4<TPixel>
where TPixel : struct, IPixel<TPixel>
{
private IMemoryOwner<TPixel> source;
protected IMemoryOwner<TPixel> source;
private IMemoryOwner<Vector4> destination;
protected IMemoryOwner<Vector4> destination;
[Params(64, 300, 1024)]
[Params(
64,
//256,
//512,
//1024,
2048
)]
public int Count { get; set; }
[GlobalSetup]
@ -38,7 +50,7 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
this.destination.Dispose();
}
[Benchmark(Baseline = true)]
//[Benchmark]
public void PerElement()
{
Span<TPixel> s = this.source.GetSpan();
@ -46,25 +58,163 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
for (int i = 0; i < this.Count; i++)
{
TPixel c = s[i];
d[i] = c.ToVector4();
d[i] = s[i].ToVector4();
}
}
[Benchmark]
public void CommonBulk()
public void PixelOperations_Base()
{
new PixelOperations<TPixel>().ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
public void PixelOperations_Specialized()
{
PixelOperations<TPixel>.Instance.ToVector4(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
}
[Config(typeof(Config.ShortClr))]
public class ToVector4_Rgba32 : ToVector4<Rgba32>
{
[Benchmark]
public void FallbackIntrinsics128()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.FallbackIntrinsics128.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
[Benchmark(Baseline = true)]
public void BasicIntrinsics256()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.BasicIntrinsics256.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
[Benchmark]
public void ExtendedIntrinsics()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
SimdUtils.ExtendedIntrinsics.BulkConvertByteToNormalizedFloat(sBytes, dFloats);
}
//[Benchmark]
public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
int n = dFloats.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference((ReadOnlySpan<byte>)sBytes));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dFloats));
ref Vector<uint> destBaseU = ref Unsafe.As<Vector<float>, Vector<uint>>(ref destBase);
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
ref Vector<uint> d = ref Unsafe.Add(ref destBaseU, i * 4);
d = w0;
Unsafe.Add(ref d, 1) = w1;
Unsafe.Add(ref d, 2) = w2;
Unsafe.Add(ref d, 3) = w3;
}
n = dFloats.Length / Vector<float>.Count;
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
ref Vector<float> dRef = ref Unsafe.Add(ref destBase, i);
Vector<int> du = Vector.AsVectorInt32(dRef);
Vector<float> v = Vector.ConvertToSingle(du);
v *= scale;
dRef = v;
}
}
//[Benchmark]
public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop()
{
Span<byte> sBytes = MemoryMarshal.Cast<Rgba32, byte>(this.source.GetSpan());
Span<float> dFloats = MemoryMarshal.Cast<Vector4, float>(this.destination.GetSpan());
int n = dFloats.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference((ReadOnlySpan<byte>)sBytes));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dFloats));
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
Vector<float> f0 = ConvertToNormalizedSingle(w0, scale);
Vector<float> f1 = ConvertToNormalizedSingle(w1, scale);
Vector<float> f2 = ConvertToNormalizedSingle(w2, scale);
Vector<float> f3 = ConvertToNormalizedSingle(w3, scale);
ref Vector<float> d = ref Unsafe.Add(ref destBase, i * 4);
d = f0;
Unsafe.Add(ref d, 1) = f1;
Unsafe.Add(ref d, 2) = f2;
Unsafe.Add(ref d, 3) = f3;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> ConvertToNormalizedSingle(Vector<uint> u, Vector<float> scale)
{
Vector<int> vi = Vector.AsVectorInt32(u);
Vector<float> v = Vector.ConvertToSingle(vi);
v *= scale;
return v;
}
// RESULTS (2018 October):
//
// Method | Runtime | Count | Mean | Error | StdDev | Scaled | ScaledSD | Gen 0 | Allocated |
// ---------------------------- |-------- |------ |------------:|-------------:|------------:|-------:|---------:|-------:|----------:|
// FallbackIntrinsics128 | Clr | 64 | 287.62 ns | 6.026 ns | 0.3405 ns | 1.19 | 0.00 | - | 0 B |
// BasicIntrinsics256 | Clr | 64 | 240.83 ns | 10.585 ns | 0.5981 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Clr | 64 | 168.28 ns | 11.478 ns | 0.6485 ns | 0.70 | 0.00 | - | 0 B |
// PixelOperations_Base | Clr | 64 | 334.08 ns | 38.048 ns | 2.1498 ns | 1.39 | 0.01 | 0.0072 | 24 B |
// PixelOperations_Specialized | Clr | 64 | 255.41 ns | 10.939 ns | 0.6181 ns | 1.06 | 0.00 | - | 0 B | <--- ceremonial overhead has been minimized!
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 64 | 183.29 ns | 8.931 ns | 0.5046 ns | 1.32 | 0.00 | - | 0 B |
// BasicIntrinsics256 | Core | 64 | 139.18 ns | 7.633 ns | 0.4313 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Core | 64 | 66.29 ns | 16.366 ns | 0.9247 ns | 0.48 | 0.01 | - | 0 B |
// PixelOperations_Base | Core | 64 | 257.75 ns | 16.959 ns | 0.9582 ns | 1.85 | 0.01 | 0.0072 | 24 B |
// PixelOperations_Specialized | Core | 64 | 90.14 ns | 9.955 ns | 0.5625 ns | 0.65 | 0.00 | - | 0 B |
// | | | | | | | | | |
// FallbackIntrinsics128 | Clr | 2048 | 5,011.84 ns | 347.991 ns | 19.6621 ns | 1.22 | 0.01 | - | 0 B |
// BasicIntrinsics256 | Clr | 2048 | 4,119.35 ns | 720.153 ns | 40.6900 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Clr | 2048 | 1,195.29 ns | 164.389 ns | 9.2883 ns |!! 0.29 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Clr | 2048 | 6,820.58 ns | 823.433 ns | 46.5255 ns | 1.66 | 0.02 | - | 24 B |
// PixelOperations_Specialized | Clr | 2048 | 4,203.53 ns | 176.714 ns | 9.9847 ns | 1.02 | 0.01 | - | 0 B | <--- can't yet detect whether ExtendedIntrinsics are available :(
// | | | | | | | | | |
// FallbackIntrinsics128 | Core | 2048 | 5,017.89 ns | 4,021.533 ns | 227.2241 ns | 1.24 | 0.05 | - | 0 B |
// BasicIntrinsics256 | Core | 2048 | 4,046.51 ns | 1,150.390 ns | 64.9992 ns | 1.00 | 0.00 | - | 0 B |
// ExtendedIntrinsics | Core | 2048 | 1,130.59 ns | 832.588 ns | 47.0427 ns |!! 0.28 | 0.01 | - | 0 B | <--- ExtendedIntrinsics rock!
// PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B |
// PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock!
}
}

32
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyz.cs

@ -4,10 +4,7 @@
// ReSharper disable InconsistentNaming
using System.Buffers;
using System;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats;
@ -38,35 +35,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
}
[Benchmark(Baseline = true)]
public void PerElement()
{
Span<TPixel> s = this.source.GetSpan();
Span<byte> d = this.destination.GetSpan();
var rgb = default(Rgb24);
for (int i = 0; i < this.Count; i++)
{
TPixel c = s[i];
int i3 = i * 3;
c.ToRgb24(ref rgb);
d[i3] = rgb.R;
d[i3 + 1] = rgb.G;
d[i3 + 2] = rgb.B;
}
}
public void CommonBulk() => new PixelOperations<TPixel>().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
public void OptimizedBulk() => PixelOperations<TPixel>.Instance.ToRgb24Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
public class ToXyz_Rgba32 : ToXyz<Rgba32>

14
tests/ImageSharp.Benchmarks/Color/Bulk/ToXyzw.cs

@ -42,13 +42,11 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
Span<TPixel> s = this.source.GetSpan();
Span<byte> d = this.destination.GetSpan();
var rgba = default(Rgba32);
for (int i = 0; i < this.Count; i++)
{
TPixel c = s[i];
int i4 = i * 4;
c.ToRgba32(ref rgba);
var rgba = c.ToRgba32();
d[i4] = rgba.R;
d[i4 + 1] = rgba.G;
d[i4 + 2] = rgba.B;
@ -57,16 +55,10 @@ namespace SixLabors.ImageSharp.Benchmarks.ColorSpaces.Bulk
}
[Benchmark]
public void CommonBulk()
{
new PixelOperations<TPixel>().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
public void CommonBulk() => new PixelOperations<TPixel>().ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
[Benchmark]
public void OptimizedBulk()
{
PixelOperations<TPixel>.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
public void OptimizedBulk() => PixelOperations<TPixel>.Instance.ToRgba32Bytes(this.source.GetSpan(), this.destination.GetSpan(), this.Count);
}
public class ToXyzw_Rgba32 : ToXyzw<Rgba32>

8
tests/ImageSharp.Benchmarks/General/Abs.cs → tests/ImageSharp.Benchmarks/General/BasicMath/Abs.cs

@ -1,9 +1,9 @@
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System;
using System;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
{
public class Abs
{
[Params(-1, 1)]

70
tests/ImageSharp.Benchmarks/General/BasicMath/ClampFloat.cs

@ -0,0 +1,70 @@
using System;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Running;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
{
public class ClampFloat
{
private readonly float min = -1.5f;
private readonly float max = 2.5f;
private static readonly float[] Values = { -10, -5, -3, -1.5f, -0.5f, 0f, 1f, 1.5f, 2.5f, 3, 10 };
[Benchmark(Baseline = true)]
public float UsingMathF()
{
float acc = 0;
for (int i = 0; i < Values.Length; i++)
{
acc += ClampUsingMathF(Values[i], this.min, this.max);
}
return acc;
}
[Benchmark]
public float UsingBranching()
{
float acc = 0;
for (int i = 0; i < Values.Length; i++)
{
acc += ClampUsingBranching(Values[i], this.min, this.max);
}
return acc;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ClampUsingMathF(float x, float min, float max)
{
return Math.Min(max, Math.Max(min, x));
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ClampUsingBranching(float x, float min, float max)
{
if (x >= max)
{
return max;
}
if (x <= min)
{
return min;
}
return x;
}
// RESULTS:
// Method | Mean | Error | StdDev | Scaled |
// --------------- |---------:|----------:|----------:|-------:|
// UsingMathF | 30.37 ns | 0.3764 ns | 0.3337 ns | 1.00 |
// UsingBranching | 18.66 ns | 0.1043 ns | 0.0871 ns | 0.61 |
}
}

12
tests/ImageSharp.Benchmarks/General/Clamp.cs → tests/ImageSharp.Benchmarks/General/BasicMath/ClampInt32IntoByte.cs

@ -3,14 +3,14 @@
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System;
using System.Runtime.CompilerServices;
using System;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
public class Clamp
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
{
public class ClampInt32IntoByte
{
[Params(-1, 0, 255, 256)]
public int Value { get; set; }

23
tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoConstant.cs

@ -0,0 +1,23 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Jobs;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
{
[LongRunJob]
public class ModuloPowerOfTwoConstant
{
private readonly int value = 42;
[Benchmark(Baseline = true)]
public int Standard()
{
return this.value % 8;
}
[Benchmark]
public int Bitwise()
{
return ImageMaths.Modulo8(this.value);
}
}
}

32
tests/ImageSharp.Benchmarks/General/BasicMath/ModuloPowerOfTwoVariable.cs

@ -0,0 +1,32 @@
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes.Jobs;
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
{
[LongRunJob]
public class ModuloPowerOfTwoVariable
{
private readonly int value = 42;
private readonly int m = 32;
[Benchmark(Baseline = true)]
public int Standard()
{
return this.value % this.m;
}
[Benchmark]
public int Bitwise()
{
return ImageMaths.ModuloP2(this.value, this.m);
}
// RESULTS:
//
// Method | Mean | Error | StdDev | Median | Scaled | ScaledSD |
// --------- |----------:|----------:|----------:|----------:|-------:|---------:|
// Standard | 1.2465 ns | 0.0093 ns | 0.0455 ns | 1.2423 ns | 1.00 | 0.00 |
// Bitwise | 0.0265 ns | 0.0103 ns | 0.0515 ns | 0.0000 ns | 0.02 | 0.04 |
}
}

3
tests/ImageSharp.Benchmarks/General/Pow.cs → tests/ImageSharp.Benchmarks/General/BasicMath/Pow.cs

@ -1,7 +1,8 @@
using System;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General
namespace SixLabors.ImageSharp.Benchmarks.General.BasicMath
{
public class Pow
{

19
tests/ImageSharp.Benchmarks/General/Modulus.cs

@ -1,19 +0,0 @@
namespace SixLabors.ImageSharp.Benchmarks.General
{
using BenchmarkDotNet.Attributes;
public class Modulus
{
[Benchmark(Baseline = true, Description = "Standard Modulus using %")]
public int StandardModulus()
{
return 255 % 256;
}
[Benchmark(Description = "Bitwise Modulus using &")]
public int BitwiseModulus()
{
return 255 & 255;
}
}
}

28
tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs

@ -0,0 +1,28 @@
using System.Numerics;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
interface ITestPixel<T>
where T : struct, ITestPixel<T>
{
void FromRgba32(Rgba32 source);
void FromRgba32(ref Rgba32 source);
void FromBytes(byte r, byte g, byte b, byte a);
void FromVector4(Vector4 source);
void FromVector4(ref Vector4 source);
Rgba32 ToRgba32();
void CopyToRgba32(ref Rgba32 dest);
Vector4 ToVector4();
void CopyToVector4(ref Vector4 dest);
}
}

81
tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromRgba32.cs → tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs

@ -1,86 +1,15 @@
// ReSharper disable InconsistentNaming
using SixLabors.ImageSharp.PixelFormats;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_ConvertFromRgba32
{
interface ITestPixel<T>
where T : struct, ITestPixel<T>
{
void FromRgba32(Rgba32 source);
void FromRgba32(ref Rgba32 source);
void FromBytes(byte r, byte g, byte b, byte a);
}
[StructLayout(LayoutKind.Sequential)]
struct TestArgb : ITestPixel<TestArgb>
{
private byte a, r, g, b;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(Rgba32 p)
{
this.r = p.R;
this.g = p.G;
this.b = p.B;
this.a = p.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(ref Rgba32 p)
{
this.r = p.R;
this.g = p.G;
this.b = p.B;
this.a = p.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBytes(byte r, byte g, byte b, byte a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
}
[StructLayout(LayoutKind.Sequential)]
struct TestRgba : ITestPixel<TestRgba>
{
private byte r, g, b, a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(Rgba32 source)
{
this = Unsafe.As<Rgba32, TestRgba>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(ref Rgba32 source)
{
this = Unsafe.As<Rgba32, TestRgba>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBytes(byte r, byte g, byte b, byte a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
}
struct ConversionRunner<T>
where T : struct, ITestPixel<T>
{

58
tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertFromVector4.cs → tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs

@ -1,62 +1,48 @@
// ReSharper disable InconsistentNaming
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
public class PixelConversion_ConvertFromVector4
{
interface ITestPixel<T>
where T : struct, ITestPixel<T>
{
void FromVector4(Vector4 source);
using BenchmarkDotNet.Attributes;
void FromVector4(ref Vector4 source);
}
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_ConvertFromVector4
{
[StructLayout(LayoutKind.Sequential)]
struct TestArgb : ITestPixel<TestArgb>
struct TestRgbaVector : ITestPixel<TestRgbaVector>
{
private byte a, r, g, b;
private Vector4 v;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(Vector4 p)
{
this.r = (byte)p.X;
this.g = (byte)p.Y;
this.b = (byte)p.Z;
this.a = (byte)p.W;
this.v = p;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(ref Vector4 p)
{
this.r = (byte)p.X;
this.g = (byte)p.Y;
this.b = (byte)p.Z;
this.a = (byte)p.W;
this.v = p;
}
}
[StructLayout(LayoutKind.Sequential)]
struct TestRgbaVector : ITestPixel<TestRgbaVector>
{
private Vector4 v;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(Vector4 p)
{
this.v = p;
}
public Vector4 ToVector4() => this.v;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(ref Vector4 p)
public void CopyToVector4(ref Vector4 dest)
{
this.v = p;
dest = this.v;
}
public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException();
public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException();
public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException();
public Rgba32 ToRgba32() => throw new System.NotImplementedException();
public void CopyToRgba32(ref Rgba32 dest) => throw new System.NotImplementedException();
}
struct ConversionRunner<T>

61
tests/ImageSharp.Benchmarks/General/PixelConversion_ConvertToRgba32.cs → tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32.cs

@ -1,14 +1,14 @@
// ReSharper disable InconsistentNaming
using SixLabors.ImageSharp.PixelFormats;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Benchmarks.General
{
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using BenchmarkDotNet.Attributes;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
/// <summary>
/// When implementing TPixel --> Rgba32 style conversions on IPixel, should which API should we prefer?
/// 1. Rgba32 ToRgba32();
@ -18,53 +18,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General
/// </summary>
public class PixelConversion_ConvertToRgba32
{
interface ITestPixel<T>
where T : struct, ITestPixel<T>
{
Rgba32 ToRgba32();
void CopyToRgba32(ref Rgba32 dest);
}
[StructLayout(LayoutKind.Sequential)]
struct TestArgb : ITestPixel<TestArgb>
{
private byte a, r, g, b;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32()
{
return new Rgba32(this.r, this.g, this.b, this.a);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToRgba32(ref Rgba32 dest)
{
dest.R = this.r;
dest.G = this.g;
dest.B = this.b;
dest.A = this.a;
}
}
[StructLayout(LayoutKind.Sequential)]
struct TestRgba : ITestPixel<TestRgba>
{
private byte r, g, b, a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32()
{
return Unsafe.As<TestRgba, Rgba32>(ref this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToRgba32(ref Rgba32 dest)
{
dest = Unsafe.As<TestRgba, Rgba32>(ref this);
}
}
struct ConversionRunner<T>
where T : struct, ITestPixel<T>
{
@ -111,7 +64,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General
private ConversionRunner<TestArgb> permutedRunner;
[Params(128)]
[Params(32)]
public int Count { get; set; }
[GlobalSetup]

113
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation.cs

@ -0,0 +1,113 @@
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_ConvertToRgba32_AsPartOfCompositeOperation
{
struct ConversionRunner<T>
where T : struct, ITestPixel<T>
{
private T[] source;
private Rgba32[] dest;
public ConversionRunner(int count)
{
this.source = new T[count];
this.dest = new Rgba32[count];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunRetvalConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Rgba32 destBaseRef = ref this.dest[0];
Rgba32 temp;
for (int i = 0; i < count; i++)
{
temp = Unsafe.Add(ref sourceBaseRef, i).ToRgba32();
// manipulate pixel before saving to dest buffer:
temp.A = 0;
Unsafe.Add(ref destBaseRef, i) = temp;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunCopyToConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Rgba32 destBaseRef = ref this.dest[0];
Rgba32 temp = default;
for (int i = 0; i < count; i++)
{
Unsafe.Add(ref sourceBaseRef, i).CopyToRgba32(ref temp);
// manipulate pixel before saving to dest buffer:
temp.A = 0;
Unsafe.Add(ref destBaseRef, i) = temp;
}
}
}
private ConversionRunner<TestRgba> compatibleMemoryLayoutRunner;
private ConversionRunner<TestArgb> permutedRunner;
[Params(32)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.compatibleMemoryLayoutRunner = new ConversionRunner<TestRgba>(this.Count);
this.permutedRunner = new ConversionRunner<TestArgb>(this.Count);
}
[Benchmark(Baseline = true)]
public void CompatibleRetval()
{
this.compatibleMemoryLayoutRunner.RunRetvalConversion();
}
[Benchmark]
public void CompatibleCopyTo()
{
this.compatibleMemoryLayoutRunner.RunCopyToConversion();
}
[Benchmark]
public void PermutedRetval()
{
this.permutedRunner.RunRetvalConversion();
}
[Benchmark]
public void PermutedCopyTo()
{
this.permutedRunner.RunCopyToConversion();
}
}
// RESULTS:
// Method | Count | Mean | Error | StdDev | Scaled | ScaledSD |
// ----------------- |------ |----------:|----------:|----------:|-------:|---------:|
// CompatibleRetval | 32 | 53.05 ns | 0.1865 ns | 0.1557 ns | 1.00 | 0.00 |
// CompatibleCopyTo | 32 | 36.12 ns | 0.3596 ns | 0.3003 ns | 0.68 | 0.01 |
// PermutedRetval | 32 | 303.61 ns | 5.1697 ns | 4.8358 ns | 5.72 | 0.09 |
// PermutedCopyTo | 32 | 38.05 ns | 0.8053 ns | 1.2297 ns | 0.72 | 0.02 |
}

83
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4.cs

@ -0,0 +1,83 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_ConvertToVector4
{
struct ConversionRunner<T>
where T : struct, ITestPixel<T>
{
private T[] source;
private Vector4[] dest;
public ConversionRunner(int count)
{
this.source = new T[count];
this.dest = new Vector4[count];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunRetvalConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Vector4 destBaseRef = ref this.dest[0];
for (int i = 0; i < count; i++)
{
Unsafe.Add(ref destBaseRef, i) = Unsafe.Add(ref sourceBaseRef, i).ToVector4();
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunCopyToConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Vector4 destBaseRef = ref this.dest[0];
for (int i = 0; i < count; i++)
{
Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref Unsafe.Add(ref destBaseRef, i));
}
}
}
private ConversionRunner<TestRgba> runner;
[Params(32)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.runner = new ConversionRunner<TestRgba>(this.Count);
}
[Benchmark(Baseline = true)]
public void UseRetval()
{
this.runner.RunRetvalConversion();
}
[Benchmark]
public void UseCopyTo()
{
this.runner.RunCopyToConversion();
}
// RESULTS:
// Method | Count | Mean | Error | StdDev | Scaled |
// ---------- |------ |---------:|----------:|----------:|-------:|
// UseRetval | 32 | 94.99 ns | 1.1199 ns | 0.9352 ns | 1.00 |
// UseCopyTo | 32 | 59.47 ns | 0.6104 ns | 0.5710 ns | 0.63 |
}
}

95
tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertToVector4_AsPartOfCompositeOperation.cs

@ -0,0 +1,95 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
public class PixelConversion_ConvertToVector4_AsPartOfCompositeOperation
{
struct ConversionRunner<T>
where T : struct, ITestPixel<T>
{
private T[] source;
private Vector4[] dest;
public ConversionRunner(int count)
{
this.source = new T[count];
this.dest = new Vector4[count];
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunRetvalConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Vector4 destBaseRef = ref this.dest[0];
Vector4 temp;
for (int i = 0; i < count; i++)
{
temp = Unsafe.Add(ref sourceBaseRef, i).ToVector4();
// manipulate pixel before saving to dest buffer:
temp.W = 0;
Unsafe.Add(ref destBaseRef, i) = temp;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void RunCopyToConversion()
{
int count = this.source.Length;
ref T sourceBaseRef = ref this.source[0];
ref Vector4 destBaseRef = ref this.dest[0];
Vector4 temp = default;
for (int i = 0; i < count; i++)
{
Unsafe.Add(ref sourceBaseRef, i).CopyToVector4(ref temp);
// manipulate pixel before saving to dest buffer:
temp.W = 0;
Unsafe.Add(ref destBaseRef, i) = temp;
}
}
}
private ConversionRunner<TestRgba> runner;
[Params(32)]
public int Count { get; set; }
[GlobalSetup]
public void Setup()
{
this.runner = new ConversionRunner<TestRgba>(this.Count);
}
[Benchmark(Baseline = true)]
public void UseRetval()
{
this.runner.RunRetvalConversion();
}
[Benchmark]
public void UseCopyTo()
{
this.runner.RunCopyToConversion();
}
// RESULTS:
// Method | Count | Mean | Error | StdDev | Scaled |
// ---------- |------ |----------:|----------:|----------:|-------:|
// UseRetval | 32 | 100.35 ns | 0.4844 ns | 0.4532 ns | 1.00 |
// UseCopyTo | 32 | 53.95 ns | 0.1269 ns | 0.1125 ns | 0.54 |
}
}

89
tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs

@ -0,0 +1,89 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
[StructLayout(LayoutKind.Sequential)]
struct TestArgb : ITestPixel<TestArgb>
{
private byte a, r, g, b;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(Rgba32 p)
{
this.r = p.R;
this.g = p.G;
this.b = p.B;
this.a = p.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(ref Rgba32 p)
{
this.r = p.R;
this.g = p.G;
this.b = p.B;
this.a = p.A;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBytes(byte r, byte g, byte b, byte a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(Vector4 p)
{
this.r = (byte)p.X;
this.g = (byte)p.Y;
this.b = (byte)p.Z;
this.a = (byte)p.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromVector4(ref Vector4 p)
{
this.r = (byte)p.X;
this.g = (byte)p.Y;
this.b = (byte)p.Z;
this.a = (byte)p.W;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32()
{
return new Rgba32(this.r, this.g, this.b, this.a);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToRgba32(ref Rgba32 dest)
{
dest.R = this.r;
dest.G = this.g;
dest.B = this.b;
dest.A = this.a;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.r, this.g, this.b, this.a);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToVector4(ref Vector4 dest)
{
dest.X = this.r;
dest.Y = this.g;
dest.Z = this.b;
dest.W = this.a;
}
}
}

72
tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs

@ -0,0 +1,72 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion
{
[StructLayout(LayoutKind.Sequential)]
struct TestRgba : ITestPixel<TestRgba>
{
private byte r, g, b, a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(Rgba32 source)
{
this = Unsafe.As<Rgba32, TestRgba>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromRgba32(ref Rgba32 source)
{
this = Unsafe.As<Rgba32, TestRgba>(ref source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void FromBytes(byte r, byte g, byte b, byte a)
{
this.r = r;
this.g = g;
this.b = b;
this.a = a;
}
public void FromVector4(Vector4 source)
{
throw new System.NotImplementedException();
}
public void FromVector4(ref Vector4 source)
{
throw new System.NotImplementedException();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32()
{
return Unsafe.As<TestRgba, Rgba32>(ref this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToRgba32(ref Rgba32 dest)
{
dest = Unsafe.As<TestRgba, Rgba32>(ref this);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToVector4()
{
return new Vector4(this.r, this.g, this.b, this.a);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void CopyToVector4(ref Vector4 dest)
{
dest.X = this.r;
dest.Y = this.g;
dest.Z = this.b;
dest.W = this.a;
}
}
}

113
tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs

@ -0,0 +1,113 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
[Config(typeof(Config.ShortClr))]
public class UInt32ToSingle
{
private float[] data;
private const int Count = 32;
[GlobalSetup]
public void Setup()
{
this.data = new float[Count];
}
[Benchmark(Baseline = true)]
public void MagicMethod()
{
ref Vector<float> b = ref Unsafe.As<float, Vector<float>>(ref this.data[0]);
int n = Count / Vector<float>.Count;
var bVec = new Vector<float>(256.0f / 255.0f);
var magicFloat = new Vector<float>(32768.0f);
var magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
var mask = new Vector<uint>(255);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
ref Vector<float> df = ref Unsafe.Add(ref b, i);
var vi = Vector.AsVectorUInt32(df);
vi &= mask;
vi |= magicInt;
var vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
df = vf;
}
}
[Benchmark]
public void StandardSimd()
{
int n = Count / Vector<float>.Count;
ref Vector<float> bf = ref Unsafe.As<float, Vector<float>>(ref this.data[0]);
ref Vector<uint> bu = ref Unsafe.As<Vector<float>, Vector<uint>>(ref bf);
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
Vector<uint> u = Unsafe.Add(ref bu, i);
Vector<float> v = Vector.ConvertToSingle(u);
v *= scale;
Unsafe.Add(ref bf, i) = v;
}
}
[Benchmark]
public void StandardSimdFromInt()
{
int n = Count / Vector<float>.Count;
ref Vector<float> bf = ref Unsafe.As<float, Vector<float>>(ref this.data[0]);
ref Vector<int> bu = ref Unsafe.As<Vector<float>, Vector<int>>(ref bf);
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
Vector<int> u = Unsafe.Add(ref bu, i);
Vector<float> v = Vector.ConvertToSingle(u);
v *= scale;
Unsafe.Add(ref bf, i) = v;
}
}
[Benchmark]
public void StandardSimdFromInt_RefCast()
{
int n = Count / Vector<float>.Count;
ref Vector<float> bf = ref Unsafe.As<float, Vector<float>>(ref this.data[0]);
ref Vector<int> bu = ref Unsafe.As<Vector<float>, Vector<int>>(ref bf);
var scale = new Vector<float>(1f / 255f);
for (int i = 0; i < n; i++)
{
ref Vector<float> fRef = ref Unsafe.Add(ref bf, i);
Vector<int> du = Vector.AsVectorInt32(fRef);
Vector<float> v = Vector.ConvertToSingle(du);
v *= scale;
fRef = v;
}
}
}
}

64
tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs

@ -0,0 +1,64 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization
{
[Config(typeof(Config.ShortClr))]
public class WidenBytesToUInt32
{
private byte[] source;
private uint[] dest;
private const int Count = 64;
[GlobalSetup]
public void Setup()
{
this.source = new byte[Count];
this.dest = new uint[Count];
}
[Benchmark(Baseline = true)]
public void Standard()
{
const int N = Count / 8;
ref Octet.OfByte sBase = ref Unsafe.As<byte, Octet.OfByte>(ref this.source[0]);
ref Octet.OfUInt32 dBase = ref Unsafe.As<uint, Octet.OfUInt32>(ref this.dest[0]);
for (int i = 0; i < N; i++)
{
Unsafe.Add(ref dBase, i).LoadFrom(ref Unsafe.Add(ref sBase, i));
}
}
[Benchmark]
public void Simd()
{
int n = Count / Vector<byte>.Count;
ref Vector<byte> sBase = ref Unsafe.As<byte, Vector<byte>>(ref this.source[0]);
ref Vector<uint> dBase = ref Unsafe.As<uint, Vector<uint>>(ref this.dest[0]);
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
ref Vector<uint> d = ref Unsafe.Add(ref dBase, i * 4);
d = w0;
Unsafe.Add(ref d, 1) = w1;
Unsafe.Add(ref d, 2) = w2;
Unsafe.Add(ref d, 3) = w3;
}
}
}
}

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

Loading…
Cancel
Save