fromXyzInViewingConditions static method

Cam16 fromXyzInViewingConditions(
  1. double x,
  2. double y,
  3. double z,
  4. ViewingConditions viewingConditions,
)

Given color expressed in XYZ and viewed in viewingConditions, convert to CAM16.

Implementation

static Cam16 fromXyzInViewingConditions(double x, double y, double z, ViewingConditions viewingConditions) {
  // Transform XYZ to 'cone'/'rgb' responses

  final double rC = 0.401288 * x + 0.650173 * y - 0.051461 * z;
  final double gC = -0.250268 * x + 1.204414 * y + 0.045854 * z;
  final double bC = -0.002079 * x + 0.048952 * y + 0.953127 * z;

  // Discount illuminant
  final double rD = viewingConditions.rgbD[0] * rC;
  final double gD = viewingConditions.rgbD[1] * gC;
  final double bD = viewingConditions.rgbD[2] * bC;

  // chromatic adaptation
  final double rAF = math.pow(viewingConditions.fl * rD.abs() / 100.0, 0.42).toDouble();
  final double gAF = math.pow(viewingConditions.fl * gD.abs() / 100.0, 0.42).toDouble();
  final double bAF = math.pow(viewingConditions.fl * bD.abs() / 100.0, 0.42).toDouble();
  final double rA = MathUtils.signum(rD) * 400.0 * rAF / (rAF + 27.13);
  final double gA = MathUtils.signum(gD) * 400.0 * gAF / (gAF + 27.13);
  final double bA = MathUtils.signum(bD) * 400.0 * bAF / (bAF + 27.13);

  // redness-greenness
  final double a = (11.0 * rA + -12.0 * gA + bA) / 11.0;
  // yellowness-blueness
  final double b = (rA + gA - 2.0 * bA) / 9.0;

  // auxiliary components
  final double u = (20.0 * rA + 20.0 * gA + 21.0 * bA) / 20.0;
  final double p2 = (40.0 * rA + 20.0 * gA + bA) / 20.0;

  // hue
  final double atan2 = math.atan2(b, a);
  final double atanDegrees = atan2 * 180.0 / math.pi;
  final double hue = MathUtils.sanitizeDegreesDouble(atanDegrees);
  final double hueRadians = hue * math.pi / 180.0;
  assert(hue >= 0 && hue < 360, 'hue was really $hue');

  // achromatic response to color
  final double ac = p2 * viewingConditions.nbb;

  // CAM16 lightness and brightness
  final double J = 100.0 * math.pow(ac / viewingConditions.aw, viewingConditions.c * viewingConditions.z);
  final double Q =
      (4.0 / viewingConditions.c) * math.sqrt(J / 100.0) * (viewingConditions.aw + 4.0) * (viewingConditions.fLRoot);

  final double huePrime = (hue < 20.14) ? hue + 360 : hue;
  final double eHue = (1.0 / 4.0) * (math.cos(huePrime * math.pi / 180.0 + 2.0) + 3.8);
  final double p1 = 50000.0 / 13.0 * eHue * viewingConditions.nC * viewingConditions.ncb;
  final double t = p1 * math.sqrt(a * a + b * b) / (u + 0.305);
  final num alpha =
      math.pow(t, 0.9) * math.pow(1.64 - math.pow(0.29, viewingConditions.backgroundYTowhitePointY), 0.73);
  // CAM16 chroma, colorfulness, chroma
  final double C = alpha * math.sqrt(J / 100.0);
  final double M = C * viewingConditions.fLRoot;
  final double s = 50.0 * math.sqrt((alpha * viewingConditions.c) / (viewingConditions.aw + 4.0));

  // CAM16-UCS components
  final double jstar = (1.0 + 100.0 * 0.007) * J / (1.0 + 0.007 * J);
  final double mstar = math.log(1.0 + 0.0228 * M) / 0.0228;
  final double astar = mstar * math.cos(hueRadians);
  final double bstar = mstar * math.sin(hueRadians);
  return Cam16(hue, C, J, Q, M, s, jstar, astar, bstar);
}