Re: [csswg-drafts] [css-color-4] Evaluate static gamut mapping algorithms for oklab/oklch spaces (#10579)

@jamesnw I would expect results in the same ballpark for the others as well. If you want to directly test, Björn's approach and raytrace can easily be adjusted to do rec2020 as well if your interested.

For Björn's you need new Rec. 2020 matrices and coefficients (you can update the variable names). Also, update any conversions using the Color.js API to reference Rec.2020 opposed to P3.

```js
lmsToP3Linear: [
   [2.1399067304346517, -1.2463894937606181, 0.10648276332596672],
   [-0.8847358357577675, 2.1632309383612007, -0.27849510260343346],
   [-0.04857374640044416, -0.454503149714096, 1.5030768961145402]
  ],
  P3Coeff: [
   // Red
   [
    // Limit
    [-1.36834899, -0.46664773],
    // `Kn` coefficients
    [1.2572445, 1.71580176, 0.5648733,  0.79507316, 0.58716363],
   ],
   // Green
   [
    // Limit
    [2.01150796, -2.0379096],
    // `Kn` coefficients
    [0.74087755, -0.4586733, 0.08182977, 0.12598705, -0.14570327],
   ],
   // Blue
   [
    // Limit
    [0.06454093, 2.29709336],
    // `Kn` coefficients
    [1.36920484e+00, -1.64666735e-02, -1.14197870e+00, -5.01064768e-01, 1.19905985e-03],
   ],
  ]
```

For ray trace, you just need to update the RGB to LMS and LMS to RGB matrices. Also, update any conversions using the Color.js API to reference Rec.2020 and/or Linear Rec. 2020 opposed to P3.

```js
  oklchToLinearRGB (lch) {
   // Convert from Oklab to linear RGB.
   //
   // Can be any gamut as long as `lmsToRgb` is a matrix
   // that transform the LMS values to the linear RGB space.

   let c = lch[1];
   let h = lch[2];
   // to lab
   let result = [
    lch[0],
    c * Math.cos((h * Math.PI) / 180),
    c * Math.sin((h * Math.PI) / 180)
   ];

   // To LMS
   util.multiply_v3_m3x3(
    result,
    [
     [ 1.0000000000000000,  0.3963377773761749,  0.2158037573099136 ],
     [ 1.0000000000000000, -0.1055613458156586, -0.0638541728258133 ],
     [ 1.0000000000000000, -0.0894841775298119, -1.2914855480194092 ]
    ],
    result
   );
   result[0] = result[0] ** 3;
   result[1] = result[1] ** 3;
   result[2] = result[2] ** 3;

   // To RGB
   util.multiply_v3_m3x3(
    result,
    [
     [2.1399067304346517, -1.2463894937606181, 0.10648276332596672],
     [-0.8847358357577675, 2.1632309383612007, -0.27849510260343346],
     [-0.04857374640044416, -0.454503149714096, 1.5030768961145402]
    ],
    result
   );
   return result;
  },

  LinearRGBtoOklch (rgb) {
   // Convert from Oklch to linear RGB.
   //
   // Can be any gamut as long as `lmsToRgb` is a matrix
   // that transform the LMS values to the linear RGB space.

   // To LMS
   let result = util.multiply_v3_m3x3(
    rgb,
    [
     [0.6167557848654442, 0.3601984012264634, 0.023045813908092294],
     [0.2651330593926367, 0.6358393720678492, 0.0990275685395141],
     [0.10010262952034829, 0.20390652261661446, 0.6959908478630372]
    ]
   );

   result[0] = Math.cbrt(result[0]);
   result[1] = Math.cbrt(result[1]);
   result[2] = Math.cbrt(result[2]);

   util.multiply_v3_m3x3(
    result,
    [
     [ 0.2104542683093140,  0.7936177747023054, -0.0040720430116193 ],
     [ 1.9779985324311684, -2.4285922420485799,  0.4505937096174110 ],
     [ 0.0259040424655478,  0.7827717124575296, -0.8086757549230774 ]
    ],
    result
   );

   let a = result[1];
   let b = result[2];
   return [
    result[0],
    Math.sqrt(a ** 2 + b ** 2),
    constrainAngle((Math.atan2(b, a) * 180) / Math.PI)
   ];
  },

```

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


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

Received on Wednesday, 11 June 2025 03:09:05 UTC