|
| 1 | +function XYZ_to_Jzazbz (XYZ) { |
| 2 | + // convert an array of D65 XYZ toJzAzBz |
| 3 | + // such that [0,0,0] is black and |
| 4 | + // media white is [0.2220, -0.00016, -0.0001] |
| 5 | + |
| 6 | + const Yw = 203; // absolute luminance of media white |
| 7 | + const M = [ |
| 8 | + [ 0.41478972, 0.579999, 0.0146480 ], |
| 9 | + [ -0.2015100, 1.120649, 0.0531008 ], |
| 10 | + [ -0.0166008, 0.264800, 0.6684799 ], |
| 11 | + ]; |
| 12 | + const b = 1.15; |
| 13 | + const g = 0.66; |
| 14 | + |
| 15 | + // First make XYZ absolute, not relative to media white |
| 16 | + // Maximum luminance in PQ is 10,000 cd/m² |
| 17 | + // BT.2048 says media white Y=203 cd/m² |
| 18 | + let [Xa, Ya, Za] = XYZ.map(v => v * Yw); |
| 19 | + |
| 20 | + // then modify X and Y, to minimize blue curvature |
| 21 | + let Xm = b * Xa - (b - 1) * Za; |
| 22 | + let Ym = g * Ya - (g - 1) * Xa; |
| 23 | + |
| 24 | + // now move to LMS cone domain |
| 25 | + let LMS = multiplyMatrices(M, [Xm, Ym, Za]); |
| 26 | + return LMStoJzazbz(LMS); |
| 27 | +} |
| 28 | + |
| 29 | +function LMStoJzazbz(LMS) { |
| 30 | + |
| 31 | + const M = [ |
| 32 | + [ 0.5, 0.5, 0 ], |
| 33 | + [ 3.524000, -4.066708, 0.542708 ], |
| 34 | + [ 0.199076, 1.096799, -1.295875 ], |
| 35 | + ]; |
| 36 | + const c1 = 3424 / 2 ** 12; |
| 37 | + const c2 = 2413 / 2 ** 7; |
| 38 | + const c3 = 2392 / 2 ** 7; |
| 39 | + const n = 2610 / 2 ** 14; |
| 40 | + const p = (1.7 * 2523) / 2 ** 5; // compared to usual PQ, 1.7 scale |
| 41 | + const d = -0.56; |
| 42 | + const d0 = 1.6295499532821566e-11; // tiny shift to move black back to 0 |
| 43 | + |
| 44 | + |
| 45 | + // PQ-encode LMS |
| 46 | + let PQLMS = ( |
| 47 | + LMS.map(function (val) { |
| 48 | + let num = c1 + c2 * spow((val / 10000), n); |
| 49 | + let denom = 1 + c3 * spow((val / 10000), n); |
| 50 | + |
| 51 | + return spow((num / denom), p); |
| 52 | + }) |
| 53 | + ); |
| 54 | + |
| 55 | + // calculate Iz az bz |
| 56 | + let [Iz, az, bz] = multiplyMatrices(M, PQLMS); |
| 57 | + // now Jz from Iz |
| 58 | + let Jz = ((1 + d) * Iz) / (1 + d * Iz) - d0; |
| 59 | + return [Jz, az, bz]; |
| 60 | +} |
| 61 | + |
0 commit comments