[babl/wip/pippin/inverted-cmyk: 4/5] babl: implement proper CMYK support



commit 92c36826c1cdbeca96633a6ead78dba9423688ef
Author: Øyvind Kolås <pippin gimp org>
Date:   Mon Nov 12 23:35:31 2018 +0100

    babl: implement proper CMYK support

 babl/babl-conversion.c     |   27 +-
 babl/babl-fish-reference.c |  480 +++++++++++++++-----
 babl/babl-fish.c           |   58 +--
 babl/babl-icc.c            |   60 ++-
 babl/babl-internal.h       |    9 +-
 babl/babl-model.c          |   12 +-
 babl/babl-model.h          |    1 +
 babl/babl-sanity.c         |   11 +-
 babl/babl-space.c          |   63 ++-
 babl/babl-space.h          |   16 +
 babl/babl.c                |    4 -
 babl/babl.h                |    3 +
 babl/base/Makefile.am      |    1 +
 babl/base/babl-base.c      |    1 +
 babl/base/babl-base.h      |    1 +
 babl/base/model-cmyk.c     | 1083 ++++++++++++++++++++++++++++++++++++++++++++
 export-symbols             |    1 +
 extensions/Makefile.am     |    1 +
 extensions/naive-CMYK.c    |  243 +---------
 19 files changed, 1667 insertions(+), 408 deletions(-)
---
diff --git a/babl/babl-conversion.c b/babl/babl-conversion.c
index ef68fd3..b4af910 100644
--- a/babl/babl-conversion.c
+++ b/babl/babl-conversion.c
@@ -152,7 +152,8 @@ _conversion_new (const char    *name,
                  BablFuncLinear linear,
                  BablFuncPlane  plane,
                  BablFuncPlanar planar,
-                 void          *user_data)
+                 void          *user_data,
+                 int            allow_collision)
 {
   Babl *babl = NULL;
 
@@ -237,16 +238,17 @@ _conversion_new (const char    *name,
         BABL (babl->conversion.destination),
         babl_type_from_id (BABL_DOUBLE));
 
-      if(0){
+      if(allow_collision){
         const Babl *fish = babl_conversion_find (src_format, dst_format);
         if (fish)
-          return fish;
+          return (void*)fish;
       }
       babl_conversion_new (
         src_format,
         dst_format,
         "linear", linear,
         "data", user_data,
+        allow_collision?"allow-collision":NULL,
         NULL);
       babl->conversion.error = 0.0;
     }
@@ -283,13 +285,10 @@ create_name (Babl *source, Babl *destination, int type)
     }
   return buf;
 }
-const char *
-babl_conversion_create_name (Babl *source, Babl *destination, int type);
-
-int _babl_loaded = 0;
 
 const char *
-babl_conversion_create_name (Babl *source, Babl *destination, int type)
+babl_conversion_create_name (Babl *source, Babl *destination, int type,
+                             int allow_collision)
 {
   Babl *babl;
   char *name;
@@ -297,7 +296,7 @@ babl_conversion_create_name (Babl *source, Babl *destination, int type)
   collisions = 0;
   name = create_name (source, destination, type);
 
-  if (!_babl_loaded)
+  if (allow_collision == 0)
   {
   babl = babl_db_exist (db, id, name);
   while (babl)
@@ -331,8 +330,8 @@ babl_conversion_new (const void *first_arg,
 
   Babl          *source;
   Babl          *destination;
-
   char          *name;
+  int            allow_collision = 0;
 
   va_start (varg, first_arg);
   source      = (Babl *) arg;
@@ -355,6 +354,10 @@ babl_conversion_new (const void *first_arg,
           user_data = va_arg (varg, void*);
         }
 
+      else if (!strcmp (arg, "allow-collision"))
+        {
+          allow_collision = 1;
+        }
       else if (!strcmp (arg, "linear"))
         {
           if (got_func++)
@@ -408,10 +411,10 @@ babl_conversion_new (const void *first_arg,
       type = BABL_CONVERSION_PLANAR;
     }
 
-  name = (void*) babl_conversion_create_name (source, destination, type);
+  name = (void*) babl_conversion_create_name (source, destination, type, allow_collision);
 
   babl = _conversion_new (name, id, source, destination, linear, plane, planar,
-                         user_data);
+                          user_data, allow_collision);
 
   /* Since there is not an already registered instance by the required
    * id/name, inserting newly created class into database.
diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c
index 6d1aa84..e4f1bc4 100644
--- a/babl/babl-fish-reference.c
+++ b/babl/babl-fish-reference.c
@@ -18,6 +18,10 @@
 
 #include "config.h"
 #include "babl-internal.h"
+#ifdef HAVE_LCMS
+#include "lcms2.h"
+#endif
+
 
 static Babl *
 assert_conversion_find (const void *source,
@@ -28,6 +32,7 @@ assert_conversion_find (const void *source,
   if (!ret)
     babl_fatal ("failed finding conversion between %s and %s aborting",
                 babl_get_name (source), babl_get_name (destination));
+
   return ret;
 }
 
@@ -251,7 +256,6 @@ convert_from_double (BablFormat *destination_fmt,
   src_img->stride[0] = 0;
 
   dst_img->data[0]  = destination_buf;
-  dst_img->type[0]  = (BablType *) babl_type_from_id (BABL_DOUBLE);
   dst_img->pitch[0] = destination_fmt->bytes_per_pixel;
   dst_img->stride[0] = 0;
 
@@ -690,6 +694,13 @@ process_same_model (const Babl  *babl,
   }
 }
 
+typedef enum _Kind Kind;
+enum _Kind { KIND_RGB, KIND_CMYK};
+
+static int format_has_cmyk_model (const Babl *format)
+{
+  return format->format.model->is_cmyk;
+}
 
 static void
 babl_fish_reference_process_double (const Babl *babl,
@@ -698,81 +709,122 @@ babl_fish_reference_process_double (const Babl *babl,
                                     long        n,
                                     void       *data)
 {
-    Babl *source_image = NULL;
-    Babl *rgba_image = NULL;
-    Babl *destination_image = NULL;
-    void *source_double_buf_alloc = NULL;
-    void *source_double_buf;
-    void *rgba_double_buf_alloc = NULL;
-    void *rgba_double_buf;
-    void *destination_double_buf_alloc = NULL;
-    void *destination_double_buf;
-    const void *type_double  = babl_type_from_id (BABL_DOUBLE);
-
-    if (babl->fish.source->format.type[0] == type_double &&
-        BABL(babl->fish.source)->format.components ==
-        BABL(babl->fish.source)->format.model->components && 0)
-    {
-      source_double_buf = (void*)source;
-      source_image = babl_image_from_linear (
-         source_double_buf, BABL (BABL ((babl->fish.source))->format.model));
-    }
-    else
-    {
-      source_double_buf_alloc = babl_malloc (sizeof (double) * n *
-                                  BABL (babl->fish.source)->format.model->components);
-
-      source_double_buf = source_double_buf_alloc;
-      source_image = babl_image_from_linear (
-        source_double_buf, BABL (BABL ((babl->fish.source))->format.model));
-      convert_to_double (
-        (BablFormat *) BABL (babl->fish.source),
-        source,
-        source_double_buf,
-        n
-      );
-    }
-
-    if (babl_model_is ((void*)babl->fish.source->format.model, "RGBA"))
-    {
-      rgba_double_buf = source_double_buf;
-      rgba_image = babl_image_from_linear (
-          rgba_double_buf,
-          (void*)babl->fish.source->format.model);
-    }
-    else
-    {
-      Babl *conv =
-        assert_conversion_find (
-        BABL (babl->fish.source)->format.model,
+  Kind  source_kind             = KIND_RGB;
+  Kind  destination_kind        = KIND_RGB;
+  Babl *source_image            = NULL;
+  Babl *rgba_image              = NULL;
+  Babl *cmyka_image             = NULL;
+  Babl *destination_image       = NULL;
+  void *source_double_buf_alloc = NULL;
+  void *source_double_buf;
+  void *rgba_double_buf_alloc   = NULL;
+  void *rgba_double_buf;
+  void *cmyka_double_buf_alloc  = NULL;
+  void *cmyka_double_buf;
+  void *destination_double_buf_alloc = NULL;
+  void *destination_double_buf;
+  const void *type_double  = babl_type_from_id (BABL_DOUBLE);
+
+  /* This is not the full/only condition XXX */
+
+  /* XXX : sometimes is_cmyk is neither 0 or 1 */
+
+  if (format_has_cmyk_model (babl->fish.source))
+    source_kind = KIND_CMYK;
+  if (format_has_cmyk_model (babl->fish.destination))
+    destination_kind = KIND_CMYK;
+
+  if (babl->fish.source->format.type[0] == type_double &&
+      BABL(babl->fish.source)->format.components ==
+      BABL(babl->fish.source)->format.model->components)
+  {
+    source_double_buf = (void*)source;
+    source_image = babl_image_from_linear (
+       source_double_buf, BABL (BABL ((babl->fish.source))->format.model));
+  }
+  else
+  {
+    source_double_buf =
+    source_double_buf_alloc = babl_malloc (sizeof (double) * n *
+                                BABL (babl->fish.source)->format.model->components);
+
+    source_image = babl_image_from_linear (
+      source_double_buf, BABL (BABL ((babl->fish.source))->format.model));
+    convert_to_double (
+      (BablFormat *) BABL (babl->fish.source),
+      source,
+      source_double_buf,
+      n
+    );
+  }
 
-      babl_remodel_with_space (babl_model_from_id (BABL_RGBA),
-                           BABL (BABL ((babl->fish.source))->format.space)));
+  babl_mutex_lock (babl_reference_mutex);
+  switch (source_kind)
+  {
+    case KIND_RGB:
+     {
+       Babl *conv = assert_conversion_find (
+           BABL (babl->fish.source)->format.model,
+       babl_remodel_with_space (babl_model_from_id (BABL_RGBA),
+                         BABL (BABL ((babl->fish.source))->format.space)));
 
-      rgba_double_buf_alloc  = babl_malloc (sizeof (double) * n * 4);
-      rgba_double_buf        = rgba_double_buf_alloc;
+       rgba_double_buf       =
+       rgba_double_buf_alloc = babl_malloc (sizeof (double) * n * 4);
 
-      rgba_image = babl_image_from_linear (
+       rgba_image = babl_image_from_linear (
           rgba_double_buf, babl_remodel_with_space (babl_model_from_id (BABL_RGBA),
           BABL (BABL ((babl->fish.source))->format.space)) );
 
-      if (conv->class_type == BABL_CONVERSION_PLANAR)
+       if (conv->class_type == BABL_CONVERSION_PLANAR)
+       {
+          babl_conversion_process (conv,
+               (void*)source_image, (void*)rgba_image, n);
+       }
+       else if (conv->class_type == BABL_CONVERSION_LINEAR)
+       {
+         babl_conversion_process (conv, source_double_buf, rgba_double_buf, n);
+       }
+       else babl_fatal ("oops");
+      }
+      break;
+    case KIND_CMYK:
+      if (babl_model_is ((void*)babl->fish.source->format.model, "cmykA"))
       {
-        babl_conversion_process (
-          conv,
-          (void*)source_image, (void*)rgba_image,
-          n);
+        cmyka_double_buf = source_double_buf;
+        cmyka_image = babl_image_from_linear (cmyka_double_buf,
+                                (void*)babl->fish.source->format.model);
       }
-      else if (conv->class_type == BABL_CONVERSION_LINEAR)
+      else
       {
-        babl_conversion_process (
-          conv,
-          source_double_buf, rgba_double_buf,
-          n);
+        Babl *conv = assert_conversion_find (
+                   BABL (babl->fish.source)->format.model,
+                   babl_remodel_with_space (babl_model ("cmykA"),
+                         BABL (BABL ((babl->fish.source))->format.space)));
+
+        cmyka_double_buf        =
+        cmyka_double_buf_alloc  = babl_malloc (sizeof (double) * n * 5);
+
+        cmyka_image = babl_image_from_linear (
+          cmyka_double_buf, babl_remodel_with_space (babl_model ("cmykA"),
+          BABL (BABL ((babl->fish.source))->format.space)) );
+
+        if (conv->class_type == BABL_CONVERSION_PLANAR)
+        {
+          babl_conversion_process (conv,
+           (void*)source_image, (void*)cmyka_image, n);
+        }
+        else if (conv->class_type == BABL_CONVERSION_LINEAR)
+        {
+          babl_conversion_process (conv,source_double_buf, cmyka_double_buf, n);
+        }
+        else babl_fatal ("oops");
       }
-      else babl_fatal ("oops");
-    }
+      break;
+  }
 
+  if (source_kind      == KIND_RGB &&
+      destination_kind == KIND_RGB)
+  {
     if (((babl->fish.source)->format.space !=
         ((babl->fish.destination)->format.space)))
     {
@@ -785,67 +837,262 @@ babl_fish_reference_process_double (const Babl *babl,
 
       babl_matrix_mul_vector_buf4 (matrix, rgba, rgba, n);
     }
+  }
+  else if (source_kind      == KIND_RGB &&
+           destination_kind == KIND_CMYK)
+  {
+    cmyka_double_buf        =
+    cmyka_double_buf_alloc  = babl_malloc (sizeof (double) * n * 5);
+    cmyka_image = babl_image_from_linear (
+        cmyka_double_buf, babl_remodel_with_space (babl_model ("cmykA"),
+        BABL (BABL ((babl->fish.destination))->format.space)) );
+
+#if HAVE_LCMS
+    if (babl->fish.destination->format.space->space.cmyk.lcms_profile)
+    {
+      /* lcms expect floats with normalized range 0.0-100.0 for CMYK data,
+         we also do our inversion from profile here.
+       */
+      double *rgba=rgba_double_buf;
+      double *cmyka=cmyka_double_buf;
+      int i;
+      /* use lcms for doing conversion from RGBA */
+      cmsDoTransform (babl->fish.destination->format.space->space.cmyk.lcms_from_rgba,
+         rgba_double_buf, cmyka_double_buf, n);
+
+      for (i = 0; i < n; i++)
+      {
+        cmyka[i * 5 + 0] = 1.0-(cmyka[i * 5 + 0])/100.0;
+        cmyka[i * 5 + 1] = 1.0-(cmyka[i * 5 + 1])/100.0;
+        cmyka[i * 5 + 2] = 1.0-(cmyka[i * 5 + 2])/100.0;
+        cmyka[i * 5 + 3] = 1.0-(cmyka[i * 5 + 3])/100.0;
+        cmyka[i * 5 + 4] = rgba[i * 4 + 3];
+      }
+    }
+    else
+#endif
+    {
+      double *rgba=rgba_double_buf;
+      double *cmyka=cmyka_double_buf;
+      int i;
+      for (i = 0; i < n; i++)
+      {
+        /* A very naive conversion - but it is usable */
+        double key=0.0;
+        cmyka[i * 5 + 0] = 1.0 - rgba[i * 4 + 0];
+        cmyka[i * 5 + 1] = 1.0 - rgba[i * 4 + 1];
+        cmyka[i * 5 + 2] = 1.0 - rgba[i * 4 + 2];
+
+        if (cmyka[i * 5 + 0] < key) key = cmyka[i*5+0];
+        if (cmyka[i * 5 + 1] < key) key = cmyka[i*5+1];
+        if (cmyka[i * 5 + 2] < key) key = cmyka[i*5+2];
 
+        key *= 1.0; // pullout - XXX tune default pullout?;
+
+        if (key < 1.0)
+        {
+          cmyka[i * 5 + 0] = (cmyka[i * 5 + 0] - key) / (1.0-key);
+          cmyka[i * 5 + 1] = (cmyka[i * 5 + 1] - key) / (1.0-key);
+          cmyka[i * 5 + 2] = (cmyka[i * 5 + 2] - key) / (1.0-key);
+        }
+        cmyka[i * 5 + 0] = 1.0-cmyka[i * 5 + 0];
+        cmyka[i * 5 + 1] = 1.0-cmyka[i * 5 + 1];
+        cmyka[i * 5 + 2] = 1.0-cmyka[i * 5 + 2];
+        cmyka[i * 5 + 3] = 1.0-key;
+        cmyka[i * 5 + 4] = rgba[i * 4 + 3];
+      }
+    }
+ }
+ else if (source_kind      == KIND_CMYK &&
+          destination_kind == KIND_RGB)
+ {
+    /* */
+    rgba_double_buf_alloc  = babl_malloc (sizeof (double) * n * 4);
+    rgba_double_buf        = rgba_double_buf_alloc;
+    rgba_image = babl_image_from_linear (
+        rgba_double_buf, babl_remodel_with_space (babl_model_from_id (BABL_RGBA),
+        BABL (BABL ((babl->fish.source))->format.space)) );
+
+#if HAVE_LCMS
+    if (babl->fish.source->format.space->space.cmyk.lcms_profile)
+    {
     {
-      const Babl *destination_rgba_format =
-        babl_remodel_with_space (babl_model_from_id (BABL_RGBA),
-             BABL (BABL ((babl->fish.destination))->format.space));
+      /* lcms expect floats with normalized range 0.0-100.0 for CMYK data,
+         we also do our inversion from profile here.
+       */
+      double *cmyka=cmyka_double_buf;
+      int i;
+      for (i = 0; i < n; i++)
+      {
+        cmyka[i * 5 + 0] = (1.0-cmyka[i * 5 + 0])*100.0;
+        cmyka[i * 5 + 1] = (1.0-cmyka[i * 5 + 1])*100.0;
+        cmyka[i * 5 + 2] = (1.0-cmyka[i * 5 + 2])*100.0;
+        cmyka[i * 5 + 3] = (1.0-cmyka[i * 5 + 3])*100.0;
+      }
+    }
+    /* use lcms for doing conversion to RGBA */
+    cmsDoTransform (babl->fish.source->format.space->space.cmyk.lcms_to_rgba,
+       cmyka_double_buf, rgba_double_buf, n);
 
-      if(BABL (babl->fish.destination)->format.model == (void*)destination_rgba_format)
+    {
+      double *rgba=rgba_double_buf;
+      double *cmyka=cmyka_double_buf;
+      int i;
+      for (i = 0; i < n; i++)
       {
-         destination_double_buf = rgba_double_buf;
+        rgba[i * 4 + 3] = cmyka[i * 5 + 4];
       }
-      else
+    }
+    }
+    else
+#endif
+    {
+      double *rgba=rgba_double_buf;
+      double *cmyka=cmyka_double_buf;
+      int i;
+      for (i = 0; i < n; i++)
       {
-      Babl *conv =
-        assert_conversion_find (destination_rgba_format,
-           BABL (babl->fish.destination)->format.model);
+        /* A very naive conversion - but it is usable */
+        rgba[i * 4 + 0] = cmyka[i * 5 + 0]*cmyka[i*5+3];
+        rgba[i * 4 + 1] = cmyka[i * 5 + 1]*cmyka[i*5+3];
+        rgba[i * 4 + 2] = cmyka[i * 5 + 2]*cmyka[i*5+3];
+        rgba[i * 4 + 3] = cmyka[i * 5 + 4];
+      }
+    }
 
-         destination_double_buf_alloc = babl_malloc (sizeof (double) * n *
-                                          BABL (babl->fish.destination)->format.model->components);
-         destination_double_buf = destination_double_buf_alloc;
+    /* color space conversions */
+     if ((babl_space ("babl-rgb")!=
+        ((babl->fish.destination)->format.space)))
+    {
+      double matrix[9];
+      double *rgba = rgba_double_buf;
+      babl_matrix_mul_matrix (
+        (babl->fish.destination)->format.space->space.XYZtoRGB,
+        babl_space("babl-rgb")->space.RGBtoXYZ,
+        matrix);
 
-      if (conv->class_type == BABL_CONVERSION_PLANAR)
-        {
-          destination_image = babl_image_from_linear (
-            destination_double_buf, BABL (BABL ((babl->fish.destination))->format.model));
+      babl_matrix_mul_vector_buf4 (matrix, rgba, rgba, n);
+    }
+ }
+ else if (source_kind      == KIND_CMYK &&
+          destination_kind == KIND_CMYK)
+ {
+#if HAVE_LCMS
+   /* XXX XXX XXX NYI, keep a global list of lcms2 based conversions,
+      make k-preserve k-plane preserve intents a global setting, defaulting
+      to k-preserve
+    */
+#endif
+ }
 
 
-          babl_conversion_process (
-            conv,
-            (void*)rgba_image, (void*)destination_image,
-            n);
+  switch (destination_kind) /* XXX: the cases can share logic */
+  {
+    case KIND_CMYK:
+      {
+        const Babl *destination_cmyka_format =
+          babl_remodel_with_space (babl_model ("cmykA"),
+               BABL (BABL ((babl->fish.destination))->format.space));
+        if(BABL (babl->fish.destination)->format.model == (void*)destination_cmyka_format)
+        {
+           destination_double_buf = cmyka_double_buf;
         }
-      else if (conv->class_type == BABL_CONVERSION_LINEAR)
+        else
         {
-          babl_conversion_process (
-            conv,
-            rgba_double_buf, destination_double_buf,
-            n);
+          Babl *conv =
+            assert_conversion_find (destination_cmyka_format,
+                             BABL (babl->fish.destination)->format.model);
+          destination_double_buf =
+          destination_double_buf_alloc = babl_malloc (sizeof (double) * n *
+                                          BABL (babl->fish.destination)->format.model->components);
+          if (conv->class_type == BABL_CONVERSION_PLANAR)
+          {
+            destination_image = babl_image_from_linear (
+              destination_double_buf, BABL (BABL ((babl->fish.destination))->format.model));
+            babl_conversion_process (conv,
+              (void*)cmyka_image, (void*)destination_image, n);
+          }
+          else if (conv->class_type == BABL_CONVERSION_LINEAR)
+          {
+            babl_conversion_process (conv,
+                           cmyka_double_buf, destination_double_buf, n);
+          }
+          else
+          {
+            babl_fatal ("oops");
+          }
         }
-      else babl_fatal ("oops");
-      }
-   }
-
-    convert_from_double (
-      (BablFormat *) BABL (babl->fish.destination),
-      destination_double_buf,
-      destination,
-      n
-    );
+     }
+     break;
+  case KIND_RGB:
+      {
+        const Babl *destination_rgba_format =
+          babl_remodel_with_space (babl_model_from_id (BABL_RGBA),
+               BABL (BABL ((babl->fish.destination))->format.space));
 
-    if (destination_double_buf_alloc)
-      babl_free (destination_double_buf_alloc);
-    if (rgba_double_buf_alloc)
-      babl_free (rgba_double_buf_alloc);
-    if (source_double_buf_alloc)
-      babl_free (source_double_buf_alloc);
-    if (source_image)
-      babl_free (source_image);
-    if (rgba_image)
-      babl_free (rgba_image);
-    if (destination_image)
-      babl_free (destination_image);
+        if(BABL (babl->fish.destination)->format.model == (void*)destination_rgba_format)
+        {
+           destination_double_buf = rgba_double_buf;
+        }
+        else
+        {
+        Babl *conv =
+          assert_conversion_find (destination_rgba_format,
+             BABL (babl->fish.destination)->format.model);
+           destination_double_buf_alloc = babl_malloc (sizeof (double) * n *
+                                            BABL (babl->fish.destination)->format.model->components);
+           destination_double_buf = destination_double_buf_alloc;
+
+        if (conv->class_type == BABL_CONVERSION_PLANAR)
+          {
+            destination_image = babl_image_from_linear (
+              destination_double_buf, BABL (BABL ((babl->fish.destination))->format.model));
+            babl_conversion_process (
+              conv,
+              (void*)rgba_image, (void*)destination_image,
+              n);
+          }
+        else if (conv->class_type == BABL_CONVERSION_LINEAR)
+          {
+            babl_conversion_process (
+              conv,
+              rgba_double_buf, destination_double_buf,
+              n);
+          }
+        else
+          {
+            babl_fatal ("oops");
+          }
+        }
+     }
+   break;
+  }
+  babl_mutex_unlock (babl_reference_mutex);
+
+ /* convert from double model backing target pixel format to final representation */
+  convert_from_double (
+    (BablFormat *) BABL (babl->fish.destination),
+    destination_double_buf,
+    destination,
+    n
+  );
+
+  if (destination_double_buf_alloc)
+    babl_free (destination_double_buf_alloc);
+  if (rgba_double_buf_alloc)
+    babl_free (rgba_double_buf_alloc);
+  if (cmyka_double_buf_alloc)
+    babl_free (cmyka_double_buf_alloc);
+  if (source_double_buf_alloc)
+    babl_free (source_double_buf_alloc);
+  if (source_image)
+    babl_free (source_image);
+  if (rgba_image)
+    babl_free (rgba_image);
+  if (cmyka_image)
+    babl_free (cmyka_image);
+  if (destination_image)
+    babl_free (destination_image);
 }
 
 static void
@@ -870,6 +1117,7 @@ babl_fish_reference_process_float (const Babl *babl,
     Babl *conv_from_rgba;
     char dst_name[256];
 
+
     {
     char src_name[256];
     sprintf (src_name, "%s float", babl_get_name((void*)babl->fish.source->format.model));
@@ -978,7 +1226,6 @@ babl_fish_reference_process_float (const Babl *babl,
     }
 
     {
-
       if(babl_format_with_space ("RGBA float",
                    BABL (BABL ((babl->fish.destination))->format.space)) ==
          babl_format_with_space (dst_name,
@@ -1070,6 +1317,13 @@ babl_fish_reference_process (const Babl *babl,
     return;
   }
 
+  if (format_has_cmyk_model (babl->fish.source) ||
+      format_has_cmyk_model (babl->fish.destination))
+  {
+    babl_fish_reference_process_double (babl, source, destination, n, data);
+    return;
+  }
+
   if (allow_float_reference == -1)
     allow_float_reference = getenv ("BABL_REFERENCE_NOFLOAT") ? 0 : 1;
 
diff --git a/babl/babl-fish.c b/babl/babl-fish.c
index 8c239eb..a3d299c 100644
--- a/babl/babl-fish.c
+++ b/babl/babl-fish.c
@@ -126,7 +126,7 @@ babl_conversion_find (const void *source,
     babl_list_each (BABL (source)->type.from_list, match_conversion, &data);
   if (data != (void*)destination) /* didn't change */
   {
-    return data;
+    return data; /* found conversion */
   }
   data = NULL;
 
@@ -160,19 +160,19 @@ babl_conversion_find (const void *source,
                             reference->conversion.function.linear,
                             NULL,
                             NULL,
-                            reference->conversion.data);
+                            reference->conversion.data, 1);
         case BABL_CONVERSION_PLANE:
           return _conversion_new ("", 0, source, destination,
                             NULL,
                             reference->conversion.function.plane,
                             NULL,
-                            reference->conversion.data);
+                            reference->conversion.data, 1);
         case BABL_CONVERSION_PLANAR:
           return _conversion_new ("", 0, source, destination,
                             NULL,
                             NULL,
                             reference->conversion.function.planar,
-                            reference->conversion.data);
+                            reference->conversion.data, 1);
      }
   }
   return NULL;
@@ -278,33 +278,39 @@ babl_fish (const void *source,
 
         if (!ffish.fish_fish)
           {
+            const Babl *src_space = (void*)source_format->format.space;
+            const Babl *dst_space = (void*)destination_format->format.space;
             /* we haven't tried to search for suitable path yet */
-            Babl *fish_path = babl_fish_path (source_format, destination_format);
 
-            if (fish_path)
+            if (src_space->space.cmyk.is_cmyk == 0 &&
+                dst_space->space.cmyk.is_cmyk == 0)
               {
-                return fish_path;
-              }
+                Babl *fish_path = babl_fish_path (source_format, destination_format);
+                if (fish_path)
+                  {
+                    return fish_path;
+                  }
 #if 1
-            else
-              {
-                /* there isn't a suitable path for requested formats,
-                 * let's create a dummy BABL_FISH instance and insert
-                 * it into the fish database to indicate that such path
-                 * does not exist.
-                 */
-                char *name = "X"; /* name does not matter */
-                Babl *fish = babl_calloc (1, sizeof (BablFish) + strlen (name) + 1);
-
-                fish->class_type                = BABL_FISH;
-                fish->instance.id               = babl_fish_get_id (source_format, destination_format);
-                fish->instance.name             = ((char *) fish) + sizeof (BablFish);
-                strcpy (fish->instance.name, name);
-                fish->fish.source               = source_format;
-                fish->fish.destination          = destination_format;
-                babl_db_insert (babl_fish_db (), fish);
-              }
+                else
+                  {
+                    /* there isn't a suitable path for requested formats,
+                     * let's create a dummy BABL_FISH instance and insert
+                     * it into the fish database to indicate that such path
+                     * does not exist.
+                     */
+                    char *name = "X"; /* name does not matter */
+                    Babl *fish = babl_calloc (1, sizeof (BablFish) + strlen (name) + 1);
+
+                    fish->class_type                = BABL_FISH;
+                    fish->instance.id               = babl_fish_get_id (source_format, destination_format);
+                    fish->instance.name             = ((char *) fish) + sizeof (BablFish);
+                    strcpy (fish->instance.name, name);
+                    fish->fish.source               = source_format;
+                    fish->fish.destination          = destination_format;
+                    babl_db_insert (babl_fish_db (), fish);
+                  }
 #endif
+                }
           }
         else if (ffish.fish_fish->fish.data)
           {
diff --git a/babl/babl-icc.c b/babl/babl-icc.c
index 1ffe415..67c98e6 100644
--- a/babl/babl-icc.c
+++ b/babl/babl-icc.c
@@ -16,7 +16,7 @@
  * <https://www.gnu.org/licenses/>.
  */
 
-#include "config.h"
+#include "../config.h"
 #include "babl-internal.h"
 #include <stdio.h>
 #include <stdlib.h>
@@ -720,6 +720,10 @@ static char *decode_string (ICC *state, const char *tag, const char *lang, const
   return NULL;
 }
 
+#ifdef HAVE_LCMS
+static cmsHPROFILE sRGBProfile = 0;
+#endif
+
 const Babl *
 babl_space_from_icc (const char   *icc_data,
                      int           icc_length,
@@ -748,14 +752,55 @@ babl_space_from_icc (const char   *icc_data,
   else
   {
     profile_class = icc_read (sign, 12);
-    if (strcmp (profile_class.str, "mntr"))
-      *error = "not a monitor-class profile";
-     else
+    color_space = icc_read (sign, 16);
+
+    if (!strcmp (color_space.str, "CMYK"))
     {
-      color_space = icc_read (sign, 16);
-      if (strcmp (color_space.str, "RGB "))
-        *error = "not defining an RGB space";
+       ret = _babl_space_for_lcms (icc_data, icc_length);
+       if (ret->space.cmyk.is_cmyk)
+         return ret;
+       ret->space.cmyk.is_cmyk = 1;
+       ret->space.icc_length = icc_length;
+       ret->space.icc_profile = malloc (icc_length);
+       memcpy (ret->space.icc_profile, icc_data, icc_length);
+
+#ifdef HAVE_LCMS
+       if (sRGBProfile == 0)
+       {
+         const Babl *rgb = babl_space("babl-rgb"); /* should use a forced linear profile */
+         sRGBProfile = cmsOpenProfileFromMem(rgb->space.icc_profile, rgb->space.icc_length);
+       }
+
+       ret->space.cmyk.lcms_profile = cmsOpenProfileFromMem(ret->space.icc_profile, ret->space.icc_length);
+
+/* these are not defined by lcms2.h we hope that following the existing pattern of pixel-format definitions 
work */
+#ifndef TYPE_CMYKA_DBL
+#define TYPE_CMYKA_DBL      (FLOAT_SH(1)|COLORSPACE_SH(PT_CMYK)|EXTRA_SH(1)|CHANNELS_SH(4)|BYTES_SH(0))
+#endif
+#ifndef TYPE_RGBA_DBL
+#define TYPE_RGBA_DBL      (FLOAT_SH(1)|COLORSPACE_SH(PT_RGB)|EXTRA_SH(1)|CHANNELS_SH(3)|BYTES_SH(0))
+#endif
+
+       ret->space.cmyk.lcms_to_rgba = cmsCreateTransform(ret->space.cmyk.lcms_profile, TYPE_CMYKA_DBL,
+                                                    sRGBProfile, TYPE_RGBA_DBL,
+                                                    INTENT_RELATIVE_COLORIMETRIC, 
cmsFLAGS_BLACKPOINTCOMPENSATION);
+// INTENT_PERCEPTUAL,0);//intent & 7, 0);
+       ret->space.cmyk.lcms_from_rgba = cmsCreateTransform(sRGBProfile, TYPE_RGBA_DBL,
+                                                      ret->space.cmyk.lcms_profile, TYPE_CMYKA_DBL,
+                                                    INTENT_RELATIVE_COLORIMETRIC, 
cmsFLAGS_BLACKPOINTCOMPENSATION);
+                                                    //  INTENT_PERCEPTUAL,0);//intent & 7, 0);
+       cmsCloseProfile (ret->space.cmyk.lcms_profile); // XXX keep it open in case of CMYK to CMYK 
transforms needed?
+#endif
+       return ret;
     }
+
+    if (strcmp (color_space.str, "RGB "))
+      *error = "not defining an RGB space";
+    else
+     {
+       if (strcmp (profile_class.str, "mntr"))
+         *error = "not a monitor-class profile";
+     }
   }
 
   if (!*error)
@@ -827,6 +872,7 @@ babl_space_from_icc (const char   *icc_data,
 
   if (*error)
   {
+
     babl_free (state);
     return NULL;
   }
diff --git a/babl/babl-internal.h b/babl/babl-internal.h
index 73fe18f..95ca661 100644
--- a/babl/babl-internal.h
+++ b/babl/babl-internal.h
@@ -347,7 +347,8 @@ _conversion_new (const char    *name,
                  BablFuncLinear linear,
                  BablFuncPlane  plane,
                  BablFuncPlanar planar,
-                 void          *user_data);
+                 void          *user_data,
+                 int            allow_collision);
 
 double _babl_legal_error (void);
 void babl_init_db (void);
@@ -373,7 +374,9 @@ Babl * format_new_from_format_with_space (const Babl *format, const Babl *space)
 int babl_list_destroy (void *data);
 
 const char *
-babl_conversion_create_name (Babl *source, Babl *destination, int is_reference);
+babl_conversion_create_name (Babl *source, Babl *destination, int type,
+                             int allow_collision);
+
 void _babl_space_add_universal_rgb (const Babl *space);
 const Babl *
 babl_trc_formula_srgb (double gamma, double a, double b, double c, double d);
@@ -453,5 +456,7 @@ char *babl_space_to_icc (const Babl  *space,
                          const char  *copyright,
                          BablICCFlags flags,
                          int         *icc_length);
+Babl *
+_babl_space_for_lcms (const char *icc_data, int icc_length); // XXX pass profile for dedup?
 
 #endif
diff --git a/babl/babl-model.c b/babl/babl-model.c
index f5330fe..4ce2211 100644
--- a/babl/babl-model.c
+++ b/babl/babl-model.c
@@ -56,7 +56,8 @@ model_new (const char     *name,
            const Babl     *space,
            int             id,
            int             components,
-           BablComponent **component)
+           BablComponent **component,
+           int             is_cmyk)
 {
   Babl *babl;
 
@@ -73,6 +74,7 @@ model_new (const char     *name,
   babl->model.space      = space;
   babl->model.data       = NULL;
   babl->model.model      = NULL;
+  babl->model.is_cmyk    = is_cmyk;
   strcpy (babl->instance.name, name);
   memcpy (babl->model.component, component, sizeof (BablComponent *) * components);
 
@@ -114,6 +116,7 @@ babl_model_new (void *first_argument,
   char          *name          = NULL;
   const Babl    *space         = babl_space ("sRGB");
   BablComponent *component [BABL_MAX_COMPONENTS];
+  int            is_cmyk       = 0;
 
   va_start (varg, first_argument);
 
@@ -130,6 +133,11 @@ babl_model_new (void *first_argument,
           assigned_name = va_arg (varg, char *);
         }
 
+      else if (!strcmp (arg, "cmyk"))
+        {
+          is_cmyk = 1;
+        }
+
       /* if we didn't point to a known string, we assume argument to be babl */
       else if (BABL_IS_BABL (arg))
         {
@@ -211,7 +219,7 @@ babl_model_new (void *first_argument,
 
   if (! babl)
     {
-      babl = model_new (name, space, id, components, component);
+      babl = model_new (name, space, id, components, component, is_cmyk);
       babl_db_insert (db, babl);
       construct_double_format (babl);
     }
diff --git a/babl/babl-model.h b/babl/babl-model.h
index ee0e51f..74595a8 100644
--- a/babl/babl-model.h
+++ b/babl/babl-model.h
@@ -32,6 +32,7 @@ typedef struct
   void             *data;    /* user-data, used for palette */
   const Babl       *space;
   void             *model;   /* back pointer to model with sRGB space */
+  int               is_cmyk; /* is an cmyk based model */
 } BablModel;
 
 #endif
diff --git a/babl/babl-sanity.c b/babl/babl-sanity.c
index 2c18d56..7282766 100644
--- a/babl/babl-sanity.c
+++ b/babl/babl-sanity.c
@@ -69,7 +69,7 @@ model_sanity (Babl *babl,
               void *user_data)
 {
   /* ensure that every type has reference conversions to
-   * and from rgba */
+   * and from RGBA / cmykA */
   int      ok, i;
   BablList *list;
 
@@ -79,17 +79,22 @@ model_sanity (Babl *babl,
     {
       for (i = 0; i < babl_list_size (list); i++)
         {
-          if (babl_conversion_destination ((Babl *) list->items[i]) == babl_model_from_id (BABL_RGBA))
+          if (babl_conversion_destination ((Babl *) list->items[i]) == babl_model_from_id (BABL_RGBA) ||
+             babl_conversion_destination ((Babl *) list->items[i]) == babl_model ("cmykA"))
             {
               ok = 1;
               break;
             }
         }
     }
+
+  if (ok == 0 && babl == babl_model ("cmykA"))
+    ok = 1;
+
   if (!ok)
     {
       OK = 0;
-      babl_log ("lack of sanity! model '%s' has no conversion to 'rgba'",
+      babl_log ("lack of sanity! model '%s' has no conversion to 'RGBA' or 'cmykA'",
                 babl->instance.name);
     }
 
diff --git a/babl/babl-space.c b/babl/babl-space.c
index 9a78d38..fcadc8c 100644
--- a/babl/babl-space.c
+++ b/babl/babl-space.c
@@ -219,6 +219,50 @@ babl_space (const char *name)
   return NULL;
 }
 
+Babl *
+_babl_space_for_lcms (const char *icc_data, int icc_length)
+{
+  int i=0;
+  BablSpace space;
+
+
+  for (i = 0; space_db[i].instance.class_type; i++)
+  {
+    if (space_db[i].icc_length ==
+        icc_length &&
+        (memcmp (space_db[i].icc_profile, icc_data, icc_length) == 0))
+    {
+        return (void*)&space_db[i];
+    }
+  }
+
+  memset (&space, 0, sizeof(space));
+  space.instance.class_type = BABL_SPACE;
+  space.instance.id         = 0;
+
+  if (i >= MAX_SPACES-1)
+  {
+    babl_log ("too many BablSpaces");
+    return NULL;
+  }
+
+  /* initialize it with copy of srgb content */
+  if(1){
+    const BablSpace *srgb = &babl_space("sRGB")->space;
+    memcpy (&space.xw,
+            &srgb->xw,
+((char*)&srgb->icc_profile -
+(char*)&srgb->xw));
+  }
+
+  space_db[i]=space;
+  space_db[i].instance.name = space_db[i].name;
+  snprintf (space_db[i].name, sizeof (space_db[i].name), "space-lcms-%i", i);
+
+
+  return (Babl*)&space_db[i];
+}
+
 const Babl *
 babl_space_from_rgbxyz_matrix (const char *name,
                                double wx, double wy, double wz,
@@ -310,6 +354,7 @@ babl_space_from_rgbxyz_matrix (const char *name,
              wx,wy,rx,ry,bx,by,gx,gy,babl_get_name (space.trc[0]),
              babl_get_name(space.trc[1]), babl_get_name(space.trc[2]));
 
+  babl_space_get_icc ((Babl*)&space_db[i], NULL);
   return (Babl*)&space_db[i];
 }
 
@@ -373,6 +418,7 @@ const Babl * babl_space_from_chromaticities (const char *name,
   /* compute matrixes */
   babl_space_compute_matrices (&space_db[i], flags);
 
+  babl_space_get_icc ((Babl*)&space_db[i], NULL);
   return (Babl*)&space_db[i];
 }
 
@@ -406,6 +452,14 @@ babl_space_class_init (void)
                 0);
   /* hard-coded pre-quantized values - to match exactly what is used in standards see issue #18 */
 #endif
+  babl_space_from_chromaticities ("babl-rgb",
+                0.3127,  0.3290, /* D65 */
+                0.639998686, 0.330010138,
+                0.300003784, 0.600003357,
+                0.150002046, 0.059997204,
+                babl_trc("linear"), NULL, NULL,
+                0);
+  /* hard-coded pre-quantized values - to match exactly what is used in standards see issue #18 */
 
   babl_space_from_chromaticities ("Rec2020",
                0.3127,  0.3290, /* D65 */
@@ -1015,7 +1069,8 @@ const Babl *babl_space_match_trc_matrix (const Babl *trc_red,
   for (i = 0; space_db[i].instance.class_type; i++)
   {
     BablSpace *space = &space_db[i];
-    if (trc_red == space->trc[0] &&
+    if (space->cmyk.is_cmyk == 0 &&
+        trc_red == space->trc[0] &&
         trc_green == space->trc[1] &&
         trc_blue == space->trc[2] &&
         fabs(rx - space->RGBtoXYZ[0]) < delta &&
@@ -1082,6 +1137,11 @@ void babl_space_get (const Babl *babl,
   if(blue_trc)*blue_trc = space->trc[2];
 }
 
+int babl_space_is_cmyk (const Babl *space)
+{
+  return space?space->space.cmyk.is_cmyk:0;
+}
+
 /* Trademarks:
  *
  * International Color Consortium is a registered trademarks of the.
@@ -1091,3 +1151,4 @@ void babl_space_get (const Babl *babl,
  * RGB- without actualy being it, Adobe is a trademark or registered trademark
  * of Adobe Systems Incorporated in many countires.
  */
+
diff --git a/babl/babl-space.h b/babl/babl-space.h
index 35fd2c3..92926ba 100644
--- a/babl/babl-space.h
+++ b/babl/babl-space.h
@@ -19,13 +19,28 @@
 #ifndef _BABL_SPACE_H
 #define _BABL_SPACE_H
 
+#include "../config.h"
 #include <math.h>
 #include <string.h>
 #include "base/util.h"
 #include "babl-matrix.h"
 
+#ifdef HAVE_LCMS
+#include <lcms2.h>
+#endif
+
 BABL_CLASS_DECLARE (space);
 
+typedef struct
+{
+  int           is_cmyk;
+#ifdef HAVE_LCMS
+  cmsHPROFILE   lcms_profile;
+  cmsHTRANSFORM lcms_to_rgba;
+  cmsHTRANSFORM lcms_from_rgba;
+#endif
+} BablCMYK;
+
 typedef struct
 {
   BablInstance     instance;
@@ -62,6 +77,7 @@ typedef struct
   char *icc_profile;
   int   icc_length;
 
+  BablCMYK cmyk;
 } BablSpace;
 
 
diff --git a/babl/babl.c b/babl/babl.c
index ef2cfb7..4479f68 100644
--- a/babl/babl.c
+++ b/babl/babl.c
@@ -125,8 +125,6 @@ babl_dir_list (void)
   return ret;
 }
 
-extern int _babl_loaded;
-
 void
 babl_init (void)
 {
@@ -135,7 +133,6 @@ babl_init (void)
   if (ref_count++ == 0)
     {
       char * dir_list;
-      _babl_loaded = 0;
 
       babl_internal_init ();
       babl_sampling_class_init ();
@@ -158,7 +155,6 @@ babl_init (void)
       babl_free (dir_list);
 
       babl_init_db ();
-      _babl_loaded = 1;
     }
 }
 
diff --git a/babl/babl.h b/babl/babl.h
index 943de99..1301270 100644
--- a/babl/babl.h
+++ b/babl/babl.h
@@ -584,6 +584,9 @@ babl_space_from_rgbxyz_matrix (const char *name,
  */
 const char * babl_format_get_encoding (const Babl *babl);
 
+
+int babl_space_is_cmyk (const Babl *space);
+
 /* values below this are stored premultiplied with this value,
  * it can also be used as a generic alpha zero epsilon in GEGL
  *
diff --git a/babl/base/Makefile.am b/babl/base/Makefile.am
index 1b0fabe..70a2f30 100644
--- a/babl/base/Makefile.am
+++ b/babl/base/Makefile.am
@@ -14,6 +14,7 @@ c_sources =                   \
        type-u32.c              \
        model-rgb.c             \
        model-gray.c            \
+       model-cmyk.c            \
        model-ycbcr.c
 
 AM_CPPFLAGS = -I$(top_srcdir) -I$(top_srcdir)/babl
diff --git a/babl/base/babl-base.c b/babl/base/babl-base.c
index 7931cfc..1d93341 100644
--- a/babl/base/babl-base.c
+++ b/babl/base/babl-base.c
@@ -69,6 +69,7 @@ models (void)
   babl_hmpf_on_name_lookups--;
   babl_base_model_rgb ();
   babl_base_model_gray ();
+  babl_base_model_cmyk ();
   babl_hmpf_on_name_lookups++;
   babl_base_model_ycbcr ();
 }
diff --git a/babl/base/babl-base.h b/babl/base/babl-base.h
index bc67f5c..64f1667 100644
--- a/babl/base/babl-base.h
+++ b/babl/base/babl-base.h
@@ -33,6 +33,7 @@ void babl_base_type_u32    (void);
 
 void babl_base_model_pal   (void);
 void babl_base_model_rgb   (void);
+void babl_base_model_cmyk  (void);
 void babl_base_model_gray  (void);
 void babl_base_model_ycbcr (void);
 
diff --git a/babl/base/model-cmyk.c b/babl/base/model-cmyk.c
new file mode 100644
index 0000000..6b771a5
--- /dev/null
+++ b/babl/base/model-cmyk.c
@@ -0,0 +1,1083 @@
+/* babl - dynamically extendable universal pixel conversion library.
+ * Copyright (C) 2005, 2018 Øyvind Kolås.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see
+ * <https://www.gnu.org/licenses/>.
+ */
+
+/* This file define the "cmy" and "cmyk" models and related formats these
+ * are CMYK formats withthe components stored so that 0 means full coverage
+ * and 1.0 means no coverage which makes additive compositing/blending work
+ * like as if it was RGB
+
+ * conversions should be made with reference to the icc profile in the space
+ * using lcms2 for handling.
+ */
+
+#include "config.h"
+#include <math.h>
+#include <string.h>
+
+#include "babl.h"
+#include "babl-base.h"
+#include "base/util.h"
+
+
+static void
+cmyka_to_cmykA (const Babl *conversion,char *src,
+                char *dst,
+                long  n)
+{
+  while (n--)
+    {
+      double cyan    = ((double *) src)[0];
+      double magenta = ((double *) src)[1];
+      double yellow  = ((double *) src)[2];
+      double key     = ((double *) src)[3];
+      double alpha   = ((double *) src)[4];
+
+      ((double *) dst)[0] = (cyan)    * alpha;
+      ((double *) dst)[1] = (magenta) * alpha;
+      ((double *) dst)[2] = (yellow)  * alpha;
+      ((double *) dst)[3] = (key)     * alpha;
+      ((double *) dst)[4] = alpha;
+
+      src += 5 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+static void
+cmykA_to_cmyka (const Babl *conversion,char *src,
+                char *dst,
+                long  n)
+{
+  while (n--)
+    {
+      double alpha   = ((double *) src)[4];
+      double ralpha  = alpha>0.000001?1.0/alpha:0.0;
+      double cyan   = ((double *) src)[0] * ralpha;
+      double magenta= ((double *) src)[1] * ralpha;
+      double yellow = ((double *) src)[2] * ralpha;
+      double key    = ((double *) src)[3] * ralpha;
+
+      ((double *) dst)[0] = cyan;
+      ((double *) dst)[1] = magenta;
+      ((double *) dst)[2] = yellow;
+      ((double *) dst)[3] = key;
+      ((double *) dst)[4] = alpha;
+
+      src += 5 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+static void
+cmyk_to_cmyka (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double cyan    = ((double *) src)[0];
+      double magenta = ((double *) src)[1];
+      double yellow  = ((double *) src)[2];
+      double key     = ((double *) src)[3];
+
+      ((double *) dst)[0] = cyan;
+      ((double *) dst)[1] = magenta;
+      ((double *) dst)[2] = yellow;
+      ((double *) dst)[3] = key;
+      ((double *) dst)[4] = 1.0;
+
+      src += 4 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+static void
+cmyka_to_cmyk (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double cyan    = ((double *) src)[0];
+      double magenta = ((double *) src)[1];
+      double yellow  = ((double *) src)[2];
+      double key     = ((double *) src)[3];
+
+      ((double *) dst)[0] = cyan;
+      ((double *) dst)[1] = magenta;
+      ((double *) dst)[2] = yellow;
+      ((double *) dst)[3] = key;
+
+      src += 5 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+}
+
+/////////////////////
+static void
+cmyka_to_CMYKA (const Babl *conversion,char *src,
+                char *dst,
+                long  n)
+{
+  while (n--)
+    {
+      double cyan    = ((double *) src)[0];
+      double magenta = ((double *) src)[1];
+      double yellow  = ((double *) src)[2];
+      double key     = ((double *) src)[3];
+      double alpha   = ((double *) src)[4];
+
+      ((double *) dst)[0] = (1.0-cyan)    * alpha;
+      ((double *) dst)[1] = (1.0-magenta) * alpha;
+      ((double *) dst)[2] = (1.0-yellow)  * alpha;
+      ((double *) dst)[3] = (1.0-key)     * alpha;
+      ((double *) dst)[4] = alpha;
+
+      src += 5 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+static void
+CMYKA_to_cmyka (const Babl *conversion,char *src,
+                char *dst,
+                long  n)
+{
+  while (n--)
+    {
+      double alpha   = ((double *) src)[4];
+      double ralpha  = alpha>0.000001?1.0/alpha:0.0;
+      double cyan   = ((double *) src)[0] * ralpha;
+      double magenta= ((double *) src)[1] * ralpha;
+      double yellow = ((double *) src)[2] * ralpha;
+      double key    = ((double *) src)[3] * ralpha;
+
+      ((double *) dst)[0] = 1.0-cyan;
+      ((double *) dst)[1] = 1.0-magenta;
+      ((double *) dst)[2] = 1.0-yellow;
+      ((double *) dst)[3] = 1.0-key;
+      ((double *) dst)[4] = alpha;
+
+      src += 5 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+
+
+static void
+CMYK_to_cmyka (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double cyan    = ((double *) src)[0];
+      double magenta = ((double *) src)[1];
+      double yellow  = ((double *) src)[2];
+      double key     = ((double *) src)[3];
+
+      ((double *) dst)[0] = 1.0-cyan;
+      ((double *) dst)[1] = 1.0-magenta;
+      ((double *) dst)[2] = 1.0-yellow;
+      ((double *) dst)[3] = 1.0-key;
+      ((double *) dst)[4] = 1.0;
+
+      src += 4 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+static void
+cmyka_to_CMYK (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double cyan    = ((double *) src)[0];
+      double magenta = ((double *) src)[1];
+      double yellow  = ((double *) src)[2];
+      double key     = ((double *) src)[3];
+
+      ((double *) dst)[0] = 1.0-cyan;
+      ((double *) dst)[1] = 1.0-magenta;
+      ((double *) dst)[2] = 1.0-yellow;
+      ((double *) dst)[3] = 1.0-key;
+
+      src += 5 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+}
+
+static void
+cmyka_to_CMYKa (const Babl *conversion,char *src,
+                char *dst,
+                long  n)
+{
+  while (n--)
+    {
+      double cyan    = ((double *) src)[0];
+      double magenta = ((double *) src)[1];
+      double yellow  = ((double *) src)[2];
+      double key     = ((double *) src)[3];
+      double alpha   = ((double *) src)[4];
+
+      ((double *) dst)[0] = 1.0-cyan;
+      ((double *) dst)[1] = 1.0-magenta;
+      ((double *) dst)[2] = 1.0-yellow;
+      ((double *) dst)[3] = 1.0-key;
+      ((double *) dst)[4] = alpha;
+
+      src += 5 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+
+
+
+
+
+
+#if 0
+static void
+rgba_to_cmykA (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double red   = (((double *) src)[0]);
+      double green = (((double *) src)[1]);
+      double blue  = (((double *) src)[2]);
+      double alpha = ((double *) src)[3];
+
+      double cyan, magenta, yellow, key;
+
+      double pullout = 1.0;
+
+      cyan    = 1.0 - red;
+      magenta = 1.0 - green;
+      yellow  = 1.0 - blue;
+
+      key = 1.0;
+      if (cyan < key) key = cyan;
+      if (magenta < key) key = magenta;
+      if (yellow < key) key = yellow;
+
+      key *= pullout;
+
+      if (key < 1.0)
+        {
+          cyan    = (cyan - key)    / (1.0 - key);
+          magenta = (magenta - key) / (1.0 - key);
+          yellow  = (yellow - key)  / (1.0 - key);
+        }
+      else
+        {
+          cyan    = 0.0;
+          magenta = 0.0;
+          yellow  = 0.0;
+        }
+
+      ((double *) dst)[0] = (1.0-cyan) * alpha;
+      ((double *) dst)[1] = (1.0-magenta) * alpha;
+      ((double *) dst)[2] = (1.0-yellow) * alpha;
+      ((double *) dst)[3] = (1.0-key) * alpha;
+      ((double *) dst)[4] = alpha;
+
+      src += 4 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+static void
+cmykA_to_rgba (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double alpha   = ((double *) src)[4];
+      double ralpha  = alpha>0.000001?1.0/alpha:0.0;
+      double cyanI   = ((double *) src)[0] * ralpha;
+      double magentaI= ((double *) src)[1] * ralpha;
+      double yellowI = ((double *) src)[2] * ralpha;
+      double keyI    = ((double *) src)[3] * ralpha;
+
+      double cyan    = 1.0-cyanI;
+      double magenta = 1.0-magentaI;
+      double yellow  = 1.0-yellowI;
+      double key     = 1.0-keyI;
+
+      double red, green, blue;
+
+      if (key < 1.0)
+        {
+          cyan    = cyan * (1.0 - key) + key;
+          magenta = magenta * (1.0 - key) + key;
+          yellow  = yellow * (1.0 - key) + key;
+        }
+      else
+        {
+          cyan = magenta = yellow = 1.0;
+        }
+
+      red   = 1.0 - cyan;
+      green = 1.0 - magenta;
+      blue  = 1.0 - yellow;
+
+      ((double *) dst)[0] = (red);
+      ((double *) dst)[1] = (green);
+      ((double *) dst)[2] = (blue);
+      ((double *) dst)[3] = alpha;
+
+      src += 5 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+}
+
+static void
+rgba_to_cmyka (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double red   = (((double *) src)[0]);
+      double green = (((double *) src)[1]);
+      double blue  = (((double *) src)[2]);
+      double alpha = ((double *) src)[3];
+
+      double cyan, magenta, yellow, key;
+
+      double pullout = 1.0;
+
+      cyan    = 1.0 - red;
+      magenta = 1.0 - green;
+      yellow  = 1.0 - blue;
+
+      key = 1.0;
+      if (cyan < key) key = cyan;
+      if (magenta < key) key = magenta;
+      if (yellow < key) key = yellow;
+
+      key *= pullout;
+
+      if (key < 1.0)
+        {
+          cyan    = (cyan - key)    / (1.0 - key);
+          magenta = (magenta - key) / (1.0 - key);
+          yellow  = (yellow - key)  / (1.0 - key);
+        }
+      else
+        {
+          cyan    = 0.0;
+          magenta = 0.0;
+          yellow  = 0.0;
+        }
+
+      ((double *) dst)[0] = 1.0-cyan;
+      ((double *) dst)[1] = 1.0-magenta;
+      ((double *) dst)[2] = 1.0-yellow;
+      ((double *) dst)[3] = 1.0-key;
+      ((double *) dst)[4] = alpha;
+
+      src += 4 * sizeof (double);
+      dst += 5 * sizeof (double);
+    }
+}
+
+static void
+cmyka_to_rgba (const Babl *conversion,char *src,
+               char *dst,
+               long  n)
+{
+  while (n--)
+    {
+      double cyan    = 1.0-((double *) src)[0];
+      double magenta = 1.0-((double *) src)[1];
+      double yellow  = 1.0-((double *) src)[2];
+      double key     = 1.0-((double *) src)[3];
+      double alpha   = ((double *) src)[4];
+
+      double red, green, blue;
+
+      if (key < 1.0)
+        {
+          cyan    = cyan * (1.0 - key) + key;
+          magenta = magenta * (1.0 - key) + key;
+          yellow  = yellow * (1.0 - key) + key;
+        }
+      else
+        {
+          cyan = magenta = yellow = 1.0;
+        }
+
+      red   = 1.0 - cyan;
+      green = 1.0 - magenta;
+      blue  = 1.0 - yellow;
+
+      ((double *) dst)[0] = (red);
+      ((double *) dst)[1] = (green);
+      ((double *) dst)[2] = (blue);
+      ((double *) dst)[3] = alpha;
+
+      src += 5 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+}
+
+static void
+rgba_to_cmyk (const Babl *conversion,char *src,
+              char *dst,
+              long  n)
+{
+  while (n--)
+    {
+      double red   = (((double *) src)[0]);
+      double green = (((double *) src)[1]);
+      double blue  = (((double *) src)[2]);
+
+      double cyan, magenta, yellow, key;
+
+      double pullout = 1.0;
+
+      cyan    = 1.0 - red;
+      magenta = 1.0 - green;
+      yellow  = 1.0 - blue;
+
+      key = 1.0;
+      if (cyan < key) key = cyan;
+      if (magenta < key) key = magenta;
+      if (yellow < key) key = yellow;
+
+      key *= pullout;
+
+      if (key < 1.0)
+        {
+          cyan    = (cyan - key)    / (1.0 - key);
+          magenta = (magenta - key) / (1.0 - key);
+          yellow  = (yellow - key)  / (1.0 - key);
+        }
+      else
+        {
+          cyan    = 0.0;
+          magenta = 0.0;
+          yellow  = 0.0;
+        }
+
+      ((double *) dst)[0] = 1.0-cyan;
+      ((double *) dst)[1] = 1.0-magenta;
+      ((double *) dst)[2] = 1.0-yellow;
+      ((double *) dst)[3] = 1.0-key;
+
+      src += 4 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+}
+
+static void
+cmyk_to_rgba (const Babl *conversion,char *src,
+              char *dst,
+              long  n)
+{
+  while (n--)
+    {
+      double cyan    = 1.0-((double *) src)[0];
+      double magenta = 1.0-((double *) src)[1];
+      double yellow  = 1.0-((double *) src)[2];
+      double key     = 1.0-((double *) src)[3];
+
+      double red, green, blue;
+
+      if (key < 1.0)
+        {
+          cyan    = cyan * (1.0 - key) + key;
+          magenta = magenta * (1.0 - key) + key;
+          yellow  = yellow * (1.0 - key) + key;
+        }
+      else
+        {
+          cyan = magenta = yellow = 1.0;
+        }
+
+      red   = 1.0 - cyan;
+      green = 1.0 - magenta;
+      blue  = 1.0 - yellow;
+
+      ((double *) dst)[0] = (red);
+      ((double *) dst)[1] = (green);
+      ((double *) dst)[2] = (blue);
+
+      ((double *) dst)[3] = 1.0;
+
+      src += 4 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+}
+
+static void
+rgba_to_cmy (const Babl *conversion,char *src,
+             char *dst,
+             long  n)
+{
+  while (n--)
+    {
+      double red   = (((double *) src)[0]);
+      double green = (((double *) src)[1]);
+      double blue  = (((double *) src)[2]);
+
+      double cyan, magenta, yellow;
+
+      cyan    = 1.0 - red;
+      magenta = 1.0 - green;
+      yellow  = 1.0 - blue;
+
+      ((double *) dst)[0] = 1.0-cyan;
+      ((double *) dst)[1] = 1.0-magenta;
+      ((double *) dst)[2] = 1.0-yellow;
+
+      src += 4 * sizeof (double);
+      dst += 3 * sizeof (double);
+    }
+}
+
+static void
+cmy_to_rgba (const Babl *conversion,char *src,
+              char *dst,
+              long  n)
+{
+  while (n--)
+    {
+      double cyan    = 1.0-((double *) src)[0];
+      double magenta = 1.0-((double *) src)[1];
+      double yellow  = 1.0-((double *) src)[2];
+
+      double red, green, blue;
+
+      red   = 1.0 - cyan;
+      green = 1.0 - magenta;
+      blue  = 1.0 - yellow;
+
+      ((double *) dst)[0] = (red);
+      ((double *) dst)[1] = (green);
+      ((double *) dst)[2] = (blue);
+
+      ((double *) dst)[3] = 1.0;
+
+      src += 3 * sizeof (double);
+      dst += 4 * sizeof (double);
+    }
+}
+#endif
+
+void
+babl_base_model_cmyk (void)
+{
+  babl_component_new ("cyan", NULL);
+  babl_component_new ("yellow", NULL);
+  babl_component_new ("magenta", NULL);
+  babl_component_new ("key", NULL);
+
+
+  babl_component_new ("ca", NULL);
+  babl_component_new ("ma", NULL);
+  babl_component_new ("ya", NULL);
+  babl_component_new ("ka", NULL);
+
+
+  babl_component_new ("Cyan", NULL);
+  babl_component_new ("Yellow", NULL);
+  babl_component_new ("Magenta", NULL);
+  babl_component_new ("Key", NULL);
+
+
+  babl_component_new ("Ca", NULL);
+  babl_component_new ("Ma", NULL);
+  babl_component_new ("Yea", NULL);
+  babl_component_new ("Ka", NULL);
+
+  babl_model_new (
+    "name", "camayakaA",
+    babl_component ("ca"),
+    babl_component ("ma"),
+    babl_component ("ya"),
+    babl_component ("ka"),
+    babl_component ("A"),
+    "cmyk",
+    NULL
+  );
+
+  babl_model_new (
+    "name", "cmykA",
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    babl_component ("A"),
+    "cmyk",
+    NULL
+  );
+  babl_model_new (
+    "name", "cmyk",
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    "cmyk",
+    NULL
+  );
+
+  babl_model_new (
+    "name", "CaMaYaKaA",
+    babl_component ("Ca"),
+    babl_component ("Ma"),
+    babl_component ("Yea"),
+    babl_component ("Ka"),
+    babl_component ("A"),
+    "cmyk",
+    NULL
+  );
+
+  babl_model_new (
+    "name", "CMYKA",
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    babl_component ("A"),
+    "cmyk",
+    NULL
+  );
+  babl_model_new (
+    "name", "CMYK",
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    "cmyk",
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_model ("cmykA"),
+    babl_model ("cmyk"),
+    "linear", cmyka_to_cmyk,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("cmyk"),
+    babl_model ("cmykA"),
+    "linear", cmyk_to_cmyka,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("cmykA"),
+    babl_model ("camayakaA"),
+    "linear", cmyka_to_cmykA,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("camayakaA"),
+    babl_model ("cmykA"),
+    "linear", cmykA_to_cmyka,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_model ("cmykA"),
+    babl_model ("CMYKA"),
+    "linear", cmyka_to_CMYKa,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("CMYKA"),
+    babl_model ("cmykA"),
+    "linear", cmyka_to_CMYKa, // does the same job
+    NULL
+  );
+
+
+  babl_conversion_new (
+    babl_model ("cmykA"),
+    babl_model ("CMYK"),
+    "linear", cmyka_to_CMYK,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("CMYK"),
+    babl_model ("cmykA"),
+    "linear", CMYK_to_cmyka,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("cmykA"),
+    babl_model ("CaMaYaKaA"),
+    "linear", cmyka_to_CMYKA,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("CaMaYaKaA"),
+    babl_model ("cmykA"),
+    "linear", CMYKA_to_cmyka,
+    NULL
+  );
+
+
+
+#if 0
+
+  babl_conversion_new (
+    babl_model ("RGBA"),
+    babl_model ("camayakaA"),
+    "linear", rgba_to_cmykA,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("camayakaA"),
+    babl_model ("RGBA"),
+    "linear", cmykA_to_rgba,
+    NULL
+  );
+
+  babl_conversion_new (
+    babl_model ("RGBA"),
+    babl_model ("cmykA"),
+    "linear", rgba_to_cmyka,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("cmykA"),
+    babl_model ("RGBA"),
+    "linear", cmyka_to_rgba,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("RGBA"),
+    babl_model ("cmyk"),
+    "linear", rgba_to_cmyk,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("cmyk"),
+    babl_model ("RGBA"),
+    "linear", cmyk_to_rgba,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("RGBA"),
+    babl_model ("cmy"),
+    "linear", rgba_to_cmy,
+    NULL
+  );
+  babl_conversion_new (
+    babl_model ("cmy"),
+    babl_model ("RGBA"),
+    "linear", cmy_to_rgba,
+    NULL
+  );
+#endif
+
+  babl_format_new (
+    "name", "camayakaA float",
+    babl_model ("camayakaA"),
+    babl_type ("float"),
+    babl_component ("ca"),
+    babl_component ("ma"),
+    babl_component ("ya"),
+    babl_component ("ka"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "cmykA float",
+    babl_model ("cmykA"),
+    babl_type ("float"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "cmyk float",
+    babl_model ("cmyk"),
+    babl_type ("float"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    NULL
+  );
+
+  babl_format_new (
+    "name", "cmyk u8",
+    babl_model ("cmyk"),
+    babl_type ("u8"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "cmykA u8",
+    babl_model ("cmykA"),
+    babl_type ("u8"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    babl_component ("A"),
+    NULL
+  );
+
+  babl_format_new (
+    "name", "cmyk u16",
+    babl_model ("cmyk"),
+    babl_type ("u16"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "cmykA u16",
+    babl_model ("cmykA"),
+    babl_type ("u16"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "cmyk u32",
+    babl_model ("cmyk"),
+    babl_type ("u32"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "cmykA u32",
+    babl_model ("cmykA"),
+    babl_type ("u32"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    babl_component ("A"),
+    NULL
+  );
+
+  babl_format_new (
+    "name", "cmyk float",
+    babl_model ("cmyk"),
+    babl_type ("float"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "cmykA float",
+    babl_model ("cmykA"),
+    babl_type ("float"),
+    babl_component ("cyan"),
+    babl_component ("magenta"),
+    babl_component ("yellow"),
+    babl_component ("key"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "camayakaA u16",
+    babl_model ("camayakaA"),
+    babl_type ("u16"),
+    babl_component ("ca"),
+    babl_component ("ma"),
+    babl_component ("ya"),
+    babl_component ("ka"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "camayakaA half",
+    babl_model ("camayakaA"),
+    babl_type ("half"),
+    babl_component ("ca"),
+    babl_component ("ma"),
+    babl_component ("ya"),
+    babl_component ("ka"),
+    babl_component ("A"),
+    NULL
+  );
+
+  /********************************/
+  babl_format_new (
+    "name", "CaMaYaKaA float",
+    babl_model ("CaMaYaKaA"),
+    babl_type ("float"),
+    babl_component ("Ca"),
+    babl_component ("Ma"),
+    babl_component ("Ya"),
+    babl_component ("Ka"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CMYKA float",
+    babl_model ("CMYKA"),
+    babl_type ("float"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CMYK float",
+    babl_model ("CMYK"),
+    babl_type ("float"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    NULL
+  );
+
+  babl_format_new (
+    "name", "CMYK u8",
+    babl_model ("CMYK"),
+    babl_type ("u8"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CMYKA u8",
+    babl_model ("CMYKA"),
+    babl_type ("u8"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    babl_component ("A"),
+    NULL
+  );
+
+  babl_format_new (
+    "name", "CMYK u16",
+    babl_model ("CMYK"),
+    babl_type ("u16"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CMYKA u16",
+    babl_model ("CMYKA"),
+    babl_type ("u16"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CMYK u32",
+    babl_model ("CMYK"),
+    babl_type ("u32"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CMYKA u32",
+    babl_model ("CMYKA"),
+    babl_type ("u32"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    babl_component ("A"),
+    NULL
+  );
+
+  babl_format_new (
+    "name", "CMYK float",
+    babl_model ("CMYK"),
+    babl_type ("float"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CMYKA float",
+    babl_model ("CMYKA"),
+    babl_type ("float"),
+    babl_component ("Cyan"),
+    babl_component ("Magenta"),
+    babl_component ("Yellow"),
+    babl_component ("Key"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CaMaYaKaA u16",
+    babl_model ("CaMaYaKaA"),
+    babl_type ("u16"),
+    babl_component ("Ca"),
+    babl_component ("Ma"),
+    babl_component ("Yea"),
+    babl_component ("Ka"),
+    babl_component ("A"),
+    NULL
+  );
+  babl_format_new (
+    "name", "CaMaYaKaA half",
+    babl_model ("CaMaYaKaA"),
+    babl_type ("half"),
+    babl_component ("Ca"),
+    babl_component ("Ma"),
+    babl_component ("Yea"),
+    babl_component ("Ka"),
+    babl_component ("A"),
+    NULL
+  );
+}
+
diff --git a/export-symbols b/export-symbols
index 476238e..89a24e9 100644
--- a/export-symbols
+++ b/export-symbols
@@ -51,6 +51,7 @@ babl_space_to_xyz
 babl_space_from_xyz
 babl_space_to_icc
 babl_space_with_trc
+babl_space_is_cmyk
 babl_icc_make_space
 babl_icc_get_key
 babl_ticks
diff --git a/extensions/Makefile.am b/extensions/Makefile.am
index a066e8d..50e2a8e 100644
--- a/extensions/Makefile.am
+++ b/extensions/Makefile.am
@@ -54,6 +54,7 @@ gggl_table_la_SOURCES = gggl-table.c
 gggl_la_SOURCES = gggl.c
 gimp_8bit_la_SOURCES = gimp-8bit.c
 grey_la_SOURCES = grey.c
+CMYK_la_SOURCES = CMYK.c
 naive_CMYK_la_SOURCES = naive-CMYK.c
 HCY_la_SOURCES = HCY.c
 HSL_la_SOURCES = HSL.c
diff --git a/extensions/naive-CMYK.c b/extensions/naive-CMYK.c
index 3b7a70c..a8a874a 100644
--- a/extensions/naive-CMYK.c
+++ b/extensions/naive-CMYK.c
@@ -1,5 +1,5 @@
 /* babl - dynamically extendable universal pixel conversion library.
- * Copyright (C) 2005, Øyvind Kolås.
+ * Copyright (C) 2005, 2018 Øyvind Kolås.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -14,6 +14,9 @@
  * You should have received a copy of the GNU Lesser General
  * Public License along with this library; if not, see
  * <https://www.gnu.org/licenses/>.
+ *
+ * this is an interim file, to keep babl from complaining about double
+ * registration of cmyk formats.
  */
 
 #include "config.h"
@@ -23,248 +26,12 @@
 #include "babl.h"
 #include "base/util.h"
 
-
-static void  rgba_to_cmyk (const Babl *conversion,char *src,
-                           char *dst,
-                           long  n);
-
-static void  cmyk_to_rgba (const Babl *conversion,char *src,
-                           char *dst,
-                           long  n);
-
-static void  rgba_to_cmy  (const Babl *conversion,char *src,
-                           char *dst,
-                           long  n);
-
-static void  cmy_to_rgba  (const Babl *conversion,char *src,
-                           char *dst,
-                           long  n);
-
 int init (void);
 
 int
 init (void)
 {
-  babl_component_new ("cyan", NULL);
-  babl_component_new ("yellow", NULL);
-  babl_component_new ("magenta", NULL);
-  babl_component_new ("key", NULL);
-
-  babl_model_new (
-    "name", "CMYK",
-    babl_component ("cyan"),
-    babl_component ("magenta"),
-    babl_component ("yellow"),
-    babl_component ("key"),
-    NULL
-  );
-  babl_model_new (
-    "name", "CMY",
-    babl_component ("cyan"),
-    babl_component ("magenta"),
-    babl_component ("yellow"),
-    NULL
-  );
-
-  babl_conversion_new (
-    babl_model ("RGBA"),
-    babl_model ("CMYK"),
-    "linear", rgba_to_cmyk,
-    NULL
-  );
-  babl_conversion_new (
-    babl_model ("CMYK"),
-    babl_model ("RGBA"),
-    "linear", cmyk_to_rgba,
-    NULL
-  );
-  babl_conversion_new (
-    babl_model ("RGBA"),
-    babl_model ("CMY"),
-    "linear", rgba_to_cmy,
-    NULL
-  );
-  babl_conversion_new (
-    babl_model ("CMY"),
-    babl_model ("RGBA"),
-    "linear", cmy_to_rgba,
-    NULL
-  );
-
-  babl_format_new (
-    "name", "CMYK float",
-    babl_model ("CMYK"),
-    babl_type ("float"),
-    babl_component ("cyan"),
-    babl_component ("magenta"),
-    babl_component ("yellow"),
-    babl_component ("key"),
-    NULL
-  );
-  babl_format_new (
-    "name", "CMY float",
-    babl_model ("CMY"),
-    babl_type ("float"),
-    babl_component ("cyan"),
-    babl_component ("magenta"),
-    babl_component ("yellow"),
-    NULL
-  );
-
-  babl_format_new (
-    "name", "CMYK u8",
-    babl_model ("CMYK"),
-    babl_type ("u8"),
-    babl_component ("cyan"),
-    babl_component ("magenta"),
-    babl_component ("yellow"),
-    babl_component ("key"),
-    NULL
-  );
-
+  /* do nothing, drop this whole file after a couple of releases */
   return 0;
 }
 
-
-static void
-rgba_to_cmyk (const Babl *conversion,char *src,
-              char *dst,
-              long  n)
-{
-  while (n--)
-    {
-      double red   = linear_to_gamma_2_2 (((double *) src)[0]);
-      double green = linear_to_gamma_2_2 (((double *) src)[1]);
-      double blue  = linear_to_gamma_2_2 (((double *) src)[2]);
-
-      double cyan, magenta, yellow, key;
-
-      double pullout = 1.0;
-
-      cyan    = 1.0 - red;
-      magenta = 1.0 - green;
-      yellow  = 1.0 - blue;
-
-      key = 1.0;
-      if (cyan < key) key = cyan;
-      if (magenta < key) key = magenta;
-      if (yellow < key) key = yellow;
-
-      key *= pullout;
-
-      if (key < 1.0)
-        {
-          cyan    = (cyan - key) / (1.0 - key);
-          magenta = (magenta - key) / (1.0 - key);
-          yellow  = (yellow - key) / (1.0 - key);
-        }
-      else
-        {
-          cyan    = 0.0;
-          magenta = 0.0;
-          yellow  = 0.0;
-        }
-
-      ((double *) dst)[0] = cyan;
-      ((double *) dst)[1] = magenta;
-      ((double *) dst)[2] = yellow;
-      ((double *) dst)[3] = key;
-
-      src += 4 * sizeof (double);
-      dst += 4 * sizeof (double);
-    }
-}
-
-static void
-cmyk_to_rgba (const Babl *conversion,char *src,
-              char *dst,
-              long  n)
-{
-  while (n--)
-    {
-      double cyan    = ((double *) src)[0];
-      double magenta = ((double *) src)[1];
-      double yellow  = ((double *) src)[2];
-      double key     = ((double *) src)[3];
-
-      double red, green, blue;
-
-      if (key < 1.0)
-        {
-          cyan    = cyan * (1.0 - key) + key;
-          magenta = magenta * (1.0 - key) + key;
-          yellow  = yellow * (1.0 - key) + key;
-        }
-      else
-        {
-          cyan = magenta = yellow = 1.0;
-        }
-
-      red   = 1.0 - cyan;
-      green = 1.0 - magenta;
-      blue  = 1.0 - yellow;
-
-      ((double *) dst)[0] = gamma_2_2_to_linear (red);
-      ((double *) dst)[1] = gamma_2_2_to_linear (green);
-      ((double *) dst)[2] = gamma_2_2_to_linear (blue);
-
-      ((double *) dst)[3] = 1.0;
-
-      src += 4 * sizeof (double);
-      dst += 4 * sizeof (double);
-    }
-}
-
-static void
-rgba_to_cmy (const Babl *conversion,char *src,
-             char *dst,
-             long  n)
-{
-  while (n--)
-    {
-      double red   = linear_to_gamma_2_2 (((double *) src)[0]);
-      double green = linear_to_gamma_2_2 (((double *) src)[1]);
-      double blue  = linear_to_gamma_2_2 (((double *) src)[2]);
-
-      double cyan, magenta, yellow;
-
-      cyan    = 1.0 - red;
-      magenta = 1.0 - green;
-      yellow  = 1.0 - blue;
-
-      ((double *) dst)[0] = cyan;
-      ((double *) dst)[1] = magenta;
-      ((double *) dst)[2] = yellow;
-
-      src += 4 * sizeof (double);
-      dst += 3 * sizeof (double);
-    }
-}
-
-static void
-cmy_to_rgba (const Babl *conversion,char *src,
-              char *dst,
-              long  n)
-{
-  while (n--)
-    {
-      double cyan    = ((double *) src)[0];
-      double magenta = ((double *) src)[1];
-      double yellow  = ((double *) src)[2];
-
-      double red, green, blue;
-
-      red   = 1.0 - cyan;
-      green = 1.0 - magenta;
-      blue  = 1.0 - yellow;
-
-      ((double *) dst)[0] = gamma_2_2_to_linear (red);
-      ((double *) dst)[1] = gamma_2_2_to_linear (green);
-      ((double *) dst)[2] = gamma_2_2_to_linear (blue);
-
-      ((double *) dst)[3] = 1.0;
-
-      src += 3 * sizeof (double);
-      dst += 4 * sizeof (double);
-    }
-}


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]