diff --git a/src/spaces/hsv.js b/src/spaces/hsv.js index e183561a..9f997691 100644 --- a/src/spaces/hsv.js +++ b/src/spaces/hsv.js @@ -1,8 +1,6 @@ import ColorSpace from "../ColorSpace.js"; -import HSL from "./hsl.js"; +import sRGB from "./srgb.js"; -// The Hue, Whiteness Blackness (HWB) colorspace -// See https://drafts.csswg.org/css-color-4/#the-hwb-notation // Note that, like HSL, calculations are done directly on // gamma-corrected sRGB values rather than linearising them first. @@ -25,35 +23,53 @@ export default new ColorSpace({ }, }, - base: HSL, - // https://en.wikipedia.org/wiki/HSL_and_HSV#Interconversion - fromBase (hsl) { - let [h, s, l] = hsl; - s /= 100; - l /= 100; + base: sRGB, + // https://en.wikipedia.org/wiki/HSL_and_HSV#Formal_derivation + fromBase (rgb) { + let max = Math.max(...rgb); + let min = Math.min(...rgb); + let [r, g, b] = rgb; + let [h, s, v] = [null, 0, max]; + let d = max - min; + + if (d !== 0) { + switch (max) { + case r: h = (g - b) / d + (g < b ? 6 : 0); break; + case g: h = (b - r) / d + 2; break; + case b: h = (r - g) / d + 4; + } + + h = h * 60; + } - let v = l + s * Math.min(l, 1 - l); + if (v) { + s = d / v; + } - return [ - h, // h is the same - v === 0 ? 0 : 200 * (1 - l / v), // s - 100 * v, - ]; + if (h >= 360) { + h -= 360; + } + + return [h, s * 100, v * 100]; }, - // https://en.wikipedia.org/wiki/HSL_and_HSV#Interconversion + // Adapted from https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB_alternative toBase (hsv) { let [h, s, v] = hsv; + h = h % 360; + + if (h < 0) { + h += 360; + } s /= 100; v /= 100; - let l = v * (1 - s / 2); + function f (n) { + let k = (n + h / 60) % 6; + return v - v * s * Math.max(0, Math.min(k, 4 - k, 1)); + } - return [ - h, // h is the same - (l === 0 || l === 1) ? 0 : ((v - l) / Math.min(l, 1 - l)) * 100, - l * 100, - ]; + return [f(5), f(3), f(1)]; }, formats: {