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] Clamping of color values #3845

Closed
svgeesus opened this issue Apr 18, 2019 · 8 comments
Closed

[css-color-4] Clamping of color values #3845

svgeesus opened this issue Apr 18, 2019 · 8 comments

Comments

@svgeesus
Copy link
Contributor

Originally reported by @tabatkins as an inline issue

Various parts of the spec define t he kind of clamping that should happen to the various numeric notations when the numbers specified are out of range, and do so with varrying precision, sometimes saying that this happens at computed value time, sometimes not saying when it happens, and sometimes not saying anything at all.

Maybe this should be consolidated here.

@svgeesus svgeesus added the css-color-4 Current Work label Apr 18, 2019
@tabatkins tabatkins added this to Needs triage in Blink Issue Triage via automation Apr 19, 2019
@tabatkins tabatkins moved this from Needs triage to No Action Yet in Blink Issue Triage Apr 19, 2019
@karip
Copy link

karip commented Apr 5, 2020

The specification doesn't say how out-of-range values for profiled colors are handled. Are they clamped to their valid range or does an out-of-range value make the color invalid?

The rgb(), hsl() and other functions explicitly mention that their values are clamped to the valid range: "Values outside these ranges are not invalid, but are clamped to the ranges defined here at computed-value time." I would expect the values for profiled colors to be clamped, too.

@svgeesus
Copy link
Contributor Author

svgeesus commented Apr 6, 2020

Thanks for the bug report. Yes, the spec should say this clearly and yes, like the others, they should be clamped to the valid range

"Values outside these ranges are not invalid, but are clamped to the ranges defined here at computed-value time."

@svgeesus svgeesus self-assigned this Apr 6, 2020
@svgeesus
Copy link
Contributor Author

svgeesus commented Apr 6, 2020

Oh, I remember why this remains open; need to decide

  • whether negative values and values greater than 1.0 or 100% are allowed (they are, and are not invalid; rgb() already allows them)
  • when and where negative values (out of gamut colors) are dealt with
  • where to describe the relative-colorimetric-style handling of out of gamut values (currently per-component clipping, which is awful; better to do C reduction to the gamut boundary in LCH, which preserves perceptual Hue and Lightness.
  • whether to retrospectively make that change to rgb() as well.

@danburzo
Copy link

danburzo commented Apr 6, 2020

where to describe the relative-colorimetric-style handling of out of gamut values (currently per-component clipping, which is awful; better to do C reduction to the gamut boundary in LCH, which preserves perceptual Hue and Lightness.

I'm not sure if you've seen this discussion, but it became apparent that reducing C in an out-of-gamut LCH color is not always amenable to the bisection method, due to the weird shape around yellows. The solution may require a pre-computed lookup table or something to that effect.

@svgeesus
Copy link
Contributor Author

reducing C in an out-of-gamut LCH color is not always amenable to the bisection method, due to the weird shape around yellows

Yes, when doing gamut mapping from display-p3 to sRGB (or rec2020 to display-p3) I also found problems due to gamut surface concavities around yellow (and cyan). The solution was, at each iteration of the bisection method, to calculate the deltaE between the current iteration and a channel-clamped copy of current iteration (which by definition will be in gamut). If the deltaE is less than some threshold (so the two values are not easily distinguishable), terminate bisection and return the clamped value.

This is better explained, and with diagrams, on the color.js gamut mapping page. In that code, deltaE2000 is used with a threshold of 2. It made a huge difference and eliminated the spurious, ultra-low-Chroma results we were seeing with the more straightforward methods.

@svgeesus
Copy link
Contributor Author

svgeesus commented Oct 21, 2020

These two are now done:

  • whether negative values and values greater than 1.0 or 100% are allowed (they are, and are not invalid; rgb() already allows them)
  • when and where negative values (out of gamut colors) are dealt with

@svgeesus
Copy link
Contributor Author

The specification doesn't say how out-of-range values for profiled colors are handled. Are they clamped to their valid range or does an out-of-range value make the color invalid?

The specification now defines this.

For custom colorspaces, defined by an ICC profile, specified out of range values are simply clamped to the valid range at computed value time. This is because the ICC profile will not allow the out of range values as input, so this is all that can be done.

For predefined colorspaces, which have a mathematical definition of the transfer function, specified out of range values are gamut mapped using a relative colorimetric intent, at used value time.

A new section describing relative colorimetric chroma reduction with speculative clamping will be added as an appendix.

Handling of specified values which are in gamut for the specified colorspace, but out of gamut for the display device, will also be covered in the gamut mapping section. Again, relative colorimetric will be used.

@svgeesus
Copy link
Contributor Author

There is already an open issue on gamut mapping so the clamping issue is now closed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
Blink Issue Triage
  
No Action Yet
Development

No branches or pull requests

4 participants