Skip to content

Commit 65528c7

Browse files
committed
[css-color-hdr] Added sample code for Jzazbz #9934
1 parent 4011c72 commit 65528c7

File tree

3 files changed

+77
-4
lines changed

3 files changed

+77
-4
lines changed

css-color-hdr-1/ICtCp.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11

22
function XYZ_to_ICtCp (XYZ) {
3-
// convert an array of absolute, D65 XYZ to the ICtCp form of LMS
3+
// convert an array of D65 XYZ to ICtCp
44

55
// The matrix below includes the 4% crosstalk components
66
// and is from the procedure in the Dolby "What is ICtCp" paper"
@@ -10,7 +10,7 @@ function XYZ_to_ICtCp (XYZ) {
1010
[ 0.0070797844607479, 0.0748396662186362, 0.8433265453898765 ],
1111
];
1212

13-
let LMS = multiplyMatrices(M, XYZ);
13+
let LMS = multiplyMatrices(M, XYZ.map(v => v * Yw));
1414
return LMStoICtCp(LMS);
1515
}
1616

@@ -33,6 +33,7 @@ function LMStoICtCp (LMS) {
3333
];
3434

3535
// apply the PQ EOTF
36+
// values scaled so [0, 10,000] maps to [0, 1]
3637
// we can't ever be dividing by zero because of the "1 +" in the denominator
3738
let PQLMS = LMS.map (function (val) {
3839
let num = c1 + (c2 * ((val / 10000) ** m1));

css-color-hdr-1/Overview.bs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ Predefined color spaces for HDR: {#predefined-HDR}
655655
the black level should be adjusted
656656
using the PLUGE test signal and procedure
657657
specified in [[Rec_BT.814]] Annex 4.
658-
658+
659659
For HLG values in CSS, which uses wide-range,
660660
the black corresponds to code point 0.
661661

@@ -1106,6 +1106,17 @@ and both place media white at a component value of 1.0.
11061106
highlight: js
11071107
</pre>
11081108

1109+
<h3 id="jzazbz_code">
1110+
Sample code for ''jzazbz''
1111+
</h3>
1112+
1113+
This uses the same signed power (spow) function defined above.
1114+
1115+
<pre class="include-code lang-javascript">
1116+
path: jzazbz.js
1117+
highlight: js
1118+
</pre>
1119+
11091120
<h3 id="ictcp_code">
11101121
Sample code for ''ICtCp''
11111122
</h3>
@@ -1116,7 +1127,7 @@ which is how the conversion is defined in [[!Rec_BT.2100]],
11161127
this sample code proceeds directly from absolute CIE XYZ
11171128
for compatibility with the other color conversion code.
11181129

1119-
The 4% crosstalk matrix, and the rotation ,
1130+
The 4% crosstalk matrix, and the hue rotation,
11201131
are also built into the XYZ to LMS step,
11211132
rather than being applied as three separate steps.
11221133

css-color-hdr-1/jzazbz.js

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
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

Comments
 (0)