Skip to content

Commit 905e7cd

Browse files
committed
[css-color-4] Avoid returning negative saturation in rgb to hsl conversion, #9222
1 parent a9a8922 commit 905e7cd

File tree

2 files changed

+45
-1
lines changed

2 files changed

+45
-1
lines changed

css-color-4/Overview.bs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2261,8 +2261,12 @@ Converting sRGB Colors to HSL</h3>
22612261

22622262
Conversion in the reverse direction proceeds similarly.
22632263

2264+
Special care is taken to deal with
2265+
intermediate negative values of saturation,
2266+
which can be produced by colors far outside the sRGB gamut.
2267+
22642268
<pre class="include-code lang-javascript">
2265-
path: rgbToHsl.js
2269+
path: better-rgbToHsl.js
22662270
highlight: js
22672271
</pre>
22682272

css-color-4/better-rgbToHsl.js

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* @param {number} red - Red component 0..1
3+
* @param {number} green - Green component 0..1
4+
* @param {number} blue - Blue component 0..1
5+
* @return {number[]} Array of HSL values: Hue as degrees 0..360, Saturation and Lightness in reference range [0,100]
6+
*/
7+
function rgbToHsl (red, green, blue) {
8+
let max = Math.max(red, green, blue);
9+
let min = Math.min(red, green, blue);
10+
let [hue, sat, light] = [NaN, 0, (min + max)/2];
11+
let d = max - min;
12+
13+
if (d !== 0) {
14+
sat = (light === 0 || light === 1)
15+
? 0
16+
: (max - light) / Math.min(light, 1 - light);
17+
18+
switch (max) {
19+
case red: hue = (green - blue) / d + (green < blue ? 6 : 0); break;
20+
case green: hue = (blue - red) / d + 2; break;
21+
case blue: hue = (red - green) / d + 4;
22+
}
23+
24+
hue = hue * 60;
25+
}
26+
27+
// Very out of gamut colors can produce negative saturation
28+
// If so, just rotate the hue by 180 and use a positive saturation
29+
// see https://github.com/w3c/csswg-drafts/issues/9222
30+
if (sat < 0) {
31+
hue += 180;
32+
sat = Math.abs(sat);
33+
}
34+
35+
if (hue >= 360) {
36+
hue -= 360;
37+
}
38+
39+
return [hue, sat * 100, light * 100];
40+
}

0 commit comments

Comments
 (0)