- From: Chris Lilley via GitHub <sysbot+gh@w3.org>
- Date: Wed, 03 Feb 2021 17:36:10 +0000
- To: public-css-archive@w3.org
svgeesus has just created a new issue for https://github.com/w3c/csswg-drafts: == [css-color-4] Matrices for sRGB to XYZ and back were (slightly) wrong == TLDR; very small change, no visible effect, but imprecise round-trip was annoying. Non-normative sample code updated. Paywalled standards are bad and lead to errors. **What was wrong** The [normative definition of sRGB in CSS Color 4](https://drafts.csswg.org/css-color-4/#valdef-color-srgb) is correct. In the [non-normative sample code](https://drafts.csswg.org/css-color-4/#color-conversion-code), the matrix to go from linear-light sRGB to CIE XYZ, and the inverse matrix to go from CIE XYZ to linear-light sRGB, was wrong starting at the fourth decimal place. **Why** How did this happen? The official definition of sRGB **IEC 61966-2-1:1999/AMD1:2003** Amendment 1 - Multimedia systems and equipment - Colour measurement and management - Part 2-1: Colour management - Default RGB colour space - sRGB is a 16 page PDF which you [buy from the IEC webstore for 70 CHF](https://webstore.iec.ch/publication/6168). I don't have a copy. The standard is different from the [original definition of sRGB](https://www.w3.org/Graphics/Color/sRGB) because roundoff errors to 4 decimal places in the original proposal meant that the linear and curved parts of the transfer function were not continuous (although the effect made no difference, at 8 bits per component). The IEC standard fixed that. So, like [others](https://www.image-engineering.de/library/technotes/958-how-to-convert-between-srgb-and-ciexyz) I used the conversion matrices [calculated by Bruce Lindbloom](http://www.brucelindbloom.com/index.html?Eqn_RGB_XYZ_Matrix.html) in the sRGB sample code. The impact of this was fairly subtle. If you converted sRGB white, `#FFFFFF` to display-p3 you got `color(display-p3 1.0000557 0.99999258 0.99990441)` which is `color(display-p3 1.000 1.000 1.000)` to four significant figures, but `color(display-p3 1.0001 1.0000 0.9999)` to five significant figures, and this should be exactly `1 1 1` because both sRGB and display-p3 use a D65 white. This bugged me. Converting from some other D65-using colorspace, like `color(rec2020 1 1 1)` to display-p3, gave a nice satisfying round-trippable `color(display-p3 1 1 1). So this imprecision was related to sRGB. Wikipedia [has the conversion matrices, to 8 significant figures](https://en.wikipedia.org/wiki/SRGB#The_forward_transformation_(CIE_XYZ_to_sRGB)) which, it claims, come from the earlier version of the standard, **IEC 61966-2-1:1999.** Which is a [51 page PDF and costs 175 CHF](https://webstore.iec.ch/publication/6169). I don't know whether you need both this and the later standard, or just the later one. I don't have a copy of that, either. **What did I change** Today I [recalculated](https://drafts.csswg.org/css-color-4/matrixmaker.html) the sRGB ones, based on the sRGB primary chromaticities and white point. When rounded to 8 decimal places, they are _exactly_ identical to the ones that Wikipedia has. This gives me renewed confidence in those figures. ```js var M = [ [ 0.41239079926595934, 0.357584339383878, 0.1804807884018343 ], [ 0.21263900587151027, 0.715168678767756, 0.07219231536073371 ], [ 0.01933081871559182, 0.11919477979462598, 0.9505321522496607 ] ]; var Minv = [ [ 3.2409699419045226, -1.537383177570094, -0.4986107602930034 ], [ -0.9692436362808796, 1.8759675015077202, 0.04155505740717559 ], [ 0.05563007969699366, -0.20397695888897652, 1.0569715142428786 ] ]; ``` Here are what Wikipedia claims are the official ones, for the 1999 version of the standard: ```js var M = [ [ 0.41239080, 0.35758434, 0.18048079 ], [ 0.21263901, 0.71516868, 0.07219232 ], [ 0.01933082 , 0.11919478, 0.95053215 ] ]; var Minv = [ [ 3.24096994, -1.53738318, -0.49861076 ], [ -0.96924364 , 1.87596750, 0.04155506 ], [ 0.05563008, -0.20397696 1.05697151 ] ]; ``` It seems that, while I calculated the conversion matrices for the other predefined RGB spaces, I copied the sRGB ones from Lindbloom. And that was the source of the error. And here are the Lindbloom ones: ```js var M = [ [0.4124564, 0.3575761, 0.1804375], [0.2126729, 0.7151522, 0.0721750], [0.0193339, 0.1191920, 0.9503041] ]; var Minv = [ [ 3.2404542, -1.5371385, -0.4985314], [-0.9692660, 1.8760108, 0.0415560], [ 0.0556434, -0.2040259, 1.0572252] ]; ``` **What difference does this actually make** In practical terms, none. The deltaE2000 between `color(display-p3 1.0000557 0.99999258 0.99990441)` and `color(display-p3 1.0000000 1.0000000 1.0000000)` is **0.015**, and a deltaE2000 of less than 1 is difficult to see. However, given the problems that sRGB already had from excessive roundoff error, it is satisfying that with this change there is no roundoff error to 8 decimal places. This does affect the values in one WPT test, but does not affect the pass/fail since the difference is very small, invisible to the eye, and hard to measure accurately even with a good spectrophotometer. **matrixmaker.html is blank** Thanks for noticing. To change what matrix is calculated, edit the source. To see the result, open the console. Please view or discuss this issue at https://github.com/w3c/csswg-drafts/issues/5922 using your GitHub account -- Sent via github-notify-ml as configured in https://github.com/w3c/github-notify-ml-config
Received on Wednesday, 3 February 2021 17:36:13 UTC