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-4] proposed breaking change: predefined XYZ is D65 adapted, not D50 #6722

Closed
svgeesus opened this issue Oct 11, 2021 · 11 comments
Closed

Comments

@svgeesus
Copy link
Contributor

Originally raised in WICG/color-api#24 and also related to #6061

Most RGB colorspaces use a D65 whitepoint. (The sole exception in CSS Color 4 is ProPhoto RGB, which uses D50; other examples include DCI-P3, which has a weird greenish white, and ACEScc which has a white similar to, but not the same as, D60).

In practice this means that most RGB to RGB conversions will proceed via CIE XYZ with a D65 whitepoint. In some cases, there will need to be chromatic adaptation, when the white points differ, because the user is assumed to be adapted to the reference white.

So internally, color conversion code will have various different relative XYZ spaces; the question becomes which one to expose to the user (by CSS syntax).

Because most practical use of CIE Lab has a D50 white, at first I defined the white for XYZ in CSS to be D50 as well.

This causes some issues (adaptation is needed) when:

  • calculating WCAG 2.1 contrast, which assumes a D65 white
  • using OKLab and OKLCH (which use a D65 white)
  • creating uv chromaticity diagrams for most RGB spaces
  • performing most calculations that one might want to do on XYZ in a Color object model
  • HDR usage such as PQ Rec.2100 or Jzazbz will also need an absolute XYZ; in both those cases, D65

So in WICG/color-api I proposed that the exposed XYZ be relative, D65 adapted.

For consistency, this means CSS Color 4 should also change to use relative, D65 XYZ in the color() function.

This is a breaking change in that it affects any existing usage of color(xyz ...). It does not affect any other usage (such as lab() or lch()), other code or any other conversions, because all the various XYZ versions are still needed internally anyway. It only affects what is exposed and can be specified directly in XYZ.

Usage is effectively zero at this point (I just checked the draft CSS Almanac 2021 crawl results) so the impacts are:

  • slight inconvenience for WebKit and BFO Publisher maintainers
  • change a few tests in WPT
  • back out a WCAG 21 fix (re-adapt to D65) in color.js

@weinig @faceless2

@svgeesus svgeesus added the css-color-4 Current Work label Oct 11, 2021
@weinig
Copy link

weinig commented Oct 11, 2021

@smfr What do you think? We just shipped support for this, so it's unlikely it is used anywhere, but if anyone adopts now, they are going to have slightly broken content.

My slight personal preference would be to keep it at D50, not only because we have shipped, but also because it happens to match what CoreGraphics calls kCGColorSpaceGenericXYZ, but I will admit that is arbitrary and mostly irrelevant.

When I was trying to learn about colorspaces about a year and a bit ago, the notion that XYZ came in two flavors (actually, as infinite flavors I guess, or as many valid white points as there are, but for my purposes, two, D50 and D65) and that there was a conversion between that needed to happen, was quite confusing. I think what made it so confusing was that many places simply referred to it as the XYZ colorspace, and didn't mention which whitepoint they meant (usually they meant the one corresponding to the colorspace they were converting from). If more sources had been a little more explicit and said what they meant, XYZ(D50) or XYZ(D65) I think I would have been less confused.

That all leads me to think that perhaps a better solution is to just be even more specific here and add the whitepoint to the name (or maybe do something crazy like make xyz into a function that takes a whitepoint (e.g. color(xyz(d50) ...)).

@svgeesus
Copy link
Contributor Author

I agree that it is confusing at first.

The thing is that our eyes have a built-in mechanism so that white looks like white under a fairly broad range of illuminants. The problem is that all the other colors change too. Color A no longer looks like color A.

And so, when white changes, we need to compute the corresponding color in other words, Color B, which looks like what Color A used to look like before the adaptive white point changed.

@weinig
Copy link

weinig commented Oct 11, 2021

Yeah, no, once I understood it, it made sense (these very squishy eyes of ours make everything more fun). I was more commenting on the fact that the lack of explicit-ness made even figuring out that this was something I didn't understand harder.

@svgeesus
Copy link
Contributor Author

So, maybe go with @LeaVerou suggestion, then?

There should definitely be a plain xyz, in both Color API and CSS, and it should refer to the same thing.
We should also expose the other one, either xyzD65 or xyzD50. No opinions about which one to go with for the plain xyz, I’ll defer to @svgeesus for that.

Allowing an optional whitepoint would be interesting, and for CSS Color 4 it just needs to be a string or an identifier; but in extensible APIs there needs to be a way to register a new whitepoint. Hmm. @LeaVerou ?

@LeaVerou
Copy link
Member

I think turning color spaces into functions with a mandatory whitepoint is too heavyweight for both implementors and authors. I think we can rule that custom whitepoints are out of scope for now, and just add xyz-d50 and xyz-d65 plus an xyz keyword that is aliased to one of the two (I'm convinced by @svgeesus' arguments that it should be D65, but no strong opinion there).

@svgeesus
Copy link
Contributor Author

svgeesus commented Oct 11, 2021

To let people see this change in context I pushed it to the ED

@svgeesus
Copy link
Contributor Author

Color.js is also now updated, so people can play with the new syntax; for example in the color converter

@smfr
Copy link
Contributor

smfr commented Oct 12, 2021

I'm not concerned about changing what WebKit has shipped; use in the wild is still low. Having xyz use a D65 white point sounds fine; I've no opinions on whether it's necessary to allow users to specify XYZ with a D50 white point.

@Myndex
Copy link
Member

Myndex commented Oct 12, 2021

Hi Chris @svgeesus

...In practice this means that most RGB to RGB conversions will proceed via CIE XYZ with a D65 whitepoint. ...

YAY! Seriously, as you know I agree, I applaud this move and I do recognize the difficulty of changing course on issues like these. With the rapid moving toward a more HDR/WGC world, IMO realtime gamut mapping is going to become the new "we gotta urgently fix the performance" and one part of that is a common whitepoint.

Most RGB colorspaces use a D65 whitepoint. (The sole exception in CSS Color 4 is ProPhoto RGB D50 ... DCI-P3.... has a weird greenish white, and ACEScc ....). ..... most RGB to RGB conversions will proceed via CIE XYZ with a D65 whitepoint.

I remember making some comments about ProPhoto when it was added a couple years ago, and I still don't quite get why a non-display space that's mainly for physical print workflow is part of the web which I've always seen as a delivery/distribution space (even if dynamic content is assembled on demand)... The reason ProPhoto is useful is for adjusting in RGB material destined for CMYK... but IMO ProPhoto is a poor choice if the destination is an RGB-display type space, for more reasons than I'll bore everyone with.

This makes me wonder, there must be envisioned use cases I am not aware of....?

DCI P3 is a little odd, it's a weird WP due to projector mfgs wanting to have max output from a xenon bulb, so basically that defines the WP and it's not exactly constant...

Before DCI, SMPTE 196M defined the white point for a movie theatre as 5400°K +600° -200°. This gives a range from 5200° to 6000°, But naturally the real world variation was:

Screen Shot 2021-10-12 at 8 23 05 AM

...speaking of hand wavy hand waving....

So DCI P3 was basically set at "xenon native" ... ACES is a similar story, but it's more based on the working group doing a series of tests and comparisons and an unknown amount of wavy-ness to set the WP far enough off the planckian locus that you could use it for dart board practice. That probably doesn't make sense but its the analogy that popped into my head., LOL.

Do I actually have a point this morning?

My point is really that DCI and ACES are part of a tightly closed ecosystem, and having to do with xenon projectors.

In our ecosystem of distributing little ones and zeros world wide to anyone that asks, it's just D65 and I'm thinking the likely progression is going to be something like:

  • We're on sRGB now,
  • Display P3 D65 is next, because it uses ready to go tech and give manufacturers hope that people are going to buy new displays to replace their otherwise perfectly good sRGB and Adobe98 displays...
  • Then, in a few years, Rec2020/2100... but I think the MFGs will want to unload as many P3 monitors as they can, and not sell Rec2020/2100 ones for a while... then, after everyone has P3s, they can push the Rec2100s to sell more monitors to replace perfectly good P3 monitors...

And then what? Laser primaries right on the spectral locus and HDR, what is anyone going to need to "trade up to" after that?

...Brain implants I suppose.

@svgeesus
Copy link
Contributor Author

YAY! Seriously, as you know I agree, I applaud this move

That isn't a move. It was how they were already specified (adapted if the white points are different).

The only thing that changed was which XYZ was exposed to users.

@svgeesus
Copy link
Contributor Author

@smfr thanks for the confirmation!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants