[cairo] Color space API

Francois Robert frobert at atex.com
Thu Aug 2 17:51:03 PDT 2012

From: Bill Spitzak [spitzak at gmail.com]
Sent: Wednesday, August 01, 2012 9:34 PM
To: Andrea Canciani
Cc: cairo at cairographics.org
Subject: Re: [cairo] Color space API

>>> Does that mean that other backends (X11, gl, win32, quartz) would have to fall
>>> back to the image backend whenever a color space is involved?

>I think this is the big confusion about any color space api. I believe
>the answer is "no" for what you are thinking of.

>(At least this is my understanding, please somebody correct me if I am
>wrong, but personally I really hope I am right, otherwise cairo will be
>a nightmare to use...)

>The color space setting of any destination image, such as an on-screen
>window, has ZERO effect on how numbers stored in that image are placed
>onto the screen. In the typical case where the destination image is 3
>8-bit channels, and your screen's buffer is 3 8-bit channels, the
>numbers for opaque pixels are copied UNCHANGED from the destination
>image to the screen buffer.
I am not sure what you call "screen buffer". I believe it is an OS responsibility to alter color values passed to your video card, in accordance to the colorspace definition for your -calibrated- display. If by "screen buffer" you intend the array of values passed to the OS for blitting, then I believe you are more or less correct. If by "screen buffer" you intend the memory internal to the video card which is accessed by the DACs when they construct the signal sent down a VGA wire to the display, I believe you are wrong.

>This also means that changing the colorspace of a destination image is
>allowed, and does NOTHING to these numbers and nothing to what you see
>on the screen. Changing to any colorspace and then back to the original
>colorspace is always a lossless operation.
Hmmm. I don't think so. Or rather: If your color components are allowed to take "non-physical" values, then that *may* be possible (an example of non physical value is a negative blue component. Or a green one larger than your 8-bit maximum).
Conversion to another colorspace are typically non-bijective operations. For instance, when you go from /DeviceRGB to /DeviceCMYK, Postscript specifies :
The complete conversion from RGB to CMYK is as follows, where BG(k) and UCR(k) are invocations of the black-generation and undercolor-removal functions, respectively:
c = 1.0 - red
m = 1.0 - green
y = 1.0 - blue
k = min(c,m,y)
cyan = min(1.0,max(0.0,c - UCR(k))) 
magenta = min(1.0,max(0.0,m - UCR(k)))
yellow = min(1.0,max(0.0,y - UCR(k)))
black = min(1.0,max(0.0,BG(k)))
Clearly clamping is occurring. Well, not if you allow non-physical values... But your are left with the user-defined BG() and UCR() functions, which the opposite conversion does not consider (in Postscript or PDF at least) : 
red = 1.0 – min (1.0, cyan + black)
green = 1.0 – min (1.0, magenta + black)
blue = 1.0 – min (1.0, yellow + black)

The sad reality is that there are tuple of the destination space with no corresponding *physical* tuple in the source space. And vice versa, in the opposite direction. The only colorspace that offers some sort of guarantee is XYZ (L*a*b* also ?), which was specified from human vision characteristics and supposedly all human-visible colors fall within its physical coordinates (but the reverse is not true: they are physical XYZ triples that are not colors...)  And, a contrario, depending on the colorspace, there may be multiple source tuple corresponding to one destination tuple.
One can look at clamping as a simple modeling of a colorspace "gamut" : sRGB or RGB or any CMYK can only access a strict (and rather small) subset of XYZ. This is one reason why screen and printed colors virtually always differ. The rendering intent of Postscript or PDF is a way to declare how destination components should be adapted/clamped in relation to others so that converted results has certain characteristics. For instance, a spreadsheet graphics may print "better" if colors are kept or possible made saturated (clamped). Whereas for certain photos, a better choice may be to have the entire set of tuples scaled instead of clamped.

All of this ignores the fact that a DeviceGray (or /CIEBasedA if you prefer) colorspace obviously cannot be bijectively converted from and to RGB (or /CIEBaseABC or /CIEBasedDEF or /CIEBasedDEFG)... 
Then in the printing world, there are spot colors (spot inks really), and in PDF there are /Separation, /DeviceN and /NChannel colorspaces. If the objective of Cairo is to implement the PDF blending and therefore color model, then at some point, all of the above will have to be considered and dealt with in a way or another.

More information about the cairo mailing list