diff --git a/data/modules.json b/data/modules.json index a81e57dfe..9e263c72d 100644 --- a/data/modules.json +++ b/data/modules.json @@ -76,6 +76,13 @@ "url": "https://en.wikipedia.org/wiki/Rec._2020", "description": "A very wide gamut RGB color space used in 4k and 8k UHDTV. It is currently difficult to make a screen which displays the entire REC.2020 gamut; current movies broadcast in this colorspace do not use the full gamut, although they do use a little more than P3." }, + { + "name": "REC.2020 Scene Referred", + "id": "--rec2020-oetf", + "dependencies": ["srgb"], + "url": "https://en.wikipedia.org/wiki/Rec._2020", + "description": "Scene-referred version of REC.2020" + }, { "name": "REC.2100-PQ", "id": "rec2100pq", diff --git a/src/spaces/index-fn.js b/src/spaces/index-fn.js index 072e29e46..4f873130e 100644 --- a/src/spaces/index-fn.js +++ b/src/spaces/index-fn.js @@ -21,6 +21,7 @@ export { default as ProPhoto_Linear } from "./prophoto-linear.js"; export { default as ProPhoto } from "./prophoto.js"; export { default as REC_2020_Linear } from "./rec2020-linear.js"; export { default as REC_2020 } from "./rec2020.js"; +export { default as REC_2020_Scene_Referred } from "./rec2020-oetf.js"; export { default as OKLab } from "./oklab.js"; export { default as OKLCH } from "./oklch.js"; export { default as OKLrab } from "./oklrab.js"; diff --git a/src/spaces/rec2020-oetf.js b/src/spaces/rec2020-oetf.js new file mode 100644 index 000000000..35885211b --- /dev/null +++ b/src/spaces/rec2020-oetf.js @@ -0,0 +1,38 @@ +import RGBColorSpace from "../RGBColorSpace.js"; +import REC2020Linear from "./rec2020-linear.js"; +// import sRGB from "./srgb.js"; + +const α = 1.09929682680944; +const β = 0.018053968510807; + +export default new RGBColorSpace({ + id: "--rec2020-oetf", + name: "REC.2020_Scene_Referred", + base: REC2020Linear, + referred: "scene", + // Non-linear transfer function from Rec. ITU-R BT.2020-2 table 4 + toBase (RGB) { + return RGB.map(function (val) { + let sign = val < 0 ? -1 : 1; + let abs = val * sign; + + if (abs < β * 4.5) { + return val / 4.5; + } + + return sign * Math.pow((abs + α - 1) / α, 1 / 0.45); + }); + }, + fromBase (RGB) { + return RGB.map(function (val) { + let sign = val < 0 ? -1 : 1; + let abs = val * sign; + + if (abs >= β) { + return sign * (α * Math.pow(abs, 0.45) - (α - 1)); + } + + return 4.5 * val; + }); + }, +}); diff --git a/src/spaces/rec2020.js b/src/spaces/rec2020.js index ff9a030f5..be1d5b8cf 100644 --- a/src/spaces/rec2020.js +++ b/src/spaces/rec2020.js @@ -2,36 +2,25 @@ import RGBColorSpace from "../RGBColorSpace.js"; import REC2020Linear from "./rec2020-linear.js"; // import sRGB from "./srgb.js"; -const α = 1.09929682680944; -const β = 0.018053968510807; - export default new RGBColorSpace({ id: "rec2020", name: "REC.2020", base: REC2020Linear, - // Non-linear transfer function from Rec. ITU-R BT.2020-2 table 4 + // Reference electro-optical transfer function from Rec. ITU-R BT.1886 Annex 1 + // with b (black lift) = 0 and a (user gain) = 1 + // defined over the extended range, not clamped toBase (RGB) { return RGB.map(function (val) { let sign = val < 0 ? -1 : 1; let abs = val * sign; - - if (abs < β * 4.5) { - return val / 4.5; - } - - return sign * Math.pow((abs + α - 1) / α, 1 / 0.45); + return sign * Math.pow(abs, 2.40); }); }, fromBase (RGB) { return RGB.map(function (val) { let sign = val < 0 ? -1 : 1; let abs = val * sign; - - if (abs >= β) { - return sign * (α * Math.pow(abs, 0.45) - (α - 1)); - } - - return 4.5 * val; + return sign * Math.pow(abs, 1/2.40); }); }, }); diff --git a/test/contrast.js b/test/contrast.js index 9f5ab4361..afea8d4f2 100644 --- a/test/contrast.js +++ b/test/contrast.js @@ -136,7 +136,7 @@ export default { }, { args: ["#000", "color(rec2020 0.6301706 0.6301706 0.6301706)"], - expect: 58.146262578561334, + expect: 50.684920919, }, { args: ["color(xyz-d65 0.3820622 0.4019778 0.437777)", "#000"], diff --git a/test/conversions.js b/test/conversions.js index 6469c0890..c9ec6511f 100644 --- a/test/conversions.js +++ b/test/conversions.js @@ -1127,7 +1127,7 @@ const tests = { { name: "Negative values", args: "color(rec2020 -0.07 -0.5 0.2)", - expect: [-0.01556, -0.25972, 0.05552], + expect: [-0.001691357, -0.1894645708, 0.021012222], }, ], }, @@ -1140,7 +1140,7 @@ const tests = { { name: "Negative values", args: "color(--rec2020-linear -0.017 -0.5 0.2)", - expect: [-0.0765, -0.70544, 0.43352], + expect: [-0.183099455, -0.749153538, 0.511402090], }, ], },