Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[css-color] Should whitepoint and other canonical values be listed in the code section? #6618

Closed
Myndex opened this issue Sep 16, 2021 · 12 comments
Assignees
Labels
css-color-4 Current Work

Comments

@Myndex
Copy link
Member

Myndex commented Sep 16, 2021

Should whitepoint and other canonical values be listed in the code section? (they aren't now, as far as I can see).

https://drafts.csswg.org/css-color-4/#color-conversion-code

I ask becasue there are multiple "standards" showing slightly different values for D65 and D50 whitepoints.

For instance, Bruce Lindbloom is/was using the whitepoint from ASTM E308-01, the values of which are 0.3127266150 and 0.3290231300

But ICC uses something a little different. And the IEC and ISO seem to have their own variances, along with others.

Elle Stone has an article on the many different whitepoints in various "standards" at NineDegreesPhoto—White Point Values

ALSO: would it make sense to list primary coordinates? And then would it be useful to include matrix generation code instead of pre-calculated matrixes?

I ask because the code to generate a 3x3 matrix is fairly trivial, and then all that is needed for each colorspace are the primary coordinates, white point, and gamma or TRC.

At he very least, I do think the chromaticity coordinates, especially for whitepoint, should be a constant in the code section to provide a canonical value.

@Myndex
Copy link
Member Author

Myndex commented Sep 16, 2021

Will the real white point please stand up?

To illustrate why it might be useful to clearly specify the whitepoint(s) in the docs and code samples, a small collection of whitepoints:

Screen Shot 2021-09-15 at 10 26 29 PM

Screen Shot 2021-09-15 at 10 27 04 PM

There are about 16 different D65 whitepoint xy coordinate pairs specified in this little collection. 14 for the 2° observer. About 11 if you discount the few that were just rounding....

@svgeesus
Copy link
Contributor

I agree that these should be defined canonically in one place in the spec, so they can be referenced elsewhere.

Currently they are defined (in the definitions for the predefined rgb spaces, and in the sample code) but not in a way that can be easily referenced from other specifications:

For D50, in the code, as relative XYZ

var white = [0.96422, 1.00000, 0.82521]; // D50 reference white

In the definition of ProPhoto, as xy chromaticity

White chromaticity 0.345704 0.358540 (D50)

For D65

in the definition of each predefined rgb space, as xy chromaticity:

White chromaticity 0.31272 0.32903 (D65)

and implicitly, in the Bradford adaptation matrices.

@svgeesus svgeesus self-assigned this Sep 16, 2021
@Myndex
Copy link
Member Author

Myndex commented Sep 16, 2021

Hi Chris @svgeesus

Currently they are defined (in the definitions for the predefined rgb spaces, and in the sample code) but not in a way that can be easily referenced from other specifications:

I did eventually find many of them, but....

For D65
in the definition of each predefined rgb space, as xy chromaticity:
White chromaticity 0.31272 0.32903 (D65)

The pre-calculated matrix for sRGB to XYZ (and the inverse) in the CSS code section appears to be calculated with

 x           y
 0.312700    0.329000

Instead of the CIE values that you indicated above, partly why I was wondering as I've been testing some things here, and increasingly notice discrepancies in terms of what the correct values are (not CSS per se, everywhere) ... and I started looking into this a bit more when I ran across a comment you posted on Stack about Bruce's numbers not calculating the same... and poking around I realized that there is ample opportunity to grab "wrong numbers" that "might" have more of an actual effect than the sRGB TRC threshold error that had crept into WCAG 2. Probably not for round trips in the same view since the return error should cancel out.

For instance:

ASTM E308-01 (BL's source)
x 0.3127266150
y 0.3290231300

ICC v4
x 0.3127159070
y 0.3290014810

Naturally if someone is round-tripping in the same view using the same code, it's not likely to matter as the reverse matrix will just undo the error in the forward matrix... but that can still go wrong and lead to inconsistencies...

Run Time Matrix?

And I'm wondering about building the matrix at run time (page load), building a matrix is fairly straight forward, and would only need to run once at load (for non sRGB spaces of course). The advantage is that it's easier to see and verify code by eye a few xy coordinates, as opposed to evaluating the bigger and more arcane numbers in a matrix.

It also provides a level of future proofing, if there was an exposed method that simply took four pairs of coordinates to create the matrixes, then some arbitrary RGB space could be added at will with minimal effort (this is not considering the CMM portion of this for the moment in this hypothetical).

For instance, let's take ProPhoto:

For D50, in the code, as relative XYZ

  var white = [0.96422, 1.00000, 0.82521];   // D50 reference white

In the definition of ProPhoto, as xy chromaticity
White chromaticity 0.345704 0.358540 (D50)

So that xy of 0.345704 0.358540 calculates to a normalized WP of

 var white = [ 0.964199252524126, 1.0,  0.824889830981201 ]; // calculated D50 from ProPhoto

It's not a big error by itself relative to the pre-calculated WP, only ∆E 0.022 or so, nevertheless it led to this thought: the math to build a matrix and WP is fairly easy, assuming only for non-sRGB spaces, only needs to run at page load for a non-sRGB space. Using constants that are at the "upper root" level of chromaticity coordinates and creating the matrix at runtime for the non-sRGB spaces seems like it could be ideal for flexibility, accuracy, consistency... ?

A

@facelessuser
Copy link

I as well am interested to hear about the discrepancy of documented white point vs actual used white point. I am aware that for sRGB that 0.312700, 0.329000 are commonly used, so at first glance, it makes some sense that the examples all match that (assuming that is the intent), but then the color spec seems to indicate that the actual values that should be used are 0.31272, 0.32903. I was actually going to open this very issue until I saw it was already created.

@Myndex
Copy link
Member Author

Myndex commented Sep 18, 2021

hi @facelessuser

I as well am interested to hear about the discrepancy of documented white point vs actual used white point. I am aware that for sRGB that 0.312700, 0.329000 ....SNIP .... the actual values that should be used are 0.31272, 0.32903..

"Back in the Olden Days" (meaning the 1980s/1990s) when computers were 8bit to 16bit, and a floating point coprocessor was not a standard item, these kinds of values were typically rounded to the fourth decimal place. Floating point chips weren't really "standard" in general purpose computers 'til the 1990s with the i486 and later Pentium, and even then.....

Screen Shot 2021-09-17 at 7 02 26 PM

....back then there were plenty of good reasons, performance and otherwise, to round at 3 or 4. Today we're in a more luxurious time as far as processing speed. (Though today there are still issues with base10 floating point math on base2 computers.)

Nevertheless, a lot of "standards" prior to year 2000 were rounded at 3 or 4 places, but are being recalculated for our modern times. Is it worth it? the errors are small — but recursion can result in cumulative errors that are not small. In compositing for instance, a modern visual effect can have hundreds of layers, so a ∆E less than 1 can cumulatively become more than 1 fairly quickly.

That said, the bigger problem is when an important constant is not consistent across operations. 0.313, 0.329 is probably fine in most cases, so long as it is used for all transforms in both directions. But mixing 0.313, 0.329 for transforms in one direction and 0.31272, 0.32903 for the other direction, the errors can add up.

There is already a lot of approximation going on regarding digital color on displays ... trying to find the source of some little weird error can be maddening, it'd be good to remove as many error sources as possible.....

@facelessuser
Copy link

That said, the bigger problem is when an important constant is not consistent across operations. 0.313, 0.329 is probably fine in most cases, so long as it is used for all transforms in both directions. But mixing 0.313, 0.329 for transforms in one direction and 0.31272, 0.32903 for the other direction, the errors can add up.

Yes, I've run into this before with color conversions. Consistency is key to get the best values, though with floating-point math and more complicated color transforms, you still get some errors, but at least you'll reduce them. I know when calculating HSLuv, from sRGB, the assumption is that 0.3127, 0.3290 is used. The values aren't too clean if you are using something different. You have to download the source algorithm and plug in the new values to generate a solution that gets nice clean results.

What I've been most curious about is the advertising of 5 decimals, but all the examples are given in 4, not the actual precision itself. I can see some people implementing based on the example code and some implementing off the spec value leading to close-ish but different values. What's the point of stating the standard of the white point that should be used if the examples don't even bother using It 🤷🏻? I believe this is unintentional, but it probably should be cleared up.

The 5 decimal sRGB transform should be something more like:

--- rgb -> xyz ---
[[0.4124078805165856,  0.35758957376680744, 0.180432597687552  ],
 [0.21264781339136446, 0.7151791475336149,  0.07217303907502079],
 [0.01933161939921493, 0.11919652458893579, 0.9502783478211071 ]]

opposed to the example which is at 4 decimals:

--- rgb -> xyz ---
[[0.4123907992659593,  0.357584339383878,   0.18048078840183432],
 [0.21263900587151024, 0.715168678767756,   0.07219231536073373],
 [0.01933081871559182, 0.11919477979462598, 0.9505321522496608 ]]

This goes for all the transforms. Since I'm aware of how to get the calculations, I'm not concerned with not being consistent across conversions, I'm more concerned with what is the actual spec, and is everyone going to implement it differently? If the spec doesn't even use it the same throughout, what hope is there for anyone else 🙂 ?

@Myndex
Copy link
Member Author

Myndex commented Sep 20, 2021

Hi @facelessuser

....What's the point of stating the standard of the white point that should be used if the examples don't even bother using It 🤷🏻? I believe this is unintentional, but it probably should be cleared up. The 5 decimal sRGB transform should be something more like: ...SNIP

Yes, this is what I was mentioning above, that the pre-calculated matrix for sRGB is using the 0.3127, 0.329 values. And herein lies the rub: Some standards such as ICC are a little different from, say, the CIE. And both ICC and CIE have differences over time and release versions, compounded by other parties using their own in-house standards.

For instance, the 2004 third edition of CIE Colorimetry specifies the xy for D65 as 0.31272, 0.32903

At some point before that (1978?), the CIE for D65 was 0.3128, 0.3292

And I distinctly remember seeing it often as 0.313, 0.329 in the late 90s and early 2000s.

This goes for all the transforms. Since I'm aware of how to get the calculations, I'm not concerned with not being consistent across conversions, I'm more concerned with what is the actual spec, and is everyone going to implement it differently? If the spec doesn't even use it the same throughout, what hope is there for anyone else 🙂 ?

Well, today, the CIE says D65 is 0.31272, 0.32903 — but again there are still plenty of lingering legacy versions everywhere. And those need to be for compatibility with some apps and old content etc.

I think the code samples in CSS4 are intended as "examples" only and not as normative, and in fact says just that:

Sample code for color conversions

This section is not normative.
// Conversion can also be done using ICC profiles and a Color Management System

And in fact probably can't be normative or require the use of one spec, as there could be unintended consequences such as for legacy content, etc.

My initial post was not meant to say "this should be the absolute standard" so much as to ask "should we be consistent and also provide a canonical touch stone using the latest standard values" etc.

@facelessuser
Copy link

I think the code samples in CSS4 are intended as "examples" only and not as normative, and in fact, says just that:
...
My initial post was not meant to say "this should be the absolute standard" so much as to ask "should we be consistent and also provide a canonical touch stone using the latest standard values" etc.

Yes, and I do understand that, and you are right that it does state that This section is not normative. The spec spends time at least defining the predefined colors spaces and then showing examples, and it seems implied, that at the very least, the examples would mirror the same predefined spaces and their properties, even if implementors are free to use whatever color profiles that they need or want at a given time.

My initial post was not meant to say "this should be the absolute standard" so much as to ask "should we be consistent and also provide a canonical touchstone using the latest standard values" etc.

I do agree that at the very least, it should be consistent with itself. Or at least be more explicit at times. Like if the examples not only stated This section is not normative, but also stated what xy values were used, it would at least be more clear what was being shown.

@svgeesus
Copy link
Contributor

svgeesus commented Oct 5, 2021

A useful and relevant thread on color.js and my eventual conclusion was to not use the ASTM ones, which are calculated from only 10nm spacing data; also, sadly, to move away from CIE.15 0.31272, 0.32903 and for the most consistent results to use the same four-figure values as (allegedly) used in the (paywalled) sRGB standard, and certainly used in Rec BT.2020: 0.3127, 0.3290. So that is what color.js currently uses.

Using other values means that the conversion matrices for sRGB to/from XYZ are too different to the official ones.

I see that I didn't update the sample code or the predefined colorspace definitions in CSS Color 4. But I think that I should.

The most important thing is to use a single set of consistent values everywhere (matrices to and from XYZ, adaptation matrices).

As noted, the matrixmaker.html (which has no official status at all and is just a scratch utility) still uses the ASTM values which simply reflects the last change I happened to make while investigating.

@Myndex
Copy link
Member Author

Myndex commented Oct 5, 2021

Hi Chris @svgeesus

....not use the ASTM ones....sadly, to move away from CIE.15 0.31272, 0.32903 and for the most consistent results to use the same four-figure values as (allegedly) used in the (paywalled) sRGB standard, and certainly used in Rec BT.2020: 0.3127, 0.3290. So that is what color.js currently uses.

I can certainly agree with that, ... everything pre-2001ish seems to be 4 places... x = 0.3127, y = 0.3290 (D65) is what "everyone's using" and consistency is more important than a fifth decimal place that references a century old set of numbers created by a few young British males that were averaged into a standard observer with a known issue underreporting blue...

Not to mention the sRGB standard clearly refers to Rec.709 and CIE D65:

ITU-R BT.709-2 reference primaries & CIE Standard Illuminant D65 ... in table 1.

And also the reference monitor:

IEC sRGB:
Reference Monitor Conditions
1. Monitor luminance                    80 cd/m^2
2. Monitor white point                   x = 0.3127, y = 0.3290 (D65) 
3. Monitor model offset                  0.0
4. Monitor input/output trc              2.2

At least in the US, you can't copyright facts — so can't post a screenshot, but can post the specific facts...

Using other values means that the conversion matrices for sRGB to/from XYZ are too different to the official ones.

Most of the official matrixes are also rounded at 4 places... But everywhere else, including ICC profiles, they are calculated out to more places... while maintaining the 4-place chromaticity coordinates makes sense (the canonical values), it seems to me that limitation is not needed for the matrix which is easily calculated...

I think the ITU of one of the YCC variants uses a matrix with higher precision, but I couldn't find it just now.

The most important thing is to use a single set of consistent values everywhere (matrices to and from XYZ, adaptation matrices).

IMO as long and the in and out are using the same, then all is fine IMO... Unfortunately, there seems to be a lot of variation, more than I expected as I was trying to track down an anomaly in something and ran across Elle Stone's post on the subject.

....still uses the ASTM values which simply reflects the last change I happened to make while investigating.

I'd probably be happily using ASTM today except for trying to track down a rounding error recently.

@svgeesus svgeesus added the css-color-4 Current Work label Oct 5, 2021
@triple-underscore
Copy link

triple-underscore commented Oct 9, 2021

6503K for D50 in 47da6ee seems a typo of 5003K.
(per https://en.wikipedia.org/wiki/Standard_illuminant#White_points_of_standard_illuminants)

svgeesus added a commit that referenced this issue Oct 9, 2021
@svgeesus
Copy link
Contributor

svgeesus commented Oct 9, 2021

Oof, totally! Fixed

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
css-color-4 Current Work
Projects
None yet
Development

No branches or pull requests

4 participants