Better Gamutmapping
So, right now, we convert via LittleCMS. LittleCMS follows the ICC spec, and thus it has 4 intents available, (with some extra intents for CMYK color spaces): 1. Perceptual: This should scale the color-ranges that are out of gamut so that the contrasts are preserved. 2. Saturation: Similar to perceptual, except perceptual tries to not move colors unless necessary, saturation does. Similar issues as perceptual. 3. Absolute colorimetric: This *should* not try to do any white point adaptation, and just convert colors between two spaces, clipping out of gamut colors. 4. Relative colormetric: This should first do whitepoint adaptation, and then convert colors colors, clipping out of gamut. A. So, the first two are a bit weird: while Perceptual is marked as the preffered intent by the ICC, it only works if there's a perceptual LUT inside the ICC profile. Same thing for Saturation. And it gets even weirder: Said LUT is usually only for one given colorspace to another. Greame Gill [suggests](https://www.argyllcms.com/doc/iccgamutmapping.html) that it might be better if such a LUT was generated on the fly, and it might be more better if it were done on an [image-by-image basis](https://www.argyllcms.com/doc/Scenarios.html#LP3), because it is unlikely an image uses the full gamut of its associated colorspace. B. The last two are weird in different ways. Absolute Colorimetric, for some weird ICC-spec reason, works the exact same way as Relative Colormetric. This is because LittleCMS follows the ICC spec. LittleCMS also offers "setAdaptationState" to actually make Absolute Colorimetric work like it should. This latter is implemented for Softproofing, but we can also implement it for regular transforms. C. Right now, clipping in the colorimetric transforms is done by transforming from colorspace A to colorspace B and then bounding the colors in colorspace B to [0 1.0]. This is not the best way to do clipping, in particular in LABlikes this leads to weird distorted colors when they're out of gamut. A better way would be to do proper gamut mapping. LittleCMS seems to [avoid this](https://github.com/mm2/Little-CMS/issues/221), because the ICC way is to uh, use the LUT inside the profile... even though a matrix shaper by definition lacks this. This is somewhat annoying, as specs like [CSS-color-4](https://www.w3.org/TR/css-color-4/#css-gamut-mapping) and rec2100 require gamutmapping for the clipping, in (ok)LCH and ICtCp respectively. *What I'm most worried about is that we have a set of toggles that do nothing for 3 out of 4 intents (CMYK profiles are the only ones that commonly have LUTs), and toggles that do nothing are bad UX*. Solutions --------- For B. I suggest we remove Absolute Colorimetric from the list of intents in the dropdown, rename Relative Colormetric to "Colorimetric", and instead add an adaptation slider: If the adaptation is 0 its relative colorimetric, above 0, absolute colorimetric. Internally, ICC profiles only contain "Colorimetric" luts, so we aren't losing access to some secret Absolute Colorimetric with 0 adaptation code flow with this. Similarly, we should probably make Relative Colorimetric the default everywhere, as it apparantly already is. For C and A, because any improvement in this area is going against the ICC spec, it is probably best that it is user-configurable. Probably something like giving an option between the kinds of spaces we can gamut map in, and an option to just use whatever the ICC profile allows. We should probably then disable the intents the profile cannot handle if it doesn't have the required LUTs. For C in particular, Gamut-mapping-based-clipping is handled by first converting into a specific colorspace(typically a LAB-like for bounded spaces, and REC2100 would prefer it be done in ICtCp), and then using its polar form, so that hue, lightness and saturation are known. Then the saturation is adjusted until the color is in-gamut for the destination colorspace. This is probably best done with a LUT, and we could technically generate one on the fly with ICC device-links (pipelines in LittleCMS), question is how to avoid them taking up too much memory. Once we can figure out C, we can eventually figure out A as well, though that will take a lot more research on how to tackle that properly. I double-checked whether we had anything about this on Phab, but couldn't find anything. ![image](/uploads/f3674b3ddb9a94bcb8916f68f64edbbf/image.png){width=450 height=300} Above, two sets of three lab squares, at 75%, 50% and 25% L* respectively. The top is current behaviour, the bottom is an estimation of what gamutmapping might look like, done by first using out-of-gamut warnings to extract the sRGB area, and then using G'Mic Solidify(which causes the weird banding) filter to fill in the resulting transparent bits. Notice that at the top, the high-chroma colors being clipped actually results in uneven lightness, which is removed at the bottom.
issue