facelessuser / coloraide-extras

Some extra color spaces and such for ColorAide
https://facelessuser.github.io/coloraide-extras
MIT License
2 stars 0 forks source link

Add an HCT gamut mapping solution #21

Closed facelessuser closed 1 year ago

facelessuser commented 1 year ago

We've implemented HCT, the space as described in https://material.io/blog/science-of-color-design. The actual implementation that Material uses, does some "clever things" though.

  1. Lightness is clamped between 0 - 100. This makes sense as the conversion back to an SDR color space is easy-ish as the L* range of 0 - 100 maps to the J range of CAM16 of 0 - 100, not exactly mind you, but the range is the same. This means you can set your low and high to 0 and 100 and bisect to convert L* back to a suitable J. HDR range is more unpredictable as the J value can exceed the current L*. Limiting to SDR isn't that bad.
  2. Chroma gets clamped when it exceeds the sRGB gamut. This means that for every set of hue, chroma, or lightness, Material is recalculating the color and reduces lightness and chroma. We do not as we do not want to limit the color space to sRGB only. We live in the modern world, and modern color spaces are wide gamut. We also don't really have those kinds of hooks. We can do a simple range clamp, but not dynamic at this time. Also, dynamic range clamping that requires us to calculate what the actual max chroma can be for a given lightness and hue would be expensive to do on every set.

What this means is that if you take the color red in HCT, and adjust its tone, the chroma may not be in gamut for sRGB, Display P3, or whatever color space you plan to convert back to. You will not get the same result that the Material library would give you for tones. But there is a way to allow us to get those values.

In order to match what the Material library does, we'd need to reduce chroma in HCT until the color is within some other gamut, in the case of Material, sRGB. This is exactly what we already do with the default gamut mapping algorithm that uses LCh and the CSS proposed algorithm that uses OkLCh.

We should create a variant gamut mapping algorithm that can reduce chroma while in HCT. This would only work for SDR colors and would clip anything above SDR. I'm not sure if it is less expensive to use ∆E 2000 or use CAM16 which is designed for CAM16-based color spaces (which HCT basically is). Either way, doing this would preserve chroma and lightness and allow us to give the same or nearly the same results.

Obviously, this way is expensive to calculate, but so is HCT in general, so I see no issues. People should be able to generate very similar colors and palettes.

facelessuser commented 1 year ago

Resolved by https://github.com/facelessuser/coloraide-extras/commit/5ef7d4d639cd7ff877a6b5dc79009a4cae83b107