color-js / color.js

Color conversion & manipulation library by the editors of the CSS Color specifications
https://colorjs.io
MIT License
1.89k stars 82 forks source link

REC.21000-HLG doesn't handle negative values when converting from rec2020-linear #553

Closed lloydk closed 3 months ago

lloydk commented 3 months ago

rec2100hlg converts negative values to NaN when converting from rec2020-linear.

https://apps.colorjs.io/convert/?color=color(--rec2020-linear%20-0.0001%200%200)&precision=4

image

facelessuser commented 3 months ago

This issue is caused by the algorithm implementation in its current form. When a channel is less than 0.5, a square root is applied to the value. Negative square roots will return an undefined value. If a sane value is desired, we could utilized a signed square root using "signed power (spow)" to at least return a predictable value:

diff --git a/src/spaces/rec2100-hlg.js b/src/spaces/rec2100-hlg.js
index ba497ed..899016e 100644
--- a/src/spaces/rec2100-hlg.js
+++ b/src/spaces/rec2100-hlg.js
@@ -1,5 +1,6 @@
 import RGBColorSpace from "../RGBColorSpace.js";
 import REC2020Linear from "./rec2020-linear.js";
+import {spow} from "../util.js";

 // FIXME see https://github.com/LeaVerou/color.js/issues/190

@@ -41,7 +42,7 @@ export default new RGBColorSpace({
                        // ITU-R BT.2390-10 p.23
                        // 6.1 The hybrid log-gamma opto-electronic transfer function (OETF)
                        if (val <= 1 / 12) {
-                               return Math.sqrt(3 * val);
+                               return spow(3 * val, 0.5);
                        }
                        return a * Math.log(12 * val - b) + c;
                });
facelessuser commented 3 months ago

I've issued a PR for review if such a fix is desired.