-
Notifications
You must be signed in to change notification settings - Fork 756
Description
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 is correct. In the non-normative sample 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. I don't have a copy.
The standard is different from the original definition of 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 I used the conversion matrices calculated by Bruce Lindbloom 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 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. 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 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.
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:
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:
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.