facelessuser / coloraide

A library to aid in using colors
https://facelessuser.github.io/coloraide
MIT License
194 stars 12 forks source link

Add new GMA algorithm #394

Closed facelessuser closed 7 months ago

facelessuser commented 8 months ago

Created a new GMA algorithm inspired by a method called Scale LH over at https://github.com/color-js/color.js.

Scale LH was a fast method that very roughly approximates the gamut (currently targeting Display P3). It does so by scaling the color towards the midpoint in linear light. Essentially it does two passes with the scaling, the first it preserves L and H, hence the name. It performs admirably, but I did have a few issues with it.

This new method, which I'll call Scale LH Achromatic for now, scales the color toward an achromatic version of itself. This method requires the target gamut to be an RGB space, ideally linear RGB. Basically, the algorithm is.

  1. Calculate the OkLCh version of the color.
  2. Create an achromatic versioning OkLCh.
  3. Convert both to Linear RGB (if possible).
  4. Scale the color towards the achromatic value in the linear RGB space until the color is in the gamut.
  5. Write the original OkLCh L and H values back.
  6. Step (5) should be performed at least twice but can be done more. Currently, I've found three to be decent.
  7. Clip the color and return.

My first attempt generally worked pretty well, but I did run into issues in lower light blue (and maybe a few other places). This was a bit frustrating as the approach generally seemed to work better, but in this one area, it performed a bit worse.

After experimenting for far too long, I found that if I separated out the lightness and scaled the color so that the lightness could be better preserved, I no longer over (or under) corrected. This greatly improved performance in low-light blue and other places.

In general, this approach may be a good fit for sending colors directly to a display format (usually RGB). It performs similarly to the slower, MINDE chroma reduction method but is much faster.

Ref: https://github.com/color-js/color.js/pull/449

facelessuser commented 7 months ago

So, with further experimentation, we ended up implementing a better approach that introduced ray tracing to reduce the chroma. A PR will be up soon.