Display color management in darktable

The general picture on the modern Linux desktop

Modern Linux distros featuring either GNOME, Unity or KDE offer fairly easy configuration of color management, this system level configuration mostly pertains to the handling of an ICC display profile.

If you have set a display profile via your system configuration tool (The Color applet in System Settings for GNOME or Unity), there are a few things to keep in mind.

An ICC display profile consists of two main parts. First the so-called "vcgt", which corrects for whitepoint (this is most noticeable on laptops which shift from being very blueish to a bit more yellowish) and gamma. The "vcgt" is loaded into X11 and applied to your whole screen, so all applications automatically benefit. On a GNOME or Unity desktop this is done by GNOME Settings Daemon during login.

The second is the rest of the ICC profile, and this has to be processed in color management enabled application (typically via liblcms2). So we need a mechanism to pass the actual ICC profile to our applications without having to configure them all individually.

The oldest mechanism is the _ICC_PROFILE atom, which allows a single display profile to be defined for your system (this obviously fails for dual head configurations). You can check if a profile is setup like so:

3 thoughts on “Display color management in darktable”

1. Hi Pasacal,

This post and the link to your(?) pcode post were very helpful. However, I still have a question that I wonder if you could help me with. Suppose you have two monitors, one is standard gamut the other is wide gamut. Also suppose you have some raws that you have output to 8-bit sRGB and aRGB JPEGs and want to display. Does the pseudocode below capture sort of thing that you need to do?

sRGB = cmsCreate_sRGBProfile();
aRGB = // Load profile from image (assuming it is present)
sgMon = // Load profile for standard gamut monitor (using EDID?)
wgMon = // Load profile for wide gamut monitor (using EDID?)
// generate the transforms
// IN is one of sRGB and aRGB
// OUT is one of sgMon and wgMon
s2s = cmsCreateTransform(IN, TYPE_RGB_8, OUT,
TYPE_RGB_8, 0, 0);
// apply the transforms to the original image pixels (i.e. the JPG) then render the transformed image on the relevent screen

Now stepping back to how I got those JPEGs in the first place, what transform is applied to go from the raw to the sRGB (or aRGB) JPEG? Is there some camera profile that needs to be used at least as a starting point?

Thanks!

2. Hi dm

It’s a lot simpler than that isn’t it?

If you have profiled your screens and then view your images using a colour managed application they should render ‘correctly’ from either srgb or argb jpegs on either screen. Any transformation necessary should be transparent and handled by colord or whatever colour manager you are using.

Or are you trying to do something different?

3. Rob, please do read the article, dm isn’t far off at all… As I explicitly mention colord is just an infrastructure daemon which ties stuff together. It doesn’t do any color transforms by itself (and it shouldn’t).

As far as the pseudocode goes, you’d need to check Darktable code for the gritty details.

For a high level view, Darktable’s pipeline is completely transparant in the user interface, if you turn off plugin grouping (by clicking the active group once again), you can see all steps which are applied from bottom to the top.

Keep in mind that RAW files technically aren’t normal images to begin with, they inherently have their own sensor specific color space and are practically linear with regard to gamma. So a LOT of processing has to happen to get even a basic image.

The typical minimum steps are:

1. read sensor data from RAW
2. Whitebalance (RGB multipliers)
3. Demosaic (includes median filters/greeneq too)
4. Basecurve (corrects for gamma/contrast/tonality)
5. (CMS) Color In (Camera RGB -> color (XYZ) matrix -> LAB)
7. more plugins (for example denoise)
6. (CMS) Color Out (LAB -> output ICC -> sRGB or AdobeRGB)
8. more plugins (for example sharpen)

Some of this is discussed in the following video: