From e3a0a0d1f9f923f4271671f18b07f0c39b0a2110 Mon Sep 17 00:00:00 2001 From: Isaac Muse Date: Thu, 14 Mar 2024 07:35:07 -0600 Subject: [PATCH] Consistently handle none/NaN across library (#476) * Consistently handle none/NaN across library * Fix APCA --- src/contrast/APCA.js | 9 +++++++-- src/deltaE/deltaECMC.js | 3 ++- src/deltaE/deltaEJz.js | 7 ++++--- src/distance.js | 3 ++- src/interpolation.js | 6 +++--- src/space.js | 6 +++--- src/spaces/lch.js | 3 ++- src/spaces/lchuv.js | 3 ++- src/spaces/oklch.js | 3 ++- 9 files changed, 27 insertions(+), 16 deletions(-) diff --git a/src/contrast/APCA.js b/src/contrast/APCA.js index 51001965a..055108adc 100644 --- a/src/contrast/APCA.js +++ b/src/contrast/APCA.js @@ -4,6 +4,7 @@ import getColor from "../getColor.js"; import to from "../to.js"; +import {isNone} from "../util.js"; // exponents const normBG = 0.56; @@ -54,11 +55,15 @@ export default function contrastAPCA (background, foreground) { // Calculates "screen luminance" with non-standard simple gamma EOTF // weights should be from CSS Color 4, not the ones here which are via Myndex and copied from Lindbloom - [R, G, B] = foreground.coords; + [R, G, B] = foreground.coords.map(c => { + return isNone(c) ? 0 : c; + }); let lumTxt = linearize(R) * 0.2126729 + linearize(G) * 0.7151522 + linearize(B) * 0.0721750; background = to(background, "srgb"); - [R, G, B] = background.coords; + [R, G, B] = background.coords.map(c => { + return isNone(c) ? 0 : c; + }); let lumBg = linearize(R) * 0.2126729 + linearize(G) * 0.7151522 + linearize(B) * 0.0721750; // toe clamping of very dark values to account for flare diff --git a/src/deltaE/deltaECMC.js b/src/deltaE/deltaECMC.js index 09dec5ecf..687245964 100644 --- a/src/deltaE/deltaECMC.js +++ b/src/deltaE/deltaECMC.js @@ -1,6 +1,7 @@ import lab from "../spaces/lab.js"; import lch from "../spaces/lch.js"; import getColor from "../getColor.js"; +import {isNone} from "../util.js"; // More accurate color-difference formulae // than the simple 1976 Euclidean distance in Lab @@ -87,7 +88,7 @@ export default function (color, sample, {l = 2, c = 1} = {}) { // Cross term T for blue non-linearity let T; - if (Number.isNaN(H1)) { + if (isNone(H1)) { H1 = 0; } diff --git a/src/deltaE/deltaEJz.js b/src/deltaE/deltaEJz.js index aa25891f3..325e3874e 100644 --- a/src/deltaE/deltaEJz.js +++ b/src/deltaE/deltaEJz.js @@ -1,5 +1,6 @@ import jzczhz from "../spaces/jzczhz.js"; import getColor from "../getColor.js"; +import {isNone} from "../util.js"; // More accurate color-difference formulae // than the simple 1976 Euclidean distance in Lab @@ -23,16 +24,16 @@ export default function (color, sample) { let ΔC = Cz1 - Cz2; // length of chord for ΔH - if ((Number.isNaN(Hz1)) && (Number.isNaN(Hz2))) { + if ((isNone(Hz1)) && (isNone(Hz2))) { // both undefined hues Hz1 = 0; Hz2 = 0; } - else if (Number.isNaN(Hz1)) { + else if (isNone(Hz1)) { // one undefined, set to the defined hue Hz1 = Hz2; } - else if (Number.isNaN(Hz2)) { + else if (isNone(Hz2)) { Hz2 = Hz1; } diff --git a/src/distance.js b/src/distance.js index 788772482..dc6354dd6 100644 --- a/src/distance.js +++ b/src/distance.js @@ -1,4 +1,5 @@ import ColorSpace from "./space.js"; +import {isNone} from "./util.js"; /** * Euclidean distance of colors in an arbitrary color space @@ -12,7 +13,7 @@ export default function distance (color1, color2, space = "lab") { return Math.sqrt(coords1.reduce((acc, c1, i) => { let c2 = coords2[i]; - if (isNaN(c1) || isNaN(c2)) { + if (isNone(c1) || isNone(c2)) { return acc; } diff --git a/src/interpolation.js b/src/interpolation.js index e1f5c97a2..c7789e195 100644 --- a/src/interpolation.js +++ b/src/interpolation.js @@ -2,7 +2,7 @@ * Functions related to color interpolation */ import ColorSpace from "./space.js"; -import {type, interpolate} from "./util.js"; +import {type, interpolate, isNone} from "./util.js"; import getColor from "./getColor.js"; import clone from "./clone.js"; import to from "./to.js"; @@ -167,10 +167,10 @@ export function range (color1, color2, options = {}) { // Undefined hues must be evaluated before hue fix-up to properly // calculate hue arcs between undefined and defined hues. // See https://github.com/w3c/csswg-drafts/issues/9436#issuecomment-1746957545 - if (isNaN(θ1) && !isNaN(θ2)) { + if (isNone(θ1) && !isNone(θ2)) { θ1 = θ2; } - else if (isNaN(θ2) && !isNaN(θ1)) { + else if (isNone(θ2) && !isNone(θ1)) { θ2 = θ1; } [θ1, θ2] = angles.adjust(arc, [θ1, θ2]); diff --git a/src/space.js b/src/space.js index 9f32602bb..2b3fe6eb7 100644 --- a/src/space.js +++ b/src/space.js @@ -1,4 +1,4 @@ -import {type, parseCoordGrammar, serializeNumber, mapRange} from "./util.js"; +import {type, parseCoordGrammar, serializeNumber, mapRange, isNone} from "./util.js"; import {getWhite} from "./adapt.js"; import hooks from "./hooks.js"; import getColor from "./getColor.js"; @@ -103,7 +103,7 @@ export default class ColorSpace { let meta = coordMeta[i]; if (meta.type !== "angle" && meta.range) { - if (Number.isNaN(c)) { + if (isNone(c)) { // NaN is always in gamut return true; } @@ -186,7 +186,7 @@ export default class ColorSpace { } // Convert NaN to 0, which seems to be valid in every coordinate of every color space - coords = coords.map(c => Number.isNaN(c) ? 0 : c); + coords = coords.map(c => isNone(c) ? 0 : c); // Find connection space = lowest common ancestor in the base tree let myPath = this.path; diff --git a/src/spaces/lch.js b/src/spaces/lch.js index 0fe24e134..dfc6d9064 100644 --- a/src/spaces/lch.js +++ b/src/spaces/lch.js @@ -1,6 +1,7 @@ import ColorSpace from "../space.js"; import Lab from "./lab.js"; import {constrain as constrainAngle} from "../angles.js"; +import {isNone} from "../util.js"; export default new ColorSpace({ id: "lch", @@ -49,7 +50,7 @@ export default new ColorSpace({ Chroma = 0; } // Deal with NaN Hue - if (isNaN(Hue)) { + if (isNone(Hue)) { Hue = 0; } return [ diff --git a/src/spaces/lchuv.js b/src/spaces/lchuv.js index d26432e7b..39c30fc36 100644 --- a/src/spaces/lchuv.js +++ b/src/spaces/lchuv.js @@ -1,6 +1,7 @@ import ColorSpace from "../space.js"; import Luv from "./luv.js"; import {constrain as constrainAngle} from "../angles.js"; +import {isNone} from "../util.js"; export default new ColorSpace({ id: "lchuv", @@ -49,7 +50,7 @@ export default new ColorSpace({ Chroma = 0; } // Deal with NaN Hue - if (isNaN(Hue)) { + if (isNone(Hue)) { Hue = 0; } return [ diff --git a/src/spaces/oklch.js b/src/spaces/oklch.js index 884aef357..542899566 100644 --- a/src/spaces/oklch.js +++ b/src/spaces/oklch.js @@ -1,6 +1,7 @@ import ColorSpace from "../space.js"; import OKLab from "./oklab.js"; import {constrain as constrainAngle} from "../angles.js"; +import {isNone} from "../util.js"; export default new ColorSpace({ id: "oklch", @@ -48,7 +49,7 @@ export default new ColorSpace({ let a, b; // check for NaN hue - if (isNaN(h)) { + if (isNone(h)) { a = 0; b = 0; }