mm2 / Little-CMS

A free, open source, CMM engine. It provides fast transforms between ICC profiles.
https://www.littlecms.com
MIT License
571 stars 176 forks source link

ICC profile with CICP tag #439

Open jonsneyers opened 8 months ago

jonsneyers commented 8 months ago

I might be missing something, but it looks like lcms2 is currently not using the information in the CICP tag.

When I am saving HDR images from Adobe Camera Raw, it includes an ICC profile with curves that hard-clip the HDR headroom, mapping everything brighter than SDR white to 1. It also includes a CICP tag that describes the 'real' transfer curve (e.g. PQ). When using lcms2 to do color conversions with such profiles, it uses the curves as a transfer function, not the transfer function of the CICP tag. This means that e.g. converting an image to linear and back is now a very lossy operation that introduces bad artifacts.

Am I missing something? Is there an API option to make it give precedence to the CICP tag info? If not, having such an option would be great, and it probably should be enabled by default. The ICC 4.4 spec says the information in the CICP tag shall be equivalent to the information in the profile, so technically the profiles embedded by Adobe Camera Raw are not conforming, but I think it would make sense if lcms2 would in that case choose to believe the CICP tag and not the fallback curves which I think are only there to make applications that don't know about the CICP tag do something somewhat sensible.

mm2 commented 8 months ago

This tag is purely informative. Is a flag for capable software to discard the profile and use its own HDR color management. The profile is a simplification for ICC workflows like lcms2.

jonsneyers commented 8 months ago

The question is what to do when the tag doesn't match the profile. In this case the tag describes the actual color space while the profile implements some kind of destructive hard-clipping tone mapping that you don't want to apply when you're processing an image...

mm2 commented 8 months ago

If the profile is wrong, there is nothing lcms can do. Right now, providing a different color manager that switches and replaces the ICC one when a certain tag is found is out of the scope of this library.

jonsneyers commented 8 months ago

Technically, if the profile is wrong, lcms can do anything and still be a conforming implementation of the ICC spec :)

The ICC spec doesn't say what should take precedence in case of conflict between the CICP transfer function and the curves in the profile (it should says there shall not be such a conflict). Applications like Chrome let CICP take precedence, lcms2 lets the profile curves take precedence. Both are technically OK since they're dealing with a technically wrong profile, but if these profiles occur in the wild (Adobe software does produce them), it's a bit less than ideal that we're getting diverging behavior. The whole point of color management is to ensure consistency, after all.

mm2 commented 8 months ago

It is not a matter of precedence, the CICP tag is saying "discard all this profile and use other standards instead". Current implementation of lcms does not do this. It would require to write a new CMM for HDR.

jonsneyers commented 8 months ago

The CICP tag basically just describes primaries and a transfer function, which is something lcms can already handle just fine, no?

mm2 commented 8 months ago

Unfortunately it is not so easy. There is a database of primaries and functions, the chromatic adaptation, gamut mapping, intents, highlight handling for floating point and testbeds. Could easily take 4-5 months of development. Without a clear business case, this is a no way.

butcherg commented 8 months ago

A better question might be, "How do I use little CMS to do this thing I need to do?" There may be a sequence of API calls for you to use to do the replacement.

jonsneyers commented 8 months ago

The only things that are used in practice right now, as far as I can tell, are three sets of primaries (sRGB, P3 and Rec2020) and three transfer curves (sRGB, PQ and HLG).

I am not talking about dealing with tone mapping or any other tricky stuff. All I'm trying to do is convert to linear RGB and back, using the proper transfer curve (the one signaled in CICP) and not the clipping one that is given in the ICC profile curves. I guess I could manually parse the CICP tag (like what libjxl does, for example) and then construct a corresponding lcms profile from it using the primaries and transfer function, but I was hoping there's already an lcms function or option to do just that.

butcherg commented 8 months ago

The cICP tag is pretty simple, a set of four uint8 values that provide for enumerations of various primary and trc definitions specified in ITU-T Rec H.273 (ref: ICC.1-2022-05). So, why would you only want to replace the LittleCMS TRCs, why not also the primaries?

BTW, found a decent discussion on this at the ColorWeb-CG repo: https://github.com/w3c/ColorWeb-CG/issues/18

jonsneyers commented 7 months ago

In the example I have, the primaries in the main part of the profile are identical to the ones signaled in the CICP tag of the profile, but yes, it would make sense to take both the primaries and the transfer curves from the CICP tag.

To be clear: I am not talking about the cICP chunk in PNG files (which is quite similar but not the same thing), I am talking about the cicp tag in ICC v4.4 profiles.

In the PNG spec, it's clear what takes precedence: if there is a cICP chunk, it takes precedence over the ICC profile (https://www.w3.org/TR/png-3/#cICP-chunk).

In the ICC spec though, no precedence rules are specified (and conforming profiles should not contain conflicting tags). Currently, lcms just ignores the information given in the CICP tag, I think, or at least in case of conflict, does not give it precedence.

mm2 commented 7 months ago

Currently, lcms just ignores the information given in the CICP tag, I think, or at least in case of conflict, does not give it precedence.

In 2.16 you can use cmsReadTag to get a cmsVideoSignalType structure. Then is up to you to use cmsCreateRGBProfile or use the original profile. Using a simple matrix-shaper is in general a bad idea if you want intents, gamut mapping and precision. And cmsCreateRGBProfile only gives you a matrix-shaper. A good profile may have BToDxx tags that operates on highlights much better than a simple matrix shaper. But at that level, the CMM has no way to know if the profile is good or not, so reverting to a matrix shaper would at least risky.

jonsneyers commented 7 months ago

It would be convenient to have something like cmsCreateRGBProfileFromVideoSignalType.

I guess there are two ways in which the profiles embedded in HDR images are used: one is describing how to render the image nicely on an SDR display, the other is describing the actual colorspace of the image data (e.g. Rec.2100 PQ). It depends on the application which of these two things is relevant.

mm2 commented 7 months ago

I am adding you suggestion to the wish list. Could I close this as it is not a bug?