Skip to content

Commit ec880f0

Browse files
committed
[css-color-4] Define epsilon for returning missing hue, #11706
1 parent 07a35b4 commit ec880f0

File tree

5 files changed

+59
-13
lines changed

5 files changed

+59
-13
lines changed

css-color-4/Overview.bs

+24-7
Original file line numberDiff line numberDiff line change
@@ -1193,18 +1193,19 @@ will have a [=powerless=] hue component.
11931193
If a [=powerless component=] is manually specified,
11941194
it acts as normal;
11951195
the fact that it's [=powerless=] has no effect.
1196+
11961197
However, if a color is automatically produced by color space conversion,
11971198
then any [=powerless components=] in the result must instead be set to [=missing=],
11981199
instead of whatever value was produced by the conversion process.
11991200

1200-
User agents <em>may</em> treat a component as [=powerless=]
1201-
if the color is "sufficiently close" to the precise conditions specified.
1202-
For example, a gray color converted into ''lch()'' may,
1201+
When performing color space conversion to a [=cylindrical polar color=] space,
1202+
user agents <em>shall</em> treat a hue component as [=powerless=]
1203+
if the chroma (or other measure of colorfulness, such as saturation in ''hsl'')
1204+
is less than the epsilon (ε) specified for that color space.
1205+
For example, a gray color converted into ''oklch()'' may,
12031206
due to numerical errors,
12041207
have an <em>extremely small</em> chroma rather than precisely ''0%'';
1205-
this can, at the user agent's discretion,
1206-
still treat the hue component as [=powerless=].
1207-
It is intentionally unspecified exactly what "sufficiently close" means for this purpose.
1208+
as a result, the hue component is [=powerless=].
12081209

12091210
<h3 id=parse-color>
12101211
Parsing a <<color>> Value</h3>
@@ -2169,6 +2170,10 @@ HSL Colors: ''hsl()'' and ''hsla()'' functions</h2>
21692170
for S and L: 0% = 0.0, 100% = 100.0
21702171
</td>
21712172
</tr>
2173+
<tr>
2174+
<th>Powerless hue ε</th>
2175+
<td>S &lt;= 0.001</td>
2176+
</tr>
21722177
</table>
21732178

21742179
<wpt>
@@ -2706,6 +2711,10 @@ HWB Colors: ''hwb()'' function</h2>
27062711
for W and B: 0% = 0.0, 100% = 100.0
27072712
</td>
27082713
</tr>
2714+
<tr>
2715+
<th>Powerless hue ε</th>
2716+
<td>W + B >= 99.999</td>
2717+
</tr>
27092718
</table>
27102719

27112720
The first argument specifies the hue,
@@ -3407,6 +3416,10 @@ Specifying Lab and LCH: the ''lab()'' and ''lch()'' functional notations</h3>
34073416
for C: 0% = 0, 100% = 150
34083417
</td>
34093418
</tr>
3419+
<tr>
3420+
<th>Powerless hue ε</th>
3421+
<td>C &lt;= 0.0015</td>
3422+
</tr>
34103423
</table>
34113424

34123425
<wpt>
@@ -3576,6 +3589,10 @@ Specifying Lab and LCH: the ''lab()'' and ''lch()'' functional notations</h3>
35763589
for C: 0% = 0.0 100% = 0.4
35773590
</td>
35783591
</tr>
3592+
<tr>
3593+
<th>Powerless hue ε</th>
3594+
<td>C &lt;= 0.000004</td>
3595+
</tr>
35793596
</table>
35803597

35813598
<wpt>
@@ -3653,8 +3670,8 @@ Converting Lab or Oklab colors to LCH or OKLCh colors</h3>
36533670
Conversion to the polar form is trivial:
36543671

36553672
<ol>
3656-
<li>H = atan2(b, a)
36573673
<li>C = sqrt(a^2 + b^2)
3674+
<li>if (C > epsilon) H = atan2(b, a) else H is missing
36583675
<li>L is the same
36593676
</ol>
36603677

css-color-4/better-rgbToHsl.js

+5
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ function rgbToHsl (red, green, blue) {
99
let min = Math.min(red, green, blue);
1010
let [hue, sat, light] = [NaN, 0, (min + max)/2];
1111
let d = max - min;
12+
let epsilon = 1 / 100000; // max Sat is 1, in this code
1213

1314
if (d !== 0) {
1415
sat = (light === 0 || light === 1)
@@ -36,5 +37,9 @@ function rgbToHsl (red, green, blue) {
3637
hue -= 360;
3738
}
3839

40+
if (sat <= epsilon) {
41+
hue = NaN;
42+
}
43+
3944
return [hue, sat * 100, light * 100];
4045
}

css-color-4/conversions.js

+20-5
Original file line numberDiff line numberDiff line change
@@ -374,12 +374,19 @@ function Lab_to_XYZ(Lab) {
374374
}
375375

376376
function Lab_to_LCH(Lab) {
377-
// Convert to polar form
377+
var epsilon = 0.0015;
378+
var chroma = Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)); // Chroma
378379
var hue = Math.atan2(Lab[2], Lab[1]) * 180 / Math.PI;
380+
if (hue < 0) {
381+
hue = hue + 360;
382+
}
383+
if (chroma <= epsilon) {
384+
hue = NaN;
385+
}
379386
return [
380387
Lab[0], // L is still L
381-
Math.sqrt(Math.pow(Lab[1], 2) + Math.pow(Lab[2], 2)), // Chroma
382-
hue >= 0 ? hue : hue + 360 // Hue, in degrees [0 to 360)
388+
chroma, // Chroma
389+
hue // Hue, in degrees [0 to 360)
383390
];
384391
}
385392

@@ -439,11 +446,19 @@ function OKLab_to_XYZ(OKLab) {
439446
}
440447

441448
function OKLab_to_OKLCH(OKLab) {
449+
var epsilon = 0.000004;
442450
var hue = Math.atan2(OKLab[2], OKLab[1]) * 180 / Math.PI;
451+
var chroma = Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2);
452+
if (hue < 0) {
453+
hue = hue + 360;
454+
}
455+
if (chroma <= epsilon) {
456+
hue = NaN;
457+
}
443458
return [
444459
OKLab[0], // L is still L
445-
Math.sqrt(OKLab[1] ** 2 + OKLab[2] ** 2), // Chroma
446-
hue >= 0 ? hue : hue + 360 // Hue, in degrees [0 to 360)
460+
chroma,
461+
hue
447462
];
448463
}
449464

css-color-4/rgbToHsl.js

+6-1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ function rgbToHsl (red, green, blue) {
99
let min = Math.min(red, green, blue);
1010
let [hue, sat, light] = [NaN, 0, (min + max)/2];
1111
let d = max - min;
12+
let epsilon = 1 / 100000; // max Sat is 1, in this code
1213

1314
if (d !== 0) {
1415
sat = (light === 0 || light === 1)
@@ -21,7 +22,11 @@ function rgbToHsl (red, green, blue) {
2122
case blue: hue = (red - green) / d + 4;
2223
}
2324

24-
hue = hue * 60;
25+
hue = hue * 60; // degrees
26+
}
27+
28+
if (sat <= epsilon) {
29+
hue = NaN;
2530
}
2631

2732
return [hue, sat * 100, light * 100];

css-color-4/rgbToHwb.js

+4
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,12 @@ function rgbToHue(red, green, blue) {
3636
* @return {number[]} Array of HWB values: Hue as degrees 0..360, Whiteness and Blackness in reference range [0,100]
3737
*/
3838
function rgbToHwb(red, green, blue) {
39+
let epsilon = 1 / 100000; // account for multiply by 100
3940
var hue = rgbToHue(red, green, blue);
4041
var white = Math.min(red, green, blue);
4142
var black = 1 - Math.max(red, green, blue);
43+
if (white + black >= 1 - epsilon) {
44+
hue = NaN;
45+
}
4246
return([hue, white*100, black*100]);
4347
}

0 commit comments

Comments
 (0)