fromXyzInViewingConditions static method
- double x,
- double y,
- double z,
- 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 rC = 0.401288 * x + 0.650173 * y - 0.051461 * z;
final gC = -0.250268 * x + 1.204414 * y + 0.045854 * z;
final bC = -0.002079 * x + 0.048952 * y + 0.953127 * z;
// Discount illuminant
final rD = viewingConditions.rgbD[0] * rC;
final gD = viewingConditions.rgbD[1] * gC;
final bD = viewingConditions.rgbD[2] * bC;
// chromatic adaptation
final rAF =
math.pow(viewingConditions.fl * rD.abs() / 100.0, 0.42).toDouble();
final gAF =
math.pow(viewingConditions.fl * gD.abs() / 100.0, 0.42).toDouble();
final bAF =
math.pow(viewingConditions.fl * bD.abs() / 100.0, 0.42).toDouble();
final rA = MathUtils.signum(rD) * 400.0 * rAF / (rAF + 27.13);
final gA = MathUtils.signum(gD) * 400.0 * gAF / (gAF + 27.13);
final bA = MathUtils.signum(bD) * 400.0 * bAF / (bAF + 27.13);
// redness-greenness
final a = (11.0 * rA + -12.0 * gA + bA) / 11.0;
// yellowness-blueness
final b = (rA + gA - 2.0 * bA) / 9.0;
// auxiliary components
final u = (20.0 * rA + 20.0 * gA + 21.0 * bA) / 20.0;
final p2 = (40.0 * rA + 20.0 * gA + bA) / 20.0;
// hue
final atan2 = math.atan2(b, a);
final atanDegrees = atan2 * 180.0 / math.pi;
final hue = atanDegrees < 0
? atanDegrees + 360.0
: atanDegrees >= 360
? atanDegrees - 360
: atanDegrees;
final hueRadians = hue * math.pi / 180.0;
assert(hue >= 0 && hue < 360, 'hue was really $hue');
// achromatic response to color
final ac = p2 * viewingConditions.nbb;
// CAM16 lightness and brightness
final J = 100.0 *
math.pow(ac / viewingConditions.aw,
viewingConditions.c * viewingConditions.z);
final Q = (4.0 / viewingConditions.c) *
math.sqrt(J / 100.0) *
(viewingConditions.aw + 4.0) *
(viewingConditions.fLRoot);
final huePrime = (hue < 20.14) ? hue + 360 : hue;
final eHue =
(1.0 / 4.0) * (math.cos(huePrime * math.pi / 180.0 + 2.0) + 3.8);
final p1 =
50000.0 / 13.0 * eHue * viewingConditions.nC * viewingConditions.ncb;
final t = p1 * math.sqrt(a * a + b * b) / (u + 0.305);
final alpha = math.pow(t, 0.9) *
math.pow(
1.64 - math.pow(0.29, viewingConditions.backgroundYTowhitePointY),
0.73);
// CAM16 chroma, colorfulness, chroma
final C = alpha * math.sqrt(J / 100.0);
final M = C * viewingConditions.fLRoot;
final s = 50.0 *
math.sqrt((alpha * viewingConditions.c) / (viewingConditions.aw + 4.0));
// CAM16-UCS components
final jstar = (1.0 + 100.0 * 0.007) * J / (1.0 + 0.007 * J);
final mstar = math.log(1.0 + 0.0228 * M) / 0.0228;
final astar = mstar * math.cos(hueRadians);
final bstar = mstar * math.sin(hueRadians);
return Cam16(hue, C, J, Q, M, s, jstar, astar, bstar);
}