linebender / color

Color in Rust.
Apache License 2.0
39 stars 5 forks source link

Hwb color space #30

Closed raphlinus closed 2 weeks ago

raphlinus commented 2 weeks ago

Add HWB color space, basically following the spec. It's been spot-tested with non-HDR colors.

Serialization is to syntax which can be parsed by CSS Color 4, but doesn't include % for W and B, as is done by color.js. It also doesn't strictly follow serialization by the spec, which calls for the color to be lowered to RGB. To me this is an argument in favor of having a separate code path for strict CSS serialization.

In theory, HWB should be able to handle HDR colors with negative values for W and B. In practice, that's a bad idea, and in any case the current code does not roundtrip these correctly. That might be a flaw in the spec, and deserves deeper investigation.

Closes #19

raphlinus commented 2 weeks ago

A bit more on the HDR color issue. Using color.js, this code:

let c4 = new Color("color(srgb 1.1 1.2 1.1)");
console.log(c4.to("srgb").toString({inGamut: false}));
console.log(c4.to("hsl").toString({inGamut: false}));
console.log(c4.to("hwb").toString({inGamut: false}));

produces this output:

rgb(110% 120% 110%)
hsl(300 33.333% 115%)
hwb(120 110% -20%)

The hwb value is what I'd expect (120 is green), and this converts back correctly. The hsl value has a very strange hue, but does convert back correctly. I think the problem is that the sample code in the spec uses the hue from HSL, and that's not valid when the hue rotation hack. That was noticed in https://github.com/w3c/csswg-drafts/issues/10695 and apparently fixed by ead8668, but I don't see the update in the spec.