FastLED 3.10.6
Loading...
Searching...
No Matches

◆ oklabToXyzQ16()

void fl::oklabToXyzQ16 ( const i32(&) lab[3],
i32(&) out_xyz[3] )

OKLab (s16.16) -> XYZ (s16.16).

The inverse of xyzToOklabQ16.

Not bit-exact in round trip: both directions round to nearest and the cube root truncates. oklabToXyzQ16(xyzToOklabQ16(v)) returns within 32 ULP over the working domain.

The other order degrades near black. OKLab cube-roots the cone responses, and that root's derivative, 1 / (3 * lms^(2/3)), diverges as a response approaches zero: around L = 0.05 it is roughly 1200, so any error in the response is hugely amplified coming back out. Restricted to in-gamut colours the worst measured round trip there is about 300 ULP. This is conditioning rather than representation – carrying lms or XYZ at Q32 was measured and does not fix it – and it costs the P7 mapper nothing. tests/fl/gfx/oklab_q16.cpp pins both ends.

Definition at line 134 of file oklab_q16.cpp.hpp.

134 {
135 const i32 clamped[3] = {clampOklabQ16(lab[0], kOklabQ16MaxMagnitude),
136 clampOklabQ16(lab[1], kOklabQ16MaxMagnitude),
137 clampOklabQ16(lab[2], kOklabQ16MaxMagnitude)};
138 i32 root[3];
139 dotOklabMatrixQ16(kLmsRootFromOklab, clamped, root);
140 const i32 lms[3] = {
141 signedCubeQ16(root[0]), signedCubeQ16(root[1]), signedCubeQ16(root[2])};
142 dotOklabMatrixQ16(kXyzFromLms, lms, out_xyz);
143}
void dotOklabMatrixQ16(const i32(&matrix)[3][3], const i32(&v)[3], i32(&out)[3]) FL_NO_EXCEPT
constexpr i32 kOklabQ16MaxMagnitude
Largest magnitude either direction accepts, as an s16.16 raw value (64.0).
Definition oklab_q16.h:40

References FL_NO_EXCEPT, and kOklabQ16MaxMagnitude.

Referenced by fl::anonymous_namespace{gamut_map.cpp.hpp}::chromaCandidateXyz(), mapAndAllocateRgbwQ16(), and mapAndAllocateRgbwwQ16().

+ Here is the caller graph for this function: