[cairo] Creating CMYK and spot colors using Postscript backend

Craig Ringer craig at postnewspapers.com.au
Mon May 14 22:53:40 EEST 2007


Hi all

First, sorry this reply won't have the right headers for threading. I'm
new to the list, and replying to recent archives.

I'm no expert with Cairo either as a user or developer, but I think I
can offer some useful background on the problem being discussed, and a
few comments on the solution being tackled.

I've CC'd the OpenICC list in the hopes that a few of the folks there
will weigh in, or send me feedback directly that I can pass on to the
list. Ditto the Scribus list, where we have some serious printing and
colour experts lurking. Sorry for the cross post, but I think in this
case the crossing of areas of expertise justifies it.

Markus Meyer wrote:

> A cairo_color_t type makes sense to me, especially as it would reduce
> the number of API functions in the long run. Of course,
> cairo_set_color_rgb[a] must still be maintained for backward
> compatibility and ease of use.

This was initially what I thought too, since I've done a bit of general
thinking about CMYK in Cairo. However, I ran into problems when thinking
about:

	- Gradients & blends? How do you work with a CMYK -> RGB
	  gradient or a layer blend?

	- Colour management. A CMYK colour doesn't really mean anything
	  (nor does an RGB colour) without reference to some display
	  device. We get away with forgetting that when working only
	  within one colour space and format, but can not do so when
	  mixing CMYK and RGB colours. There *IS* no sane RGB<->CMYK
	  conversion without some knowledge of the source and target
	  devices; the best you can do is assume sRGB and SWOP Coated or
	  something like that. That won't get you great results.

	  This means that if you want CMYK support, you're probably
	  looking at either having surfaces that ONLY accept CMYK
	  colours, or introducing colour management support. The latter
	  seems much saner to me.

	- Operation implementations. Currently Cairo just has to support
	  RGB for its low level operations. How much would it increase
	  complexity to have to be able to work on m^n different
	  combinations, where m is the number of colour operands, and n
	  is the number of recognised colour formats? Even if you
	  say that a surface must be created with a particular colour
	  format and only those colours used with it (ie "create a CMYK
	  image surface"), you still have m*n different operators to
	  write and maintain.

MIXED COLOUR SPACES
===================

You could simplify this by converting to a single internal working
colour space, like L*A*B (white-point corrected XYZ). That's expensive
for rgb->rgb though, and that's currently the only use Cairo sees.

Carl Worth mentioned that the Cairo devs are already considering using a
wide-gamut RGB  space as the sole internal colour representation. My
understanding is that doing so isn't really any different from
converting to L*A*B, except that you save in the wide-RBB -> wide-RGB
case that's the most common use.

Is that correct as far as you folks on OpenICC can see? Could Cairo get
away with working in an expanded floating-point RGB space and still
produce good results on CMYK output targets with CMYK inputs - presuming
decent colour profiles are available?

In either the L*A*B or expanded gamut RGB case, colour managed
conversions must be done for all colour I/O. That requires the use of a
colour management library like lcms or ArgyllCMS (or where available
ColourSync, the Kodak CMS or the Adobe CMS, for that matter*). However,
if you're working in a simple RGB space for input and output you could
short-circuit those conversions by telling Cairo your inputs are already
in its working space, and you want output in the same space.

So, at this point it's looking fairly sane to either convert everything
into a common working space, or require that surfaces work only in a
particular colour format and space (with the latter still adding
considerably to the complexity of the task, as it requires custom CMYK
blend operations etc). The latter approach would also be less useful, as
it'd force applications to have somewhat different code to generate an
on-screen preview for the user than they used for writing out the final
document.

Another alternative, though, is to preserve colours as far as possible
through Cairo, and only convert them when an operation or surface cannot
handle that colour format. This would be ideal in many ways, as it'd
simplify the handling of spot colours (see below), permit CMYK values to
be preserved exactly as-is where no conversion is required (again, see
below), and make it possible to create mixed colour space documents in
media like PDF/X-3 that support it.

In any case, it needs to be possible to set a target colour format and
target colour profile for a surface. It also needs to be possible to
query Cairo to find out what formats and profiles each surface supports.

SPOT COLOURS
============

Now one more wrinkle pops up: spot colours. (OpenICC folks: yell at me
if any of this isn't 100% accurate in nitpicking detail please). Spot
colours are NOT just named CMYK values. A spot colour is a specific
colour *in* *the* *real* *world*. Your named colour is a placeholder for
that, and the output device is responsible for reproducing the desired
colour. This "colour" need not even be a conventional colour - it could
be gold ink, or a varnish layer. An intensity value makes sense for a
spot colour in most outputs (corresponding to things like halftoning),
but blending it with other colours generally does not.

A gradient of a spot colour to, say CMYK(0,50,0,20) doesn't make sense.
You might say "that spot colour is printed using the CMYK value
(0,10,0,10) on this device" ... but Cairo won't and *CAN'T* know that.
In fact, spot colours may be printed as separate press plates using
specific inks otherwise outside the gamut of the device (think bright
green on an offset web press) or might even not be conventional colours
at all.

However, I'd agree with Behded Esfahbod, who said that:
> To me alpha with spot colors makes a lot of sense.  That's your only way
> to create new colors after all  (which will result in halftones in
> print).

... also implying that a gradient from the spot colour that varies only
along alpha would make sense.

Spot colours are usually named according to a well understood convention
of calibrated colours & special inks (like PANTONE). However, sometimes
they're agreed upon in a case-by-case basis between printing client and
printer, mostly for offset web printing. In the latter case, my spot
colour might be called "PLATE5" or "Fred" - so long as the printer knows
that, and can configure their RIP to generate a plate for that spot, and
 load the right inks into the printing unit using that plate.

Spot colours do have a placeholder colour, typically specified in CMYK
but AFAIK that's not any sort of requirement. However, this placeholder
 may not resemble the real spot colour at all, and should not be used
for blending operations etc. The user might have set the placeholder
colour to bright pink to indicate copper ink, since it's a colour that
stands out and isn't used elsewhere on the document. They won't be
pleased if their "copper" colour comes out bright pink off the press.

Spot colours are mostly used in the PostScript and PDF formats, though
TIFF files can be used to store n-channel data including spot colour
channels.

It's important not to think of spot colours as confined to plate-based
offset printing. They're also useful and meaningful in digital press
situations or with any other target that has been calibrated for a
common spot colour library like PANTONE, and can guarantee that
PANTONE#553 will really come out just like it looks in the swatch book
in your hand.

Carl Worth suggested that Cairo might be able to implement spot colours
using patterns. I don't know enough about Cairo internals to really
understand this, but hope that's useful in combination with the
background info above.

INTERFACE/API
=============

Markus Meyer wrote:

> Regarding conversion to RGB: problem is, conversion from CMYK to RGB is
> not unambiguous. In a real world environment, it depends e.g. on the
> color profile used for the given screen, the output device (say, the
> type of paper and ink) and the actual conversion method used. It could
> be argued that someone who uses CMYK probably knows what he's doing and
> will probably not use any simple conversion method anyway. OTOH, I
> wouldn't mind if Cairo would implement a simple default conversion
> method and direct the user to direct set_rgb/set_cmyk calls for the
> cases when he wants to have more control.

Honestly, I would think it best if Cairo did *NOT* provide any default
conversions. It should make it easy for a developer to pass a CMYK
colour with a generic ICC profile like SWOP Coated, but should NEVER do
a dumb conversion or assume a profile.

The API should not make it look like a CMYK->RGB conversion without
colour profile information produces useful or meaningful results, when
it really doesn't.

I think the Create project is now distributing a set of standard ICC
profiles that may be useful.

As for how such profiles would be identified to Cairo - maybe it'd make
sense to have a series of pre-initialized instances of something like
colour_profile_t (which wraps a CMS library's colour profile type or
references an instance of it) for a few core profiles, and require users
to initialize new ones with an instance of a CMS library's profile type?

Note that you'd also need to be able to pass a profile when setting an
RGB colour. If Cairo used a wide-gamut RGB internal working space, it
could get away with exposing an API that assumed colours were already in
that space (and would have to for backward compat), but users would
still need to be able to identify colours as being in other RGB spaces.
Ditto for images.

Behdad Esfahbod wrote:
> As for implementation, we will expose an opaque cairo_color_t which
> simply maps to the internal cairo_color_t that we have already.  It
> needs an enum member to identify the type of the color (rgb/cmyk/etc),
> have a global alpha parameter, the 'short' rgb for display use, and a
> union of per rgb/cmyk/spot/... data.  The cairo_color_type_t enum needs
> to be public too.

If you plan to store and work with colours in different formats/spaces,
such colours also need to have provision for a colour profile tag as
part of the colour structure. It'd also be necessary to ensure that the
rgb for display use was only EVER used for display, not used as a
convenient pre-converted RGB value for blend operations etc.

Bitmap image data also needs a colour profile tag if it's not all
converted to a single working space.

PURE GREYS
==========

The same users who tend to want spot colours and CMYK colours also often
want pure greys. A CMYK "grey" is not necessarily all in the K channel -
there might be some CMY to produce a "warm" grey. Sometimes this is
undesirable, particularly when targeting output devices that ONLY
support black plus spot colour (common in offset printing - I'm sure
you've seen newspapers with pages that're black & white except for red
highlights, or something like that).

It'd be nice to be able to identify a colour as a pure grey, perhaps
using a similar method to how spot colours are handled.

PASS THROUGH CMYK VALUES
========================

Desktop publishing users tend to want to hand-specify a particular CMYK
colour value, and have that turn up exactly as-is in the output. They
also tend to provide pre-converted CMYK images and expect them to appear
pixel-for-pixel with the same colour values. This makes some sense when
you consider that a single colour may have many apparently equivalent
CMYK values with different (CMY) and (K) mixes.

I personally don't think Cairo should have to care about this, as I view
it as a bit of a relic from before ICC colour management was around. A
decent profile and software that uses it properly should produce a good
result when converting such CMYK data from its source colour space to
the working space and back again for output. However, I'm not an expert,
and my view is not the only one around.

While personally I'd expect it to be sufficient to pass such CMYK data
into Cairo along with an ICC colour tag that identifies its colour
space, I work in the relatively undemanding newspaper industry, where
colour isn't *that* critical. I'd love some feedback from OpenICC on how
much of an issue this is likely to be.

I'm sure it'd be BETTER to preserve CMYK values, so if Cairo did support
a cairo_color_t that could handle tagged CMYK, and tried to preserve
colours unconverted as far through as it could, that would be ideal.

PDF Details
===========

My personal interest is in CMYK and spot colour in PDF, rather than
PostScript. PDF uses /DeviceRGB (conventional RGB colour), /DeviceCMYK
(simple CMYK colour), /DeviceGray (pure K) and /DeviceN (spot colour).
It also has built-in support for tagging image data and I think solid
colours too with ICC profile information, so conversions can be deferred
to the RIP.

PDF supports mixed colour spaces. This means that except where Cairo
supports blend operations that PDF does not (so Cairo must render them
internally to a bitmap) it could output tagged mixed colour space data
directly.  That said, users need control over this, as they often want:

	- All-(CMYK|RGB) PDF with all data tagged with the target ICC
	  profile, and all inputs not already in that space converted
	  to it;
	- All-(CMYK|RBB) PDF with all data converted to the target
	  colour space and left untagged;
	- Mixed colour space PDF with all data tagged with appropriate
	  colour profiles.

The latter would be possible only if Cairo carried data through
unconverted as far as possible. The first two would work with any
reasonable approach.

CONCLUSION
==========

Well, I wish I could say that's the longest message I've written, but I
can't. Congratulations to anyone who suffered through this far, and I
hope what I've written was useful and helped clarify rather than muddle
some aspects of this situation.

--
Craig Ringer

* If cairo adds internal CMS support, as will be necessary unless it
requires all colours to be pre-converted to wide-gamut RGB and desirable
even then, it might be worth looking for CMS abstraction layers rather
than immediately latching on to lcms . Mac users in particular want
their apps to be able to talk to the system CMS, ColourSync. The OpenICC
list will be useful for this area.


More information about the cairo mailing list