From 955eead439475987e5f284c7fd1834b0f308d917 Mon Sep 17 00:00:00 2001 From: Pierre-Anthony Lemieux Date: Thu, 26 Oct 2023 09:02:06 -0700 Subject: [PATCH] Improve srgb to/from rec2100-hlg conversions https://github.com/w3c/ColorWeb-CG/issues/104 --- hdr_html_canvas_element.md | 74 +++++++++++++++++++++++++++++--------- 1 file changed, 57 insertions(+), 17 deletions(-) diff --git a/hdr_html_canvas_element.md b/hdr_html_canvas_element.md index 8864a76..910efae 100644 --- a/hdr_html_canvas_element.md +++ b/hdr_html_canvas_element.md @@ -362,7 +362,7 @@ _Process:_ 1. Pseudo-linearize the HLG signal exploiting its backwards compatibility with SDR consumer displays 2. Convert from ITU BT.2100 color space to sRGB color space - 3. Convert back to non-linear using a reciprocal transform + 3. Convert to non-linear sRGB values _NOTE_ This transform utilises the backwards compatibility of ITU-R BT.2100 HLG HDR with consumer electronic displays. Prior to display, the gamut may need @@ -371,32 +371,37 @@ gamut reduction techniques may provide better output images. ```javascript -function simpleTransform(value, systemGamma) { - if (value < 1.0) { - return -1.0 * Math.pow(-1.0 * value, systemGamma); +function simpleTransform(value, gamma) { + if (value < 0) { + return -1.0 * Math.pow(-1.0 * value, gamma); } else { - return Math.pow(value, systemGamma); + return Math.pow(value, gamma); } } -function simpleInverseTransform(value, systemGamma) { - if (value < 1.0) { - return -1.0 * Math.pow(-1.0 * value, 1.0 / systemGamma); +function simpleInverseTransform(value, gamma) { + if (value < 0) { + return -1.0 * Math.pow(-1.0 * value, 1.0 / gamma); } else { - return Math.pow(value, 1.0 / systemGamma); + return Math.pow(value, 1.0 / gamma); } } function tonemapREC2100HLGtoSRGBdisplay(r, g, b) { - const systemGamma = 2.2; - const r1 = simpleTransform(r, systemGamma); - const g1 = simpleTransform(g, systemGamma); - const b1 = simpleTransform(b, systemGamma); + const displayGamma = 2.2; + const r1 = simpleTransform(r, displayGamma); + const g1 = simpleTransform(g, displayGamma); + const b1 = simpleTransform(b, displayGamma); + const [r2, g2, b2] = matrixXYZtoSRGB(matrixBT2020toXYZ(r1, g1, b1)); - const r3 = simpleInverseTransform(r2, systemGamma); - const g3 = simpleInverseTransform(g2, systemGamma); - const b3 = simpleInverseTransform(b2, systemGamma); + + const srgbGamma = 2.2; + const r3 = simpleInverseTransform(r2, srgbGamma); + const g3 = simpleInverseTransform(g2, srgbGamma); + const b3 = simpleInverseTransform(b2, srgbGamma); + const [r4, g4, b4] = limitTosRGBGamut(r3, g3, b3); + return [r4, g4, b4]; } ``` @@ -405,7 +410,42 @@ function tonemapREC2100HLGtoSRGBdisplay(r, g, b) { #### `srgb` to `rec2100-hlg` -See [TTML 2, Annex Q.2, steps 1-8](https://www.w3.org/TR/ttml2/#hlg-hdr). +This conversion method adjust the HLG pseudo-display nominal peak luminance such +that the sRGB peak luminance maps to HDR reference white luminance. Using an +sRGB peak luminance value of 80 cd/m² and the extended range gamma formula +specified in BT.2100, Footnote 2, this results in an HLG nominal peak luminance +Lw of 302.2 cd/m² and a system gamma of 1.001. + +```js +function convertSRGBtoREC2100HLG(r, g, b) { + + /* Linearize using the sRGB EOTF */ + const r1 = srgb_eotf(r); + const g1 = srgb_eotf(g); + const b1 = srgb_eotf(b); + + /* convert color coordinates from sRGB to BT.2020 color space */ + const [r2, g2, b2] = matrixXYZtoBT2020(matrixSRGBtoXYZ(r1, g1, b1)); + + /* Scale pixel values to match the HLG nominal peak luminance */ + const linearLightScaler = 80/302.2; + const r3 = linearLightScaler * r2; + const g3 = linearLightScaler * g2; + const b3 = linearLightScaler * b2; + + /* apply HLG Inverse OOTF to obtain scene light values */ + const systemGamma = 1.001; + const [r4, g4, b4] = hlg_inverse_ootf(r3, g3, b3, systemGamma); + + /* apply HLG OETF to obtain the non-linear HLG signal (see NOTE 1) */ + const [r5, g5, b5] = hlg_oetf(r4, g4, b4); + + return [r5, g5, b5] +} +``` + +_NOTE 1_: ITU-R BT.2408-4, 5.3 discusses negative transfer functions in format +conversions. #### `srgb` to `rec2100-pq`