From d69091c6e07a04b212b593b7365e379a26db3dd1 Mon Sep 17 00:00:00 2001 From: Bertrand Madet Date: Thu, 28 Dec 2023 14:19:42 +0100 Subject: [PATCH] Fix HSL to RGB conversion Adapts the implementation given in https://drafts.csswg.org/css-color/#hsl-to-rgb. Fixes #142. --- lib/parsers.test.js | 9 ++++++++- lib/utils/colorSpace.js | 28 +++++++++++++--------------- 2 files changed, 21 insertions(+), 16 deletions(-) diff --git a/lib/parsers.test.js b/lib/parsers.test.js index 926f7e74..1d70f3d4 100644 --- a/lib/parsers.test.js +++ b/lib/parsers.test.js @@ -107,7 +107,14 @@ describe('parseColor', () => { expect(output).toEqual('rgba(5, 5, 5, 0.5)'); }); - + it.each([[120, 'rgb(0, 255, 0)'], [240, 'rgb(0, 0, 255)']])( + 'should convert not zero hsl with non zero hue %s to %s', + (hue, rgbValue) => { + let input = 'hsl(' + hue + ', 100%, 50%)'; + let output = parsers.parseColor(input); + expect(output).toEqual(rgbValue); + } + ); it.todo('Add more tests'); }); describe('parseAngle', () => { diff --git a/lib/utils/colorSpace.js b/lib/utils/colorSpace.js index 92ca7bd0..419620bf 100644 --- a/lib/utils/colorSpace.js +++ b/lib/utils/colorSpace.js @@ -1,21 +1,19 @@ 'use strict'; -const hueToRgb = (t1, t2, hue) => { - if (hue < 0) hue += 6; - if (hue >= 6) hue -= 6; - - if (hue < 1) return (t2 - t1) * hue + t1; - else if (hue < 3) return t2; - else if (hue < 4) return (t2 - t1) * (4 - hue) + t1; - else return t1; -}; +const MAX_HUE = 360; +const COLOR_NB = 12; +const MAX_RGB_VALUE = 255; // https://www.w3.org/TR/css-color-4/#hsl-to-rgb exports.hslToRgb = (hue, sat, light) => { - const t2 = light <= 0.5 ? light * (sat + 1) : light + sat - light * sat; - const t1 = light * 2 - t2; - const r = hueToRgb(t1, t2, hue + 2); - const g = hueToRgb(t1, t2, hue); - const b = hueToRgb(t1, t2, hue - 2); - return [Math.round(r * 255), Math.round(g * 255), Math.round(b * 255)]; + hue = hue % MAX_HUE; + if (hue < 0) { + hue += MAX_HUE; + } + function f(n) { + const k = (n + hue / (MAX_HUE / COLOR_NB)) % COLOR_NB; + const a = sat * Math.min(light, 1 - light); + return light - a * Math.max(-1, Math.min(k - 3, 9 - k, 1)); + } + return [f(0), f(8), f(4)].map(value => Math.round(value * MAX_RGB_VALUE)); };