Target not equal to source when converting rgb(1,1,1) to oklch, and then back to rgb. #238
-
I store original source rgb colors in an array variable, which are taken from the Rgb color space. I then have a user interface that allows a user to manipulate these source colors in the Oklch color space, which then renders the user-manipulated colors back in the Rgb color space. The problem is that the target never ends up equaling its source even when there is no manipulation of hue, chroma, or luminosity as shown here: With using
Without using
Why does this matter? Because when a user increases the chroma of pure white, I would expect pure white to stay pure white since it is achromatic. But because of this issue, white can becomes a color (often magenta) when chroma is added. |
Beta Was this translation helpful? Give feedback.
Replies: 2 comments
-
Hi Jeremy, thanks for the issue. The results you’re seeing are caused by the fact that a roundtrip from sRGB to Oklch and back introduces subtle precision errors. They are, to some extent, unavoidable and unfortunately need to be actively managed depending on the usage. I believe we are currently using the matrices from the original Oklab article, while the CSS Color Level 4 spec has updated them (see this discussion). It offers better roundtripping but does not completely eliminate these sort of small errors. You may want to experiment with rounding these small values to a number of decimals that make practical sense for your use case. Culori has the import { round } from 'culori';
round(7)(0.9999999608276361); // => 1 (As a sidenote, you may also want to look at In the specific case of Oklch colors, you may want to consider colors with a very small chroma to be achromatic: import { rgb, oklch } from 'culori';
const color = oklch(rgb(oklch('white')));
// => { mode: "oklch", l: 0.9999999934735458, c: 1.5700924586837752e-16, h: 135 }
// make color with infinitely small chroma achromatic.
if (color.c < 1e-8) {
color.c = 0;
delete color.h;
} |
Beta Was this translation helpful? Give feedback.
-
Dan, thank you so much for your quick reply and for all of the helpful tips and code examples! A good bit to add to the documentation. |
Beta Was this translation helpful? Give feedback.
Hi Jeremy, thanks for the issue.
The results you’re seeing are caused by the fact that a roundtrip from sRGB to Oklch and back introduces subtle precision errors. They are, to some extent, unavoidable and unfortunately need to be actively managed depending on the usage.
I believe we are currently using the matrices from the original Oklab article, while the CSS Color Level 4 spec has updated them (see this discussion). It offers better roundtripping but does not completely eliminate these sort of small errors.
You may want to experiment with rounding these small values to a number of decimals that make practical sense for your use case. Culori has the
culori.round()
helper for that: