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

[filter-effects] Allow intermediate negative colour values #221

Closed
ConradIrwin opened this Issue Sep 6, 2017 · 9 comments

Comments

Projects
None yet
5 participants
@ConradIrwin

ConradIrwin commented Sep 6, 2017

ref. https://www.w3.org/TR/SVG11/filters.html#feColorMatrixElement

I'm trying to invert the colour of a page (white background -> black background) but preserve the color of images. A naive solution is to do this:

body {
  filter: invert(1) hue-rotate(180deg);
}
img {
  filter: hue-rotate(180deg) invert(1);
}

But this doesn't quite work because the channel outputs of the first hue-rotate is truncated to [0..255], this causes the two hue-rotates (which should be a no-op) to lose information.

@dirkschulze

This comment has been minimized.

Show comment
Hide comment
@dirkschulze

dirkschulze Dec 23, 2017

Contributor

@ConradIrwin That is correct, because of the truncation you'll loose information. Also, hue-rotate is done in the RGB color space which is the main issue here. For compatibility reasons this can not be changed anymore.

Contributor

dirkschulze commented Dec 23, 2017

@ConradIrwin That is correct, because of the truncation you'll loose information. Also, hue-rotate is done in the RGB color space which is the main issue here. For compatibility reasons this can not be changed anymore.

@AmeliaBR

This comment has been minimized.

Show comment
Hide comment
@AmeliaBR

AmeliaBR Jan 16, 2018

Some filter effects rely on the fact that values are clamped after each operation.

It is harder to create out-of-range channel values with the shorthand filters than with SVG filters, but you can still do it. The contrast filter is the only one that can create negative out-of-range values. What you're actually seeing with hue-rotate is too-high out-of-range values (greater than 255 when converted to RGB). Blown-out highlights like that can also be created with brightness and sepia filters.

Here's an example of a filter effect that relies on contrast() values getting clamped:

https://codepen.io/AmeliaBR/pen/zpJwYX?editors=0100

The real issue with the code @ConradIrwin posts is that the hue-rotate() filter is designed to preserve luminance while changing hue, and different hues have different potential luminance ranges within the RGB gamut. So when you rotate from a bright green to a blue hue, there is no way for blue to be as bright (by luminance measure) as the green was.

The preserve-luminance adjustments are confusing in other situations, like trying to use hue-rotate to match an hsl() color (hsl() uses "lightness", not "luminance", treating the RGB channels equally; it's gamut directly matches the RGB gamut).

Ideally, there would be an extra parameter to hue-rotate to switch it to preserve "lightness" instead of "luminance":

filter: hue-rotate(180deg lightness)

Since this would a new feature, instead of a change to default behavior, it could be added in a future level of the spec if there is sufficient interest.

AmeliaBR commented Jan 16, 2018

Some filter effects rely on the fact that values are clamped after each operation.

It is harder to create out-of-range channel values with the shorthand filters than with SVG filters, but you can still do it. The contrast filter is the only one that can create negative out-of-range values. What you're actually seeing with hue-rotate is too-high out-of-range values (greater than 255 when converted to RGB). Blown-out highlights like that can also be created with brightness and sepia filters.

Here's an example of a filter effect that relies on contrast() values getting clamped:

https://codepen.io/AmeliaBR/pen/zpJwYX?editors=0100

The real issue with the code @ConradIrwin posts is that the hue-rotate() filter is designed to preserve luminance while changing hue, and different hues have different potential luminance ranges within the RGB gamut. So when you rotate from a bright green to a blue hue, there is no way for blue to be as bright (by luminance measure) as the green was.

The preserve-luminance adjustments are confusing in other situations, like trying to use hue-rotate to match an hsl() color (hsl() uses "lightness", not "luminance", treating the RGB channels equally; it's gamut directly matches the RGB gamut).

Ideally, there would be an extra parameter to hue-rotate to switch it to preserve "lightness" instead of "luminance":

filter: hue-rotate(180deg lightness)

Since this would a new feature, instead of a change to default behavior, it could be added in a future level of the spec if there is sufficient interest.

@ConradIrwin

This comment has been minimized.

Show comment
Hide comment
@ConradIrwin

ConradIrwin Jan 16, 2018

@amiliabr, thanks for the simple explanation! I'd love to have a hue-rotate that preserves lightness (or is invertible in some way).

ConradIrwin commented Jan 16, 2018

@amiliabr, thanks for the simple explanation! I'd love to have a hue-rotate that preserves lightness (or is invertible in some way).

@svgeesus

This comment has been minimized.

Show comment
Hide comment
@svgeesus

svgeesus Jan 17, 2018

Contributor

Some filter effects rely on the fact that values are clamped after each operation.

Yes. One way past this would be to use CSS4 Color Working Colorspace, whose initial value will be sRGB. Switching to another colorspace would mean that the computed colors are no longer out of gamut and thus, not clamped. Lab would be one example.

Contributor

svgeesus commented Jan 17, 2018

Some filter effects rely on the fact that values are clamped after each operation.

Yes. One way past this would be to use CSS4 Color Working Colorspace, whose initial value will be sRGB. Switching to another colorspace would mean that the computed colors are no longer out of gamut and thus, not clamped. Lab would be one example.

@AmeliaBR

This comment has been minimized.

Show comment
Hide comment
@AmeliaBR

AmeliaBR Jan 17, 2018

@svgeesus
That's a good point. Maybe the wording could be changed to say that values are clamped to the gamut of the working color space after each operation, rather than specifying particular channel values for clamping.

But that can probably wait until a future version of the spec, once the working color space syntax and behavior has been figured out.

AmeliaBR commented Jan 17, 2018

@svgeesus
That's a good point. Maybe the wording could be changed to say that values are clamped to the gamut of the working color space after each operation, rather than specifying particular channel values for clamping.

But that can probably wait until a future version of the spec, once the working color space syntax and behavior has been figured out.

@svgeesus

This comment has been minimized.

Show comment
Hide comment
@svgeesus

svgeesus Jan 17, 2018

Contributor

But that can probably wait until a future version of the spec

Yes.

Contributor

svgeesus commented Jan 17, 2018

But that can probably wait until a future version of the spec

Yes.

@smfr

This comment has been minimized.

Show comment
Hide comment
@smfr

smfr Jan 24, 2018

I don't think we can allow negative color values here; that would require the UA to store unclipped sRGB in all the intermediate buffers (including composting code paths in other graphics libraries on the system). This isn't realistic until all OSes have some kind of deep color support.

smfr commented Jan 24, 2018

I don't think we can allow negative color values here; that would require the UA to store unclipped sRGB in all the intermediate buffers (including composting code paths in other graphics libraries on the system). This isn't realistic until all OSes have some kind of deep color support.

@svgeesus

This comment has been minimized.

Show comment
Hide comment
@svgeesus

svgeesus Jan 24, 2018

Contributor

until all OSes have some kind of deep color support.

Right. Which they don't now, but that is the direction they are all headed.

Contributor

svgeesus commented Jan 24, 2018

until all OSes have some kind of deep color support.

Right. Which they don't now, but that is the direction they are all headed.

@dirkschulze

This comment has been minimized.

Show comment
Hide comment
@dirkschulze

dirkschulze Jan 25, 2018

Contributor

To summarize: We agree that we will need CSS Color to proceed and define "working colorspace", either have a new filter function or extend hue-rotate() with a keyword but defer the definition of the new filter function or keyword and the decision about either one to a future version of the specification. If there is no objection I'd like to close this issue as deferred.

Contributor

dirkschulze commented Jan 25, 2018

To summarize: We agree that we will need CSS Color to proceed and define "working colorspace", either have a new filter function or extend hue-rotate() with a keyword but defer the definition of the new filter function or keyword and the decision about either one to a future version of the specification. If there is no objection I'd like to close this issue as deferred.

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