Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

inGamut wrong result for white in OKLCH #249

Open
ai opened this issue Nov 22, 2024 · 5 comments
Open

inGamut wrong result for white in OKLCH #249

ai opened this issue Nov 22, 2024 · 5 comments

Comments

@ai
Copy link

ai commented Nov 22, 2024

const inRGB = inGamut('rgb')

inRGB({ mode: 'oklch', l: 1, c: 0, h: 0 }) // => false
// white is in sRGB and return should be true

We found this issue in OKLCH color picker.

I can’t remember this issue previously. It could be related to some recent changes, but it is hard to say when exactly (we are using culori version 4.0.1).

@danburzo
Copy link
Collaborator

oklch(100% 0 0) is ever so slightly out of gamut in sRGB:

culori.rgb({ mode: 'oklch', l: 1, c: 0, h: 0 })
Object { mode: "rgb", r: 0.9999999694343974, g: 1.000000008665371, b: 1.0000001148563589 }

This may be due to the matrices we’re using for the conversion. There’s an open issue about updating the matrices to match the latest CSS 4 spec (#237), but if I remember correctly color.js uses the new matrices and the color is still, technically, very slightly out of gamut:

new Color('oklch(100% 0 0)').to('srgb').coords
Array(3) [ 1.0000000000000007, 0.9999999999999994, 0.9999999999999999 ]

To address these, maybe it would be a good idea to round the coordinates to fewer decimal places?

@danburzo
Copy link
Collaborator

A similar issue is discussed here.

@ai
Copy link
Author

ai commented Nov 27, 2024

To address these, maybe it would be a good idea to round the coordinates to fewer decimal places?

It will be great.

@facelessuser
Copy link

This may be due to the matrices we’re using for the conversion. There’s an open issue about updating the matrices to match the latest CSS 4 spec (#237), but if I remember correctly color.js uses the new matrices and the color is still, technically, very slightly out of gamut:

This is simply due to floating point math. It can depend on how some of the calculations are done (matrix inversion etc.) , the consistency of values being used, the precision of those values, etc. Due to the complexity and type of operations being performed, getting a perfect conversion without some floating point error is impossible unless you get really lucky with the rounding.

I believe at this point the CSS issue is closed and new matrices have been applied.

The reality of the issue is that the original Oklab matrices were only provided in 32 bit precision. People always used the forward transform of the LMS to Oklab translation and generated the reverse transform in 64 bit, and assumed that was the best way to go, but the 32 bit values provided a poor translation from LMS 1, 1, 1 to Oklab 1, 0, 0 in 64 bit. In 32 bit operations it was fine. In 64 bit operations you would see a lightness that only aligned to approximately 32 bit accuracy and an LCh chroma that would drift further from zero for achromatic values as lightness approached or exceeded 1.

Taking the inverse transform (Oklab -> LMS) and converting back from Oklab 1, 0, 0 to LMS actually gave something very close, if not exact to 1, 1, 1 in LMS. Essentially, to get a closer, cleaner relation between LMS 1, 1, 1 and Oklab 1, 0, 0, it was better to use the 32 bit reverse transform and generate the forward transform by inverting the reverse transform. Generally, this reduces a lot of the noise and provides a better relationship between white and Oklab 1, 0, 0:

>>> Color('white').convert('oklch').coords()
[1.0, 5.117875266520903e-16, nan]
>>> Color('oklch', [1, 0, 0]).convert('srgb').coords()
[1.0000000000000004, 0.9999999999999997, 0.9999999999999997]

@ai
Copy link
Author

ai commented Feb 10, 2025

I fixed this issue by evilmartians/oklch-picker@3ec0931

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants