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
}
}