Closed jpap closed 3 years ago
Unfortunately this breaks gamut check, gamut warning, cache and uses a flag bit that is already used in yet existing extensions. Please see an alternative way, by using a formatter plug-in (as described in issue #276)
On the other hand, you should get same results as using integers on input. Unbounded mode is used when input values are out of bounds. If you have a sample that gives different output, please let me know.
Thanks for the quick review. The update:
IntFloatXFORM
for the Int->float transform path.Removes the opt-in flag cmsFLAGS_UNBOUNDED_INT_INPUT
. The int->float path is now only taken when clipping is not chosen (cmsFLAGS_NONEGATIVES
not set), the input format is integer, and the output format is float.
This means that when the output is integer, the same int->int path is taken as it always has. When clipping is requested and the output is float, the existing integer path is still taken, making use of the pixel cache when available.
The opt-in flag cmsFLAGS_UNBOUNDED_INT_INPUT
was previously introduced simply out of an abundance of caution and it isn't really needed: it makes sense to have removed it.
Unbounded mode is used when input values are out of bounds.
It is also useful for computing "extended range" output when the input values are within bounds.
For example, Apple uses an extended range sRGB 16bit half-float pixel format for rendering Display P3 content to their wide-gamut color displays. The deepest red in Display P3 (1.0000, 0.0000, 0.0000) maps to (1.0930, -0.2267, -0.1501) in extended sRGB.
I can generate an image in such a format by transforming (RGBA int 8bpc Display P3 colorspace) to (RGBA float 16bpc sRGB colorspace). Without this PR, lcms maps the deepest red in Display P3 RGBX = (255, 0, 0, X) to sRGB value (1.0000, 0.0000, 0.0000, X) which is incorrect. However, if I were instead to use lcms to transform Display P3 RGBX = (1.000, 0.000, 0.000, X) using a floating point format for the input, lcms yields the correct value of (1.0930, -0.2267, -0.1501, X) in the output image.
This looks like a bug because cmsFLAGS_NONEGATIVES
is not set and I get different results depending on the input format. It is for this reason that I suggest this PR be merged into lcms core, rather than use a formatter plug-in workaround.
In Unbounded Color Engines, you write,
If a color transform is setup by using exclusively this kind of profiles, and floating point is used as input and output format, there are no constrains and the color transform is not limited by any bounds. We would name this special mode as unbounded CMM.
and is exactly what has been implemented in lcms. However I would argue that unbounded should only be conditioned on the output format: when the output format is floating point, the "unbounded" mode is still relevant when the input is integer: it is the only way to compute the "extended range" color values used by Apple above.
I see the distinction between "bounded" and "unbounded" CMM as just whether you want to optimize the CMM intermediate values to avoid overflow, maximize dynamic range, and/or adhere to the constraints of a color profile (e.g. those using tables): the desired end result should be the same. If the final result is desired to be in a range outside of [0, 1] or [0, 2^n), like {16, 32}-bit float, or [-2, 2], or even fixed-point Q2.14, then the entire pipeline should carry the required amount of precision throughout, limited only by the constraints of the profiles involved. I really appreciate all the hard work you've done over the years to bring up a floating point pipeline -- I'm not asking for anything more!
If you have a sample that gives different output, please let me know.
The above example shows lcms giving different results when the input and output formats are float, vs. the input being integer (and output float). This is no surprise: the floating-point transform is only enabled in AllocEmptyTransform
when both input and output formats are float.
I hope you're able to have another look at the updated PR.
Already solved by 195c218dd3c8338e12563c9641ef89f84cc6f6b4 Thanks
However I would argue that unbounded should only be conditioned on the output format: when the output format is floating point, the "unbounded" mode is still relevant when the input is integer: it is the only way to compute the "extended range" color values used by Apple above.
I fully agree. This is now the default behaviour. Thanks for the idea!
So, following this discussion, I'd surmise that any formatter (Table 37 in the API doc) that ends in FLT or DBL used as the OutputFormat parameter in any of the cmsCreateTransform*() functions will produce an unbounded result... ?
BTW, in Table 37 there are a few integer formatters lurking at the end of the "Floating point" list on page 78...
So, following this discussion, I'd surmise that any formatter (Table 37 in the API doc) that ends in FLT or DBL used as the OutputFormat parameter in any of the cmsCreateTransform*() functions will produce an unbounded result... ?
Yes, I have taken my time to think about this, and now I believe this is the right behaviour. Just imagine this example: you do a transform from AdobeRGB in 8 bits to sRGB in floats. Then you feed the transform with some flourescent green like (12, 253,20). This is on AdobeRGB gamut but outside any reasonable gamut. Even Lab is pushed to its limits. By this color. Anyway, what would you expect on output? Since you choose floats, you can handle negative or highlight values. Then you still can use the non-negatives flag or clip highlights if you want. Much better that getting results clipped to 0..1.0, which you can always get by using integer types on output. Any thoughts?
BTW, in Table 37 there are a few integer formatters lurking at the end of the "Floating point" list on page 78...
Thanks! I will fix that ASAP
Makes perfect sense to me; any calculation to a float destination should not be bounded by data container or even black/white constraints. My software doesn't do integer->float transforms, as I translate whatever image input to float for subsequent internal use, including color transforms.
Verified 195c218dd3c8338e12563c9641ef89f84cc6f6b4 also fixes the problem.
Fixes #276.