Re: [csswg-drafts] [css-color] Add OKLab, OKLCH (#6642)

@svgeesus I only just became aware of these efforts to improve the behaviour of the OKLab matrices when used with reference white of xy=(0.3127, 0.3290). This is work I have also done separately, so I thought I should share my results.

I have adjusted the four matrices such that they are accurate to **float64** (IEEE 754 double precision), see code fragment below.

As far as I can tell the XYZtoLMS/LMStoXYZ/LMStoOKLab/OKLabtoLMS matrices currently in use (see [here](https://www.w3.org/TR/css-color-4/)) are accurate to float32 precision. You'll notice that they match my numbers to somewhere between 6 and 8 significant figures, i.e. the expected precision of float32, or thereabouts.
You should find that that my proposed values are slightly better behaved due to their additional precision, i.e. a D65 grey will map to LMS with components L=M=S, and OKLab with components a=0 and b=0.

My methodology has much in common to those proposed by @bottosson (see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-945714988) and @facelessuser (see https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-943521484).

The M1 matrix fix (which relates XYZtoLMS and LMStoXYZ) involves applying gains in LMS space such that a chromaticity of xy=(0.3127, 0.3290) is exactly mapped to LMS=(1,1,1).

The M2 matrix fix (which relates to LMStoOKLab and OKLabtoLMS) involves truncating to float32 precision from the originally published numbers, and then emitting the resulting matrix and its inverse in float64 precision. While this might sound like a bad idea, it is the correct approach because Bjorn's original optimisation emitted M1 and M2 at float32 precision, printed to 10 d.p. . Therefore it is correct to interpret them as float32 values. The result of handling the numbers in their native datatype is that my OKLabtoLMS matrix ends up with exact values (1.0, 1.0, 1.0) for its first column, and the rows of LMStoOKLab sum to (1, 0, 0). Note that due to the inherent precision of float64 there may be discrepencies in the order of 1e-15 when summing matrix rows, which is unavoidable and of no real world consequence.

Note that my knowledge of M1 and M2 matrices being defined to float32 precision comes from private communications with Bjorn in February 2021.

Note that all my calculations were carried out in "infinite precision" using a rational number library before being rounded to float64. The numeric values in the code snippet below have sufficient decimal places to exactly map to the intended float64 value, generally 16 or 17 significant figures.

```javascript
function XYZ_to_OKLab(XYZ) {
 // Given XYZ relative to D65, convert to OKLab
 var XYZtoLMS = [
  [ 0.819022442647055,   0.3619062604571286, -0.12887378595068213 ],
  [ 0.0329836558550745,  0.9292868602921457,  0.03614466586101669 ],
  [ 0.04817719382823899, 0.2642395276821537,  0.6335478283072317  ]
 ];
 var LMStoOKLab = [
  [ 0.21045426824930336,   0.7936177747759865, -0.00407204302528986 ],
  [ 1.977998539071675,    -2.4285922502018127,  0.4505937111301374  ],
  [ 0.025904030547901084,  0.7827717270900503, -0.8086757576379514  ]
 ];

 var LMS = multiplyMatrices(XYZtoLMS, XYZ);
 return multiplyMatrices(LMStoOKLab, LMS.map(c => Math.cbrt(c)));
 // L in range [0,1]. For use in CSS, multiply by 100 and add a percent
}

function OKLab_to_XYZ(OKLab) {
 // Given OKLab, convert to XYZ relative to D65
 var LMStoXYZ =  [
  [  1.226879868224423,   -0.5578149934498884,  0.281391052277137   ],
  [ -0.04057574728813353,  1.1122868053350754, -0.07171105804694196 ],
  [ -0.0763729441641797,  -0.42149332236303205, 1.5869240172870902  ]
 ];
 var OKLabtoLMS = [
        [ 1.0,  0.3963377773761749,   0.21580375730991364 ],
        [ 1.0, -0.10556134581565857, -0.0638541728258133  ],
        [ 1.0, -0.08948418498039246, -1.2914855480194092  ]
    ];

 var LMSnl = multiplyMatrices(OKLabtoLMS, OKLab);
 return multiplyMatrices(LMStoXYZ, LMSnl.map(c => c ** 3));
}
``` 

I can share my workings if desired, but it will take a bit of time to make it work as a standalone code fragment that is decoupled from proprietary libraries. In the mean time please feel free to try out these refined numbers.

-- 
GitHub Notification of comment by JamesEggleton
Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/6642#issuecomment-1490068959 using your GitHub account


-- 
Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config

Received on Thursday, 30 March 2023 10:31:53 UTC