using System; namespace Colourful.Implementation.Conversion { /// /// Converts from to . /// public sealed class XYZToLabConverter : IColorConversion { /// /// Constructs with /// public XYZToLabConverter() : this(LabColor.DefaultWhitePoint) { } /// /// Constructs with arbitrary white point /// public XYZToLabConverter(XYZColor labWhitePoint) { LabWhitePoint = labWhitePoint; } /// /// Target reference white. When not set, is used. /// public XYZColor LabWhitePoint { get; } /// /// Converts from to . /// public LabColor Convert(in XYZColor input) { // conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html double Xr = LabWhitePoint.X, Yr = LabWhitePoint.Y, Zr = LabWhitePoint.Z; double xr = input.X / Xr, yr = input.Y / Yr, zr = input.Z / Zr; var fx = f(xr); var fy = f(yr); var fz = f(zr); var L = 116 * fy - 16; var a = 500 * (fx - fy); var b = 200 * (fy - fz); var output = new LabColor(L, a, b, LabWhitePoint); return output; } private static double f(double cr) { var fc = cr > CIEConstants.Epsilon ? Math.Pow(cr, 1 / 3d) : (CIEConstants.Kappa * cr + 16) / 116d; return fc; } #region Overrides /// public bool Equals(XYZToLabConverter other) { if (other == null) return false; return ReferenceEquals(this, other) || LabWhitePoint.Equals(other.LabWhitePoint); } /// public override bool Equals(object obj) => obj is XYZToLabConverter other && Equals(other); /// public override int GetHashCode() => LabWhitePoint.GetHashCode(); /// public static bool operator ==(XYZToLabConverter left, XYZToLabConverter right) => Equals(left, right); /// public static bool operator !=(XYZToLabConverter left, XYZToLabConverter right) => !Equals(left, right); #endregion } }