culori icon indicating copy to clipboard operation
culori copied to clipboard

Conversion between `oklch` and `okhsl`

Open adithyaappu opened this issue 1 year ago • 4 comments

I was playing around with the library and converter. When attempted, conversion from oklch to okhsl yields weird results. In the documentation I haven't seen any specifics about the the color spaces supported by converter. So I assume it is expected to work.

This is my converter function.

function colorConverter(mode, colorObject) {
  let convertFunction = converter(mode);
  let convertedColor = convertFunction(colorObject);

  return convertedColor;
}

I have added,

useParser("--oklch", "oklch");

The function call is,

let elemColour = colorConverter(colorModes[i], defaultColour);

In that colorModes is

let colorModes = ["okhsl", "oklch"];

and, defaultColour is,

let defaultColour = {
  mode: "oklch",
  l: 0.2,
  c: 0.1,
  h: 230,
};

this is the results I'm getting,

image

the values are,

Object { mode: "okhsl", l: 0.09907971332700131, s: -0.14929222272569598, h: 229.99999999999997 }
Object { mode: "oklch", l: 0.2, c: 0.1, h: 230 }  

Is there anything I'm missing? Else it looks like there is some bug with converter function

adithyaappu avatar Nov 17 '24 12:11 adithyaappu

Converting from Oklch to Okhsl passes through sRGB as the base color space. The color oklch(0.2 0.1 230) is out of gamut for sRGB, and converting sRGB to Okhsl is not well defined outside the gamut. Leaving the issue open, maybe there’s something we can do to improve the algorithm.

danburzo avatar Nov 17 '24 13:11 danburzo

Oh. May I ask why sRGB, and not XYZ D65 is used as base for conversion? I'm very new to this area. I couldn't understand why it is selected.

adithyaappu avatar Nov 17 '24 13:11 adithyaappu

In general, CIEXYZ D65 is a better base for conversions. Going all the way to sRGB and back is a bit more inefficient, but should not introduce significant error. It was a design choice at the beginning of the project. In a future version of the library, we may switch to more efficient conversion chains that have XYZ at the root.

In the case of Okhsl / Okhsv, they’re ultimately derived from Oklab, but it starts with the assumption of covering the sRGB gamut. You can shortcut the conversion chain with the code below, but it results in the same color:

culori.okhsl(culori.oklab('oklch(...)'))

danburzo avatar Nov 17 '24 13:11 danburzo

Understood. Thank you so much for spending your time to explain the things. I really appreciate it.

adithyaappu avatar Nov 17 '24 13:11 adithyaappu