w3c / csswg-drafts

CSS Working Group Editor Drafts
https://drafts.csswg.org/
Other
4.47k stars 658 forks source link

[css-color] "device-cmyk" restrictions are counter-productive #2022

Closed faceless2 closed 4 years ago

faceless2 commented 6 years ago

I think the way device-cmyk is defined could be improved. I note there is a comment in the current draft:

RESOLVED: If you accurately describe the output device’s color profile in an @color-profile rule then a sane implementation will not alter your colors so this is sufficient as a replacement for device-cmyk in general and provides a good RGB fallback automatically.

Which seems to be missing some detail about this process, and still makes some assumptions about the implementation.

Currently the author of a CSS stylesheet wanting to use CMYK has three choices.

  1. Abandon device-dependent CMYK and always specify CMYK with color() and an ICC profile
  2. Use device-cmyk() but define a corresponding RGB (or convertable-to-rgb) value as a fallback color (effectively doing the job of an ICC profile themselves)
  3. Use device-cmyk() and hope the "...user agent has information about the output device such that it believes it can accurately convert the CMYK color to a correct RGB color...", and if not, make do with the CMYK to RGB conversion of the "naive CMYK" colorspace. A space which resembles no real-world device.

This wording is quite restrictive; if I am opening the file in a typical web browser, I don't have any particular information about a CMYK output device, so am required to use the naive colorspace. There is no middle-option, where the user-agent (or CSS author) may choose a typical profile, on the understanding it may be substituted when output to a particular CMYK device.

Device-dependent CMYK color is important; not every workflow is calibrated, and not every document author knows the target device. But even without any specific target device in mind results should resemble a typical printer, which the naive conversion does not.

This can be achieved with more flexibility, and less user-agent restrictions or magic, by changing the way the fallback is calculated. Something like:

If a CMYK color is specified and the user agent can natively output CMYK, the CMYK values should be used exactly as specified. Otherwise, if no fallback color is defined, the "device-cmyk" @color-profile will be used to convert to RGB. If no "device-cmyk" @color-profile" is defined, or it is defined but is not a CMYK ICC profile, then the naive conversion is used.

This removes the restrictions (and implied magic) about the user-agent having information about the output device. Instead, a user-agent might define something like

@color-profile device-cmyk { src: url(swop.icc) }

in the user-agent stylesheet as a reasonable default. The CSS author doesn't care and simply defines

color: device-cmyk(100% 80% 50% 0)

in their stylesheet, knowing that most user agents have a reasonable default and the naive conversion is unlikely to occur; and the user displaying the CSS, if print-previewing for a specific device, can override this by specifying a user-stylesheet with

@color-profile device-cmyk { src: url(myprinter.icc); }

Effectively device-cmyk(c m y k) is now identical to color(device-cmyk c m y k), but with two provisions: that any "device-cmyk" @color-profile rule is ignored if the device can natively output CMYK, and that the naive colorspace will be used if no "device-cmyk" @color-profile rule exists.

Finally, it may be that what I'm describing is largely what the aforementioned "sane implementation" is supposed to do for any CMYK profile specified - it's not clear from the "RESOLVED" section from the spec quoted at the top of this post, and I cannot find discussion of this point.

If so I'm not sure that's wise. A device-independent, ICC based colorspace defined by the document author should not be ignored in a color managed workflow, sane or otherwise; it should be preserved all the way through to conversion to PDF (our area of expertise) or when printing. This is very distinct from an unmanaged CMYK space. There is no need at all for that distinction to be discarded.

tabatkins commented 6 years ago

I think this distills down to just "the author should be able to provide the 'naive CMYK' colorspace on their own, so they can provide a better guess at the conversion when the UA has to do fallback, but will get real device-dependent CMYK when possible", right?

If so, this sounds reasonable to me, and the plan of blessing a particular color-profile name also seems reasonable. @svgeesus?

svgeesus commented 5 years ago

Related: Converting Between Uncalibrated CMYK and RGB-Based Colors, and Device cmyk still needed?

svgeesus commented 5 years ago

"Used exactly as specified" is fine for flat colors. It doesn't cope with the following:

which all need to convert the supplied parameters to an actual measured color, in Lab or XYZ or sRGB or some other color space. The problem with device-cmyk is that it is a recipe, not a color specification.

svgeesus commented 5 years ago

A device-independent, ICC based colorspace defined by the document author should not be ignored in a color managed workflow, sane or otherwise; it should be preserved all the way through to conversion to PDF (our area of expertise) or when printing. This is very distinct from an unmanaged CMYK space. There is no need at all for that distinction to be discarded.

I agree that these are completely distinct, and that any ICC based colorspace defined by the document author should not be discarded. The spec should not imply that it is ever discarded. But I don't see anything in the ICC (Calibrated color) section implying tha it would be discarded. Except for the inline issue, which I just removed as it is just a static inlining of #301.

svgeesus commented 4 years ago

Coming back to this, and specifically the idea that device-cmyk should be defined with an @color-profile in the user-agent stylesheet, this is now slightly complicated by the otherwise good resolution to https://github.com/w3c/csswg-drafts/issues/4654 which put predefined colorspaces and author-defined colorspaces into two disjoint groups, the latter using the new dashed-ident production.

However, the general idea still has merit and would be an improvement over the rather handwavy prose that sometimes magically turns a device-dependent formulation into an actual color.

On a related note there are now some examples in the spec about using color() with CMYK, with both FOGRA (Europe, UK) and SWOP (US). Which led me once again to the idea if defining how device-cmyk works in a similar manner.

faceless2 commented 4 years ago

The new examples are great, even though I'm not entirely sold on the double hyphens. Yes, the syntax makes it a bit more complex, but it's easy enough to carve out an exception for device-cmyk if required. I'm no longer sure that it is.

My only real concern is this requirement to use the "naive algorithm" for rendering. It will result in authors avoiding device-cmyk, because it looks awful when previewed in a browser.

With two years of hindsight on this issue, I think simply allowing browsers to choose an arbitrary profile for device-cmyk, instead of being forced to use the naive algorithm, is the best solution. Yes, it will make the results vary from browser to browser - that's what you'd expect from device-dependent CMYK.

Allowing an author to "redefine" device-cmyk to another space is less important - they can, of course, just use the color() function if they care that much about it.

svgeesus commented 4 years ago

My only real concern is this requirement to use the "naive algorithm" for rendering. It will result in authors avoiding device-cmyk, because it looks awful when previewed in a browser.

Mine too. I'm wanting to reword so that the naive conversion is used as little as possible, only after other things have gone wrong.

Related, I worked yesterday on an example for the spec. I took the Lab values for the Macbeth color checker, converted them to sRGB (for two patches, I had to go to LCH then reduce C until the result was inside sRGB gamut). Then I am also running the Lab values through a CMYK profile (PSOcoated_v3 from ECI, which uses the FOGRA51 characterization data) then naively converting the CMYK to sRGB. This shows the magnitude of the error on some real-world colors.

With two years of hindsight on this issue, I think simply allowing browsers to choose an arbitrary profile for device-cmyk, instead of being forced to use the naive algorithm, is the best solution. Yes, it will make the results vary from browser to browser - that's what you'd expect from device-dependent CMYK.

Agreed.

svgeesus commented 4 years ago

Related: https://github.com/w3c/csswg-drafts/issues/3449

tabatkins commented 4 years ago

I mean, feel free to put in a better conversion rule than the "naive" one. I just needed some way to convert it to a compatible color, and that method is trivial and roughly works.

svgeesus commented 4 years ago

I added a couple of figures, one showing the accuracy of Lab --> CMYK --> Lab --> sRGB conversion and one showing the results of Lab --> CMYK --naive--> sRGB.

svgeesus commented 4 years ago

Currently, @color-profile is defined to use a dashed-ident (--foo):

@color-profile = @color-profile <dashed-ident> { <declaration-list> }

https://drafts.csswg.org/css-color-4/Overview.html#at-profile

Now, if I modify this to

@color-profile = @color-profile [<dashed-ident> | 'device-cmyk'] { <declaration-list> }

then I can allow the UA stylesheet, or author stylesheet, or even the user stylesheet, to have whatever they want used as a default:

@color-profile device-cmyk {
  src: url('https://example.org/Coated_Fogra39L_VIGC_300.icc');
}

and the somewhat hand-wavy and aspirational prose:

If the user agent has information about the output device such that it believes it can accurately convert the CMYK color to a correct RGB color, the computed value of the device-cmyk() function must be that RGBA color. Otherwise, the computed value must be the fallback color.

and

Ideally, the user agent will be aware of the output device’s color profiles for RGBA and device-CMYK. If this is true, then the user agent must convert between device-CMYK and RGBA colors (and vice versa) by first converting the color into an appropriate device-independent color space, such as CIELab, and then converting into the output color space, using the appropriate color profiles for each operation.

This is not always possible, however. In that case, the user agent must use the following naive conversion algorithms.

can be replaced with something clearer, like

If a valid @color-profile rule is available for device-cmyk, the computed value of the device-cmyk() function must be that CMYK color converted to Lab. Otherwise, (if the profile cannot be retrieved or understood) and a fallback color is present, the computed value of the device-cmyk() function must be that fallback color. If no valid fallback color is specified, the computed value of the device-cmyk() function must be that CMYK color naively converted to sRGB.

This gives a clear, ordered list of ways to compute an actual color which can be used in compositing, gradients, and so forth. It also does not constrain the CMYK colors to fall in a particular RGB space (except for the naive conversion, which produces sRGB). And it means that in many cases, people using device-cmky will get usable, reasonable on-screen colors; not necessarily as good as calibrated soft-proofing, but at least useful.

svgeesus commented 4 years ago

I mean, feel free to put in a better conversion rule than the "naive" one. I just needed some way to convert it to a compatible color, and that method is trivial and roughly works.

What you have is traditional, and fine as far as it goes. I'm just rewording to limit the cases in which it needs to be used.

faceless2 commented 4 years ago

Your solution looks great to me.