[gimp] plug-ins: Convert CMYK u8 .psd to R'G'B' float on load



commit 1462a91d86ee31d98ee70bfd7fe0fad913a87883
Author: Øyvind Kolås <pippin gimp org>
Date:   Fri Feb 21 12:08:19 2020 +0100

    plug-ins: Convert CMYK u8 .psd to R'G'B' float on load
    
    Patch from Massimo Valentini in issue #354, adapted for the new object
    based plug-in APIs.

 plug-ins/file-psd/psd-image-res-load.c |  16 +++-
 plug-ins/file-psd/psd-load.c           | 142 ++++++++++++++++++++++++++++++++-
 plug-ins/file-psd/psd.h                |   4 +
 3 files changed, 155 insertions(+), 7 deletions(-)
---
diff --git a/plug-ins/file-psd/psd-image-res-load.c b/plug-ins/file-psd/psd-image-res-load.c
index 650ed44cb1..73b619d006 100644
--- a/plug-ins/file-psd/psd-image-res-load.c
+++ b/plug-ins/file-psd/psd-image-res-load.c
@@ -196,6 +196,7 @@ static gint     load_resource_1033     (const PSDimageres     *res_a,
                                         GError               **error);
 
 static gint     load_resource_1039     (const PSDimageres     *res_a,
+                                        PSDimage              *img_a,
                                         GimpImage             *image,
                                         FILE                  *f,
                                         GError               **error);
@@ -368,7 +369,7 @@ load_image_resource (PSDimageres  *res_a,
             break;
 
           case PSD_ICC_PROFILE:
-            if (! load_resource_1039 (res_a, image, f, error))
+            if (! load_resource_1039 (res_a, img_a, image, f, error))
               *profile_loaded = TRUE;
             break;
 
@@ -1105,6 +1106,7 @@ load_resource_1033 (const PSDimageres  *res_a,
 
 static gint
 load_resource_1039 (const PSDimageres  *res_a,
+                    PSDimage           *img_a,
                     GimpImage          *image,
                     FILE               *f,
                     GError            **error)
@@ -1128,8 +1130,16 @@ load_resource_1039 (const PSDimageres  *res_a,
                                                      NULL);
   if (profile)
     {
-      gimp_image_set_color_profile (image, profile);
-      g_object_unref (profile);
+      if (img_a->color_mode == PSD_CMYK &&
+          gimp_color_profile_is_cmyk (profile))
+        {
+          img_a->cmyk_profile = profile;
+        }
+      else
+        {
+          gimp_image_set_color_profile (image, profile);
+          g_object_unref (profile);
+        }
     }
 
   g_free (icc_profile);
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
index 6d429832ee..f4c8950d16 100644
--- a/plug-ins/file-psd/psd-load.c
+++ b/plug-ins/file-psd/psd-load.c
@@ -129,6 +129,8 @@ load_image (GFile        *file,
 
   filename = g_file_get_path (file);
 
+  img_a.cmyk_transform = img_a.cmyk_transform_alpha = NULL;
+  img_a.cmyk_profile = NULL;
   /* ----- Open PSD file ----- */
   if (g_stat (filename, &st) == -1)
     {
@@ -338,6 +340,7 @@ read_header_block (PSDimage  *img_a,
       && img_a->color_mode != PSD_INDEXED
       && img_a->color_mode != PSD_RGB
       && img_a->color_mode != PSD_MULTICHANNEL
+      && img_a->color_mode != PSD_CMYK
       && img_a->color_mode != PSD_DUOTONE)
     {
       g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
@@ -346,6 +349,17 @@ read_header_block (PSDimage  *img_a,
       return -1;
     }
 
+  if (img_a->color_mode == PSD_CMYK)
+    {
+      if (img_a->bps != 8)
+        {
+          g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                       _("Unsupported color mode: %s"),
+                       get_psd_color_mode_name (img_a->color_mode));
+          return -1;
+        }
+    }
+
   /* Warning for unsupported bit depth */
   switch (img_a->bps)
     {
@@ -1003,6 +1017,7 @@ create_gimp_image (PSDimage *img_a,
       img_a->base_type = GIMP_INDEXED;
       break;
 
+    case PSD_CMYK:
     case PSD_RGB:
       img_a->base_type = GIMP_RGB;
       break;
@@ -1026,7 +1041,10 @@ create_gimp_image (PSDimage *img_a,
 
       case 8:
       case 1:
-        precision = GIMP_PRECISION_U8_NON_LINEAR;
+        if (img_a->color_mode == PSD_CMYK)
+          precision = GIMP_PRECISION_FLOAT_NON_LINEAR;
+        else
+          precision = GIMP_PRECISION_U8_NON_LINEAR;
         break;
 
       default:
@@ -1121,6 +1139,74 @@ add_image_resources (GimpImage *image,
   return 0;
 }
 
+static guchar *
+psd_convert_cmyk_to_srgb (PSDimage *img_a,
+                          guchar   *dst,
+                          guchar   *src,
+                          gint      width,
+                          gint      height,
+                          gboolean  alpha)
+{
+  if (img_a->cmyk_profile)
+    {
+      if (alpha)
+        {
+          if (! img_a->cmyk_transform_alpha)
+            {
+              GimpColorProfile *srgb = gimp_color_profile_new_rgb_srgb ();
+
+              img_a->cmyk_transform_alpha = gimp_color_transform_new (img_a->cmyk_profile, babl_format 
("cmykA u8"),
+                                                                      srgb, babl_format ("R'G'B'A float"),
+                                                                      0, 0);
+
+              g_object_unref (srgb);
+            }
+
+        gimp_color_transform_process_pixels (img_a->cmyk_transform_alpha,
+                                             babl_format ("cmykA u8"),
+                                             src,
+                                             babl_format ("R'G'B'A float"),
+                                             dst,
+                                             width * height);
+        }
+      else
+        {
+          if (! img_a->cmyk_transform)
+            {
+              GimpColorProfile *srgb = gimp_color_profile_new_rgb_srgb ();
+
+              img_a->cmyk_transform = gimp_color_transform_new (img_a->cmyk_profile, babl_format ("cmyk u8"),
+                                                                      srgb, babl_format ("R'G'B' float"),
+                                                                      0, 0);
+
+
+              g_object_unref (srgb);
+            }
+
+          gimp_color_transform_process_pixels (img_a->cmyk_transform_alpha,
+                                               babl_format ("cmyk u8"),
+                                               src,
+                                               babl_format ("R'G'B' float"),
+                                               dst,
+                                               width * height);
+        }
+    }
+  else
+    {
+      const Babl *fish;
+
+      if (alpha)
+        fish = babl_fish ("cmykA u8", "R'G'B'A float");
+      else
+        fish = babl_fish ("cmyk u8", "R'G'B' float");
+
+      babl_process (fish, src, dst, width * height);
+    }
+
+  return (guchar*) dst;
+}
+
+
 static gint
 add_layers (GimpImage *image,
             PSDimage  *img_a,
@@ -1554,6 +1640,48 @@ add_layers (GimpImage *image,
                           gint                 src_step = bps;
                           gint                 dst_step = bps * layer_channels;
 
+                          if (img_a->color_mode == PSD_CMYK)
+                            {
+                              guchar              *cmyk = g_new (guchar, layer_channels * iter->length);
+
+                              for (cidx = 0; cidx < layer_channels; ++cidx)
+                                {
+                                  gint b, y, x;
+
+                                  if (roi->x == 0 && roi->y == 0)
+                                    IFDBG(3) g_debug ("Start channel %d", channel_idx[cidx]);
+
+                                  for (b = 0; b < bps; ++b)
+                                    {
+                                      guint8 *dst = &cmyk[cidx * bps + b];
+
+                                      for (y = 0; y < roi->height; y++)
+                                        {
+                                          const guint8 *src;
+
+                                          src = (const guint8 *)
+                                            &lyr_chn[channel_idx[cidx]]->data[
+                                            ((roi->y + y) * l_w +
+                                             roi->x)      * bps +
+                                              b];
+
+                                          for (x = 0; x < roi->width; ++x)
+                                            {
+                                              *dst = *src;
+
+                                              src += src_step;
+                                              dst += dst_step;
+                                            }
+                                        }
+                                    }
+                                }
+
+                              psd_convert_cmyk_to_srgb (img_a, dst0, cmyk, roi->width, roi->height, alpha);
+
+                              g_free (cmyk);
+                              continue;
+                            }
+
                           for (cidx = 0; cidx < layer_channels; ++cidx)
                             {
                               gint b;
@@ -1873,11 +2001,14 @@ add_merged_image (GimpImage *image,
       gimp_image_insert_layer (image, layer, NULL, 0);
 
       buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (layer));
+      if (img_a->color_mode == PSD_CMYK)
+        img_a->color_mode = PSD_RGB;
+
       gegl_buffer_set (buffer,
                        GEGL_RECTANGLE (0, 0,
                                        gegl_buffer_get_width (buffer),
                                        gegl_buffer_get_height (buffer)),
-                       0, get_layer_format (img_a, img_a->transparency),
+                       0, get_layer_format (img_a, (base_channels % 2) == 0),
                        pixels, GEGL_AUTO_ROWSTRIDE);
 
       /* Merged image data is blended against white.  Unblend it. */
@@ -2344,6 +2475,7 @@ get_layer_format (PSDimage *img_a,
         case 8:
         case 1:
           format = babl_format ("Y' u8");
+
           break;
 
         default:
@@ -2387,7 +2519,8 @@ get_layer_format (PSDimage *img_a,
 
         case 8:
         case 1:
-          format = babl_format ("R'G'B' u8");
+         format = babl_format (img_a->color_mode == PSD_CMYK ? "R'G'B' float" : "R'G'B' u8");
+
           break;
 
         default:
@@ -2409,7 +2542,8 @@ get_layer_format (PSDimage *img_a,
 
         case 8:
         case 1:
-          format = babl_format ("R'G'B'A u8");
+          format = babl_format (img_a->color_mode == PSD_CMYK ? "R'G'B'A float" : "R'G'B'A u8");
+
           break;
 
         default:
diff --git a/plug-ins/file-psd/psd.h b/plug-ins/file-psd/psd.h
index 5deb61c0d5..c185bc3207 100644
--- a/plug-ins/file-psd/psd.h
+++ b/plug-ins/file-psd/psd.h
@@ -673,6 +673,10 @@ typedef struct
   guint32              *alpha_id;               /* Alpha channel ids (tattoos) */
   guint16               alpha_id_count;         /* Number of alpha channel id items */
   guint16               quick_mask_id;          /* Channel number containing quick mask */
+
+  GimpColorProfile     *cmyk_profile;
+  gpointer              cmyk_transform;
+  gpointer              cmyk_transform_alpha;
 } PSDimage;
 
 /* Public functions */


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