Browse Source

Merge branch 'main' into icc-color-conversion

pull/1567/head
James Jackson-South 2 years ago
parent
commit
29ed2b458d
  1. 7
      ImageSharp.sln
  2. 20
      src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs
  3. 8
      src/ImageSharp/ColorProfiles/CieConstants.cs
  4. 178
      src/ImageSharp/ColorProfiles/CieLab.cs
  5. 155
      src/ImageSharp/ColorProfiles/CieLch.cs
  6. 167
      src/ImageSharp/ColorProfiles/CieLchuv.cs
  7. 221
      src/ImageSharp/ColorProfiles/CieLuv.cs
  8. 14
      src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs
  9. 89
      src/ImageSharp/ColorProfiles/CieXyy.cs
  10. 59
      src/ImageSharp/ColorProfiles/CieXyz.cs
  11. 165
      src/ImageSharp/ColorProfiles/Cmyk.cs
  12. 63
      src/ImageSharp/ColorProfiles/ColorConversionOptions.cs
  13. 45
      src/ImageSharp/ColorProfiles/ColorProfileConverter.cs
  14. 57
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs
  15. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs
  16. 59
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs
  17. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs
  18. 46
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs
  19. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs
  20. 59
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs
  21. 54
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs
  22. 57
      src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs
  23. 182
      src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs
  24. 56
      src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs
  25. 71
      src/ImageSharp/ColorProfiles/Companding/LCompanding.cs
  26. 75
      src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs
  27. 71
      src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs
  28. 71
      src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs
  29. 245
      src/ImageSharp/ColorProfiles/Hsl.cs
  30. 231
      src/ImageSharp/ColorProfiles/Hsv.cs
  31. 200
      src/ImageSharp/ColorProfiles/HunterLab.cs
  32. 59
      src/ImageSharp/ColorProfiles/IColorProfile.cs
  33. 18
      src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs
  34. 24
      src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs
  35. 71
      src/ImageSharp/ColorProfiles/KnownIlluminants.cs
  36. 113
      src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs
  37. 75
      src/ImageSharp/ColorProfiles/Lms.cs
  38. 269
      src/ImageSharp/ColorProfiles/Rgb.cs
  39. 20
      src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs
  40. 95
      src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs
  41. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs
  42. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs
  43. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs
  44. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs
  45. 40
      src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs
  46. 18
      src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs
  47. 87
      src/ImageSharp/ColorProfiles/YCbCr.cs
  48. 135
      src/ImageSharp/ColorSpaces/CieLab.cs
  49. 156
      src/ImageSharp/ColorSpaces/CieLchuv.cs
  50. 136
      src/ImageSharp/ColorSpaces/CieLuv.cs
  51. 107
      src/ImageSharp/ColorSpaces/Cmyk.cs
  52. 34
      src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs
  53. 36
      src/ImageSharp/ColorSpaces/Companding/LCompanding.cs
  54. 39
      src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs
  55. 35
      src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs
  56. 230
      src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs
  57. 159
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs
  58. 441
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs
  59. 441
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs
  60. 441
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs
  61. 435
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs
  62. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs
  63. 458
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs
  64. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs
  65. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs
  66. 437
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs
  67. 430
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs
  68. 429
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs
  69. 425
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs
  70. 419
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs
  71. 404
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs
  72. 59
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs
  73. 53
      src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs
  74. 31
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs
  75. 39
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs
  76. 43
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs
  77. 31
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs
  78. 39
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs
  79. 73
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs
  80. 52
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs
  81. 44
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs
  82. 69
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs
  83. 57
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs
  84. 86
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs
  85. 65
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs
  86. 55
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs
  87. 49
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs
  88. 158
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs
  89. 128
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs
  90. 37
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs
  91. 73
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs
  92. 52
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs
  93. 25
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs
  94. 25
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs
  95. 55
      src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs
  96. 36
      src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs
  97. 99
      src/ImageSharp/ColorSpaces/Conversion/Implementation/VonKriesChromaticAdaptation.cs
  98. 100
      src/ImageSharp/ColorSpaces/Hsl.cs
  99. 98
      src/ImageSharp/ColorSpaces/Hsv.cs
  100. 134
      src/ImageSharp/ColorSpaces/HunterLab.cs

7
ImageSharp.sln

@ -661,6 +661,12 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Qoi", "Qoi", "{E801B508-493
tests\Images\Input\Qoi\wikipedia_008.qoi = tests\Images\Input\Qoi\wikipedia_008.qoi
EndProjectSection
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Icon", "Icon", "{95E45DDE-A67D-48AD-BBA8-5FAA151B860D}"
ProjectSection(SolutionItems) = preProject
tests\Images\Input\Icon\aero_arrow.cur = tests\Images\Input\Icon\aero_arrow.cur
tests\Images\Input\Icon\flutter.ico = tests\Images\Input\Icon\flutter.ico
EndProjectSection
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -714,6 +720,7 @@ Global
{670DD46C-82E9-499A-B2D2-00A802ED0141} = {E1C42A6F-913B-4A7B-B1A8-2BB62843B254}
{5DFC394F-136F-4B76-9BCA-3BA786515EFC} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{E801B508-4935-41CD-BA85-CF11BFF55A45} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
{95E45DDE-A67D-48AD-BBA8-5FAA151B860D} = {9DA226A1-8656-49A8-A58A-A8B5C081AD66}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795}

20
src/ImageSharp/ColorProfiles/ChromaticAdaptionWhitePointSource.cs

@ -0,0 +1,20 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Enumerate the possible sources of the white point used in chromatic adaptation.
/// </summary>
public enum ChromaticAdaptionWhitePointSource
{
/// <summary>
/// The white point of the source color space.
/// </summary>
WhitePoint,
/// <summary>
/// The white point of the source working space.
/// </summary>
RgbWorkingSpace
}

8
src/ImageSharp/ColorSpaces/Conversion/CieConstants.cs → src/ImageSharp/ColorProfiles/CieConstants.cs

@ -1,7 +1,7 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Constants use for Cie conversion calculations
@ -12,10 +12,10 @@ internal static class CieConstants
/// <summary>
/// 216F / 24389F
/// </summary>
public const float Epsilon = 0.008856452F;
public const float Epsilon = 216f / 24389f;
/// <summary>
/// 24389F / 27F
/// </summary>
public const float Kappa = 903.2963F;
public const float Kappa = 24389f / 27f;
}

178
src/ImageSharp/ColorProfiles/CieLab.cs

@ -0,0 +1,178 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents a CIE L*a*b* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLab : IProfileConnectingSpace<CieLab, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLab(float l, float a, float b)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = l;
this.A = a;
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, a, b components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLab(Vector3 vector)
: this()
{
this.L = vector.X;
this.A = vector.Y;
this.B = vector.Z;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the a color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is green, positive magenta.</remarks>
/// </summary>
public float A { get; }
/// <summary>
/// Gets the b color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is blue, positive is yellow</remarks>
/// </summary>
public float B { get; }
/// <summary>
/// Compares two <see cref="CieLab"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLab left, CieLab right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLab"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static CieLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Conversion algorithm described here:
// http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
CieXyz whitePoint = options.TargetWhitePoint;
float wx = whitePoint.X, wy = whitePoint.Y, wz = whitePoint.Z;
float xr = source.X / wx, yr = source.Y / wy, zr = source.Z / wz;
const float inv116 = 1 / 116F;
float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116;
float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116;
float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116;
float l = (116F * fy) - 16F;
float a = 500F * (fx - fy);
float b = 200F * (fy - fz);
return new CieLab(l, a, b);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
float l = this.L, a = this.A, b = this.B;
float fy = (l + 16) / 116F;
float fx = (a / 500F) + fy;
float fz = fy - (b / 200F);
float fx3 = Numerics.Pow3(fx);
float fz3 = Numerics.Pow3(fz);
float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa;
float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa;
float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa;
CieXyz whitePoint = options.WhitePoint;
Vector3 wxyz = new(whitePoint.X, whitePoint.Y, whitePoint.Z);
Vector3 xyzr = new(xr, yr, zr);
return new(xyzr * wxyz);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLab lab = source[i];
destination[i] = lab.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLab other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLab, Vector3>(ref Unsafe.AsRef(in this));
}

155
src/ImageSharp/ColorSpaces/CieLch.cs → src/ImageSharp/ColorProfiles/CieLch.cs

@ -3,21 +3,17 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
/// </summary>
public readonly struct CieLch : IEquatable<CieLch>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLch : IColorProfile<CieLch, CieLab>
{
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new(100, 200, 360);
@ -27,23 +23,9 @@ public readonly struct CieLch : IEquatable<CieLch>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLch(float l, float c, float h)
: this(l, c, h, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLch"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLch(float l, float c, float h, CieXyz whitePoint)
: this(new Vector3(l, c, h), whitePoint)
: this(new Vector3(l, c, h))
{
}
@ -51,50 +33,32 @@ public readonly struct CieLch : IEquatable<CieLch>
/// Initializes a new instance of the <see cref="CieLch"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLch(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLch"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLch(Vector3 vector, CieXyz whitePoint)
{
vector = Vector3.Clamp(vector, Min, Max);
this.L = vector.X;
this.C = vector.Y;
this.H = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public readonly float L { get; }
public float L { get; }
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public readonly float C { get; }
public float C { get; }
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
public float H { get; }
/// <summary>
/// Compares two <see cref="CieLch"/> objects for equality.
@ -104,7 +68,7 @@ public readonly struct CieLch : IEquatable<CieLch>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLch left, CieLch right) => left.Equals(right);
/// <summary>
@ -115,45 +79,88 @@ public readonly struct CieLch : IEquatable<CieLch>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
public static CieLch FromProfileConnectingSpace(ColorConversionOptions options, in CieLab source)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = source.L, a = source.A, b = source.B;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
return new CieLch(l, c, hDegrees);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other);
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLab> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLab lab = source[i];
destination[i] = FromProfileConnectingSpace(options, in lab);
}
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLch other)
=> this.L.Equals(other.L)
&& this.C.Equals(other.C)
&& this.H.Equals(other.H)
&& this.WhitePoint.Equals(other.WhitePoint);
public CieLab ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = this.L, c = this.C, hDegrees = this.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
/// <summary>
/// Computes the saturation of the color (chroma normalized by lightness)
/// </summary>
/// <remarks>
/// A value ranging from 0 to 100.
/// </remarks>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public float Saturation()
float a = c * MathF.Cos(hRadians);
float b = c * MathF.Sin(hRadians);
return new CieLab(l, a, b);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLch> source, Span<CieLab> destination)
{
float result = 100 * (this.C / this.L);
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
if (float.IsNaN(result))
for (int i = 0; i < source.Length; i++)
{
return 0;
CieLch lch = source[i];
destination[i] = lch.ToProfileConnectingSpace(options);
}
return result;
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.L, this.C, this.H);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override bool Equals(object? obj) => obj is CieLch other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLch other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLch, Vector3>(ref Unsafe.AsRef(in this));
}

167
src/ImageSharp/ColorProfiles/CieLchuv.cs

@ -0,0 +1,167 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLchuv : IColorProfile<CieLchuv, CieXyz>
{
private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new(100, 200, 360);
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLchuv(float l, float c, float h)
: this(new Vector3(l, c, h))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLchuv(Vector3 vector)
: this()
{
vector = Vector3.Clamp(vector, Min, Max);
this.L = vector.X;
this.C = vector.Y;
this.H = vector.Z;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public float C { get; }
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public float H { get; }
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right);
/// <inheritdoc/>
public static CieLchuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
CieLuv luv = CieLuv.FromProfileConnectingSpace(options, source);
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = luv.L, u = luv.U, v = luv.V;
float c = MathF.Sqrt((u * u) + (v * v));
float hRadians = MathF.Atan2(v, u);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
return new CieLchuv(l, c, hDegrees);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = this.L, c = this.C, hDegrees = this.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float u = c * MathF.Cos(hRadians);
float v = c * MathF.Sin(hRadians);
CieLuv luv = new(l, u, v);
return luv.ToProfileConnectingSpace(options);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLchuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLchuv lch = source[i];
destination[i] = lch.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.L, this.C, this.H);
/// <inheritdoc/>
public override string ToString()
=> FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj)
=> obj is CieLchuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLchuv other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLchuv, Vector3>(ref Unsafe.AsRef(in this));
}

221
src/ImageSharp/ColorProfiles/CieLuv.cs

@ -0,0 +1,221 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International
/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which
/// attempted perceptual uniformity
/// <see href="https://en.wikipedia.org/wiki/CIELUV"/>
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieLuv : IColorProfile<CieLuv, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given white point.</param>
/// <param name="v">The red-green chromaticity coordinate of the given white point.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(float l, float u, float v)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = l;
this.U = u;
this.V = v;
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieLuv(Vector3 vector)
: this()
{
this.L = vector.X;
this.U = vector.Y;
this.V = vector.Z;
}
/// <summary>
/// Gets the lightness dimension
/// <remarks>A value usually ranging between 0 and 100.</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the blue-yellow chromaticity coordinate of the given white point.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public float U { get; }
/// <summary>
/// Gets the red-green chromaticity coordinate of the given white point.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public float V { get; }
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right);
/// <inheritdoc/>
public static CieLuv FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Use doubles here for accuracy.
// Conversion algorithm described here:
// http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html
CieXyz whitePoint = options.TargetWhitePoint;
double yr = source.Y / whitePoint.Y;
double den = source.X + (15 * source.Y) + (3 * source.Z);
double up = den > 0 ? ComputeU(in source) : 0;
double vp = den > 0 ? ComputeV(in source) : 0;
double upr = ComputeU(in whitePoint);
double vpr = ComputeV(in whitePoint);
const double e = 1 / 3d;
double l = yr > CieConstants.Epsilon
? ((116 * Math.Pow(yr, e)) - 16d)
: (CieConstants.Kappa * yr);
if (double.IsNaN(l) || l == -0d)
{
l = 0;
}
double u = 13 * l * (up - upr);
double v = 13 * l * (vp - vpr);
if (double.IsNaN(u) || u == -0d)
{
u = 0;
}
if (double.IsNaN(v) || v == -0d)
{
v = 0;
}
return new CieLuv((float)l, (float)u, (float)v);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Use doubles here for accuracy.
// Conversion algorithm described here:
// http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html
CieXyz whitePoint = options.WhitePoint;
double l = this.L, u = this.U, v = this.V;
double u0 = ComputeU(in whitePoint);
double v0 = ComputeV(in whitePoint);
double y = l > CieConstants.Kappa * CieConstants.Epsilon
? Numerics.Pow3((l + 16) / 116d)
: l / CieConstants.Kappa;
double a = ((52 * l / (u + (13 * l * u0))) - 1) / 3;
double b = -5 * y;
const double c = -1 / 3d;
double d = y * ((39 * l / (v + (13 * l * v0))) - 5);
double x = (d - b) / (a - c);
double z = (x * a) + b;
if (double.IsNaN(x) || x == -0d)
{
x = 0;
}
if (double.IsNaN(y) || y == -0d)
{
y = 0;
}
if (double.IsNaN(z) || z == -0d)
{
z = 0;
}
return new CieXyz((float)x, (float)y, (float)z);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieLuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieLuv luv = source[i];
destination[i] = luv.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieLuv other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieLuv, Vector3>(ref Unsafe.AsRef(in this));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double ComputeU(in CieXyz source)
=> (4 * source.X) / (source.X + (15 * source.Y) + (3 * source.Z));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static double ComputeV(in CieXyz source)
=> (9 * source.Y) / (source.X + (15 * source.Y) + (3 * source.Z));
}

14
src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyChromaticityCoordinates.cs → src/ImageSharp/ColorProfiles/CieXyChromaticityCoordinates.cs

@ -1,14 +1,16 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable CompareOfFloatsByEqualityOperator
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the coordinates of CIEXY chromaticity space.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromaticityCoordinates>
{
/// <summary>
@ -29,7 +31,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromatici
/// <remarks>
/// Ranges usually from 0 to 1.
/// </remarks>
public readonly float X { get; }
public float X { get; }
/// <summary>
/// Gets the chromaticity Y-coordinate
@ -37,7 +39,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromatici
/// <remarks>
/// Ranges usually from 0 to 1.
/// </remarks>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Compares two <see cref="CieXyChromaticityCoordinates"/> objects for equality.
@ -79,5 +81,7 @@ public readonly struct CieXyChromaticityCoordinates : IEquatable<CieXyChromatici
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieXyChromaticityCoordinates other)
=> this.X.Equals(other.X) && this.Y.Equals(other.Y);
=> this.AsVector2Unsafe() == other.AsVector2Unsafe();
private Vector2 AsVector2Unsafe() => Unsafe.As<CieXyChromaticityCoordinates, Vector2>(ref Unsafe.AsRef(in this));
}

89
src/ImageSharp/ColorSpaces/CieXyy.cs → src/ImageSharp/ColorProfiles/CieXyy.cs

@ -3,14 +3,16 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an CIE xyY 1931 color
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space#CIE_xy_chromaticity_diagram_and_the_CIE_xyY_color_space"/>
/// </summary>
public readonly struct CieXyy : IEquatable<CieXyy>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieXyy : IColorProfile<CieXyy, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyy"/> struct.
@ -18,7 +20,7 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// <param name="x">The x chroma component.</param>
/// <param name="y">The y chroma component.</param>
/// <param name="yl">The y luminance component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyy(float x, float y, float yl)
{
// Not clamping as documentation about this space only indicates "usual" ranges
@ -31,7 +33,7 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// Initializes a new instance of the <see cref="CieXyy"/> struct.
/// </summary>
/// <param name="vector">The vector representing the x, y, Y components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyy(Vector3 vector)
: this()
{
@ -45,19 +47,19 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// Gets the X chrominance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float X { get; }
public float X { get; }
/// <summary>
/// Gets the Y chrominance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Yl { get; }
public float Yl { get; }
/// <summary>
/// Compares two <see cref="CieXyy"/> objects for equality.
@ -67,7 +69,7 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieXyy left, CieXyy right) => left.Equals(right);
/// <summary>
@ -78,22 +80,79 @@ public readonly struct CieXyy : IEquatable<CieXyy>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Yl);
public static CieXyy FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
float x = source.X / (source.X + source.Y + source.Z);
float y = source.Y / (source.X + source.Y + source.Z);
if (float.IsNaN(x) || float.IsNaN(y))
{
return new CieXyy(0, 0, source.Y);
}
return new CieXyy(x, y, source.Y);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})");
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
if (MathF.Abs(this.Y) < Constants.Epsilon)
{
return new CieXyz(0, 0, this.Yl);
}
float x = (this.X * this.Yl) / this.Y;
float y = this.Yl;
float z = ((1 - this.X - this.Y) * y) / this.Y;
return new CieXyz(x, y, z);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyy> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyy xyz = source[i];
destination[i] = xyz.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode()
=> HashCode.Combine(this.X, this.Y, this.Yl);
/// <inheritdoc/>
public override string ToString()
=> FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieXyy other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieXyy other)
=> this.X.Equals(other.X)
&& this.Y.Equals(other.Y)
&& this.Yl.Equals(other.Yl);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieXyy, Vector3>(ref Unsafe.AsRef(in this));
}

59
src/ImageSharp/ColorSpaces/CieXyz.cs → src/ImageSharp/ColorProfiles/CieXyz.cs

@ -3,14 +3,16 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an CIE XYZ 1931 color
/// <see href="https://en.wikipedia.org/wiki/CIE_1931_color_space#Definition_of_the_CIE_XYZ_color_space"/>
/// </summary>
public readonly struct CieXyz : IEquatable<CieXyz>
[StructLayout(LayoutKind.Sequential)]
public readonly struct CieXyz : IProfileConnectingSpace<CieXyz, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyz"/> struct.
@ -18,10 +20,13 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// <param name="x">X is a mix (a linear combination) of cone response curves chosen to be nonnegative</param>
/// <param name="y">The y luminance component.</param>
/// <param name="z">Z is quasi-equal to blue stimulation, or the S cone of the human eye.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public CieXyz(float x, float y, float z)
: this(new Vector3(x, y, z))
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.X = x;
this.Y = y;
this.Z = z;
}
/// <summary>
@ -31,7 +36,6 @@ public readonly struct CieXyz : IEquatable<CieXyz>
public CieXyz(Vector3 vector)
: this()
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.X = vector.X;
this.Y = vector.Y;
this.Z = vector.Z;
@ -41,19 +45,19 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float X { get; }
public float X { get; }
/// <summary>
/// Gets the Y luminance component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Z { get; }
public float Z { get; }
/// <summary>
/// Compares two <see cref="CieXyz"/> objects for equality.
@ -63,7 +67,7 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(CieXyz left, CieXyz right) => left.Equals(right);
/// <summary>
@ -74,16 +78,41 @@ public readonly struct CieXyz : IEquatable<CieXyz>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(CieXyz left, CieXyz right) => !left.Equals(right);
/// <summary>
/// Returns a new <see cref="Vector3"/> representing this instance.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3() => new(this.X, this.Y, this.Z);
/// <inheritdoc/>
public static CieXyz FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
=> new(source.X, source.Y, source.Z);
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
source.CopyTo(destination[..source.Length]);
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
=> new(this.X, this.Y, this.Z);
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
source.CopyTo(destination[..source.Length]);
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.X, this.Y, this.Z);
@ -94,9 +123,9 @@ public readonly struct CieXyz : IEquatable<CieXyz>
public override bool Equals(object? obj) => obj is CieXyz other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(CieXyz other)
=> this.X.Equals(other.X)
&& this.Y.Equals(other.Y)
&& this.Z.Equals(other.Z);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<CieXyz, Vector3>(ref Unsafe.AsRef(in this));
}

165
src/ImageSharp/ColorProfiles/Cmyk.cs

@ -0,0 +1,165 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Cmyk : IColorProfile<Cmyk, Rgb>
{
private static readonly Vector4 Min = Vector4.Zero;
private static readonly Vector4 Max = Vector4.One;
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="c">The cyan component.</param>
/// <param name="m">The magenta component.</param>
/// <param name="y">The yellow component.</param>
/// <param name="k">The keyline black component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Cmyk(float c, float m, float y, float k)
: this(new Vector4(c, m, y, k))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="vector">The vector representing the c, m, y, k components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Cmyk(Vector4 vector)
{
vector = Numerics.Clamp(vector, Min, Max);
this.C = vector.X;
this.M = vector.Y;
this.Y = vector.Z;
this.K = vector.W;
}
/// <summary>
/// Gets the cyan color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float C { get; }
/// <summary>
/// Gets the magenta color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float M { get; }
/// <summary>
/// Gets the yellow color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float Y { get; }
/// <summary>
/// Gets the keyline black color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float K { get; }
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right);
/// <inheritdoc/>
public static Cmyk FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
// To CMY
Vector3 cmy = Vector3.One - source.ToScaledVector3();
// To CMYK
Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z)));
if (MathF.Abs(k.X - 1F) < Constants.Epsilon)
{
return new Cmyk(0, 0, 0, 1F);
}
cmy = (cmy - k) / (Vector3.One - k);
return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
// TODO: We can optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
Vector3 rgb = (Vector3.One - new Vector3(this.C, this.M, this.Y)) * (Vector3.One - new Vector3(this.K));
return Rgb.FromScaledVector3(rgb);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Cmyk> source, Span<Rgb> destination)
{
// TODO: We can possibly optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
Cmyk cmyk = source[i];
destination[i] = cmyk.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode()
=> HashCode.Combine(this.C, this.M, this.Y, this.K);
/// <inheritdoc/>
public override string ToString()
=> FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj)
=> obj is Cmyk other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Cmyk other)
=> this.AsVector4Unsafe() == other.AsVector4Unsafe();
private Vector4 AsVector4Unsafe() => Unsafe.As<Cmyk, Vector4>(ref Unsafe.AsRef(in this));
}

63
src/ImageSharp/ColorProfiles/ColorConversionOptions.cs

@ -0,0 +1,63 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Provides options for color profile conversion.
/// </summary>
public class ColorConversionOptions
{
private Matrix4x4 adaptationMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="ColorConversionOptions"/> class.
/// </summary>
public ColorConversionOptions() => this.AdaptationMatrix = KnownChromaticAdaptationMatrices.Bradford;
/// <summary>
/// Gets the memory allocator.
/// </summary>
public MemoryAllocator MemoryAllocator { get; init; } = MemoryAllocator.Default;
/// <summary>
/// Gets the source white point used for chromatic adaptation in conversions from/to XYZ color space.
/// </summary>
public CieXyz WhitePoint { get; init; } = KnownIlluminants.D50;
/// <summary>
/// Gets the destination white point used for chromatic adaptation in conversions from/to XYZ color space.
/// </summary>
public CieXyz TargetWhitePoint { get; init; } = KnownIlluminants.D50;
/// <summary>
/// Gets the source working space used for companding in conversions from/to XYZ color space.
/// </summary>
public RgbWorkingSpace RgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb;
/// <summary>
/// Gets the destination working space used for companding in conversions from/to XYZ color space.
/// </summary>
public RgbWorkingSpace TargetRgbWorkingSpace { get; init; } = KnownRgbWorkingSpaces.SRgb;
/// <summary>
/// Gets the transformation matrix used in conversion to perform chromatic adaptation.
/// <see cref="KnownChromaticAdaptationMatrices"/> for further information. Default is Bradford.
/// </summary>
public Matrix4x4 AdaptationMatrix
{
get => this.adaptationMatrix;
init
{
this.adaptationMatrix = value;
Matrix4x4.Invert(value, out Matrix4x4 inverted);
this.InverseAdaptationMatrix = inverted;
}
}
internal Matrix4x4 InverseAdaptationMatrix { get; private set; }
}

45
src/ImageSharp/ColorProfiles/ColorProfileConverter.cs

@ -0,0 +1,45 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Allows the conversion of color profiles.
/// </summary>
public class ColorProfileConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="ColorProfileConverter"/> class.
/// </summary>
public ColorProfileConverter()
: this(new())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ColorProfileConverter"/> class.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
public ColorProfileConverter(ColorConversionOptions options)
=> this.Options = options;
/// <summary>
/// Gets the color profile conversion options.
/// </summary>
public ColorConversionOptions Options { get; }
internal (CieXyz From, CieXyz To) GetChromaticAdaptionWhitePoints<TFrom, TTo>()
where TFrom : struct, IColorProfile
where TTo : struct, IColorProfile
{
CieXyz sourceWhitePoint = TFrom.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint
? this.Options.WhitePoint
: this.Options.RgbWorkingSpace.WhitePoint;
CieXyz targetWhitePoint = TTo.GetChromaticAdaptionWhitePointSource() == ChromaticAdaptionWhitePointSource.WhitePoint
? this.Options.TargetWhitePoint
: this.Options.TargetRgbWorkingSpace.WhitePoint;
return (sourceWhitePoint, targetWhitePoint);
}
}

57
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieLab.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieLabCieLab
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieLab pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieLab> pcsFromToOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsFromTo = pcsFromToOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromTo);
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
CieLab.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsFromTo, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabCieXyz.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieLabCieXyz
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieLab pcsFrom = source.ToProfileConnectingSpace(options);
// Convert between PCS
CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieLab> pcsFromOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Convert between PCS.
using IMemoryOwner<CieXyz> pcsToOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsTo = pcsToOwner.GetSpan();
CieLab.ToProfileConnectionSpace(options, pcsFrom, pcsTo);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

59
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieLabRgb.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieLabRgb
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieLab pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieLab>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieLab> pcsFromAOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsFromA = pcsFromAOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromA);
using IMemoryOwner<CieXyz> pcsFromBOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFromB = pcsFromBOwner.GetSpan();
CieLab.ToProfileConnectionSpace(options, pcsFromA, pcsFromB);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<Rgb> pcsToOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsTo = pcsToOwner.GetSpan();
Rgb.FromProfileConnectionSpace(options, pcsFromB, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieLab.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieXyzCieLab
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieXyz pcsFrom = source.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS
CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFrom);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<CieLab> pcsToOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsTo = pcsToOwner.GetSpan();
CieLab.FromProfileConnectionSpace(options, pcsFrom, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

46
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzCieXyz.cs

@ -0,0 +1,46 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieXyzCieXyz
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieXyz pcsFrom = source.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsFrom);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsFrom, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsCieXyzRgb.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsCieXyzRgb
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
CieXyz pcsFrom = source.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFrom = VonKriesChromaticAdaptation.Transform(in pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS
Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFrom);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, CieXyz>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<Rgb> pcsToOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsTo = pcsToOwner.GetSpan();
Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

59
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieLab.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsRgbCieLab
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
Rgb pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
CieLab pcsTo = CieLab.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieLab>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<Rgb> pcsFromAOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsFromA = pcsFromAOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromA);
using IMemoryOwner<CieXyz> pcsFromBOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFromB = pcsFromBOwner.GetSpan();
Rgb.ToProfileConnectionSpace(options, pcsFromA, pcsFromB);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFromB, pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
using IMemoryOwner<CieLab> pcsToOwner = options.MemoryAllocator.Allocate<CieLab>(source.Length);
Span<CieLab> pcsTo = pcsToOwner.GetSpan();
CieLab.FromProfileConnectionSpace(options, pcsFromB, pcsTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

54
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbCieXyz.cs

@ -0,0 +1,54 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsRgbCieXyz
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
Rgb pcsFrom = source.ToProfileConnectingSpace(options);
// Convert between PCS
CieXyz pcsTo = pcsFrom.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsTo = VonKriesChromaticAdaptation.Transform(in pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, CieXyz>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<Rgb> pcsFromOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsFrom = pcsFromOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFrom);
// Convert between PCS.
using IMemoryOwner<CieXyz> pcsToOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsTo = pcsToOwner.GetSpan();
Rgb.ToProfileConnectionSpace(options, pcsFrom, pcsTo);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsTo, pcsTo, whitePoints, options.AdaptationMatrix);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsTo, destination);
}
}

57
src/ImageSharp/ColorProfiles/ColorProfileConverterExtensionsRgbRgb.cs

@ -0,0 +1,57 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Buffers;
using SixLabors.ImageSharp.Memory;
namespace SixLabors.ImageSharp.ColorProfiles;
internal static class ColorProfileConverterExtensionsRgbRgb
{
public static TTo Convert<TFrom, TTo>(this ColorProfileConverter converter, in TFrom source)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS
Rgb pcsFromA = source.ToProfileConnectingSpace(options);
CieXyz pcsFromB = pcsFromA.ToProfileConnectingSpace(options);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
pcsFromB = VonKriesChromaticAdaptation.Transform(in pcsFromB, whitePoints, options.AdaptationMatrix);
// Convert between PCS
Rgb pcsTo = Rgb.FromProfileConnectingSpace(options, in pcsFromB);
// Convert to output from PCS
return TTo.FromProfileConnectingSpace(options, in pcsTo);
}
public static void Convert<TFrom, TTo>(this ColorProfileConverter converter, ReadOnlySpan<TFrom> source, Span<TTo> destination)
where TFrom : struct, IColorProfile<TFrom, Rgb>
where TTo : struct, IColorProfile<TTo, Rgb>
{
ColorConversionOptions options = converter.Options;
// Convert to input PCS.
using IMemoryOwner<Rgb> pcsFromToOwner = options.MemoryAllocator.Allocate<Rgb>(source.Length);
Span<Rgb> pcsFromTo = pcsFromToOwner.GetSpan();
TFrom.ToProfileConnectionSpace(options, source, pcsFromTo);
using IMemoryOwner<CieXyz> pcsFromOwner = options.MemoryAllocator.Allocate<CieXyz>(source.Length);
Span<CieXyz> pcsFrom = pcsFromOwner.GetSpan();
Rgb.ToProfileConnectionSpace(options, pcsFromTo, pcsFrom);
// Adapt to target white point
(CieXyz From, CieXyz To) whitePoints = converter.GetChromaticAdaptionWhitePoints<TFrom, TTo>();
VonKriesChromaticAdaptation.Transform(pcsFrom, pcsFrom, whitePoints, options.AdaptationMatrix);
// Convert between PCS.
Rgb.FromProfileConnectionSpace(options, pcsFrom, pcsFromTo);
// Convert to output from PCS
TTo.FromProfileConnectionSpace(options, pcsFromTo, destination);
}
}

182
src/ImageSharp/ColorProfiles/Companding/CompandingUtilities.cs

@ -0,0 +1,182 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Collections.Concurrent;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Companding utilities that allow the accelerated compression-expansion of color channels.
/// </summary>
public static class CompandingUtilities
{
private const int Length = Scale + 2; // 256kb @ 16bit precision.
private const int Scale = (1 << 16) - 1;
private static readonly ConcurrentDictionary<(Type, double), float[]> CompressLookupTables = new();
private static readonly ConcurrentDictionary<(Type, double), float[]> ExpandLookupTables = new();
/// <summary>
/// Lazily creates and stores a companding compression lookup table using the given function and modifier.
/// </summary>
/// <typeparam name="T">The type of companding function.</typeparam>
/// <param name="compandingFunction">The companding function.</param>
/// <param name="modifier">A modifier to pass to the function.</param>
/// <returns>The <see cref="float"/> array.</returns>
public static float[] GetCompressLookupTable<T>(Func<double, double, double> compandingFunction, double modifier = 0)
=> CompressLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2));
/// <summary>
/// Lazily creates and stores a companding expanding lookup table using the given function and modifier.
/// </summary>
/// <typeparam name="T">The type of companding function.</typeparam>
/// <param name="compandingFunction">The companding function.</param>
/// <param name="modifier">A modifier to pass to the function.</param>
/// <returns>The <see cref="float"/> array.</returns>
public static float[] GetExpandLookupTable<T>(Func<double, double, double> compandingFunction, double modifier = 0)
=> ExpandLookupTables.GetOrAdd((typeof(T), modifier), args => CreateLookupTableImpl(compandingFunction, args.Item2));
/// <summary>
/// Creates a companding lookup table using the given function.
/// </summary>
/// <param name="compandingFunction">The companding function.</param>
/// <param name="modifier">A modifier to pass to the function.</param>
/// <returns>The <see cref="float"/> array.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float[] CreateLookupTableImpl(Func<double, double, double> compandingFunction, double modifier = 0)
{
float[] result = new float[Length];
for (int i = 0; i < result.Length; i++)
{
double d = (double)i / Scale;
d = compandingFunction(d, modifier);
result[i] = (float)d;
}
return result;
}
/// <summary>
/// Performs the companding operation on the given vectors using the given table.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
/// <param name="table">The lookup table.</param>
public static void Compand(Span<Vector4> vectors, float[] table)
{
DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table));
if (Avx2.IsSupported && vectors.Length >= 2)
{
CompandAvx2(vectors, table);
if (Numerics.Modulo2(vectors.Length) != 0)
{
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
ref Vector4 last = ref MemoryMarshal.GetReference(vectors[^1..]);
last = Compand(last, table);
}
}
else
{
CompandScalar(vectors, table);
}
}
/// <summary>
/// Performs the companding operation on the given vector using the given table.
/// </summary>
/// <param name="vector">The vector.</param>
/// <param name="table">The lookup table.</param>
/// <returns>The <see cref="Vector4"/></returns>
public static Vector4 Compand(Vector4 vector, float[] table)
{
DebugGuard.MustBeGreaterThanOrEqualTo(table.Length, Length, nameof(table));
Vector4 zero = Vector4.Zero;
Vector4 scale = new(Scale);
Vector4 multiplied = Numerics.Clamp(vector * Scale, zero, scale);
float f0 = multiplied.X;
float f1 = multiplied.Y;
float f2 = multiplied.Z;
uint i0 = (uint)f0;
uint i1 = (uint)f1;
uint i2 = (uint)f2;
// Alpha is already a linear representation of opacity so we do not want to convert it.
vector.X = Numerics.Lerp(table[i0], table[i0 + 1], f0 - (int)i0);
vector.Y = Numerics.Lerp(table[i1], table[i1 + 1], f1 - (int)i1);
vector.Z = Numerics.Lerp(table[i2], table[i2 + 1], f2 - (int)i2);
return vector;
}
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
Vector256<float> scale = Vector256.Create((float)Scale);
Vector256<float> zero = Vector256<float>.Zero;
Vector256<int> offset = Vector256.Create(1);
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector256<float> multiplied = Avx.Multiply(scale, vectorsBase);
multiplied = Avx.Min(Avx.Max(zero, multiplied), scale);
Vector256<int> truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied);
Vector256<float> truncatedF = Avx.ConvertToVector256Single(truncated);
Vector256<float> low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float));
Vector256<float> high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float));
// Alpha is already a linear representation of opacity so we do not want to convert it.
Vector256<float> companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF));
vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
Vector4 zero = Vector4.Zero;
Vector4 scale = new(Scale);
ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale);
float f0 = multiplied.X;
float f1 = multiplied.Y;
float f2 = multiplied.Z;
uint i0 = (uint)f0;
uint i1 = (uint)f1;
uint i2 = (uint)f2;
// Alpha is already a linear representation of opacity so we do not want to convert it.
vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0);
vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1);
vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
}

56
src/ImageSharp/ColorProfiles/Companding/GammaCompanding.cs

@ -0,0 +1,56 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements gamma companding.
/// </summary>
/// <remarks>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class GammaCompanding
{
private static Func<double, double, double> CompressFunction => (d, m) => Math.Pow(d, 1 / m);
private static Func<double, double, double> ExpandFunction => Math.Pow;
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
/// <param name="gamma">The gamma value.</param>
public static void Compress(Span<Vector4> vectors, double gamma)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<GammaCompandingKey>(CompressFunction, gamma));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
/// <param name="gamma">The gamma value.</param>
public static void Expand(Span<Vector4> vectors, double gamma)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<GammaCompandingKey>(ExpandFunction, gamma));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector, double gamma)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<GammaCompandingKey>(CompressFunction, gamma));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector, double gamma)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<GammaCompandingKey>(ExpandFunction, gamma));
private class GammaCompandingKey;
}

71
src/ImageSharp/ColorProfiles/Companding/LCompanding.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements L* companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class LCompanding
{
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d <= CieConstants.Epsilon)
{
return (d * CieConstants.Kappa) / 100;
}
return (1.16 * Math.Pow(d, 0.3333333)) - 0.16;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d <= 0.08)
{
return (100 * d) / CieConstants.Kappa;
}
return Numerics.Pow3(((float)(d + 0.16f)) / 1.16f);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<LCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<LCompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<LCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<LCompandingKey>(ExpandFunction));
private class LCompandingKey;
}

75
src/ImageSharp/ColorProfiles/Companding/Rec2020Companding.cs

@ -0,0 +1,75 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements Rec. 2020 companding function.
/// </summary>
/// <remarks>
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
/// </remarks>
public static class Rec2020Companding
{
private const double Alpha = 1.09929682680944;
private const double AlphaMinusOne = Alpha - 1;
private const double Beta = 0.018053968510807;
private const double InverseBeta = Beta * 4.5;
private const double Epsilon = 1 / 0.45;
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d < Beta)
{
return 4.5 * d;
}
return (Alpha * Math.Pow(d, 0.45)) - AlphaMinusOne;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d < InverseBeta)
{
return d / 4.5;
}
return Math.Pow((d + AlphaMinusOne) / Alpha, Epsilon);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
private class Rec2020CompandingKey;
}

71
src/ImageSharp/ColorProfiles/Companding/Rec709Companding.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements the Rec. 709 companding function.
/// </summary>
/// <remarks>
/// http://en.wikipedia.org/wiki/Rec._709
/// </remarks>
public static class Rec709Companding
{
private const double Epsilon = 1 / 0.45;
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d < 0.018)
{
return 4.5 * d;
}
return (1.099 * Math.Pow(d, 0.45)) - 0.099;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d < 0.081)
{
return d / 4.5;
}
return Math.Pow((d + 0.099) / 1.099, Epsilon);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<Rec2020CompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<Rec2020CompandingKey>(ExpandFunction));
private class Rec2020CompandingKey;
}

71
src/ImageSharp/ColorProfiles/Companding/SRgbCompanding.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.Companding;
/// <summary>
/// Implements sRGB companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class SRgbCompanding
{
private static Func<double, double, double> CompressFunction
=> (d, _) =>
{
if (d <= (0.04045 / 12.92))
{
return d * 12.92;
}
return (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055;
};
private static Func<double, double, double> ExpandFunction
=> (d, _) =>
{
if (d <= 0.04045)
{
return d / 12.92;
}
return Math.Pow((d + 0.055) / 1.055, 2.4);
};
/// <summary>
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Compress(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetCompressLookupTable<SRgbCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public static void Expand(Span<Vector4> vectors)
=> CompandingUtilities.Compand(vectors, CompandingUtilities.GetExpandLookupTable<SRgbCompandingKey>(ExpandFunction));
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Compress(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetCompressLookupTable<SRgbCompandingKey>(CompressFunction));
/// <summary>
/// Expands the nonlinear vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public static Vector4 Expand(Vector4 vector)
=> CompandingUtilities.Compand(vector, CompandingUtilities.GetExpandLookupTable<SRgbCompandingKey>(ExpandFunction));
private class SRgbCompandingKey;
}

245
src/ImageSharp/ColorProfiles/Hsl.cs

@ -0,0 +1,245 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents a Hsl (hue, saturation, lightness) color.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Hsl : IColorProfile<Hsl, Rgb>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="l">The l value (lightness) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsl(float h, float s, float l)
: this(new Vector3(h, s, l))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct.
/// </summary>
/// <param name="vector">The vector representing the h, s, l components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsl(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
this.H = vector.X;
this.S = vector.Y;
this.L = vector.Z;
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float S { get; }
/// <summary>
/// Gets the lightness component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Compares two <see cref="Hsl"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Hsl"/> on the left side of the operand.
/// </param>
/// <param name="right">The <see cref="Hsl"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Hsl left, Hsl right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Hsl"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Hsl"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsl"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right);
/// <inheritdoc/>
public static Hsl FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
float r = source.R;
float g = source.G;
float b = source.B;
float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0F;
float s = 0F;
float l = (max + min) / 2F;
if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsl(0F, s, l);
}
if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2F + ((b - r) / chroma);
}
else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4F + ((r - g) / chroma);
}
h *= 60F;
if (h < -Constants.Epsilon)
{
h += 360F;
}
if (l <= .5F)
{
s = chroma / (max + min);
}
else
{
s = chroma / (2F - max - min);
}
return new Hsl(h, s, l);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
float rangedH = this.H / 360F;
float r = 0;
float g = 0;
float b = 0;
float s = this.S;
float l = this.L;
if (MathF.Abs(l) > Constants.Epsilon)
{
if (MathF.Abs(s) < Constants.Epsilon)
{
r = g = b = l;
}
else
{
float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s);
float temp1 = (2F * l) - temp2;
r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
g = GetColorComponent(temp1, temp2, rangedH);
b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
}
}
return new Rgb(r, g, b);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Hsl> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Hsl hsl = source[i];
destination[i] = hsl.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Hsl other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Hsl, Vector3>(ref Unsafe.AsRef(in this));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float GetColorComponent(float first, float second, float third)
{
third = MoveIntoRange(third);
if (third < 0.1666667F)
{
return first + ((second - first) * 6F * third);
}
if (third < .5F)
{
return second;
}
if (third < 0.6666667F)
{
return first + ((second - first) * (0.6666667F - third) * 6F);
}
return first;
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float MoveIntoRange(float value)
{
if (value < 0F)
{
value++;
}
else if (value > 1F)
{
value--;
}
return value;
}
}

231
src/ImageSharp/ColorProfiles/Hsv.cs

@ -0,0 +1,231 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness).
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Hsv : IColorProfile<Hsv, Rgb>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="v">The v value (brightness) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsv(float h, float s, float v)
: this(new Vector3(h, s, v))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the h, s, v components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Hsv(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
this.H = vector.X;
this.S = vector.Y;
this.V = vector.Z;
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float S { get; }
/// <summary>
/// Gets the value (brightness) component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public float V { get; }
/// <summary>
/// Compares two <see cref="Hsv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Hsv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Hsv left, Hsv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Hsv"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Hsv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right);
/// <inheritdoc/>
public static Hsv FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
float r = source.R;
float g = source.G;
float b = source.B;
float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0;
float s = 0;
float v = max;
if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsv(0, s, v);
}
if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2 + ((b - r) / chroma);
}
else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4 + ((r - g) / chroma);
}
h *= 60F;
if (h < -Constants.Epsilon)
{
h += 360F;
}
s = chroma / v;
return new Hsv(h, s, v);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
float s = this.S;
float v = this.V;
if (MathF.Abs(s) < Constants.Epsilon)
{
return new Rgb(v, v, v);
}
float h = (MathF.Abs(this.H - 360) < Constants.Epsilon) ? 0 : this.H / 60;
int i = (int)Math.Truncate(h);
float f = h - i;
float p = v * (1F - s);
float q = v * (1F - (s * f));
float t = v * (1F - (s * (1F - f)));
float r, g, b;
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default:
r = v;
g = p;
b = q;
break;
}
return new Rgb(r, g, b);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Hsv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Hsv hsv = source[i];
destination[i] = hsv.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Hsv other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Hsv, Vector3>(ref Unsafe.AsRef(in this));
}

200
src/ImageSharp/ColorProfiles/HunterLab.cs

@ -0,0 +1,200 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an Hunter LAB color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct HunterLab : IColorProfile<HunterLab, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HunterLab(float l, float a, float b)
{
this.L = l;
this.A = a;
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l a b components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public HunterLab(Vector3 vector)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = vector.X;
this.A = vector.Y;
this.B = vector.Z;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public float L { get; }
/// <summary>
/// Gets the a color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is green, positive magenta.</remarks>
/// </summary>
public float A { get; }
/// <summary>
/// Gets the b color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is blue, positive is yellow</remarks>
/// </summary>
public float B { get; }
/// <summary>
/// Compares two <see cref="HunterLab"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="HunterLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HunterLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(HunterLab left, HunterLab right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="HunterLab"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="HunterLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HunterLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right);
/// <inheritdoc/>
public static HunterLab FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Conversion algorithm described here:
// http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
CieXyz whitePoint = options.TargetWhitePoint;
float x = source.X, y = source.Y, z = source.Z;
float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z;
float ka = ComputeKa(in whitePoint);
float kb = ComputeKb(in whitePoint);
float yByYn = y / yn;
float sqrtYbyYn = MathF.Sqrt(yByYn);
float l = 100 * sqrtYbyYn;
float a = ka * (((x / xn) - yByYn) / sqrtYbyYn);
float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn);
if (float.IsNaN(a))
{
a = 0;
}
if (float.IsNaN(b))
{
b = 0;
}
return new HunterLab(l, a, b);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// Conversion algorithm described here:
// http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
CieXyz whitePoint = options.WhitePoint;
float l = this.L, a = this.A, b = this.B;
float xn = whitePoint.X, yn = whitePoint.Y, zn = whitePoint.Z;
float ka = ComputeKa(in whitePoint);
float kb = ComputeKb(in whitePoint);
float pow = Numerics.Pow2(l / 100F);
float sqrtPow = MathF.Sqrt(pow);
float y = pow * yn;
float x = (((a / ka) * sqrtPow) + pow) * xn;
float z = (((b / kb) * sqrtPow) - pow) * (-zn);
return new CieXyz(x, y, z);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<HunterLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
HunterLab lab = source[i];
destination[i] = lab.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(HunterLab other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<HunterLab, Vector3>(ref Unsafe.AsRef(in this));
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeKa(in CieXyz whitePoint)
{
if (whitePoint.Equals(KnownIlluminants.C))
{
return 175F;
}
return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeKb(in CieXyz whitePoint)
{
if (whitePoint == KnownIlluminants.C)
{
return 70F;
}
return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z);
}
}

59
src/ImageSharp/ColorProfiles/IColorProfile.cs

@ -0,0 +1,59 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Defines the contract for all color profiles.
/// </summary>
public interface IColorProfile
{
/// <summary>
/// Gets the chromatic adaption white point source.
/// </summary>
/// <returns>The <see cref="ChromaticAdaptionWhitePointSource"/>.</returns>
public static abstract ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource();
}
/// <summary>
/// Defines the contract for all color profiles.
/// </summary>
/// <typeparam name="TSelf">The type of color profile.</typeparam>
/// <typeparam name="TProfileSpace">The type of color profile connecting space.</typeparam>
public interface IColorProfile<TSelf, TProfileSpace> : IColorProfile, IEquatable<TSelf>
where TSelf : IColorProfile<TSelf, TProfileSpace>
where TProfileSpace : struct, IProfileConnectingSpace
{
#pragma warning disable CA1000 // Do not declare static members on generic types
/// <summary>
/// Converts the color from the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <param name="source">The color profile connecting space.</param>
/// <returns>The <typeparamref name="TSelf"/>.</returns>
public static abstract TSelf FromProfileConnectingSpace(ColorConversionOptions options, in TProfileSpace source);
/// <summary>
/// Converts the span of colors from the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <param name="source">The color profile span to convert from.</param>
/// <param name="destination">The color span to write the results to.</param>
public static abstract void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<TProfileSpace> source, Span<TSelf> destination);
/// <summary>
/// Converts the color to the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <returns>The <typeparamref name="TProfileSpace"/>.</returns>
public TProfileSpace ToProfileConnectingSpace(ColorConversionOptions options);
/// <summary>
/// Converts the span of colors to the profile connection space.
/// </summary>
/// <param name="options">The color profile conversion options.</param>
/// <param name="source">The color span to convert from.</param>
/// <param name="destination">The color profile span to write the results to.</param>
public static abstract void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<TSelf> source, Span<TProfileSpace> destination);
#pragma warning restore CA1000 // Do not declare static members on generic types
}

18
src/ImageSharp/ColorProfiles/IProfileConnectingSpace.cs

@ -0,0 +1,18 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Defines the contract for all color profile connection spaces.
/// </summary>
public interface IProfileConnectingSpace;
/// <summary>
/// Defines the contract for all color profile connection spaces.
/// </summary>
/// <typeparam name="TSelf">The type of color profile.</typeparam>
/// <typeparam name="TProfileSpace">The type of color profile connecting space.</typeparam>
public interface IProfileConnectingSpace<TSelf, TProfileSpace> : IColorProfile<TSelf, TProfileSpace>, IProfileConnectingSpace
where TSelf : struct, IColorProfile<TSelf, TProfileSpace>, IProfileConnectingSpace
where TProfileSpace : struct, IProfileConnectingSpace;

24
src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs → src/ImageSharp/ColorProfiles/KnownChromaticAdaptationMatrices.cs

@ -3,23 +3,25 @@
using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Matrices used for transformation from <see cref="CieXyz"/> to <see cref="Lms"/>, defining the cone response domain.
/// Used in <see cref="IChromaticAdaptation"/>
/// Provides matrices for chromatic adaptation, facilitating the adjustment of color values
/// under different light sources to maintain color constancy. This class supports common
/// adaptation transforms based on the von Kries coefficient law, which assumes independent
/// scaling of the cone responses in the human eye. These matrices can be applied to convert
/// color coordinates between different illuminants, ensuring consistent color appearance
/// across various lighting conditions.
/// </summary>
/// <remarks>
/// Matrix data obtained from:
/// Two New von Kries Based Chromatic Adaptation Transforms Found by Numerical Optimization
/// S. Bianco, R. Schettini
/// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy
/// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf
/// Supported adaptation matrices include the Bradford, von Kries, and Sharp transforms.
/// These matrices are typically used in conjunction with color space conversions, such as from XYZ
/// to RGB, to achieve accurate color rendition in digital imaging applications.
/// </remarks>
public static class LmsAdaptationMatrix
public static class KnownChromaticAdaptationMatrices
{
/// <summary>
/// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65)
/// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65)
/// </summary>
public static readonly Matrix4x4 VonKriesHPEAdjusted
= Matrix4x4.Transpose(new Matrix4x4
@ -37,7 +39,7 @@ public static class LmsAdaptationMatrix
});
/// <summary>
/// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy)
/// von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez for equal energy)
/// </summary>
public static readonly Matrix4x4 VonKriesHPE
= Matrix4x4.Transpose(new Matrix4x4

71
src/ImageSharp/ColorProfiles/KnownIlluminants.cs

@ -0,0 +1,71 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// The well known standard illuminants.
/// Standard illuminants provide a basis for comparing images or colors recorded under different lighting
/// </summary>
/// <remarks>
/// Coefficients taken from: http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// <br />
/// Descriptions taken from: http://en.wikipedia.org/wiki/Standard_illuminant
/// </remarks>
public static class KnownIlluminants
{
/// <summary>
/// Gets the Incandescent / Tungsten illuminant.
/// </summary>
public static CieXyz A { get; } = new(1.09850F, 1F, 0.35585F);
/// <summary>
/// Gets the Direct sunlight at noon (obsoleteF) illuminant.
/// </summary>
public static CieXyz B { get; } = new(0.99072F, 1F, 0.85223F);
/// <summary>
/// Gets the Average / North sky Daylight (obsoleteF) illuminant.
/// </summary>
public static CieXyz C { get; } = new(0.98074F, 1F, 1.18232F);
/// <summary>
/// Gets the Horizon Light. ICC profile PCS illuminant.
/// </summary>
public static CieXyz D50 { get; } = new(0.96422F, 1F, 0.82521F);
/// <summary>
/// Gets the Mid-morning / Mid-afternoon Daylight illuminant.
/// </summary>
public static CieXyz D55 { get; } = new(0.95682F, 1F, 0.92149F);
/// <summary>
/// Gets the Noon Daylight: TelevisionF, sRGB color space illuminant.
/// </summary>
public static CieXyz D65 { get; } = new(0.95047F, 1F, 1.08883F);
/// <summary>
/// Gets the North sky Daylight illuminant.
/// </summary>
public static CieXyz D75 { get; } = new(0.94972F, 1F, 1.22638F);
/// <summary>
/// Gets the Equal energy illuminant.
/// </summary>
public static CieXyz E { get; } = new(1F, 1F, 1F);
/// <summary>
/// Gets the Cool White Fluorescent illuminant.
/// </summary>
public static CieXyz F2 { get; } = new(0.99186F, 1F, 0.67393F);
/// <summary>
/// Gets the D65 simulatorF, Daylight simulator illuminant.
/// </summary>
public static CieXyz F7 { get; } = new(0.95041F, 1F, 1.08747F);
/// <summary>
/// Gets the Philips TL84F, Ultralume 40 illuminant.
/// </summary>
public static CieXyz F11 { get; } = new(1.00962F, 1F, 0.64350F);
}

113
src/ImageSharp/ColorProfiles/KnownRgbWorkingSpaces.cs

@ -0,0 +1,113 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using SixLabors.ImageSharp.ColorProfiles.Companding;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Chromaticity coordinates based on: <see href="http://www.brucelindbloom.com/index.html?WorkingSpaceInfo.html"/>
/// </summary>
public static class KnownRgbWorkingSpaces
{
/// <summary>
/// sRgb working space.
/// </summary>
/// <remarks>
/// Uses proper companding function, according to:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_Rgb_to_XYZ.html"/>
/// </remarks>
public static readonly RgbWorkingSpace SRgb = new SRgbWorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// Simplified sRgb working space (uses <see cref="GammaCompanding">gamma companding</see> instead of <see cref="SRgbCompanding"/>).
/// See also <see cref="SRgb"/>.
/// </summary>
public static readonly RgbWorkingSpace SRgbSimplified = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// Rec. 709 (ITU-R Recommendation BT.709) working space.
/// </summary>
public static readonly RgbWorkingSpace Rec709 = new Rec709WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F)));
/// <summary>
/// Rec. 2020 (ITU-R Recommendation BT.2020F) working space.
/// </summary>
public static readonly RgbWorkingSpace Rec2020 = new Rec2020WorkingSpace(KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F)));
/// <summary>
/// ECI Rgb v2 working space.
/// </summary>
public static readonly RgbWorkingSpace ECIRgbv2 = new LWorkingSpace(KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F)));
/// <summary>
/// Adobe Rgb (1998) working space.
/// </summary>
public static readonly RgbWorkingSpace AdobeRgb1998 = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// Apple sRgb working space.
/// </summary>
public static readonly RgbWorkingSpace ApplesRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F)));
/// <summary>
/// Best Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace BestRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F)));
/// <summary>
/// Beta Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace BetaRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F)));
/// <summary>
/// Bruce Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace BruceRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// CIE Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace CIERgb = new GammaWorkingSpace(2.2F, KnownIlluminants.E, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F)));
/// <summary>
/// ColorMatch Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace ColorMatchRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F)));
/// <summary>
/// Don Rgb 4 working space.
/// </summary>
public static readonly RgbWorkingSpace DonRgb4 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F)));
/// <summary>
/// Ekta Space PS5 working space.
/// </summary>
public static readonly RgbWorkingSpace EktaSpacePS5 = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F)));
/// <summary>
/// NTSC Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace NTSCRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.C, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F)));
/// <summary>
/// PAL/SECAM Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace PALSECAMRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F)));
/// <summary>
/// ProPhoto Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace ProPhotoRgb = new GammaWorkingSpace(1.8F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F)));
/// <summary>
/// SMPTE-C Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace SMPTECRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F)));
/// <summary>
/// Wide Gamut Rgb working space.
/// </summary>
public static readonly RgbWorkingSpace WideGamutRgb = new GammaWorkingSpace(2.2F, KnownIlluminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F)));
}

75
src/ImageSharp/ColorSpaces/Lms.cs → src/ImageSharp/ColorProfiles/Lms.cs

@ -3,15 +3,17 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// LMS is a color space represented by the response of the three types of cones of the human eye,
/// named after their responsivity (sensitivity) at long, medium and short wavelengths.
/// <see href="https://en.wikipedia.org/wiki/LMS_color_space"/>
/// </summary>
public readonly struct Lms : IEquatable<Lms>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Lms : IColorProfile<Lms, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="Lms"/> struct.
@ -19,17 +21,19 @@ public readonly struct Lms : IEquatable<Lms>
/// <param name="l">L represents the responsivity at long wavelengths.</param>
/// <param name="m">M represents the responsivity at medium wavelengths.</param>
/// <param name="s">S represents the responsivity at short wavelengths.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lms(float l, float m, float s)
: this(new Vector3(l, m, s))
{
this.L = l;
this.M = m;
this.S = s;
}
/// <summary>
/// Initializes a new instance of the <see cref="Lms"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, m, s components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Lms(Vector3 vector)
{
// Not clamping as documentation about this space only indicates "usual" ranges
@ -42,19 +46,19 @@ public readonly struct Lms : IEquatable<Lms>
/// Gets the L long component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float L { get; }
public float L { get; }
/// <summary>
/// Gets the M medium component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float M { get; }
public float M { get; }
/// <summary>
/// Gets the S short component.
/// <remarks>A value usually ranging between -1 and 1.</remarks>
/// </summary>
public readonly float S { get; }
public float S { get; }
/// <summary>
/// Compares two <see cref="Lms"/> objects for equality.
@ -64,7 +68,7 @@ public readonly struct Lms : IEquatable<Lms>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Lms left, Lms right) => left.Equals(right);
/// <summary>
@ -75,16 +79,57 @@ public readonly struct Lms : IEquatable<Lms>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Lms left, Lms right) => !left.Equals(right);
/// <summary>
/// Returns a new <see cref="Vector3"/> representing this instance.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3() => new(this.L, this.M, this.S);
/// <inheritdoc/>
public static Lms FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
Vector3 vector = Vector3.Transform(source.ToVector3(), options.AdaptationMatrix);
return new Lms(vector);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
CieXyz xyz = source[i];
destination[i] = FromProfileConnectingSpace(options, in xyz);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
Vector3 vector = Vector3.Transform(this.ToVector3(), options.InverseAdaptationMatrix);
return new CieXyz(vector);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Lms> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
for (int i = 0; i < source.Length; i++)
{
Lms lms = source[i];
destination[i] = lms.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.WhitePoint;
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.M, this.S);
@ -95,9 +140,9 @@ public readonly struct Lms : IEquatable<Lms>
public override bool Equals(object? obj) => obj is Lms other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Lms other)
=> this.L.Equals(other.L)
&& this.M.Equals(other.M)
&& this.S.Equals(other.S);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Lms, Vector3>(ref Unsafe.AsRef(in this));
}

269
src/ImageSharp/ColorProfiles/Rgb.cs

@ -0,0 +1,269 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an RGB (red, green, blue) color profile.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
public readonly struct Rgb : IProfileConnectingSpace<Rgb, CieXyz>
{
/// <summary>
/// Initializes a new instance of the <see cref="Rgb"/> struct.
/// </summary>
/// <param name="r">The red component usually ranging between 0 and 1.</param>
/// <param name="g">The green component usually ranging between 0 and 1.</param>
/// <param name="b">The blue component usually ranging between 0 and 1.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgb(float r, float g, float b)
{
// Not clamping as this space can exceed "usual" ranges
this.R = r;
this.G = g;
this.B = b;
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgb"/> struct.
/// </summary>
/// <param name="source">The vector representing the r, g, b components.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgb(Vector3 source)
{
this.R = source.X;
this.G = source.Y;
this.B = source.Z;
}
/// <summary>
/// Gets the red component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public float R { get; }
/// <summary>
/// Gets the green component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public float G { get; }
/// <summary>
/// Gets the blue component.
/// <remarks>A value usually ranging between 0 and 1.</remarks>
/// </summary>
public float B { get; }
/// <summary>
/// Compares two <see cref="Rgb"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Rgb"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator ==(Rgb left, Rgb right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rgb"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Rgb"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right);
/// <inheritdoc/>
public static Rgb FromProfileConnectingSpace(ColorConversionOptions options, in CieXyz source)
{
// Convert to linear rgb then compress.
Rgb linear = new(Vector3.Transform(source.ToVector3(), GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace)));
return FromScaledVector4(options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4()));
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<CieXyz> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
Matrix4x4 matrix = GetCieXyzToRgbMatrix(options.TargetRgbWorkingSpace);
for (int i = 0; i < source.Length; i++)
{
// Convert to linear rgb then compress.
Rgb linear = new(Vector3.Transform(source[i].ToVector3(), matrix));
Vector4 nonlinear = options.TargetRgbWorkingSpace.Compress(linear.ToScaledVector4());
destination[i] = FromScaledVector4(nonlinear);
}
}
/// <inheritdoc/>
public CieXyz ToProfileConnectingSpace(ColorConversionOptions options)
{
// First expand to linear rgb
Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(this.ToScaledVector4()));
// Then convert to xyz
return new CieXyz(Vector3.Transform(linear.ToScaledVector3(), GetRgbToCieXyzMatrix(options.RgbWorkingSpace)));
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
Matrix4x4 matrix = GetRgbToCieXyzMatrix(options.RgbWorkingSpace);
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
// First expand to linear rgb
Rgb linear = FromScaledVector4(options.RgbWorkingSpace.Expand(rgb.ToScaledVector4()));
// Then convert to xyz
destination[i] = new CieXyz(Vector3.Transform(linear.ToScaledVector3(), matrix));
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource() => ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <summary>
/// Initializes the color instance from a generic scaled <see cref="Vector3"/>.
/// </summary>
/// <param name="source">The vector to load the color from.</param>
/// <returns>The <see cref="Rgb"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rgb FromScaledVector3(Vector3 source) => new(Vector3.Clamp(source, Vector3.Zero, Vector3.One));
/// <summary>
/// Initializes the color instance from a generic scaled <see cref="Vector4"/>.
/// </summary>
/// <param name="source">The vector to load the color from.</param>
/// <returns>The <see cref="Rgb"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rgb FromScaledVector4(Vector4 source)
{
source = Vector4.Clamp(source, Vector4.Zero, Vector4.One);
return new(source.X, source.Y, source.Z);
}
/// <summary>
/// Initializes the color instance for a source clamped between <value>0</value> and <value>1</value>
/// </summary>
/// <param name="source">The source to load the color from.</param>
/// <returns>The <see cref="Rgb"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Rgb Clamp(Rgb source) => new(Vector3.Clamp(new(source.R, source.G, source.B), Vector3.Zero, Vector3.One));
/// <summary>
/// Expands the color into a generic ("scaled") <see cref="Vector3"/> representation
/// with values scaled and usually clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToScaledVector3() => Clamp(this).ToVector3();
/// <summary>
/// Expands the color into a generic <see cref="Vector3"/> representation.
/// 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() => new(this.R, this.G, this.B);
/// <summary>
/// Expands the color into a generic ("scaled") <see cref="Vector4"/> representation
/// with values scaled and usually clamped between <value>0</value> and <value>1</value>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector4"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4() => new(this.ToScaledVector3(), 1f);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Rgb other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(Rgb other)
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<Rgb, Vector3>(ref Unsafe.AsRef(in this));
private static Matrix4x4 GetCieXyzToRgbMatrix(RgbWorkingSpace workingSpace)
{
Matrix4x4 matrix = GetRgbToCieXyzMatrix(workingSpace);
Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix);
return inverseMatrix;
}
private static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace)
{
DebugGuard.NotNull(workingSpace, nameof(workingSpace));
RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates;
float xr = chromaticity.R.X;
float xg = chromaticity.G.X;
float xb = chromaticity.B.X;
float yr = chromaticity.R.Y;
float yg = chromaticity.G.Y;
float yb = chromaticity.B.Y;
float mXr = xr / yr;
float mZr = (1 - xr - yr) / yr;
float mXg = xg / yg;
float mZg = (1 - xg - yg) / yg;
float mXb = xb / yb;
float mZb = (1 - xb - yb) / yb;
Matrix4x4 xyzMatrix = new()
{
M11 = mXr,
M21 = mXg,
M31 = mXb,
M12 = 1F,
M22 = 1F,
M32 = 1F,
M13 = mZr,
M23 = mZg,
M33 = mZb,
M44 = 1F
};
Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix);
Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix);
// Use transposed Rows/Columns
return new Matrix4x4
{
M11 = vector.X * mXr,
M21 = vector.Y * mXg,
M31 = vector.Z * mXb,
M12 = vector.X,
M22 = vector.Y,
M32 = vector.Z,
M13 = vector.X * mZr,
M23 = vector.Y * mZg,
M33 = vector.Z * mZb,
M44 = 1F
};
}
}

20
src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs → src/ImageSharp/ColorProfiles/RgbPrimariesChromaticityCoordinates.cs

@ -1,7 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
using SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents the chromaticity coordinates of RGB primaries.
@ -50,9 +52,7 @@ public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable<RgbPrima
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right)
{
return left.Equals(right);
}
=> left.Equals(right);
/// <summary>
/// Compares two <see cref="RgbPrimariesChromaticityCoordinates"/> objects for inequality
@ -67,21 +67,15 @@ public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable<RgbPrima
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(RgbPrimariesChromaticityCoordinates left, RgbPrimariesChromaticityCoordinates right)
{
return !left.Equals(right);
}
=> !left.Equals(right);
/// <inheritdoc/>
public override bool Equals(object? obj)
{
return obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other);
}
=> obj is RgbPrimariesChromaticityCoordinates other && this.Equals(other);
/// <inheritdoc/>
public bool Equals(RgbPrimariesChromaticityCoordinates other)
{
return this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
}
=> this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
/// <inheritdoc />
public override int GetHashCode() => HashCode.Combine(this.R, this.G, this.B);

95
src/ImageSharp/ColorProfiles/VonKriesChromaticAdaptation.cs

@ -0,0 +1,95 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Implementation of the Von Kries chromatic adaptation model.
/// </summary>
/// <remarks>
/// Transformation described here:
/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// </remarks>
public static class VonKriesChromaticAdaptation
{
/// <summary>
/// Performs a linear transformation of a source color in to the destination color.
/// </summary>
/// <remarks>Doesn't crop the resulting color space coordinates (e.g. allows negative values for XYZ coordinates).</remarks>
/// <param name="source">The source color.</param>
/// <param name="whitePoints">The conversion white points.</param>
/// <param name="matrix">The chromatic adaptation matrix.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public static CieXyz Transform(in CieXyz source, (CieXyz From, CieXyz To) whitePoints, Matrix4x4 matrix)
{
CieXyz from = whitePoints.From;
CieXyz to = whitePoints.To;
if (from.Equals(to))
{
return new(source.X, source.Y, source.Z);
}
Vector3 sourceColorLms = Vector3.Transform(source.ToVector3(), matrix);
Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix);
Vector3 vector = targetWhitePointLms / sourceWhitePointLms;
Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms);
Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix);
return new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix));
}
/// <summary>
/// Performs a bulk linear transformation of a source color in to the destination color.
/// </summary>
/// <remarks>Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates).</remarks>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
/// <param name="whitePoints">The conversion white points.</param>
/// <param name="matrix">The chromatic adaptation matrix.</param>
public static void Transform(
ReadOnlySpan<CieXyz> source,
Span<CieXyz> destination,
(CieXyz From, CieXyz To) whitePoints,
Matrix4x4 matrix)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
CieXyz from = whitePoints.From;
CieXyz to = whitePoints.To;
if (from.Equals(to))
{
source.CopyTo(destination[..count]);
return;
}
Matrix4x4.Invert(matrix, out Matrix4x4 inverseMatrix);
ref CieXyz sourceBase = ref MemoryMarshal.GetReference(source);
ref CieXyz destinationBase = ref MemoryMarshal.GetReference(destination);
Vector3 sourceWhitePointLms = Vector3.Transform(from.ToVector3(), matrix);
Vector3 targetWhitePointLms = Vector3.Transform(to.ToVector3(), matrix);
Vector3 vector = targetWhitePointLms / sourceWhitePointLms;
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceBase, i);
ref CieXyz dp = ref Unsafe.Add(ref destinationBase, i);
Vector3 sourceColorLms = Vector3.Transform(sp.ToVector3(), matrix);
Vector3 targetColorLms = Vector3.Multiply(vector, sourceColorLms);
dp = new CieXyz(Vector3.Transform(targetColorLms, inverseMatrix));
}
}
}

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/GammaWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// The gamma working space.
@ -26,12 +26,16 @@ public sealed class GammaWorkingSpace : RgbWorkingSpace
public float Gamma { get; }
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => GammaCompanding.Compress(channel, this.Gamma);
public override void Compress(Span<Vector4> vectors) => GammaCompanding.Compress(vectors, this.Gamma);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => GammaCompanding.Expand(channel, this.Gamma);
public override void Expand(Span<Vector4> vectors) => GammaCompanding.Expand(vectors, this.Gamma);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => GammaCompanding.Compress(vector, this.Gamma);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => GammaCompanding.Expand(vector, this.Gamma);
/// <inheritdoc/>
public override bool Equals(object? obj)

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/LWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// L* working space.
@ -22,10 +22,14 @@ public sealed class LWorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => LCompanding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => LCompanding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => LCompanding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => LCompanding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => LCompanding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => LCompanding.Expand(vector);
}

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/Rec2020WorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// Rec. 2020 (ITU-R Recommendation BT.2020F) working space.
@ -22,10 +22,14 @@ public sealed class Rec2020WorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => Rec2020Companding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => Rec2020Companding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => Rec2020Companding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => Rec2020Companding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => Rec2020Companding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => Rec2020Companding.Expand(vector);
}

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/Rec709WorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// Rec. 709 (ITU-R Recommendation BT.709) working space.
@ -22,10 +22,14 @@ public sealed class Rec709WorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => Rec709Companding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => Rec709Companding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => Rec709Companding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => Rec709Companding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => Rec709Companding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => Rec709Companding.Expand(vector);
}

40
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/RgbWorkingSpace.cs

@ -1,7 +1,9 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
using System.Numerics;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// Base class for all implementations of <see cref="RgbWorkingSpace"/>.
@ -30,26 +32,30 @@ public abstract class RgbWorkingSpace
public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; }
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// Compresses the linear vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public abstract void Compress(Span<Vector4> vectors);
/// <summary>
/// Expands the nonlinear vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
public abstract void Expand(Span<Vector4> vectors);
/// <summary>
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// </remarks>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
public abstract float Expand(float channel);
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public abstract Vector4 Compress(Vector4 vector);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system).
/// Compresses the linear vector to its nonlinear equivalent with respect to the energy.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
public abstract float Compress(float channel);
/// <param name="vector">The vector.</param>
/// <returns>The <see cref="Vector4"/>.</returns>
public abstract Vector4 Expand(Vector4 vector);
/// <inheritdoc/>
public override bool Equals(object? obj)

18
src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs → src/ImageSharp/ColorProfiles/WorkingSpaces/SRgbWorkingSpace.cs

@ -1,10 +1,10 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Companding;
using System.Numerics;
using SixLabors.ImageSharp.ColorProfiles.Companding;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorProfiles.WorkingSpaces;
/// <summary>
/// The sRgb working space.
@ -22,10 +22,14 @@ public sealed class SRgbWorkingSpace : RgbWorkingSpace
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Compress(float channel) => SRgbCompanding.Compress(channel);
public override void Compress(Span<Vector4> vectors) => SRgbCompanding.Compress(vectors);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override float Expand(float channel) => SRgbCompanding.Expand(channel);
public override void Expand(Span<Vector4> vectors) => SRgbCompanding.Expand(vectors);
/// <inheritdoc/>
public override Vector4 Compress(Vector4 vector) => SRgbCompanding.Compress(vector);
/// <inheritdoc/>
public override Vector4 Expand(Vector4 vector) => SRgbCompanding.Expand(vector);
}

87
src/ImageSharp/ColorSpaces/YCbCr.cs → src/ImageSharp/ColorProfiles/YCbCr.cs

@ -3,15 +3,17 @@
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces;
namespace SixLabors.ImageSharp.ColorProfiles;
/// <summary>
/// Represents an YCbCr (luminance, blue chroma, red chroma) color as defined in the ITU-T T.871 specification for the JFIF use with Jpeg.
/// <see href="http://en.wikipedia.org/wiki/YCbCr"/>
/// <see href="http://www.ijg.org/files/T-REC-T.871-201105-I!!PDF-E.pdf"/>
/// </summary>
public readonly struct YCbCr : IEquatable<YCbCr>
[StructLayout(LayoutKind.Sequential)]
public readonly struct YCbCr : IColorProfile<YCbCr, Rgb>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(255);
@ -22,7 +24,7 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// <param name="y">The y luminance component.</param>
/// <param name="cb">The cb chroma component.</param>
/// <param name="cr">The cr chroma component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public YCbCr(float y, float cb, float cr)
: this(new Vector3(y, cb, cr))
{
@ -32,7 +34,7 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// Initializes a new instance of the <see cref="YCbCr"/> struct.
/// </summary>
/// <param name="vector">The vector representing the y, cb, cr components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public YCbCr(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
@ -45,19 +47,19 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Y { get; }
public float Y { get; }
/// <summary>
/// Gets the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cb { get; }
public float Cb { get; }
/// <summary>
/// Gets the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary>
public readonly float Cr { get; }
public float Cr { get; }
/// <summary>
/// Compares two <see cref="YCbCr"/> objects for equality.
@ -77,11 +79,70 @@ public readonly struct YCbCr : IEquatable<YCbCr>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static bool operator !=(YCbCr left, YCbCr right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public static YCbCr FromProfileConnectingSpace(ColorConversionOptions options, in Rgb source)
{
Vector3 rgb = source.ToScaledVector3() * Max;
float r = rgb.X;
float g = rgb.Y;
float b = rgb.Z;
float y = (0.299F * r) + (0.587F * g) + (0.114F * b);
float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b));
float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b));
return new YCbCr(y, cb, cr);
}
/// <inheritdoc/>
public static void FromProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<Rgb> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
// TODO: We can optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
Rgb rgb = source[i];
destination[i] = FromProfileConnectingSpace(options, in rgb);
}
}
/// <inheritdoc/>
public Rgb ToProfileConnectingSpace(ColorConversionOptions options)
{
float y = this.Y;
float cb = this.Cb - 128F;
float cr = this.Cr - 128F;
float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero);
float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero);
float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero);
return Rgb.FromScaledVector3(new Vector3(r, g, b) / Max);
}
/// <inheritdoc/>
public static void ToProfileConnectionSpace(ColorConversionOptions options, ReadOnlySpan<YCbCr> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
// TODO: We can optimize this by using SIMD
for (int i = 0; i < source.Length; i++)
{
YCbCr ycbcr = source[i];
destination[i] = ycbcr.ToProfileConnectingSpace(options);
}
}
/// <inheritdoc/>
public static ChromaticAdaptionWhitePointSource GetChromaticAdaptionWhitePointSource()
=> ChromaticAdaptionWhitePointSource.RgbWorkingSpace;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => HashCode.Combine(this.Y, this.Cb, this.Cr);
/// <inheritdoc/>
@ -91,9 +152,9 @@ public readonly struct YCbCr : IEquatable<YCbCr>
public override bool Equals(object? obj) => obj is YCbCr other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public bool Equals(YCbCr other)
=> this.Y.Equals(other.Y)
&& this.Cb.Equals(other.Cb)
&& this.Cr.Equals(other.Cr);
=> this.AsVector3Unsafe() == other.AsVector3Unsafe();
private Vector3 AsVector3Unsafe() => Unsafe.As<YCbCr, Vector3>(ref Unsafe.AsRef(in this));
}

135
src/ImageSharp/ColorSpaces/CieLab.cs

@ -1,135 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents a CIE L*a*b* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>
/// </summary>
public readonly struct CieLab : IEquatable<CieLab>
{
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D50;
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(float l, float a, float b)
: this(l, a, b, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(float l, float a, float b, CieXyz whitePoint)
: this(new Vector3(l, a, b), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, a, b components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, a, b components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab(Vector3 vector, CieXyz whitePoint)
: this()
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = vector.X;
this.A = vector.Y;
this.B = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Gets the a color component.
/// <remarks>A value usually ranging from −128 to 127. Negative is green, positive magenta.</remarks>
/// </summary>
public readonly float A { get; }
/// <summary>
/// Gets the b color component.
/// <remarks>A value usually ranging from −128 to 127. Negative is blue, positive is yellow</remarks>
/// </summary>
public readonly float B { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
/// <summary>
/// Compares two <see cref="CieLab"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(CieLab left, CieLab right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLab"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLab other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLab other) =>
this.L.Equals(other.L)
&& this.A.Equals(other.A)
&& this.B.Equals(other.B)
&& this.WhitePoint.Equals(other.WhitePoint);
}

156
src/ImageSharp/ColorSpaces/CieLchuv.cs

@ -1,156 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color.
/// <see href="https://en.wikipedia.org/wiki/CIELAB_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC"/>
/// </summary>
public readonly struct CieLchuv : IEquatable<CieLchuv>
{
private static readonly Vector3 Min = new(0, -200, 0);
private static readonly Vector3 Max = new(100, 200, 360);
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(float l, float c, float h)
: this(l, c, h, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="c">The chroma, relative saturation.</param>
/// <param name="h">The hue in degrees.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(float l, float c, float h, CieXyz whitePoint)
: this(new Vector3(l, c, h), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLchuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, c, h components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLchuv(Vector3 vector, CieXyz whitePoint)
: this()
{
vector = Vector3.Clamp(vector, Min, Max);
this.L = vector.X;
this.C = vector.Y;
this.H = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Gets the a chroma component.
/// <remarks>A value ranging from 0 to 200.</remarks>
/// </summary>
public readonly float C { get; }
/// <summary>
/// Gets the h° hue component in degrees.
/// <remarks>A value ranging from 0 to 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLchuv"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="CieLchuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLchuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.C, this.H, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLchuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLchuv other)
=> this.L.Equals(other.L)
&& this.C.Equals(other.C)
&& this.H.Equals(other.H)
&& this.WhitePoint.Equals(other.WhitePoint);
/// <summary>
/// Computes the saturation of the color (chroma normalized by lightness)
/// </summary>
/// <remarks>
/// A value ranging from 0 to 100.
/// </remarks>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public float Saturation()
{
float result = 100 * (this.C / this.L);
if (float.IsNaN(result))
{
return 0;
}
return result;
}
}

136
src/ImageSharp/ColorSpaces/CieLuv.cs

@ -1,136 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// The CIE 1976 (L*, u*, v*) color space, commonly known by its abbreviation CIELUV, is a color space adopted by the International
/// Commission on Illumination (CIE) in 1976, as a simple-to-compute transformation of the 1931 CIE XYZ color space, but which
/// attempted perceptual uniformity
/// <see href="https://en.wikipedia.org/wiki/CIELUV"/>
/// </summary>
public readonly struct CieLuv : IEquatable<CieLuv>
{
/// <summary>
/// D65 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.D65;
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(float l, float u, float v)
: this(l, u, v, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="u">The blue-yellow chromaticity coordinate of the given whitepoint.</param>
/// <param name="v">The red-green chromaticity coordinate of the given whitepoint.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(float l, float u, float v, CieXyz whitePoint)
: this(new Vector3(l, u, v), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieLuv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, u, v components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLuv(Vector3 vector, CieXyz whitePoint)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = vector.X;
this.U = vector.Y;
this.V = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension
/// <remarks>A value usually ranging between 0 and 100.</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Gets the blue-yellow chromaticity coordinate of the given whitepoint.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public readonly float U { get; }
/// <summary>
/// Gets the red-green chromaticity coordinate of the given whitepoint.
/// <remarks>A value usually ranging between -100 and 100.</remarks>
/// </summary>
public readonly float V { get; }
/// <summary>
/// Gets the reference white point of this color
/// </summary>
public readonly CieXyz WhitePoint { get; }
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="CieLuv"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="CieLuv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="CieLuv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right);
/// <inheritdoc/>
public override int GetHashCode() => HashCode.Combine(this.L, this.U, this.V, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is CieLuv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(CieLuv other)
=> this.L.Equals(other.L)
&& this.U.Equals(other.U)
&& this.V.Equals(other.V)
&& this.WhitePoint.Equals(other.WhitePoint);
}

107
src/ImageSharp/ColorSpaces/Cmyk.cs

@ -1,107 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents an CMYK (cyan, magenta, yellow, keyline) color.
/// </summary>
public readonly struct Cmyk : IEquatable<Cmyk>
{
private static readonly Vector4 Min = Vector4.Zero;
private static readonly Vector4 Max = Vector4.One;
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="c">The cyan component.</param>
/// <param name="m">The magenta component.</param>
/// <param name="y">The yellow component.</param>
/// <param name="k">The keyline black component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Cmyk(float c, float m, float y, float k)
: this(new Vector4(c, m, y, k))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct.
/// </summary>
/// <param name="vector">The vector representing the c, m, y, k components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Cmyk(Vector4 vector)
{
vector = Numerics.Clamp(vector, Min, Max);
this.C = vector.X;
this.M = vector.Y;
this.Y = vector.Z;
this.K = vector.W;
}
/// <summary>
/// Gets the cyan color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float C { get; }
/// <summary>
/// Gets the magenta color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float M { get; }
/// <summary>
/// Gets the yellow color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float Y { get; }
/// <summary>
/// Gets the keyline black color component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float K { get; }
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Cmyk"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Cmyk"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Cmyk"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => HashCode.Combine(this.C, this.M, this.Y, this.K);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Cmyk other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Cmyk other)
=> this.C.Equals(other.C)
&& this.M.Equals(other.M)
&& this.Y.Equals(other.Y)
&& this.K.Equals(other.K);
}

34
src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs

@ -1,34 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements gamma companding.
/// </summary>
/// <remarks>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class GammaCompanding
{
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel, float gamma) => MathF.Pow(channel, gamma);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <param name="gamma">The gamma value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel, float gamma) => MathF.Pow(channel, 1 / gamma);
}

36
src/ImageSharp/ColorSpaces/Companding/LCompanding.cs

@ -1,36 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using SixLabors.ImageSharp.ColorSpaces.Conversion;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements L* companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class LCompanding
{
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel <= 0.08F ? (100F * channel) / CieConstants.Kappa : Numerics.Pow3((channel + 0.16F) / 1.16F);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel <= CieConstants.Epsilon ? (channel * CieConstants.Kappa) / 100F : (1.16F * MathF.Pow(channel, 0.3333333F)) - 0.16F;
}

39
src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs

@ -1,39 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements Rec. 2020 companding function.
/// </summary>
/// <remarks>
/// <see href="http://en.wikipedia.org/wiki/Rec._2020"/>
/// </remarks>
public static class Rec2020Companding
{
private const float Alpha = 1.09929682680944F;
private const float AlphaMinusOne = Alpha - 1F;
private const float Beta = 0.018053968510807F;
private const float InverseBeta = Beta * 4.5F;
private const float Epsilon = 1 / 0.45F;
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < InverseBeta ? channel / 4.5F : MathF.Pow((channel + AlphaMinusOne) / Alpha, Epsilon);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < Beta ? 4.5F * channel : (Alpha * MathF.Pow(channel, 0.45F)) - AlphaMinusOne;
}

35
src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs

@ -1,35 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements the Rec. 709 companding function.
/// </summary>
/// <remarks>
/// http://en.wikipedia.org/wiki/Rec._709
/// </remarks>
public static class Rec709Companding
{
private const float Epsilon = 1 / 0.45F;
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Expand(float channel)
=> channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, Epsilon);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float Compress(float channel)
=> channel < 0.018F ? 4.5F * channel : (1.099F * MathF.Pow(channel, 0.45F)) - 0.099F;
}

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

@ -1,230 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.X86;
namespace SixLabors.ImageSharp.ColorSpaces.Companding;
/// <summary>
/// Implements sRGB companding.
/// </summary>
/// <remarks>
/// For more info see:
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_RGB_to_XYZ.html"/>
/// <see href="http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_RGB.html"/>
/// </remarks>
public static class SRgbCompanding
{
private const int Length = Scale + 2; // 256kb @ 16bit precision.
private const int Scale = (1 << 16) - 1;
private static readonly Lazy<float[]> LazyCompressTable = new(
() =>
{
float[] result = new float[Length];
for (int i = 0; i < result.Length; i++)
{
double d = (double)i / Scale;
if (d <= (0.04045 / 12.92))
{
d *= 12.92;
}
else
{
d = (1.055 * Math.Pow(d, 1.0 / 2.4)) - 0.055;
}
result[i] = (float)d;
}
return result;
},
true);
private static readonly Lazy<float[]> LazyExpandTable = new(
() =>
{
float[] result = new float[Length];
for (int i = 0; i < result.Length; i++)
{
double d = (double)i / Scale;
if (d <= 0.04045)
{
d /= 12.92;
}
else
{
d = Math.Pow((d + 0.055) / 1.055, 2.4);
}
result[i] = (float)d;
}
return result;
},
true);
private static float[] ExpandTable => LazyExpandTable.Value;
private static float[] CompressTable => LazyCompressTable.Value;
/// <summary>
/// Expands the companded vectors to their linear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Expand(Span<Vector4> vectors)
{
if (Avx2.IsSupported && vectors.Length >= 2)
{
CompandAvx2(vectors, ExpandTable);
if (Numerics.Modulo2(vectors.Length) != 0)
{
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Expand(ref MemoryMarshal.GetReference(vectors[^1..]));
}
}
else
{
CompandScalar(vectors, ExpandTable);
}
}
/// <summary>
/// Compresses the uncompanded vectors to their nonlinear equivalents with respect to the energy.
/// </summary>
/// <param name="vectors">The span of vectors.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe void Compress(Span<Vector4> vectors)
{
if (Avx2.IsSupported && vectors.Length >= 2)
{
CompandAvx2(vectors, CompressTable);
if (Numerics.Modulo2(vectors.Length) != 0)
{
// Vector4 fits neatly in pairs. Any overlap has to be equal to 1.
Compress(ref MemoryMarshal.GetReference(vectors[^1..]));
}
}
else
{
CompandScalar(vectors, CompressTable);
}
}
/// <summary>
/// Expands a companded vector to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="vector">The vector.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Expand(ref Vector4 vector)
{
// Alpha is already a linear representation of opacity so we do not want to convert it.
vector.X = Expand(vector.X);
vector.Y = Expand(vector.Y);
vector.Z = Expand(vector.Z);
}
/// <summary>
/// Compresses an uncompanded vector (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="vector">The vector.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static void Compress(ref Vector4 vector)
{
// Alpha is already a linear representation of opacity so we do not want to convert it.
vector.X = Compress(vector.X);
vector.Y = Compress(vector.Y);
vector.Z = Compress(vector.Z);
}
/// <summary>
/// Expands a companded channel to its linear equivalent with respect to the energy.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the linear channel value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Expand(float channel)
=> channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F);
/// <summary>
/// Compresses an uncompanded channel (linear) to its nonlinear equivalent.
/// </summary>
/// <param name="channel">The channel value.</param>
/// <returns>The <see cref="float"/> representing the nonlinear channel value.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static float Compress(float channel)
=> channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandAvx2(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
var scale = Vector256.Create((float)Scale);
Vector256<float> zero = Vector256<float>.Zero;
var offset = Vector256.Create(1);
// Divide by 2 as 4 elements per Vector4 and 8 per Vector256<float>
ref Vector256<float> vectorsBase = ref Unsafe.As<Vector4, Vector256<float>>(ref MemoryMarshal.GetReference(vectors));
ref Vector256<float> vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length / 2u);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector256<float> multiplied = Avx.Multiply(scale, vectorsBase);
multiplied = Avx.Min(Avx.Max(zero, multiplied), scale);
Vector256<int> truncated = Avx.ConvertToVector256Int32WithTruncation(multiplied);
Vector256<float> truncatedF = Avx.ConvertToVector256Single(truncated);
Vector256<float> low = Avx2.GatherVector256(tablePointer, truncated, sizeof(float));
Vector256<float> high = Avx2.GatherVector256(tablePointer, Avx2.Add(truncated, offset), sizeof(float));
// Alpha is already a linear representation of opacity so we do not want to convert it.
Vector256<float> companded = Numerics.Lerp(low, high, Avx.Subtract(multiplied, truncatedF));
vectorsBase = Avx.Blend(companded, vectorsBase, Numerics.BlendAlphaControl);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static unsafe void CompandScalar(Span<Vector4> vectors, float[] table)
{
fixed (float* tablePointer = &MemoryMarshal.GetArrayDataReference(table))
{
Vector4 zero = Vector4.Zero;
var scale = new Vector4(Scale);
ref Vector4 vectorsBase = ref MemoryMarshal.GetReference(vectors);
ref Vector4 vectorsLast = ref Unsafe.Add(ref vectorsBase, (uint)vectors.Length);
while (Unsafe.IsAddressLessThan(ref vectorsBase, ref vectorsLast))
{
Vector4 multiplied = Numerics.Clamp(vectorsBase * Scale, zero, scale);
float f0 = multiplied.X;
float f1 = multiplied.Y;
float f2 = multiplied.Z;
uint i0 = (uint)f0;
uint i1 = (uint)f1;
uint i2 = (uint)f2;
// Alpha is already a linear representation of opacity so we do not want to convert it.
vectorsBase.X = Numerics.Lerp(tablePointer[i0], tablePointer[i0 + 1], f0 - (int)i0);
vectorsBase.Y = Numerics.Lerp(tablePointer[i1], tablePointer[i1 + 1], f1 - (int)i1);
vectorsBase.Z = Numerics.Lerp(tablePointer[i2], tablePointer[i2 + 1], f2 - (int)i2);
vectorsBase = ref Unsafe.Add(ref vectorsBase, 1);
}
}
}
}

159
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs

@ -1,159 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Performs chromatic adaptation on the various color spaces.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs chromatic adaptation of given <see cref="CieXyz"/> color.
/// Target white point is <see cref="ColorSpaceConverterOptions.WhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <param name="sourceWhitePoint">The source white point.</param>
/// <returns>The adapted color</returns>
public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint) => this.Adapt(color, sourceWhitePoint, this.whitePoint);
/// <summary>
/// Performs chromatic adaptation of given <see cref="CieXyz"/> color.
/// Target white point is <see cref="ColorSpaceConverterOptions.WhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <param name="sourceWhitePoint">The source white point.</param>
/// <param name="targetWhitePoint">The target white point.</param>
/// <returns>The adapted color</returns>
public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint)
{
if (!this.performChromaticAdaptation || sourceWhitePoint.Equals(targetWhitePoint))
{
return color;
}
// We know that chromaticAdaption is not null because performChromaticAdaption is checked
return this.chromaticAdaptation!.Transform(color, sourceWhitePoint, targetWhitePoint);
}
/// <summary>
/// Adapts <see cref="CieLab"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLab Adapt(in CieLab color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint))
{
return color;
}
var xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Adapts <see cref="CieLch"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLch Adapt(in CieLch color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint))
{
return color;
}
var labColor = this.ToCieLab(color);
return this.ToCieLch(labColor);
}
/// <summary>
/// Adapts <see cref="CieLchuv"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLchuv Adapt(in CieLchuv color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint))
{
return color;
}
var luvColor = this.ToCieLuv(color);
return this.ToCieLchuv(luvColor);
}
/// <summary>
/// Adapts <see cref="CieLuv"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetLuvWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public CieLuv Adapt(in CieLuv color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLuvWhitePoint))
{
return color;
}
var xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Adapts <see cref="HunterLab"/> color from the source white point to white point set in <see cref="ColorSpaceConverterOptions.TargetHunterLabWhitePoint"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public HunterLab Adapt(in HunterLab color)
{
if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetHunterLabWhitePoint))
{
return color;
}
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Adapts a <see cref="LinearRgb"/> color from the source working space to working space set in <see cref="ColorSpaceConverterOptions.TargetRgbWorkingSpace"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public LinearRgb Adapt(in LinearRgb color)
{
if (!this.performChromaticAdaptation || color.WorkingSpace.Equals(this.targetRgbWorkingSpace))
{
return color;
}
// Conversion to XYZ
LinearRgbToCieXyzConverter converterToXYZ = GetLinearRgbToCieXyzConverter(color.WorkingSpace);
CieXyz unadapted = converterToXYZ.Convert(color);
// Adaptation
// We know that chromaticAdaption is not null because performChromaticAdaption is checked
CieXyz adapted = this.chromaticAdaptation!.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint);
// Conversion back to RGB
return this.cieXyzToLinearRgbConverter.Convert(adapted);
}
/// <summary>
/// Adapts an <see cref="Rgb"/> color from the source working space to working space set in <see cref="ColorSpaceConverterOptions.TargetRgbWorkingSpace"/>.
/// </summary>
/// <param name="color">The color to adapt</param>
/// <returns>The adapted color</returns>
public Rgb Adapt(in Rgb color)
{
if (!this.performChromaticAdaptation)
{
return color;
}
var linearInput = ToLinearRgb(color);
LinearRgb linearOutput = this.Adapt(linearInput);
return ToRgb(linearOutput);
}
}

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

@ -1,441 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLab"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLch color)
{
// Conversion (preserving white point)
CieLab unadapted = CieLchToCieLabConverter.Convert(color);
return this.Adapt(unadapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in CieXyz color)
{
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint);
return this.cieXyzToCieLabConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLab"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLab ToCieLab(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLab(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLab(sp);
}
}
}

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

@ -1,441 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLch"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLch"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLab color)
{
CieLab adapted = this.Adapt(color);
return CieLabToCieLchConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLchuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieLuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieXyy color)
{
var xyzColor = ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLch"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in CieXyz color)
{
var labColor = this.ToCieLab(color);
return this.ToCieLch(labColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Cmyk color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Hsl color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Hsv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in HunterLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in LinearRgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Lms color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in Rgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLch"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLch"/></returns>
public CieLch ToCieLch(in YCbCr color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToCieLch(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLch"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLch> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLch destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLch dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLch(sp);
}
}
}

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

@ -1,441 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLchuv"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLchuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieLuv color)
{
CieLuv adapted = this.Adapt(color);
return CieLuvToCieLchuvConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in CieXyz color)
{
CieLuv luvColor = this.ToCieLuv(color);
return this.ToCieLchuv(luvColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLchuv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLchuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLchuv"/></returns>
public CieLchuv ToCieLchuv(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLchuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLchuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLchuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLchuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLchuv(sp);
}
}
}

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

@ -1,435 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieLuv"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLab"/></returns>
public CieLuv ToCieLuv(in CieLchuv color)
{
// Conversion (preserving white point)
CieLuv unadapted = CieLchuvToCieLuvConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in CieXyz color)
{
// Adaptation
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLuvWhitePoint);
// Conversion
return this.cieXyzToCieLuvConverter.Convert(adapted);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieLuv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieLuv"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieLuv"/></returns>
public CieLuv ToCieLuv(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCieLuv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieLuv"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieLuv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieLuv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieLuv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieLuv(sp);
}
}
}

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

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieXyy"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public static CieXyy ToCieXyy(in CieXyz color) => CieXyzAndCieXyyConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<CieXyz> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Cmyk color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(Hsl color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Hsv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in LinearRgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in Rgb color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieXyy"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyy"/></returns>
public CieXyy ToCieXyy(in YCbCr color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return ToCieXyy(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieXyy"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieXyy> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyy destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyy dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyy(sp);
}
}
}

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

@ -1,458 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Collections.Concurrent;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="CieXyz"/>.
/// </content>
public partial class ColorSpaceConverter
{
private static readonly ConcurrentDictionary<RgbWorkingSpace, LinearRgbToCieXyzConverter> ConverterCache = new();
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLab color)
{
// Conversion
CieXyz unadapted = CieLabToCieXyzConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted, color.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLch color)
{
// Conversion to Lab
CieLab labColor = CieLchToCieLabConverter.Convert(color);
// Conversion to XYZ (incl. adaptation)
return this.ToCieXyz(labColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLchuv color)
{
// Conversion to Luv
CieLuv luvColor = CieLchuvToCieLuvConverter.Convert(color);
// Conversion to XYZ (incl. adaptation)
return this.ToCieXyz(luvColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="CieXyz"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in CieLuv color)
{
// Conversion
CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color);
// Adaptation
return this.Adapt(unadapted, color.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public static CieXyz ToCieXyz(in CieXyy color)
// Conversion
=> CieXyzAndCieXyyConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<CieXyy> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Hsl color)
{
Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Hsv color)
{
// Conversion
Rgb rgb = ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in HunterLab color)
{
CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color);
return this.Adapt(unadapted, color.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in LinearRgb color)
{
// Conversion
LinearRgbToCieXyzConverter converter = GetLinearRgbToCieXyzConverter(color.WorkingSpace);
CieXyz unadapted = converter.Convert(color);
return this.Adapt(unadapted, color.WorkingSpace.WhitePoint);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="CieXyz"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Lms color)
=> this.cieXyzAndLmsConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="CieXyz"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="CieXyz"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in Rgb color)
{
// Conversion
LinearRgb linear = RgbToLinearRgbConverter.Convert(color);
return this.ToCieXyz(linear);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="CieXyz"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="CieXyz"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="CieXyz"/></returns>
public CieXyz ToCieXyz(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return this.ToCieXyz(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="CieXyz"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<CieXyz> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCieXyz(sp);
}
}
/// <summary>
/// Gets the correct converter for the given rgb working space.
/// </summary>
/// <param name="workingSpace">The source working space</param>
/// <returns>The <see cref="LinearRgbToCieXyzConverter"/></returns>
private static LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace)
=> ConverterCache.GetOrAdd(workingSpace, (key) => new LinearRgbToCieXyzConverter(key));
}

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

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Cmyk"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Cmyk"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Cmyk"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in Hsl color)
{
Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in Hsv color)
{
Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToCmyk(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors,</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public static Cmyk ToCmyk(in Rgb color) => CmykAndRgbConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Cmyk"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = ToCmyk(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Cmyk"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Cmyk"/></returns>
public Cmyk ToCmyk(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return CmykAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Cmyk"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Cmyk> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Cmyk destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Cmyk dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToCmyk(sp);
}
}
}

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

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Hsl"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in Hsv color)
{
Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Hsl"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsl(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Hsl"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public static Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsl(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Hsl"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsl"/></returns>
public Hsl ToHsl(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return HslAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Hsl"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Hsl> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsl destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsl dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsl(sp);
}
}
}

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

@ -1,437 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Hsv"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in Hsl color)
{
Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToHsv(xyzColor);
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public static Hsv ToHsv(in Rgb color) => HsvAndRgbConverter.Convert(color);
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = ToHsv(sp);
}
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Hsv"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Hsv"/></returns>
public Hsv ToHsv(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return HsvAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Hsv"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Hsv> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Hsv destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Hsv dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHsv(sp);
}
}
}

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

@ -1,430 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="HunterLab"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="HunterLab"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="HunterLab"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<HunterLab> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref HunterLab destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref HunterLab dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToHunterLab(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLch color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLchuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieLuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieXyy color)
{
var xyzColor = ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in CieXyz color)
{
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint);
return this.cieXyzToHunterLabConverter.Convert(adapted);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Cmyk color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Hsl color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Hsv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in LinearRgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Lms color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="HunterLab"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in Rgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="HunterLab"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="HunterLab"/></returns>
public HunterLab ToHunterLab(in YCbCr color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToHunterLab(xyzColor);
}
}

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

@ -1,429 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="LinearRgb"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<Lms> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToLinearRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="LinearRgb"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<LinearRgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref LinearRgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLinearRgb(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="LinearRgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in CieXyz color)
{
// Adaptation
CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint);
// Conversion
return this.cieXyzToLinearRgbConverter.Convert(adapted);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return ToLinearRgb(rgb);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Hsl color)
{
Rgb rgb = ToRgb(color);
return ToLinearRgb(rgb);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Hsv color)
{
Rgb rgb = ToRgb(color);
return ToLinearRgb(rgb);
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToLinearRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="LinearRgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public static LinearRgb ToLinearRgb(in Rgb color)
=> RgbToLinearRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="LinearRgb"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="LinearRgb"/></returns>
public LinearRgb ToLinearRgb(in YCbCr color)
{
Rgb rgb = this.ToRgb(color);
return ToLinearRgb(rgb);
}
}

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

@ -1,425 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Lms"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Cmyk> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsl> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Hsv> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<LinearRgb> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Rgb> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Lms"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Lms> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Lms destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Lms dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToLms(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLch color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLchuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieLuv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieXyy color)
{
var xyzColor = ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Cmyk color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Hsl color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Hsv color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in HunterLab color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in LinearRgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in Rgb color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Lms"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Lms"/></returns>
public Lms ToLms(in YCbCr color)
{
var xyzColor = this.ToCieXyz(color);
return this.ToLms(xyzColor);
}
}

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

@ -1,419 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="Rgb"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLchuv"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLchuv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="YCbCr"/> into <see cref="Rgb"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<YCbCr> source, Span<Rgb> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgb destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToRgb(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLchuv"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLchuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in CieXyz color)
{
// Conversion
LinearRgb linear = this.ToLinearRgb(color);
// Compand
return ToRgb(linear);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in Cmyk color) => CmykAndRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in Hsv color) => HsvAndRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in Hsl color) => HslAndRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public static Rgb ToRgb(in LinearRgb color) => LinearRgbToRgbConverter.Convert(color);
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToRgb(xyzColor);
}
/// <summary>
/// Converts a <see cref="YCbCr"/> into a <see cref="Rgb"/>
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="Rgb"/></returns>
public Rgb ToRgb(in YCbCr color)
{
// Conversion
Rgb rgb = YCbCrAndRgbConverter.Convert(color);
// Adaptation
return this.Adapt(rgb);
}
}

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

@ -1,404 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <content>
/// Allows conversion to <see cref="YCbCr"/>.
/// </content>
public partial class ColorSpaceConverter
{
/// <summary>
/// Performs the bulk conversion from <see cref="CieLab"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLab> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLab sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLab sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLch"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
public void Convert(ReadOnlySpan<CieLch> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLch sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLch sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieLuv"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieLuv> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyy"/> into <see cref="YCbCr"/>
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyy> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="CieXyz"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<CieXyz> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Cmyk"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Cmyk> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsl"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsl> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsl sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsl sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Hsv"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Hsv> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Hsv sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Hsv sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="HunterLab"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<HunterLab> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="LinearRgb"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<LinearRgb> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Lms"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public void Convert(ReadOnlySpan<Lms> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Lms sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Lms sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = this.ToYCbCr(sp);
}
}
/// <summary>
/// Performs the bulk conversion from <see cref="Rgb"/> into <see cref="YCbCr"/>.
/// </summary>
/// <param name="source">The span to the source colors</param>
/// <param name="destination">The span to the destination colors</param>
public static void Convert(ReadOnlySpan<Rgb> source, Span<YCbCr> destination)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
ref Rgb sourceRef = ref MemoryMarshal.GetReference(source);
ref YCbCr destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref Rgb sp = ref Unsafe.Add(ref sourceRef, i);
ref YCbCr dp = ref Unsafe.Add(ref destRef, i);
dp = ToYCbCr(sp);
}
}
/// <summary>
/// Converts a <see cref="CieLab"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLch"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLch color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieLuv"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieLuv color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyy"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieXyy color)
{
CieXyz xyzColor = ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="CieXyz"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in CieXyz color)
{
Rgb rgb = this.ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Cmyk"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Cmyk color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Hsl"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Hsl color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Hsv"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Hsv color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="HunterLab"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in HunterLab color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="LinearRgb"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in LinearRgb color)
{
Rgb rgb = ToRgb(color);
return YCbCrAndRgbConverter.Convert(rgb);
}
/// <summary>
/// Converts a <see cref="Lms"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public YCbCr ToYCbCr(in Lms color)
{
CieXyz xyzColor = this.ToCieXyz(color);
return this.ToYCbCr(xyzColor);
}
/// <summary>
/// Converts a <see cref="Rgb"/> into a <see cref="YCbCr"/>.
/// </summary>
/// <param name="color">The color to convert.</param>
/// <returns>The <see cref="YCbCr"/></returns>
public static YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color);
}

59
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs

@ -1,59 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Provides methods to allow the conversion of color values between different color spaces.
/// </summary>
public partial class ColorSpaceConverter
{
// Options.
private static readonly ColorSpaceConverterOptions DefaultOptions = new();
private readonly Matrix4x4 lmsAdaptationMatrix;
private readonly CieXyz whitePoint;
private readonly CieXyz targetLuvWhitePoint;
private readonly CieXyz targetLabWhitePoint;
private readonly CieXyz targetHunterLabWhitePoint;
private readonly RgbWorkingSpace targetRgbWorkingSpace;
private readonly IChromaticAdaptation? chromaticAdaptation;
private readonly bool performChromaticAdaptation;
private readonly CieXyzAndLmsConverter cieXyzAndLmsConverter;
private readonly CieXyzToCieLabConverter cieXyzToCieLabConverter;
private readonly CieXyzToCieLuvConverter cieXyzToCieLuvConverter;
private readonly CieXyzToHunterLabConverter cieXyzToHunterLabConverter;
private readonly CieXyzToLinearRgbConverter cieXyzToLinearRgbConverter;
/// <summary>
/// Initializes a new instance of the <see cref="ColorSpaceConverter"/> class.
/// </summary>
public ColorSpaceConverter()
: this(DefaultOptions)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="ColorSpaceConverter"/> class.
/// </summary>
/// <param name="options">The configuration options.</param>
public ColorSpaceConverter(ColorSpaceConverterOptions options)
{
Guard.NotNull(options, nameof(options));
this.whitePoint = options.WhitePoint;
this.targetLuvWhitePoint = options.TargetLuvWhitePoint;
this.targetLabWhitePoint = options.TargetLabWhitePoint;
this.targetHunterLabWhitePoint = options.TargetHunterLabWhitePoint;
this.targetRgbWorkingSpace = options.TargetRgbWorkingSpace;
this.chromaticAdaptation = options.ChromaticAdaptation;
this.performChromaticAdaptation = this.chromaticAdaptation != null;
this.lmsAdaptationMatrix = options.LmsAdaptationMatrix;
this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix);
this.cieXyzToCieLabConverter = new CieXyzToCieLabConverter(this.targetLabWhitePoint);
this.cieXyzToCieLuvConverter = new CieXyzToCieLuvConverter(this.targetLuvWhitePoint);
this.cieXyzToHunterLabConverter = new CieXyzToHunterLabConverter(this.targetHunterLabWhitePoint);
this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace);
}
}

53
src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs

@ -1,53 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Configuration options for the <see cref="ColorSpaceConverter"/> class.
/// </summary>
public class ColorSpaceConverterOptions
{
/// <summary>
/// Gets or sets the white point used for chromatic adaptation in conversions from/to XYZ color space.
/// When <value>default</value>, no adaptation will be performed.
/// Defaults to: <see cref="CieLuv.DefaultWhitePoint"/>.
/// </summary>
public CieXyz WhitePoint { get; set; } = CieLuv.DefaultWhitePoint;
/// <summary>
/// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information)
/// Defaults to: <see cref="CieLuv.DefaultWhitePoint"/>.
/// </summary>
public CieXyz TargetLuvWhitePoint { get; set; } = CieLuv.DefaultWhitePoint;
/// <summary>
/// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information)
/// Defaults to: <see cref="CieLab.DefaultWhitePoint"/>.
/// </summary>
public CieXyz TargetLabWhitePoint { get; set; } = CieLab.DefaultWhitePoint;
/// <summary>
/// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information)
/// Defaults to: <see cref="HunterLab.DefaultWhitePoint"/>.
/// </summary>
public CieXyz TargetHunterLabWhitePoint { get; set; } = HunterLab.DefaultWhitePoint;
/// <summary>
/// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information)
/// Defaults to: <see cref="Rgb.DefaultWorkingSpace"/>.
/// </summary>
public RgbWorkingSpace TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace;
/// <summary>
/// Gets or sets the chromatic adaptation method used. When <value>null</value>, no adaptation will be performed.
/// </summary>
public IChromaticAdaptation? ChromaticAdaptation { get; set; } = new VonKriesChromaticAdaptation();
/// <summary>
/// Gets or sets transformation matrix used in conversion to and from <see cref="Lms"/>.
/// </summary>
public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix;
}

31
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs

@ -1,31 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
/// </summary>
internal static class CieLchToCieLabConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLch"/> input to an instance of <see cref="CieLab"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLab Convert(in CieLch input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float a = c * MathF.Cos(hRadians);
float b = c * MathF.Sin(hRadians);
return new CieLab(l, a, b, input.WhitePoint);
}
}

39
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs

@ -1,39 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
/// </summary>
internal static class CieLabToCieLchConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieLch"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLch Convert(in CieLab input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/Lab_color_space#Cylindrical_representation:_CIELCh_or_CIEHLC
float l = input.L, a = input.A, b = input.B;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
return new CieLch(l, c, hDegrees, input.WhitePoint);
}
}

43
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs

@ -1,43 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieXyz"/>.
/// </summary>
internal static class CieLabToCieXyzConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLab"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieXyz Convert(in CieLab input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html
float l = input.L, a = input.A, b = input.B;
float fy = (l + 16) / 116F;
float fx = (a / 500F) + fy;
float fz = fy - (b / 200F);
float fx3 = Numerics.Pow3(fx);
float fz3 = Numerics.Pow3(fz);
float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa;
float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? Numerics.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa;
float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa;
Vector3 wxyz = new(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z);
// Avoids XYZ coordinates out range (restricted by 0 and XYZ reference white)
Vector3 xyzr = Vector3.Clamp(new Vector3(xr, yr, zr), Vector3.Zero, Vector3.One);
Vector3 xyz = xyzr * wxyz;
return new CieXyz(xyz);
}
}

31
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs

@ -1,31 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLch"/> to <see cref="CieLab"/>.
/// </summary>
internal static class CieLchuvToCieLuvConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLchuv"/> input to an instance of <see cref="CieLuv"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLuv Convert(in CieLchuv input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, c = input.C, hDegrees = input.H;
float hRadians = GeometryUtilities.DegreeToRadian(hDegrees);
float u = c * MathF.Cos(hRadians);
float v = c * MathF.Sin(hRadians);
return new CieLuv(l, u, v, input.WhitePoint);
}
}

39
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs

@ -1,39 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLab"/> to <see cref="CieLch"/>.
/// </summary>
internal static class CieLuvToCieLchuvConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieLchuv"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieLchuv Convert(in CieLuv input)
{
// Conversion algorithm described here:
// https://en.wikipedia.org/wiki/CIELUV#Cylindrical_representation_.28CIELCH.29
float l = input.L, a = input.U, b = input.V;
float c = MathF.Sqrt((a * a) + (b * b));
float hRadians = MathF.Atan2(b, a);
float hDegrees = GeometryUtilities.RadianToDegree(hRadians);
// Wrap the angle round at 360.
hDegrees %= 360;
// Make sure it's not negative.
while (hDegrees < 0)
{
hDegrees += 360;
}
return new CieLchuv(l, c, hDegrees, input.WhitePoint);
}
}

73
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs

@ -1,73 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieLuv"/> to <see cref="CieXyz"/>.
/// </summary>
internal static class CieLuvToCieXyzConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieLuv"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
public static CieXyz Convert(in CieLuv input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html
float l = input.L, u = input.U, v = input.V;
float u0 = ComputeU0(input.WhitePoint);
float v0 = ComputeV0(input.WhitePoint);
float y = l > CieConstants.Kappa * CieConstants.Epsilon
? Numerics.Pow3((l + 16) / 116)
: l / CieConstants.Kappa;
float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3;
float b = -5 * y;
const float c = -0.3333333F;
float d = y * ((39 * l / (v + (13 * l * v0))) - 5);
float x = (d - b) / (a - c);
float z = (x * a) + b;
if (float.IsNaN(x) || x < 0)
{
x = 0;
}
if (float.IsNaN(y) || y < 0)
{
y = 0;
}
if (float.IsNaN(z) || z < 0)
{
z = 0;
}
return new CieXyz(x, y, z);
}
/// <summary>
/// Calculates the blue-yellow chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float ComputeU0(in CieXyz input)
=> (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
/// <summary>
/// Calculates the red-green chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float ComputeV0(in CieXyz input)
=> (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}

52
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs

@ -1,52 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between CIE XYZ and CIE xyY.
/// <see href="http://www.brucelindbloom.com/"/> for formulas.
/// </summary>
internal static class CieXyzAndCieXyyConverter
{
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="CieXyy"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieXyy Convert(in CieXyz input)
{
float x = input.X / (input.X + input.Y + input.Z);
float y = input.Y / (input.X + input.Y + input.Z);
if (float.IsNaN(x) || float.IsNaN(y))
{
return new CieXyy(0, 0, input.Y);
}
return new CieXyy(x, y, input.Y);
}
/// <summary>
/// Performs the conversion from the <see cref="CieXyy"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieXyz Convert(in CieXyy input)
{
if (MathF.Abs(input.Y) < Constants.Epsilon)
{
return new CieXyz(0, 0, input.Yl);
}
float x = (input.X * input.Yl) / input.Y;
float y = input.Yl;
float z = ((1 - input.X - input.Y) * y) / input.Y;
return new CieXyz(x, y, z);
}
}

44
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs

@ -1,44 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// The base class for converting between <see cref="HunterLab"/> and <see cref="CieXyz"/> color spaces.
/// </summary>
internal abstract class CieXyzAndHunterLabConverterBase
{
/// <summary>
/// Returns the Ka coefficient that depends upon the whitepoint illuminant.
/// </summary>
/// <param name="whitePoint">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float ComputeKa(CieXyz whitePoint)
{
if (whitePoint.Equals(Illuminants.C))
{
return 175F;
}
return 100F * (175F / 198.04F) * (whitePoint.X + whitePoint.Y);
}
/// <summary>
/// Returns the Kb coefficient that depends upon the whitepoint illuminant.
/// </summary>
/// <param name="whitePoint">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static float ComputeKb(CieXyz whitePoint)
{
if (whitePoint == Illuminants.C)
{
return 70F;
}
return 100F * (70F / 218.11F) * (whitePoint.Y + whitePoint.Z);
}
}

69
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs

@ -1,69 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="Lms"/>
/// </summary>
internal sealed class CieXyzAndLmsConverter
{
/// <summary>
/// Default transformation matrix used, when no other is set. (Bradford)
/// <see cref="LmsAdaptationMatrix"/>
/// </summary>
public static readonly Matrix4x4 DefaultTransformationMatrix = LmsAdaptationMatrix.Bradford;
private Matrix4x4 inverseTransformationMatrix;
private Matrix4x4 transformationMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzAndLmsConverter"/> class.
/// </summary>
public CieXyzAndLmsConverter()
: this(DefaultTransformationMatrix)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzAndLmsConverter"/> class.
/// </summary>
/// <param name="transformationMatrix">
/// Definition of the cone response domain (see <see cref="LmsAdaptationMatrix"/>),
/// if not set <see cref="DefaultTransformationMatrix"/> will be used.
/// </param>
public CieXyzAndLmsConverter(Matrix4x4 transformationMatrix)
{
this.transformationMatrix = transformationMatrix;
Matrix4x4.Invert(this.transformationMatrix, out this.inverseTransformationMatrix);
}
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="Lms"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Lms Convert(in CieXyz input)
{
Vector3 vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix);
return new Lms(vector);
}
/// <summary>
/// Performs the conversion from the <see cref="Lms"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public CieXyz Convert(in Lms input)
{
Vector3 vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix);
return new CieXyz(vector);
}
}

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

@ -1,57 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieXyz"/> to <see cref="CieLab"/>.
/// </summary>
internal sealed class CieXyzToCieLabConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLabConverter"/> class.
/// </summary>
public CieXyzToCieLabConverter()
: this(CieLab.DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLabConverter"/> class.
/// </summary>
/// <param name="labWhitePoint">The target reference lab white point</param>
public CieXyzToCieLabConverter(CieXyz labWhitePoint) => this.LabWhitePoint = labWhitePoint;
/// <summary>
/// Gets the target reference whitepoint. When not set, <see cref="CieLab.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz LabWhitePoint { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="CieLab"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public CieLab Convert(in CieXyz input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html
float wx = this.LabWhitePoint.X, wy = this.LabWhitePoint.Y, wz = this.LabWhitePoint.Z;
float xr = input.X / wx, yr = input.Y / wy, zr = input.Z / wz;
const float inv116 = 1 / 116F;
float fx = xr > CieConstants.Epsilon ? MathF.Pow(xr, 0.3333333F) : ((CieConstants.Kappa * xr) + 16F) * inv116;
float fy = yr > CieConstants.Epsilon ? MathF.Pow(yr, 0.3333333F) : ((CieConstants.Kappa * yr) + 16F) * inv116;
float fz = zr > CieConstants.Epsilon ? MathF.Pow(zr, 0.3333333F) : ((CieConstants.Kappa * zr) + 16F) * inv116;
float l = (116F * fy) - 16F;
float a = 500F * (fx - fy);
float b = 200F * (fy - fz);
return new CieLab(l, a, b, this.LabWhitePoint);
}
}

86
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs

@ -1,86 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Converts from <see cref="CieXyz"/> to <see cref="CieLuv"/>.
/// </summary>
internal sealed class CieXyzToCieLuvConverter
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
/// </summary>
public CieXyzToCieLuvConverter()
: this(CieLuv.DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToCieLuvConverter"/> class.
/// </summary>
/// <param name="luvWhitePoint">The target reference luv white point</param>
public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) => this.LuvWhitePoint = luvWhitePoint;
/// <summary>
/// Gets the target reference whitepoint. When not set, <see cref="CieLuv.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz LuvWhitePoint { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="CieLuv"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
public CieLuv Convert(in CieXyz input)
{
// Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html
float yr = input.Y / this.LuvWhitePoint.Y;
float up = ComputeUp(input);
float vp = ComputeVp(input);
float upr = ComputeUp(this.LuvWhitePoint);
float vpr = ComputeVp(this.LuvWhitePoint);
float l = yr > CieConstants.Epsilon ? ((116 * MathF.Pow(yr, 0.3333333F)) - 16F) : (CieConstants.Kappa * yr);
if (float.IsNaN(l) || l < 0)
{
l = 0;
}
float u = 13 * l * (up - upr);
float v = 13 * l * (vp - vpr);
if (float.IsNaN(u))
{
u = 0;
}
if (float.IsNaN(v))
{
v = 0;
}
return new CieLuv(l, u, v, this.LuvWhitePoint);
}
/// <summary>
/// Calculates the blue-yellow chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static float ComputeUp(in CieXyz input)
=> (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z));
/// <summary>
/// Calculates the red-green chromacity based on the given whitepoint.
/// </summary>
/// <param name="input">The whitepoint</param>
/// <returns>The <see cref="float"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float ComputeVp(in CieXyz input)
=> (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z));
}

65
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs

@ -1,65 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="HunterLab"/>
/// </summary>
internal sealed class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase
{
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToHunterLabConverter"/> class.
/// </summary>
public CieXyzToHunterLabConverter()
: this(HunterLab.DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToHunterLabConverter"/> class.
/// </summary>
/// <param name="labWhitePoint">The hunter Lab white point.</param>
public CieXyzToHunterLabConverter(CieXyz labWhitePoint) => this.HunterLabWhitePoint = labWhitePoint;
/// <summary>
/// Gets the target reference white. When not set, <see cref="HunterLab.DefaultWhitePoint"/> is used.
/// </summary>
public CieXyz HunterLabWhitePoint { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="HunterLab"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public HunterLab Convert(in CieXyz input)
{
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
float x = input.X, y = input.Y, z = input.Z;
float xn = this.HunterLabWhitePoint.X, yn = this.HunterLabWhitePoint.Y, zn = this.HunterLabWhitePoint.Z;
float ka = ComputeKa(this.HunterLabWhitePoint);
float kb = ComputeKb(this.HunterLabWhitePoint);
float yByYn = y / yn;
float sqrtYbyYn = MathF.Sqrt(yByYn);
float l = 100 * sqrtYbyYn;
float a = ka * (((x / xn) - yByYn) / sqrtYbyYn);
float b = kb * ((yByYn - (z / zn)) / sqrtYbyYn);
if (float.IsNaN(a))
{
a = 0;
}
if (float.IsNaN(b))
{
b = 0;
}
return new HunterLab(l, a, b, this.HunterLabWhitePoint);
}
}

55
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs

@ -1,55 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="CieXyz"/> and <see cref="LinearRgb"/>
/// </summary>
internal sealed class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase
{
private readonly Matrix4x4 conversionMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToLinearRgbConverter"/> class.
/// </summary>
public CieXyzToLinearRgbConverter()
: this(Rgb.DefaultWorkingSpace)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="CieXyzToLinearRgbConverter"/> class.
/// </summary>
/// <param name="workingSpace">The target working space.</param>
public CieXyzToLinearRgbConverter(RgbWorkingSpace workingSpace)
{
this.TargetWorkingSpace = workingSpace;
// Gets the inverted Rgb -> Xyz matrix
Matrix4x4.Invert(GetRgbToCieXyzMatrix(workingSpace), out Matrix4x4 inverted);
this.conversionMatrix = inverted;
}
/// <summary>
/// Gets the target working space.
/// </summary>
public RgbWorkingSpace TargetWorkingSpace { get; }
/// <summary>
/// Performs the conversion from the <see cref="CieXyz"/> input to an instance of <see cref="LinearRgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public LinearRgb Convert(in CieXyz input)
{
var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix);
return new LinearRgb(vector, this.TargetWorkingSpace);
}
}

49
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs

@ -1,49 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="Cmyk"/> and <see cref="Rgb"/>.
/// </summary>
internal static class CmykAndRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="Cmyk"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Rgb Convert(in Cmyk input)
{
Vector3 rgb = (Vector3.One - new Vector3(input.C, input.M, input.Y)) * (Vector3.One - new Vector3(input.K));
return new Rgb(rgb);
}
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Cmyk"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Cmyk Convert(in Rgb input)
{
// To CMY
Vector3 cmy = Vector3.One - input.ToVector3();
// To CMYK
Vector3 k = new(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z)));
if (MathF.Abs(k.X - 1F) < Constants.Epsilon)
{
return new Cmyk(0, 0, 0, 1F);
}
cmy = (cmy - k) / (Vector3.One - k);
return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X);
}
}

158
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs

@ -1,158 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between HSL and Rgb
/// See <see href="http://www.poynton.com/PDFs/coloureq.pdf"/> for formulas.
/// </summary>
internal static class HslAndRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="Hsl"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Rgb Convert(in Hsl input)
{
float rangedH = input.H / 360F;
float r = 0;
float g = 0;
float b = 0;
float s = input.S;
float l = input.L;
if (MathF.Abs(l) > Constants.Epsilon)
{
if (MathF.Abs(s) < Constants.Epsilon)
{
r = g = b = l;
}
else
{
float temp2 = (l < .5F) ? l * (1F + s) : l + s - (l * s);
float temp1 = (2F * l) - temp2;
r = GetColorComponent(temp1, temp2, rangedH + 0.3333333F);
g = GetColorComponent(temp1, temp2, rangedH);
b = GetColorComponent(temp1, temp2, rangedH - 0.3333333F);
}
}
return new Rgb(r, g, b);
}
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Hsl"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Hsl Convert(in Rgb input)
{
float r = input.R;
float g = input.G;
float b = input.B;
float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0F;
float s = 0F;
float l = (max + min) / 2F;
if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsl(0F, s, l);
}
if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2F + ((b - r) / chroma);
}
else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4F + ((r - g) / chroma);
}
h *= 60F;
if (h < 0F)
{
h += 360F;
}
if (l <= .5F)
{
s = chroma / (max + min);
}
else
{
s = chroma / (2F - max - min);
}
return new Hsl(h, s, l);
}
/// <summary>
/// Gets the color component from the given values.
/// </summary>
/// <param name="first">The first value.</param>
/// <param name="second">The second value.</param>
/// <param name="third">The third value.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float GetColorComponent(float first, float second, float third)
{
third = MoveIntoRange(third);
if (third < 0.1666667F)
{
return first + ((second - first) * 6F * third);
}
if (third < .5F)
{
return second;
}
if (third < 0.6666667F)
{
return first + ((second - first) * (0.6666667F - third) * 6F);
}
return first;
}
/// <summary>
/// Moves the specific value within the acceptable range for
/// conversion.
/// <remarks>Used for converting <see cref="Hsl"/> colors to this type.</remarks>
/// </summary>
/// <param name="value">The value to shift.</param>
/// <returns>
/// The <see cref="float"/>.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
private static float MoveIntoRange(float value)
{
if (value < 0F)
{
value++;
}
else if (value > 1F)
{
value--;
}
return value;
}
}

128
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs

@ -1,128 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between HSV and Rgb
/// See <see href="http://www.poynton.com/PDFs/coloureq.pdf"/> for formulas.
/// </summary>
internal static class HsvAndRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="Hsv"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Rgb Convert(in Hsv input)
{
float s = input.S;
float v = input.V;
if (MathF.Abs(s) < Constants.Epsilon)
{
return new Rgb(v, v, v);
}
float h = (MathF.Abs(input.H - 360) < Constants.Epsilon) ? 0 : input.H / 60;
int i = (int)Math.Truncate(h);
float f = h - i;
float p = v * (1F - s);
float q = v * (1F - (s * f));
float t = v * (1F - (s * (1F - f)));
float r, g, b;
switch (i)
{
case 0:
r = v;
g = t;
b = p;
break;
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
default:
r = v;
g = p;
b = q;
break;
}
return new Rgb(r, g, b);
}
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="Hsv"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Hsv Convert(in Rgb input)
{
float r = input.R;
float g = input.G;
float b = input.B;
float max = MathF.Max(r, MathF.Max(g, b));
float min = MathF.Min(r, MathF.Min(g, b));
float chroma = max - min;
float h = 0;
float s = 0;
float v = max;
if (MathF.Abs(chroma) < Constants.Epsilon)
{
return new Hsv(0, s, v);
}
if (MathF.Abs(r - max) < Constants.Epsilon)
{
h = (g - b) / chroma;
}
else if (MathF.Abs(g - max) < Constants.Epsilon)
{
h = 2 + ((b - r) / chroma);
}
else if (MathF.Abs(b - max) < Constants.Epsilon)
{
h = 4 + ((r - g) / chroma);
}
h *= 60;
if (h < 0.0)
{
h += 360;
}
s = chroma / v;
return new Hsv(h, s, v);
}
}

37
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs

@ -1,37 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="HunterLab"/> and <see cref="CieXyz"/>
/// </summary>
internal sealed class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase
{
/// <summary>
/// Performs the conversion from the <see cref="HunterLab"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static CieXyz Convert(in HunterLab input)
{
// Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab
float l = input.L, a = input.A, b = input.B;
float xn = input.WhitePoint.X, yn = input.WhitePoint.Y, zn = input.WhitePoint.Z;
float ka = ComputeKa(input.WhitePoint);
float kb = ComputeKb(input.WhitePoint);
float pow = Numerics.Pow2(l / 100F);
float sqrtPow = MathF.Sqrt(pow);
float y = pow * yn;
float x = (((a / ka) * sqrtPow) + pow) * xn;
float z = (((b / kb) * sqrtPow) - pow) * (-zn);
return new CieXyz(x, y, z);
}
}

73
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs

@ -1,73 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Provides base methods for converting between <see cref="LinearRgb"/> and <see cref="CieXyz"/> color spaces.
/// </summary>
internal abstract class LinearRgbAndCieXyzConverterBase
{
/// <summary>
/// Returns the correct matrix to convert between the Rgb and CieXyz color space.
/// </summary>
/// <param name="workingSpace">The Rgb working space.</param>
/// <returns>The <see cref="Matrix4x4"/> based on the chromaticity and working space.</returns>
public static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace)
{
DebugGuard.NotNull(workingSpace, nameof(workingSpace));
RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates;
float xr = chromaticity.R.X;
float xg = chromaticity.G.X;
float xb = chromaticity.B.X;
float yr = chromaticity.R.Y;
float yg = chromaticity.G.Y;
float yb = chromaticity.B.Y;
float mXr = xr / yr;
float mZr = (1 - xr - yr) / yr;
float mXg = xg / yg;
float mZg = (1 - xg - yg) / yg;
float mXb = xb / yb;
float mZb = (1 - xb - yb) / yb;
Matrix4x4 xyzMatrix = new()
{
M11 = mXr,
M21 = mXg,
M31 = mXb,
M12 = 1F,
M22 = 1F,
M32 = 1F,
M13 = mZr,
M23 = mZg,
M33 = mZb,
M44 = 1F
};
Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix);
Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix);
// Use transposed Rows/Columns
// TODO: Is there a built in method for this multiplication?
return new Matrix4x4
{
M11 = vector.X * mXr,
M21 = vector.Y * mXg,
M31 = vector.Z * mXb,
M12 = vector.X * 1,
M22 = vector.Y * 1,
M32 = vector.Z * 1,
M13 = vector.X * mZr,
M23 = vector.Y * mZg,
M33 = vector.Z * mZb,
M44 = 1F
};
}
}

52
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs

@ -1,52 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="LinearRgb"/> and <see cref="CieXyz"/>
/// </summary>
internal sealed class LinearRgbToCieXyzConverter : LinearRgbAndCieXyzConverterBase
{
private readonly Matrix4x4 conversionMatrix;
/// <summary>
/// Initializes a new instance of the <see cref="LinearRgbToCieXyzConverter"/> class.
/// </summary>
public LinearRgbToCieXyzConverter()
: this(Rgb.DefaultWorkingSpace)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="LinearRgbToCieXyzConverter"/> class.
/// </summary>
/// <param name="workingSpace">The target working space.</param>
public LinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace)
{
this.SourceWorkingSpace = workingSpace;
this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace);
}
/// <summary>
/// Gets the source working space
/// </summary>
public RgbWorkingSpace SourceWorkingSpace { get; }
/// <summary>
/// Performs the conversion from the <see cref="LinearRgb"/> input to an instance of <see cref="CieXyz"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public CieXyz Convert(in LinearRgb input)
{
DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal.");
Vector3 vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix);
return new CieXyz(vector);
}
}

25
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs

@ -1,25 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="LinearRgb"/> and <see cref="Rgb"/>.
/// </summary>
internal static class LinearRgbToRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="LinearRgb"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Rgb Convert(in LinearRgb input) =>
new(
r: input.WorkingSpace.Compress(input.R),
g: input.WorkingSpace.Compress(input.G),
b: input.WorkingSpace.Compress(input.B),
workingSpace: input.WorkingSpace);
}

25
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs

@ -1,25 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between Rgb and LinearRgb.
/// </summary>
internal static class RgbToLinearRgbConverter
{
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="LinearRgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static LinearRgb Convert(in Rgb input)
=> new(
r: input.WorkingSpace.Expand(input.R),
g: input.WorkingSpace.Expand(input.G),
b: input.WorkingSpace.Expand(input.B),
workingSpace: input.WorkingSpace);
}

55
src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs

@ -1,55 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Color converter between <see cref="YCbCr"/> and <see cref="Rgb"/>
/// See <see href="https://en.wikipedia.org/wiki/YCbCr#JPEG_conversion"/> for formulas.
/// </summary>
internal static class YCbCrAndRgbConverter
{
private static readonly Vector3 MaxBytes = new(255F);
/// <summary>
/// Performs the conversion from the <see cref="YCbCr"/> input to an instance of <see cref="Rgb"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static Rgb Convert(in YCbCr input)
{
float y = input.Y;
float cb = input.Cb - 128F;
float cr = input.Cr - 128F;
float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero);
float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero);
float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero);
return new Rgb(new Vector3(r, g, b) / MaxBytes);
}
/// <summary>
/// Performs the conversion from the <see cref="Rgb"/> input to an instance of <see cref="YCbCr"/> type.
/// </summary>
/// <param name="input">The input color instance.</param>
/// <returns>The converted result.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static YCbCr Convert(in Rgb input)
{
Vector3 rgb = input.ToVector3() * MaxBytes;
float r = rgb.X;
float g = rgb.Y;
float b = rgb.Z;
float y = (0.299F * r) + (0.587F * g) + (0.114F * b);
float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b));
float cr = 128F + ((0.5F * r) - (0.418688F * g) - (0.081312F * b));
return new YCbCr(y, cb, cr);
}
}

36
src/ImageSharp/ColorSpaces/Conversion/Implementation/IChromaticAdaptation.cs

@ -1,36 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Chromatic adaptation.
/// A linear transformation of a source color (XS, YS, ZS) into a destination color (XD, YD, ZD) by a linear transformation [M]
/// which is dependent on the source reference white (XWS, YWS, ZWS) and the destination reference white (XWD, YWD, ZWD).
/// </summary>
public interface IChromaticAdaptation
{
/// <summary>
/// Performs a linear transformation of a source color in to the destination color.
/// </summary>
/// <remarks>Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates).</remarks>
/// <param name="source">The source color.</param>
/// <param name="sourceWhitePoint">The source white point.</param>
/// <param name="destinationWhitePoint">The destination white point.</param>
/// <returns>The <see cref="CieXyz"/></returns>
CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint);
/// <summary>
/// Performs a bulk linear transformation of a source color in to the destination color.
/// </summary>
/// <remarks>Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates).</remarks>
/// <param name="source">The span to the source colors.</param>
/// <param name="destination">The span to the destination colors.</param>
/// <param name="sourceWhitePoint">The source white point.</param>
/// <param name="destinationWhitePoint">The destination white point.</param>
void Transform(
ReadOnlySpan<CieXyz> source,
Span<CieXyz> destination,
CieXyz sourceWhitePoint,
in CieXyz destinationWhitePoint);
}

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

@ -1,99 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.ColorSpaces.Conversion;
/// <summary>
/// Implementation of the von Kries chromatic adaptation model.
/// </summary>
/// <remarks>
/// Transformation described here:
/// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
/// </remarks>
public sealed class VonKriesChromaticAdaptation : IChromaticAdaptation
{
private readonly CieXyzAndLmsConverter converter;
/// <summary>
/// Initializes a new instance of the <see cref="VonKriesChromaticAdaptation"/> class.
/// </summary>
public VonKriesChromaticAdaptation()
: this(new CieXyzAndLmsConverter())
{
}
/// <summary>
/// Initializes a new instance of the <see cref="VonKriesChromaticAdaptation"/> class.
/// </summary>
/// <param name="transformationMatrix">
/// The transformation matrix used for the conversion (definition of the cone response domain).
/// <see cref="LmsAdaptationMatrix"/>
/// </param>
public VonKriesChromaticAdaptation(Matrix4x4 transformationMatrix)
: this(new CieXyzAndLmsConverter(transformationMatrix))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="VonKriesChromaticAdaptation"/> class.
/// </summary>
/// <param name="converter">The color converter</param>
internal VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) => this.converter = converter;
/// <inheritdoc/>
public CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint)
{
if (sourceWhitePoint.Equals(destinationWhitePoint))
{
return source;
}
Lms sourceColorLms = this.converter.Convert(source);
Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint);
Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint);
Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3();
var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3()));
return this.converter.Convert(targetColorLms);
}
/// <inheritdoc/>
public void Transform(
ReadOnlySpan<CieXyz> source,
Span<CieXyz> destination,
CieXyz sourceWhitePoint,
in CieXyz destinationWhitePoint)
{
Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination));
int count = source.Length;
if (sourceWhitePoint.Equals(destinationWhitePoint))
{
source.CopyTo(destination[..count]);
return;
}
ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source);
ref CieXyz destRef = ref MemoryMarshal.GetReference(destination);
for (nuint i = 0; i < (uint)count; i++)
{
ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i);
ref CieXyz dp = ref Unsafe.Add(ref destRef, i);
Lms sourceColorLms = this.converter.Convert(sp);
Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint);
Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint);
Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3();
var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3()));
dp = this.converter.Convert(targetColorLms);
}
}
}

100
src/ImageSharp/ColorSpaces/Hsl.cs

@ -1,100 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents a Hsl (hue, saturation, lightness) color.
/// </summary>
public readonly struct Hsl : IEquatable<Hsl>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="l">The l value (lightness) component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Hsl(float h, float s, float l)
: this(new Vector3(h, s, l))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct.
/// </summary>
/// <param name="vector">The vector representing the h, s, l components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Hsl(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
this.H = vector.X;
this.S = vector.Y;
this.L = vector.Z;
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float S { get; }
/// <summary>
/// Gets the lightness component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Compares two <see cref="Hsl"/> objects for equality.
/// </summary>
/// <param name="left">
/// The <see cref="Hsl"/> on the left side of the operand.
/// </param>
/// <param name="right">The <see cref="Hsl"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Hsl left, Hsl right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Hsl"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Hsl"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsl"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.L);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Hsl other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Hsl other)
=> this.H.Equals(other.H)
&& this.S.Equals(other.S)
&& this.L.Equals(other.L);
}

98
src/ImageSharp/ColorSpaces/Hsv.cs

@ -1,98 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness).
/// </summary>
public readonly struct Hsv : IEquatable<Hsv>
{
private static readonly Vector3 Min = Vector3.Zero;
private static readonly Vector3 Max = new(360, 1, 1);
/// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct.
/// </summary>
/// <param name="h">The h hue component.</param>
/// <param name="s">The s saturation component.</param>
/// <param name="v">The v value (brightness) component.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Hsv(float h, float s, float v)
: this(new Vector3(h, s, v))
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct.
/// </summary>
/// <param name="vector">The vector representing the h, s, v components.</param>
[MethodImpl(InliningOptions.ShortMethod)]
public Hsv(Vector3 vector)
{
vector = Vector3.Clamp(vector, Min, Max);
this.H = vector.X;
this.S = vector.Y;
this.V = vector.Z;
}
/// <summary>
/// Gets the hue component.
/// <remarks>A value ranging between 0 and 360.</remarks>
/// </summary>
public readonly float H { get; }
/// <summary>
/// Gets the saturation component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float S { get; }
/// <summary>
/// Gets the value (brightness) component.
/// <remarks>A value ranging between 0 and 1.</remarks>
/// </summary>
public readonly float V { get; }
/// <summary>
/// Compares two <see cref="Hsv"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Hsv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Hsv left, Hsv right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Hsv"/> objects for inequality.
/// </summary>
/// <param name="left">The <see cref="Hsv"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Hsv"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => HashCode.Combine(this.H, this.S, this.V);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is Hsv other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Hsv other)
=> this.H.Equals(other.H)
&& this.S.Equals(other.S)
&& this.V.Equals(other.V);
}

134
src/ImageSharp/ColorSpaces/HunterLab.cs

@ -1,134 +0,0 @@
// Copyright (c) Six Labors.
// Licensed under the Six Labors Split License.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.ColorSpaces;
/// <summary>
/// Represents an Hunter LAB color.
/// <see href="https://en.wikipedia.org/wiki/Lab_color_space"/>.
/// </summary>
public readonly struct HunterLab : IEquatable<HunterLab>
{
/// <summary>
/// D50 standard illuminant.
/// Used when reference white is not specified explicitly.
/// </summary>
public static readonly CieXyz DefaultWhitePoint = Illuminants.C;
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public HunterLab(float l, float a, float b)
: this(new Vector3(l, a, b), DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="l">The lightness dimension.</param>
/// <param name="a">The a (green - magenta) component.</param>
/// <param name="b">The b (blue - yellow) component.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public HunterLab(float l, float a, float b, CieXyz whitePoint)
: this(new Vector3(l, a, b), whitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l, a, b components.</param>
/// <remarks>Uses <see cref="DefaultWhitePoint"/> as white point.</remarks>
[MethodImpl(InliningOptions.ShortMethod)]
public HunterLab(Vector3 vector)
: this(vector, DefaultWhitePoint)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="HunterLab"/> struct.
/// </summary>
/// <param name="vector">The vector representing the l a b components.</param>
/// <param name="whitePoint">The reference white point. <see cref="Illuminants"/></param>
[MethodImpl(InliningOptions.ShortMethod)]
public HunterLab(Vector3 vector, CieXyz whitePoint)
{
// Not clamping as documentation about this space only indicates "usual" ranges
this.L = vector.X;
this.A = vector.Y;
this.B = vector.Z;
this.WhitePoint = whitePoint;
}
/// <summary>
/// Gets the lightness dimension.
/// <remarks>A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white).</remarks>
/// </summary>
public readonly float L { get; }
/// <summary>
/// Gets the a color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is green, positive magenta.</remarks>
/// </summary>
public readonly float A { get; }
/// <summary>
/// Gets the b color component.
/// <remarks>A value usually ranging from -100 to 100. Negative is blue, positive is yellow</remarks>
/// </summary>
public readonly float B { get; }
/// <summary>
/// Gets the reference white point of this color.
/// </summary>
public readonly CieXyz WhitePoint { get; }
/// <summary>
/// Compares two <see cref="HunterLab"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="HunterLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HunterLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
public static bool operator ==(HunterLab left, HunterLab right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="HunterLab"/> objects for inequality
/// </summary>
/// <param name="left">The <see cref="HunterLab"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="HunterLab"/> on the right side of the operand.</param>
/// <returns>
/// True if the current left is unequal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => HashCode.Combine(this.L, this.A, this.B, this.WhitePoint);
/// <inheritdoc/>
public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/>
public override bool Equals(object? obj) => obj is HunterLab other && this.Equals(other);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(HunterLab other)
=> this.L.Equals(other.L)
&& this.A.Equals(other.A)
&& this.B.Equals(other.B)
&& this.WhitePoint.Equals(other.WhitePoint);
}

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

Loading…
Cancel
Save