diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs
index 17b57e4c70..7b0b69a68c 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieLab.cs
@@ -31,5 +31,57 @@ namespace ImageSharp.Colors.Spaces.Conversion
CieXyzToCieLabConverter converter = new CieXyzToCieLabConverter(this.TargetLabWhitePoint);
return converter.Convert(adapted);
}
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public CieLab ToCieLab(LinearRgb color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToCieLab(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public CieLab ToCieLab(Rgb color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToCieLab(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public CieLab ToCieLab(HunterLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToCieLab(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public CieLab ToCieLab(Lms color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToCieLab(xyzColor);
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs
index 01a9680611..ab42c10433 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.CieXyz.cs
@@ -7,6 +7,7 @@ namespace ImageSharp.Colors.Spaces.Conversion
{
using ImageSharp.Colors.Spaces;
using ImageSharp.Colors.Spaces.Conversion.Implementation.CieLab;
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.HunterLab;
using ImageSharp.Colors.Spaces.Conversion.Implementation.Rgb;
///
@@ -16,6 +17,8 @@ namespace ImageSharp.Colors.Spaces.Conversion
{
private static readonly CieLabToCieXyzConverter CieLabToCieXyzConverter = new CieLabToCieXyzConverter();
+ private static readonly HunterLabToCieXyzConverter HunterLabToCieXyzConverter = new HunterLabToCieXyzConverter();
+
private LinearRgbToCieXyzConverter linearRgbToCieXyzConverter;
///
@@ -84,6 +87,26 @@ namespace ImageSharp.Colors.Spaces.Conversion
: this.Adapt(unadapted, color.WorkingSpace.WhitePoint);
}
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public CieXyz ToCieXyz(HunterLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ // Conversion
+ CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color);
+
+ // Adaptation
+ CieXyz adapted = color.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed
+ ? unadapted
+ : this.Adapt(unadapted, color.WhitePoint);
+
+ return adapted;
+ }
+
///
/// Gets the correct converter for the given rgb working space.
///
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.HunterLab.cs
new file mode 100644
index 0000000000..630b1cfbeb
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.HunterLab.cs
@@ -0,0 +1,85 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion
+{
+ using ImageSharp.Colors.Spaces.Conversion.Implementation.HunterLab;
+
+ ///
+ /// Converts between color spaces ensuring that the color is adapted using chromatic adaptation.
+ ///
+ public partial class ColorSpaceConverter
+ {
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public HunterLab ToHunterLab(CieXyz color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ // Adaptation
+ CieXyz adapted = !this.WhitePoint.Equals(this.TargetHunterLabWhitePoint) && this.IsChromaticAdaptationPerformed
+ ? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetHunterLabWhitePoint)
+ : color;
+
+ // Conversion
+ return new CieXyzToHunterLabConverter(this.TargetHunterLabWhitePoint).Convert(adapted);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public HunterLab ToHunterLab(Rgb color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToHunterLab(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public HunterLab ToHunterLab(LinearRgb color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToHunterLab(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public HunterLab ToHunterLab(CieLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToHunterLab(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public HunterLab ToHunterLab(Lms color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToHunterLab(xyzColor);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs
index 3724efaf2c..41cba6f67a 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.LinearRgb.cs
@@ -48,6 +48,45 @@ namespace ImageSharp.Colors.Spaces.Conversion
return xyzConverter.Convert(adapted);
}
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public LinearRgb ToLinearRGB(HunterLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToLinearRgb(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public LinearRgb ToLinearRGB(CieLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToLinearRgb(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public LinearRgb ToLinearRGB(Lms color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToLinearRgb(xyzColor);
+ }
+
///
/// Gets the correct converter for the given rgb working space.
///
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs
index 25f5941772..c53e999ecf 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Lms.cs
@@ -24,5 +24,57 @@ namespace ImageSharp.Colors.Spaces.Conversion
// Conversion
return this.cachedCieXyzAndLmsConverter.Convert(color);
}
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public Lms ToLms(CieLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToLms(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public Lms ToLms(HunterLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToLms(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public Lms ToLms(LinearRgb color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToLms(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public Lms ToLms(Rgb color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToLms(xyzColor);
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs
index b6a7dd86d4..c82e554e49 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.Rgb.cs
@@ -42,5 +42,44 @@ namespace ImageSharp.Colors.Spaces.Conversion
// Compand
return this.ToRgb(linear);
}
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public Rgb ToRgb(HunterLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToRgb(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public Rgb ToRgb(CieLab color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToRgb(xyzColor);
+ }
+
+ ///
+ /// Converts a into a
+ ///
+ /// The color to convert.
+ /// The
+ public Rgb ToRgb(Lms color)
+ {
+ Guard.NotNull(color, nameof(color));
+
+ CieXyz xyzColor = this.ToCieXyz(color);
+ return this.ToRgb(xyzColor);
+ }
}
}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs
index 459a4f474a..8727c4e6a3 100644
--- a/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs
+++ b/src/ImageSharp/Colors/Spaces/Conversion/ColorSpaceConverter.cs
@@ -33,6 +33,7 @@ namespace ImageSharp.Colors.Spaces.Conversion
this.LmsAdaptationMatrix = CieXyzAndLmsConverter.DefaultTransformationMatrix;
this.ChromaticAdaptation = new VonKriesChromaticAdaptation(this.cachedCieXyzAndLmsConverter, this.cachedCieXyzAndLmsConverter);
this.TargetLabWhitePoint = CieLab.DefaultWhitePoint;
+ this.TargetHunterLabWhitePoint = HunterLab.DefaultWhitePoint;
this.TargetRgbWorkingSpace = Rgb.DefaultWorkingSpace;
}
@@ -48,6 +49,12 @@ namespace ImageSharp.Colors.Spaces.Conversion
///
public CieXyz TargetLabWhitePoint { get; set; }
+ ///
+ /// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information)
+ /// Defaults to: .
+ ///
+ public CieXyz TargetHunterLabWhitePoint { get; set; }
+
///
/// 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: .
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs
new file mode 100644
index 0000000000..aa8851cfca
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs
@@ -0,0 +1,51 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.HunterLab
+{
+ using System.Runtime.CompilerServices;
+
+ ///
+ /// The base class for converting between and color spaces.
+ ///
+ internal abstract class CieXyzAndHunterLabConverterBase
+ {
+ ///
+ /// Returns the Ka coefficient that depends upon the whitepoint illuminant.
+ ///
+ /// The whitepoint
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float ComputeKa(CieXyz whitePoint)
+ {
+ DebugGuard.NotNull(whitePoint, nameof(whitePoint));
+
+ if (whitePoint.Equals(Illuminants.C))
+ {
+ return 175;
+ }
+
+ return 100 * (175 / 198.04F) * (whitePoint.X + whitePoint.Y);
+ }
+
+ ///
+ /// Returns the Kb coefficient that depends upon the whitepoint illuminant.
+ ///
+ /// The whitepoint
+ /// The
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public static float ComputeKb(CieXyz whitePoint)
+ {
+ DebugGuard.NotNull(whitePoint, nameof(whitePoint));
+
+ if (whitePoint == Illuminants.C)
+ {
+ return 70;
+ }
+
+ return 100 * (70 / 218.11F) * (whitePoint.Y + whitePoint.Z);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs
new file mode 100644
index 0000000000..c9b31e7e18
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs
@@ -0,0 +1,66 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.HunterLab
+{
+ using HunterLab = ImageSharp.Colors.Spaces.HunterLab;
+
+ ///
+ /// Color converter between CieXyz and HunterLab
+ ///
+ internal class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase, IColorConversion
+ {
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ public CieXyzToHunterLabConverter()
+ : this(HunterLab.DefaultWhitePoint)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the class.
+ ///
+ /// The hunter Lab white point.
+ public CieXyzToHunterLabConverter(CieXyz labWhitePoint)
+ {
+ this.HunterLabWhitePoint = labWhitePoint;
+ }
+
+ ///
+ /// Gets the target reference white. When not set, is used.
+ ///
+ public CieXyz HunterLabWhitePoint { get; }
+
+ ///
+ public HunterLab Convert(CieXyz input)
+ {
+ DebugGuard.NotNull(input, nameof(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 l = 100 * MathF.Sqrt(y / yn);
+ float a = ka * (((x / xn) - (y / yn)) / MathF.Sqrt(y / yn));
+ float b = kb * (((y / yn) - (z / zn)) / MathF.Sqrt(y / yn));
+
+ if (float.IsNaN(a))
+ {
+ a = 0;
+ }
+
+ if (float.IsNaN(b))
+ {
+ b = 0;
+ }
+
+ return new HunterLab(l, a, b, this.HunterLabWhitePoint);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs
new file mode 100644
index 0000000000..73190884a8
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs
@@ -0,0 +1,34 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces.Conversion.Implementation.HunterLab
+{
+ using HunterLab = ImageSharp.Colors.Spaces.HunterLab;
+
+ ///
+ /// Color converter between HunterLab and CieXyz
+ ///
+ internal class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase, IColorConversion
+ {
+ ///
+ public CieXyz Convert(HunterLab input)
+ {
+ DebugGuard.NotNull(input, nameof(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 y = MathF.Pow(l / 100F, 2) * yn;
+ float x = (((a / ka) * MathF.Sqrt(y / yn)) + (y / yn)) * xn;
+ float z = (((b / kb) * MathF.Sqrt(y / yn)) - (y / yn)) * (-zn);
+
+ return new CieXyz(x, y, z);
+ }
+ }
+}
diff --git a/src/ImageSharp/Colors/Spaces/HunterLab.cs b/src/ImageSharp/Colors/Spaces/HunterLab.cs
new file mode 100644
index 0000000000..b156f081ad
--- /dev/null
+++ b/src/ImageSharp/Colors/Spaces/HunterLab.cs
@@ -0,0 +1,190 @@
+//
+// Copyright (c) James Jackson-South and contributors.
+// Licensed under the Apache License, Version 2.0.
+//
+
+namespace ImageSharp.Colors.Spaces
+{
+ using System;
+ using System.ComponentModel;
+ using System.Numerics;
+
+ ///
+ /// Represents an Hunter LAB color.
+ ///
+ ///
+ public struct HunterLab : IColorVector, IEquatable, IAlmostEquatable
+ {
+ ///
+ /// D50 standard illuminant.
+ /// Used when reference white is not specified explicitly.
+ ///
+ public static readonly CieXyz DefaultWhitePoint = Illuminants.C;
+
+ ///
+ /// Represents a that has L, A, B values set to zero.
+ ///
+ public static readonly HunterLab Empty = default(HunterLab);
+
+ ///
+ /// The backing vector for SIMD support.
+ ///
+ private readonly Vector3 backingVector;
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The lightness dimension.
+ /// The a (green - magenta) component.
+ /// The b (blue - yellow) component.
+ /// Uses as white point.
+ public HunterLab(float l, float a, float b)
+ : this(new Vector3(l, a, b), DefaultWhitePoint)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The lightness dimension.
+ /// The a (green - magenta) component.
+ /// The b (blue - yellow) component.
+ /// The reference white point.
+ public HunterLab(float l, float a, float b, CieXyz whitePoint)
+ : this(new Vector3(l, a, b), whitePoint)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The vector representing the l, a, b components.
+ /// Uses as white point.
+ public HunterLab(Vector3 vector)
+ : this(vector, DefaultWhitePoint)
+ {
+ }
+
+ ///
+ /// Initializes a new instance of the struct.
+ ///
+ /// The vector representing the l a b components.
+ /// The reference white point.
+ public HunterLab(Vector3 vector, CieXyz whitePoint)
+ : this()
+ {
+ this.backingVector = vector;
+ this.WhitePoint = whitePoint;
+ }
+
+ ///
+ /// Gets the reference white point of this color
+ ///
+ public CieXyz WhitePoint { get; }
+
+ ///
+ /// Gets the lightness dimension.
+ /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white).
+ ///
+ public float L => this.backingVector.X;
+
+ ///
+ /// Gets the a color component.
+ /// A value ranging from -100 to 100. Negative is green, positive magenta.
+ ///
+ public float A => this.backingVector.Y;
+
+ ///
+ /// Gets the b color component.
+ /// A value ranging from -100 to 100. Negative is blue, positive is yellow
+ ///
+ public float B => this.backingVector.Z;
+
+ ///
+ /// Gets a value indicating whether this is empty.
+ ///
+ [EditorBrowsable(EditorBrowsableState.Never)]
+ public bool IsEmpty => this.Equals(Empty);
+
+ ///
+ public Vector3 Vector => this.backingVector;
+
+ ///
+ /// Compares two objects for equality.
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is equal to the parameter; otherwise, false.
+ ///
+ public static bool operator ==(HunterLab left, HunterLab right)
+ {
+ return left.Equals(right);
+ }
+
+ ///
+ /// Compares two objects for inequality
+ ///
+ ///
+ /// The on the left side of the operand.
+ ///
+ ///
+ /// The on the right side of the operand.
+ ///
+ ///
+ /// True if the current left is unequal to the parameter; otherwise, false.
+ ///
+ public static bool operator !=(HunterLab left, HunterLab right)
+ {
+ return !left.Equals(right);
+ }
+
+ ///
+ public override int GetHashCode()
+ {
+ return this.backingVector.GetHashCode();
+ }
+
+ ///
+ public override string ToString()
+ {
+ if (this.IsEmpty)
+ {
+ return "HunterLab [Empty]";
+ }
+
+ return $"HunterLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]";
+ }
+
+ ///
+ public override bool Equals(object obj)
+ {
+ if (obj is HunterLab)
+ {
+ return this.Equals((HunterLab)obj);
+ }
+
+ return false;
+ }
+
+ ///
+ public bool Equals(HunterLab other)
+ {
+ return this.backingVector.Equals(other.backingVector);
+ }
+
+ ///
+ public bool AlmostEquals(HunterLab other, float precision)
+ {
+ Vector3 result = Vector3.Abs(this.backingVector - other.backingVector);
+
+ return result.X <= precision
+ && result.Y <= precision
+ && result.Z <= precision;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/ImageSharp/Colors/Spaces/LinearRgb.cs b/src/ImageSharp/Colors/Spaces/LinearRgb.cs
index c101d66ece..8ae4e01511 100644
--- a/src/ImageSharp/Colors/Spaces/LinearRgb.cs
+++ b/src/ImageSharp/Colors/Spaces/LinearRgb.cs
@@ -22,7 +22,7 @@ namespace ImageSharp.Colors.Spaces
///
/// The default LinearRgb working space
///
- private static readonly IRgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb;
+ public static readonly IRgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb;
///
/// The backing vector for SIMD support.
diff --git a/src/ImageSharp/Colors/Spaces/Rgb.cs b/src/ImageSharp/Colors/Spaces/Rgb.cs
index e97b57bee0..85378a1c8f 100644
--- a/src/ImageSharp/Colors/Spaces/Rgb.cs
+++ b/src/ImageSharp/Colors/Spaces/Rgb.cs
@@ -22,7 +22,7 @@ namespace ImageSharp.Colors.Spaces
///
/// The default rgb working space
///
- internal static readonly IRgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb;
+ public static readonly IRgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb;
///
/// The backing vector for SIMD support.
diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs
new file mode 100644
index 0000000000..895d7c891d
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToCieLabConvert.cs
@@ -0,0 +1,34 @@
+namespace ImageSharp.Benchmarks.Color
+{
+ using BenchmarkDotNet.Attributes;
+
+ using Colourful;
+ using Colourful.Conversion;
+
+ using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion;
+
+ public class ColorspaceCieXyzToCieLabConvert
+ {
+ private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F);
+
+ private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883);
+
+ private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter();
+
+ private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter();
+
+
+ [Benchmark(Baseline = true, Description = "Colourful Convert")]
+ public LabColor ColourfulConvert()
+ {
+ return ColourfulConverter.ToLab(XYZColor);
+ }
+
+ [Benchmark(Description = "ImageSharp Convert")]
+ public CieLab ColorSpaceConvert()
+ {
+ return ColorSpaceConverter.ToCieLab(CieXyz);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs
new file mode 100644
index 0000000000..d686d38c85
--- /dev/null
+++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToHunterLabConvert.cs
@@ -0,0 +1,35 @@
+namespace ImageSharp.Benchmarks.Color
+{
+ using BenchmarkDotNet.Attributes;
+
+ using Colourful;
+ using Colourful.Conversion;
+
+ using ImageSharp.Colors.Spaces;
+
+ using ColorSpaceConverter = ImageSharp.Colors.Spaces.Conversion.ColorSpaceConverter;
+
+ public class ColorspaceCieXyzToHunterLabConvert
+ {
+ private static readonly CieXyz CieXyz = new CieXyz(0.95047F, 1, 1.08883F);
+
+ private static readonly XYZColor XYZColor = new XYZColor(0.95047, 1, 1.08883);
+
+ private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter();
+
+ private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter();
+
+
+ [Benchmark(Baseline = true, Description = "Colourful Convert")]
+ public HunterLabColor ColourfulConvert()
+ {
+ return ColourfulConverter.ToHunterLab(XYZColor);
+ }
+
+ [Benchmark(Description = "ImageSharp Convert")]
+ public HunterLab ColorSpaceConvert()
+ {
+ return ColorSpaceConverter.ToHunterLab(CieXyz);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs
index 007f45f8e3..8d167d7450 100644
--- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs
+++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToLmsConvert.cs
@@ -6,8 +6,7 @@
using Colourful.Conversion;
using ImageSharp.Colors.Spaces;
-
- using ColorSpaceConverter = ImageSharp.Colors.Spaces.Conversion.ColorSpaceConverter;
+ using ImageSharp.Colors.Spaces.Conversion;
public class ColorspaceCieXyzToLmsConvert
{
diff --git a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs
index d45267cff0..f56bde7390 100644
--- a/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs
+++ b/tests/ImageSharp.Benchmarks/Color/ColorspaceCieXyzToRgbConvert.cs
@@ -6,8 +6,7 @@
using Colourful.Conversion;
using ImageSharp.Colors.Spaces;
-
- using ColorSpaceConverter = ImageSharp.Colors.Spaces.Conversion.ColorSpaceConverter;
+ using ImageSharp.Colors.Spaces.Conversion;
public class ColorspaceCieXyzToRgbConvert
{
diff --git a/tests/ImageSharp.Tests/App.config b/tests/ImageSharp.Tests/App.config
deleted file mode 100644
index 7b47f780e3..0000000000
--- a/tests/ImageSharp.Tests/App.config
+++ /dev/null
@@ -1,6 +0,0 @@
-
-
-
-
-
-
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest - Copy.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest - Copy.cs
new file mode 100644
index 0000000000..55aec4db56
--- /dev/null
+++ b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest - Copy.cs
@@ -0,0 +1,73 @@
+namespace ImageSharp.Tests
+{
+ using System.Collections.Generic;
+ using ImageSharp.Colors.Spaces;
+ using ImageSharp.Colors.Spaces.Conversion;
+
+ using Xunit;
+
+ ///
+ /// Tests - conversions.
+ ///
+ ///
+ /// Test data generated using:
+ /// http://www.brucelindbloom.com/index.html?ColorCalculator.html
+ ///
+ public class CieXyzAndCieLabConversionTest
+ {
+ private static readonly IEqualityComparer FloatComparerLabPrecision = new ApproximateFloatComparer(4);
+ private static readonly IEqualityComparer FloatComparerXyzPrecision = new ApproximateFloatComparer(6);
+
+ ///
+ /// Tests conversion from to ().
+ ///
+ [Theory]
+ [InlineData(100, 0, 0, 0.95047, 1, 1.08883)]
+ [InlineData(0, 0, 0, 0, 0, 0)]
+ [InlineData(0, 431.0345, 0, 0.95047, 0, 0)]
+ [InlineData(100, -431.0345, 172.4138, 0, 1, 0)]
+ [InlineData(0, 0, -172.4138, 0, 0, 1.08883)]
+ [InlineData(45.6398, 39.8753, 35.2091, 0.216938, 0.150041, 0.048850)]
+ [InlineData(77.1234, -40.1235, 78.1120, 0.358530, 0.517372, 0.076273)]
+ [InlineData(10, -400, 20, 0, 0.011260, 0)]
+ public void Convert_Lab_to_XYZ(float l, float a, float b, float x, float y, float z)
+ {
+ // Arrange
+ CieLab input = new CieLab(l, a, b, Illuminants.D65);
+ ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 };
+
+ // Act
+ CieXyz output = converter.ToCieXyz(input);
+
+ // Assert
+ Assert.Equal(output.X, x, FloatComparerXyzPrecision);
+ Assert.Equal(output.Y, y, FloatComparerXyzPrecision);
+ Assert.Equal(output.Z, z, FloatComparerXyzPrecision);
+ }
+
+ ///
+ /// Tests conversion from () to .
+ ///
+ [Theory]
+ [InlineData(0.95047, 1, 1.08883, 100, 0, 0)]
+ [InlineData(0, 0, 0, 0, 0, 0)]
+ [InlineData(0.95047, 0, 0, 0, 431.0345, 0)]
+ [InlineData(0, 1, 0, 100, -431.0345, 172.4138)]
+ [InlineData(0, 0, 1.08883, 0, 0, -172.4138)]
+ [InlineData(0.216938, 0.150041, 0.048850, 45.6398, 39.8753, 35.2091)]
+ public void Convert_XYZ_to_Lab(float x, float y, float z, float l, float a, float b)
+ {
+ // Arrange
+ CieXyz input = new CieXyz(x, y, z);
+ ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 };
+
+ // Act
+ CieLab output = converter.ToCieLab(input);
+
+ // Assert
+ Assert.Equal(output.L, l, FloatComparerLabPrecision);
+ Assert.Equal(output.A, a, FloatComparerLabPrecision);
+ Assert.Equal(output.B, b, FloatComparerLabPrecision);
+ }
+ }
+}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs
index 55aec4db56..afcb2d7195 100644
--- a/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs
+++ b/tests/ImageSharp.Tests/Colors/Colorspaces/CieXyzAndCieLabConversionTest.cs
@@ -13,61 +13,71 @@
/// Test data generated using:
/// http://www.brucelindbloom.com/index.html?ColorCalculator.html
///
- public class CieXyzAndCieLabConversionTest
+ public class CieXyzAndHunterLabConversionTest
{
- private static readonly IEqualityComparer FloatComparerLabPrecision = new ApproximateFloatComparer(4);
- private static readonly IEqualityComparer FloatComparerXyzPrecision = new ApproximateFloatComparer(6);
+ private static readonly IEqualityComparer FloatComparer = new ApproximateFloatComparer(4);
+
+ ///
+ /// Tests conversion from to ().
+ ///
+ [Theory]
+ [InlineData(0, 0, 0, 0, 0, 0)]
+ [InlineData(100, 0, 0, 0.98074, 1, 1.18232)] // C white point is HunterLab 100, 0, 0
+ public void Convert_HunterLab_to_XYZ(float l, float a, float b, float x, float y, float z)
+ {
+ // Arrange
+ HunterLab input = new HunterLab(l, a, b);
+ ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.C };
+
+ // Act
+ CieXyz output = converter.ToCieXyz(input);
+
+ // Assert
+ Assert.Equal(output.X, x, FloatComparer);
+ Assert.Equal(output.Y, y, FloatComparer);
+ Assert.Equal(output.Z, z, FloatComparer);
+ }
///
/// Tests conversion from to ().
///
[Theory]
- [InlineData(100, 0, 0, 0.95047, 1, 1.08883)]
[InlineData(0, 0, 0, 0, 0, 0)]
- [InlineData(0, 431.0345, 0, 0.95047, 0, 0)]
- [InlineData(100, -431.0345, 172.4138, 0, 1, 0)]
- [InlineData(0, 0, -172.4138, 0, 0, 1.08883)]
- [InlineData(45.6398, 39.8753, 35.2091, 0.216938, 0.150041, 0.048850)]
- [InlineData(77.1234, -40.1235, 78.1120, 0.358530, 0.517372, 0.076273)]
- [InlineData(10, -400, 20, 0, 0.011260, 0)]
- public void Convert_Lab_to_XYZ(float l, float a, float b, float x, float y, float z)
+ [InlineData(100, 0, 0, 0.95047, 1, 1.08883)] // D65 white point is HunerLab 100, 0, 0 (adaptation to C performed)
+ public void Convert_HunterLab_to_XYZ_D65(float l, float a, float b, float x, float y, float z)
{
// Arrange
- CieLab input = new CieLab(l, a, b, Illuminants.D65);
- ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 };
+ HunterLab input = new HunterLab(l, a, b);
+ ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 };
// Act
CieXyz output = converter.ToCieXyz(input);
// Assert
- Assert.Equal(output.X, x, FloatComparerXyzPrecision);
- Assert.Equal(output.Y, y, FloatComparerXyzPrecision);
- Assert.Equal(output.Z, z, FloatComparerXyzPrecision);
+ Assert.Equal(output.X, x, FloatComparer);
+ Assert.Equal(output.Y, y, FloatComparer);
+ Assert.Equal(output.Z, z, FloatComparer);
}
///
/// Tests conversion from () to .
///
[Theory]
- [InlineData(0.95047, 1, 1.08883, 100, 0, 0)]
[InlineData(0, 0, 0, 0, 0, 0)]
- [InlineData(0.95047, 0, 0, 0, 431.0345, 0)]
- [InlineData(0, 1, 0, 100, -431.0345, 172.4138)]
- [InlineData(0, 0, 1.08883, 0, 0, -172.4138)]
- [InlineData(0.216938, 0.150041, 0.048850, 45.6398, 39.8753, 35.2091)]
- public void Convert_XYZ_to_Lab(float x, float y, float z, float l, float a, float b)
+ [InlineData(0.95047, 1, 1.08883, 100, 0, 0)] // D65 white point is HunerLab 100, 0, 0 (adaptation to C performed)
+ public void Convert_XYZ_D65_to_HunterLab(float x, float y, float z, float l, float a, float b)
{
// Arrange
CieXyz input = new CieXyz(x, y, z);
- ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 };
+ ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 };
// Act
- CieLab output = converter.ToCieLab(input);
+ HunterLab output = converter.ToHunterLab(input);
// Assert
- Assert.Equal(output.L, l, FloatComparerLabPrecision);
- Assert.Equal(output.A, a, FloatComparerLabPrecision);
- Assert.Equal(output.B, b, FloatComparerLabPrecision);
+ Assert.Equal(output.L, l, FloatComparer);
+ Assert.Equal(output.A, a, FloatComparer);
+ Assert.Equal(output.B, b, FloatComparer);
}
}
}
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
index c6f916e00c..ff5eccc787 100644
--- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
+++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj
@@ -19,4 +19,9 @@
+
+
+ PreserveNewest
+
+
\ No newline at end of file
diff --git a/tests/ImageSharp.Tests/xunit.runner.json b/tests/ImageSharp.Tests/xunit.runner.json
new file mode 100644
index 0000000000..df1c3d50d0
--- /dev/null
+++ b/tests/ImageSharp.Tests/xunit.runner.json
@@ -0,0 +1,3 @@
+{
+ "methodDisplay": "method"
+}
\ No newline at end of file