Colour management - intents (997 Bytes)
After the discussion in Comparing filmic color science v5/v6 and GitHub issues/discussions like, I’ve decided to check what

  • darktable, applying the output profile
    – using its own colour management
    – via LCMS2
  • LCMS2
  • Argyll

do when facing out-of-gamut colours (converting an image from a large colour space to a more limited one).

I’ve made a simple ‘colour ramp’, going from quite low saturation up to full, for each of red, yellow, green, cyan, blue.
color-ramp-rec2020-g10.tif (32.4 KB)

The image has Elle’s Rec2020 linear (‘Gamma = 1.0’) profile embedded.

I then opened it in darktable; set the monitor, soft-proofing and histogram profiles all to linear Rec709, and selected two areas: one, where the Rec709 values exceeded 255; another, when one of them went negative.

I exported the image from darktable with all rendering intents; I then repeated the process after telling darktable to use LCMS to apply the output profile.

On the command-line, I used tificc (from LCMS) and cctiff (from Argyll) to convert the Rec2020 ramp to ‘sRGB linear’ (sRGB uses the same primaries as Rec709). I used a script to iterate through the rendering intents for each; for LCMS, which supports V4 profiles, I repeated the process using Elle’s V4 profile for output. The conversion script is attached with a .txt suffix.

Finally, I compared all output files using GraphicsMagick’s gm compare tool.
For example, this command compares the results of the different intents in Argyll:
for i in p s r ; do gm compare -metric mse color-ramp-rec2020-g10.tif-argyll-sRGB-g10-ia.tif color-ramp-rec2020-g10.tif-argyll-sRGB-g10-i$i.tif ; done

So, the results (may be valid for this particular image only):

  • it does not matter if LCMS or darktable’s own method was used for export, the output was identical;
  • it does not matter which rendering intent was used in darktable, the output was identical;
  • Argyll also produced the same output for each rendering intent;
  • and so did LCMS, regardless of the V2 or V4 output profile.

The output from Argyll and darktable were the same (if I used Elle’s linear sRGB profile); there was a tiny mismatch (due to subtle differences in the profiles) if I used the built-in linear Rec709:

$ gm compare  -metric mse argyll.tif dt.tif 
Image Difference (MeanSquaredError):
         Normalized    Absolute
        ============  =========
   Red: 0.0000000001        0.0
 Green: 0.0000000000        0.0
  Blue: 0.0000000001        0.0
 Total: 0.0000000001        0.0

LCMS differed from the other two:

$ gm compare  -metric mse argyll.tif lcms.tif 
Image Difference (MeanSquaredError):
           Normalized    Absolute
          ============  ==========
     Red: 0.0000005761        0.0
   Green: 0.0000011243        0.1
    Blue: 0.0000002813        0.0
   Total: 0.0000006605        0.0

Exaggerated differences in the Gimp:

One of the questions was what happens when we go out of gamut: do we get a reasonable compression/management, or are we simply clipping?

A red pixel that read > 100% in darktable’s darkroom (for easier comparison, I multiplied the RGB values by 256, as in the Gimp I got 16-bit readings). This is at Y=419 in the TIF, when opened in Gimp (note that I got the darkroom green simply by multiplying 2 by 256, so it’s not reliable; if I convert the Rec2020 value to linear sRGB in the Gimp, I get 0.006354, which corresponds to the reading of 416 that Argyll produced):

Rec2020:   RGB: 46˙310,  5˙501, 5˙501; HSV: 346.10, 93.00, 105.00
Rec709 values:
darkroom:  RGB: 72˙960,    512, 4˙864; HSV: 356.42, 99.40, 111.65
dt export,
 & Argyll: RGB: 65˙535,    416, 4˙761; HSV: 345.40, 92.70, 100.00
LCMS:      RGB: 65˙535,    733, 4˙761; HSV: 347.10, 89.30, 100.00

An even more saturated red, with a negative Rec709 green component, at line 463 in the original TIF (a conversion in Gimp yields a green value of -0.037803, or -2477; the darkroom value shown below comes from multiplying the darkrooms -10 reading by 256):

Rec2020:   RGB: 52˙793,  3˙646, 3˙646; HSV: 333.40, 143.50, 112.20
Rec709 values:
darkroom:  RGB: 84˙736, -2˙560, 2˙816; HSV: 356.42, 102.87, 129.90
dt export,
 & Argyll
 & LCMS:   RGB: 65˙535,      0, 2˙754; HSV: 346.40, 100.00, 100.00

100% Rec2020 red:

Rec2020:   RGB: 65535,      0,      0; HSV: 331.10, 229.00, 124.80
darkroom: RGB: 108˙288, -8˙192, -1280;  HSV: 356.42, 107.50, 166.05
dt export,
 & Argyll
 & LCMS:   RGB: 65˙535,      0,    0;  HSV: 346.40, 100.00, 100.00

So, with the negative values we simply get clipping. Most probably that is also what happens for values > 100%.

ps. The profiles are from Elle Stone. See Elle Stone's well-behaved ICC profiles and code or download from elles_icc_profiles/profiles at master · ellelstone/elles_icc_profiles · GitHub


Hi @kofa, thank you for sharing this experiment. Color management and ICC profiles are confusing so it makes sense to probe things like this to gain an understanding.

Personally I kind of expected this result. Elle Stone’s profiles from the repo you linked are matrix profiles and as such don’t contain any intent look-up tables (LUTs). It is also stated on Elle’s page:

As a very relevant aside, using perceptual intent when converting to sRGB for photographic image editing does not magically makes otherwise out of gamut colors fit inside the sRGB color gamut! The standard sRGB color space (along with all the other the RGB profiles provided in my profile pack) is a matrix profile, and matrix profiles don’t have perceptual intent tables.

There’s a special v4 sRGB profile available from ICC here that contains a look-up table for the perceptual intent. Might be interesting to see the experiment repeated with that as the output profile. It would seem to me, though, that in order to correctly apply the v4 output profile, the source profile would also have to be a v4 profile. More information in this white paper. The last chapter would seem to be the most relevant one.


I also expected that perceptual wouldn’t work (because of the lack of LUTs). In ICC intents/Gamut mapping broken at output profile · Issue #11777 · darktable-org/darktable · GitHub, Aurélien writes:

relative colorimetric states that “colors should be clipped to the boundary of the gamut”. For the longest time, I thought this implied “chroma-clipped at constant hue”, but I actually didn’t find anything clearly saying that

I think the numbers in the post confirm that what is done is per-channel clipping, with no concern about hue.

1 Like

helped shape my perspective on rendering intents. The Flash animation was particularly insightful; too bad it no longer plays…

LCMS2 will silently default to an attainable rendering intent if the one specified in the transform call is not available. So, you need to know the contents of both the input and output profiles to know how it’ll go…