CMYK in RGB - Explained

31 October 2010

When I first posted the action set for this, I promised I'd write more later about it.  Since then, I've also received a few inquiries asking that I explain what the actions are doing in order to achieve something which many believed wasn't possible.  Today, after much, much too long a delay I'll do that - it seems like an easy topic in comparison to what I last wrote about!  I'll even leave out the math... well, mostly!

To understand what's going on, we need to discuss what happens when we normally convert an image from RGB to CMYK.  In the first place, the color modes themselves are opposite one another - where RGB is additive, CMYK is subtractive (or multiplicative, depending on the verbage you prefer).  This is fairly straightforward to understand, as adding more light in RGB makes things brighter (which is intuitive), while adding more ink (which absorbs, or subtracts, more light) in CMYK makes things darker.  That's the change in color mode.  [If you'd like to read more or see a video, I suggest Joe Francis' discussion of it here].

But traditional conversion to CMYK also involves converting to a different color space.  Not surprisingly, standard printing presses can't reproduce the same range of colors which our increasingly wide-gamut monitors can (at least, not at prices most of us can afford).  So conversion to CMYK also involves a color space change which results in the undesirable color shifts which many users end of feeling is just a part of the CMYK color mode.

To be clear: CMYK conversion also deals with the dot gain of the printing press involved, the interplay of the machine's physical configuration as well the actual density of individual inks.  Like the mathematical difference between subtractive and multiplicative blending, that's beyond what we need to deal with today.
The actions which I presented avoid the issue of color shifts by maintaining the same color space.  Now, there are two ways which we could go about doing this.  In the first, we could pull an old Dan Margulis trick and create a 'false' CMYK profile, spending a lot of time tweaking our color coordinates to both give us a suitably large color space as well as ink primaries which could accurately create said colors.  But that takes time.  And false profiles confuse people.  And above all, it doesn't give you those channels back in your RGB document - which is what I needed at the time.  So let's go with option two.

In option two, we calculate the CMYK equivalent values manually as if we were acting as PS's conversion engine.  I'll spare you the actual math, but the crux of the concept is to act like we're already in a CMYK document.
  1.  We start (because we have to) with the hard part - creating the black layer.  Whereas each of the other channels has a direct analog in RGB (C->R, M->G, Y->B), K has nothing which we can easily relate it to.  Because the CMYK color mode is subtractive, that means that the equivalent K value could be anything from 0 up to the lowest value of the other "inks" (C, M, or Y).  To find that 'maximum black' value, we merge the inverse of each of the R, G, and B channels into a new channel using the Darken blend mode.
  2. Next, we let the user decide whether they want to lighten that black value at all before continuing by giving them a standard Curves dialog.  This lets them tamp down that black to something which gives more emphasis to the color channels should they desire it.
  3. Then we tell PS to show us what the 'CMYK' image would look like without its black component, by subtracting it out of the whole.  Conveniently, this creates the R, G, and B inverses of the C, M, and Y channels which we're after and so we can simply make inverted copies of each to create our final channels - it's that easy!
All of this happens with almost no loss of image fidelity.  In 8bpc color, there is literally no difference between the original image and the CMYK version which we generate.  In 16bpc color we can get errors as high as 64 / 32768, though the average is < 16 / 32768 per channel.  Functionally, it's a lossless conversion while retaining the entire color spectrum which existed in the original image.

A related note and a few completely unrelated observations which I made while writing this:
  • Just because the actions as provided are functionally lossless doesn't mean that the academic in me is satisfied.  When I get some more time I'm going to try to actually make the reconstruction perfect.  If you beat me to it, please let me know :).
  • Don't use the color sampler tool (Info Palette) to test error levels at anything less than 100% zoom.  Otherwise it uses that same awful resizing algorithm which PS uses to preview images on non-HW-accelerated systems in order to estimate what a value might be, not actually reporting the real value to you.  This can give you all sorts of ghosts to chase.
  • There are some idiosyncracies to the way that Calculations and Apply Image each do what should be the same math.  The differences are small, but real.  If I have time in the future I'll delve deeper into it, but just be aware of it if it's the sort of thing which interests you.
  • As discussed a few times elsewhere, there is a difference in the output between the Image->Adjustments version of the Brightness / Contrast tool and its Adjustment Layer counterpart, specifically in how Legacy-mode Contrast is calculated.  The Image->Adjustments version calculates it based around the actual mean value of the image, while the Adjustment Layer version assumes a mean of 127.5.  The results are the same, albeit offset from one another (in brightness) by the distance of the actual mean from 127.5.  Generally speaking that's not terribly important (though it does make an argument for greater granularity in the PS controls), but I filed a bug report with Adobe just the same detailing the problem and asking that they bring the tools into alignment with one another.  The discrepancy confuses some people horribly.  Vote for me as your CS6 Beta Tester :).
Please feel free to ask if you still have questions!