SpecIccForCairo

From Inkscape Wiki
Jump to navigation Jump to search

Why

In order for inkscape to produce CMYK PDFs and PSs with cairo, Cairo needs to support ICC. This is an intent to propose a Cairo API that would be suitable with inkscape needs.

Profiles

A set of profiles will apply to the whole Cairo surface. Cairo needs to be able to compute a transform from this set. We can get inspiration from the lcms api [1], in particular the cmsCreateMultiprofileTransform (more generic than cmsCreateTransform that handles only a single pair of color profiles).

So a proposal would be:

typedef enum cairo_color_intent {
  CAIRO_COLOR_INTENT_PERCEPTUAL,
  CAIRO_COLOR_INTENT_RELATIVE_COLORIMETRIC,
  CAIRO_COLOR_INTENT_SATURATION,
  CAIRO_COLOR_INTENT_ABSOLUTE_COLORIMETRIC
} cairo_color_intent_t;

typedef struct cairo_color_profile cairo_color_profile_t;
void cairo_surface_set_color_profile_srgb(cairo_surface_t *surf);

void
cairo_surface_set_color_profile(cairo_surface_t *surf,
                                cairo_color_profile_t *profile);

cairo_color_profile_t *
cairo_surface_get_color_profile(cairo_surface_t *surf);

void
cairo_surface_add_profile_mapping(cairo_surface_t *surf, 
                                  cairo_color_profile_t *in, 
                                  cairo_color_profile_t *out);

void
cairo_surface_remove_profile_mappings(cairo_surface_t *surf);

void
cairo_surface_set_color_intent(cairo_surface_t *surf,
                               cairo_color_intent_t intent);

cairo_color_intent_t
cairo_surface_get_color_intent(cairo_surface_t *surf);

void
cairo_set_source_icc_color(cairo_t *cr,
                           cairo_color_profile_t *profile,
                           const double *components,
                           int num_components);

Color transformations would be performed when painting from a pattern to a surface, based on the surface's profile, mappings, intent, etc.

Functional spec

Cairo has several ways to accept color information (e.g. cairo_set_source_rgb). The cairo back-end produces an output (a file or calls to third party libraries). The colors of this output are only back-end and cairo dependent, and there is no way for the cairo user to specify something different.

A color management system provides a way to specify input and output color formats (bit orders, meaning of the channels, etc) as well as a way to transform input colors to output ones.

Cairo needs a ways to permit cairo users to input this information (basically, those would be stored alongside the surface).

As the format for inputing colors is variable, a color is defined as an array of doubles (size to be specified at each time, each double is a channel). Cairo stores these informations internally.

At render time, the backend computes the color transformation (typically a call to cmsCreateTransform ) and applies it to every color. Back-end will also use the color output format as a clue to the desired output (e.g. the pdf backend with color output format TYPE_CMYK_8 will generate a CMYK pdf). Each cairo backend will be able to render only some of the output color formats (e.g. X backend does not know how to render CMYK, but would know ho to render RGBA 32, RGB 24). Trying to render to an unsupported color format would trigger an error.

Open issues

Should surface profile/color rendering changes be allowed once the surface is being actively used?

Why should we allow this ? Is there any use case ? The ones I can see are: render the same surface with two different profiles at the same time (e.g. on a multihead screen with different profiles, but is'nt X already handling that, batch export of the same file in many different colorspaces)

How should gradients work in this regime?

What is the issue here ? like we have a set_source_icc_color, we can have a set_stop_icc color, isnt'it ?

How should cairo_color_profile_ts be created/loaded?

lcms provides 2 ways, load from a file or from memory. I think cairo should provide the same ways, I dont see an additional one that could bring some benefit here, appart from direct reuse of a lcms handler for applications already using lcms like inkscape but that's not really clean - makes cairo API depend from lcms API.