[babl/wip/pippin/inverted-cmyk: 4/11] babl: implement own reference code paths for CMYK color spaces



commit 078f37abe819896ee93078367b727a8ee6155d63
Author: Øyvind Kolås <pippin gimp org>
Date:   Mon Nov 12 23:33:31 2018 +0100

    babl: implement own reference code paths for CMYK color spaces
    
    The double version of the refernce code paths now give CMYK special
    handling that invokes the relevant lcms2 conversions when needed,
    enabling sloow CMYK color management.

 babl/babl-fish-reference.c | 464 ++++++++++++++++++++++++++++++++++-----------
 babl/babl-fish.c           |  50 ++---
 babl/babl-icc.c            |  59 +++++-
 babl/babl-internal.h       |   2 +
 babl/babl-space.c          |  57 ++++++
 babl/babl-space.h          |  16 ++
 babl/babl.h                |   3 +
 export-symbols             |   1 +
 8 files changed, 511 insertions(+), 141 deletions(-)
---
diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c
index 6d1aa84..aaba920 100644
--- a/babl/babl-fish-reference.c
+++ b/babl/babl-fish-reference.c
@@ -18,6 +18,8 @@
 
 #include "config.h"
 #include "babl-internal.h"
+#include "lcms2.h"
+
 
 static Babl *
 assert_conversion_find (const void *source,
@@ -28,6 +30,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 +254,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 +692,8 @@ process_same_model (const Babl  *babl,
   }
 }
 
+typedef enum _Kind Kind;
+enum _Kind { KIND_RGB, KIND_CMYK};
 
 static void
 babl_fish_reference_process_double (const Babl *babl,
@@ -698,81 +702,118 @@ 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 */
+  if (babl->fish.source->format.space->space.cmyk.is_cmyk)
+    source_kind = KIND_CMYK;
+  if (babl->fish.destination->format.space->space.cmyk.is_cmyk)
+    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)));
+  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 +826,257 @@ 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.source))->format.space)) );
+
+#if HAVE_LCMS
+    if (babl->fish.destination->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));
-
-      if(BABL (babl->fish.destination)->format.model == (void*)destination_rgba_format)
+      /* 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++)
       {
-         destination_double_buf = rgba_double_buf;
+        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
+    }
+    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 */
+        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];
 
-         destination_double_buf_alloc = babl_malloc (sizeof (double) * n *
-                                          BABL (babl->fish.destination)->format.model->components);
-         destination_double_buf = destination_double_buf_alloc;
+        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;
 
-      if (conv->class_type == BABL_CONVERSION_PLANAR)
+        if (key < 1.0)
         {
-          destination_image = babl_image_from_linear (
-            destination_double_buf, BABL (BABL ((babl->fish.destination))->format.model));
+          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)
+    {
+    {
+      /* 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);
 
+    {
+      double *rgba=rgba_double_buf;
+      double *cmyka=cmyka_double_buf;
+      int i;
+      for (i = 0; i < n; i++)
+      {
+        rgba[i * 4 + 3] = cmyka[i * 5 + 4];
+      }
+    }
+    }
+    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 */
+        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];
+      }
+    }
 
-          babl_conversion_process (
-            conv,
-            (void*)rgba_image, (void*)destination_image,
-            n);
+    /* 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);
+
+      babl_matrix_mul_vector_buf4 (matrix, rgba, rgba, n);
+    }
+ }
+ else if (source_kind      == KIND_CMYK &&
+          destination_kind == KIND_CMYK)
+ {
+    /* nop for now, but we should use lcms to do a black-channel
+     * preserving transform
+     */
+ }
+
+  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");
-      }
-   }
+     }
+     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));
 
-    convert_from_double (
-      (BablFormat *) BABL (babl->fish.destination),
-      destination_double_buf,
-      destination,
-      n
-    );
+        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;
+  }
 
-    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);
+ /* 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 +1101,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));
@@ -1070,6 +1302,14 @@ babl_fish_reference_process (const Babl *babl,
     return;
   }
 
+  if (babl->fish.source->format.space->space.cmyk.is_cmyk ||
+      babl->fish.destination->format.space->space.cmyk.is_cmyk
+     )
+  {
+    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 65c482e..d64f2d8 100644
--- a/babl/babl-fish.c
+++ b/babl/babl-fish.c
@@ -264,33 +264,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..6a29e5b 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,54 @@ 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,
+                                                    1,0);//intent & 7, 0);
+       ret->space.cmyk.lcms_from_rgba = cmsCreateTransform(sRGBProfile, TYPE_RGBA_DBL,
+                                                      ret->space.cmyk.lcms_profile, TYPE_CMYKA_DBL,
+                                                      1,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 +871,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..ed91e4d 100644
--- a/babl/babl-internal.h
+++ b/babl/babl-internal.h
@@ -453,5 +453,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-space.c b/babl/babl-space.c
index 9a78d38..4872f3d 100644
--- a/babl/babl-space.c
+++ b/babl/babl-space.c
@@ -219,6 +219,47 @@ babl_space (const char *name)
   return NULL;
 }
 
+Babl *
+_babl_space_for_lcms (const char *icc_data, int icc_length)
+{
+  int i=0;
+  BablSpace space;
+  space.instance.class_type = BABL_SPACE;
+  space.instance.id         = 0;
+
+  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];
+    }
+  }
+  if (i >= MAX_SPACES-1)
+  {
+    babl_log ("too many BablSpaces");
+    return NULL;
+  }
+
+  /* initialize it with copy of srgb content */
+  {
+    const BablSpace *srgb = &babl_space("sRGB")->space;
+    BablSpace *space=&space_db[i];
+    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 +351,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 +415,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 +449,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 */
@@ -1082,6 +1133,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 +1147,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.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/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


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