[babl: 4/5] babl: implement CMYK color model in reference and base



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

    babl: implement CMYK color model in reference and base
    
    This commit adds support to the reference fishes of babl to deal
    with CMYK based pixel format encodings, backed by babl spaces with
    ICC CMYK ICC profiles.

 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]