[gimp/gimp-2-10] plug-ins: add support for loading merged image data from PSD files



commit d49e038ed3611409010fa78a061916b4bdca207a
Author: Ell <ell_se yahoo com>
Date:   Mon Jun 18 06:17:04 2018 -0400

    plug-ins: add support for loading merged image data from PSD files
    
    PSD files may include a "merged", pre-composited, version of the
    image (in Photoshop, this is the case when saving files with
    "Maximize Compatibility" enabled; GIMP always saves the merged
    image data in exported PSD files.)  This commit adds support for
    loading the merged image version from PSDs, instead of the full
    layer hierarchy.  This is useful when loading PSD files that use
    features that we don't currently support, and therefore can't
    render correctly, such as adjustment layers.
    
    When loading the merged image version, we avoid loading certain
    additional data from the file, such as channels, paths, and
    guides, while still loading metadata, making this akin to loading
    other "flat" image formats.
    
    This option is currently exposed as an additional file type
    ("Photoshop image (merged)"), which has to be explicitly selected
    from the file-type list when opening the image.
    
    (cherry picked from commit 1d9a8a91ab74061f17f1f52fa269ce6aff6e529e)

 plug-ins/file-psd/psd-image-res-load.c | 21 +++++---
 plug-ins/file-psd/psd-load.c           | 88 ++++++++++++++++++++++++++--------
 plug-ins/file-psd/psd-load.h           |  1 +
 plug-ins/file-psd/psd.c                | 25 +++++++++-
 plug-ins/file-psd/psd.h                |  3 ++
 5 files changed, 111 insertions(+), 27 deletions(-)
---
diff --git a/plug-ins/file-psd/psd-image-res-load.c b/plug-ins/file-psd/psd-image-res-load.c
index b59c700cfc..ec86dbaa2d 100644
--- a/plug-ins/file-psd/psd-image-res-load.c
+++ b/plug-ins/file-psd/psd-image-res-load.c
@@ -330,7 +330,8 @@ load_image_resource (PSDimageres  *res_a,
             break;
 
           case PSD_ALPHA_NAMES:
-            load_resource_1006 (res_a, image_id, img_a, f, error);
+            if (! img_a->merged_image_only)
+              load_resource_1006 (res_a, image_id, img_a, f, error);
             break;
 
           case PSD_DISPLAY_INFO:
@@ -342,15 +343,18 @@ load_image_resource (PSDimageres  *res_a,
             break;
 
           case PSD_QUICK_MASK:
-            load_resource_1022 (res_a, image_id, img_a, f, error);
+            if (! img_a->merged_image_only)
+              load_resource_1022 (res_a, image_id, img_a, f, error);
             break;
 
           case PSD_LAYER_STATE:
-            load_resource_1024 (res_a, image_id, img_a, f, error);
+            if (! img_a->merged_image_only)
+              load_resource_1024 (res_a, image_id, img_a, f, error);
             break;
 
           case PSD_WORKING_PATH:
-            load_resource_2000 (res_a, image_id, f, error);
+            if (! img_a->merged_image_only)
+              load_resource_2000 (res_a, image_id, f, error);
             break;
 
           case PSD_IPTC_NAA_DATA:
@@ -358,7 +362,8 @@ load_image_resource (PSDimageres  *res_a,
             break;
 
           case PSD_GRID_GUIDE:
-            load_resource_1032 (res_a, image_id, f, error);
+            if (! img_a->merged_image_only)
+              load_resource_1032 (res_a, image_id, f, error);
             break;
 
           case PSD_ICC_PROFILE:
@@ -366,7 +371,8 @@ load_image_resource (PSDimageres  *res_a,
             break;
 
           case PSD_ALPHA_NAMES_UNI:
-            load_resource_1045 (res_a, image_id, img_a, f, error);
+            if (! img_a->merged_image_only)
+              load_resource_1045 (res_a, image_id, img_a, f, error);
             break;
 
           case PSD_IDX_COL_TAB_CNT:
@@ -374,7 +380,8 @@ load_image_resource (PSDimageres  *res_a,
             break;
 
           case PSD_ALPHA_ID:
-            load_resource_1053 (res_a, image_id, img_a, f, error);
+            if (! img_a->merged_image_only)
+              load_resource_1053 (res_a, image_id, img_a, f, error);
             break;
 
           case PSD_EXIF_DATA:
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
index 87b94a1a81..dc794bc1f7 100644
--- a/plug-ins/file-psd/psd-load.c
+++ b/plug-ins/file-psd/psd-load.c
@@ -113,6 +113,7 @@ static const Babl*      get_mask_format            (PSDimage    *img_a);
 /* Main file load function */
 gint32
 load_image (const gchar  *filename,
+            gboolean      merged_image_only,
             gboolean     *resolution_loaded,
             GError      **load_error)
 {
@@ -140,6 +141,8 @@ load_image (const gchar  *filename,
       return -1;
     }
 
+  img_a.merged_image_only = merged_image_only;
+
   /* ----- Read the PSD file Header block ----- */
   IFDBG(2) g_debug ("Read header block");
   if (read_header_block (&img_a, f, &error) < 0)
@@ -161,7 +164,7 @@ load_image (const gchar  *filename,
   /* ----- Read the PSD file Layer & Mask block ----- */
   IFDBG(2) g_debug ("Read layer & mask block");
   lyr_a = read_layer_block (&img_a, f, &error);
-  if (img_a.num_layers != 0 && lyr_a == NULL)
+  if (! img_a.merged_image_only && img_a.num_layers != 0 && lyr_a == NULL)
     goto load_error;
   gimp_progress_update (0.4);
 
@@ -496,7 +499,7 @@ read_layer_info (PSDimage  *img_a,
       img_a->num_layers = -img_a->num_layers;
     }
 
-  if (img_a->num_layers)
+  if (! img_a->merged_image_only && img_a->num_layers)
     {
       /* Read layer records */
       PSDlayerres           res_a;
@@ -1146,7 +1149,7 @@ add_layers (gint32     image_id,
 
   IFDBG(2) g_debug ("Number of layers: %d", img_a->num_layers);
 
-  if (img_a->num_layers == 0)
+  if (img_a->merged_image_only || img_a->num_layers == 0)
     {
       IFDBG(2) g_debug ("No layers to process");
       return 0;
@@ -1734,9 +1737,16 @@ add_merged_image (gint32     image_id,
     extra_channels--;
   base_channels = total_channels - extra_channels;
 
+  if (img_a->merged_image_only)
+    {
+      extra_channels = 0;
+      total_channels = base_channels;
+    }
+
   /* ----- Read merged image & extra channel pixel data ----- */
-  if (img_a->num_layers == 0
-      || extra_channels > 0)
+  if (img_a->merged_image_only ||
+      img_a->num_layers == 0   ||
+      extra_channels > 0)
     {
       guint32 block_len;
       guint32 block_start;
@@ -1790,6 +1800,14 @@ add_merged_image (gint32     image_id,
                   }
               }
 
+            /* Skip channel length data for unloaded channels */
+            if (fseek (f, (img_a->channels - total_channels) * img_a->rows * 2,
+                       SEEK_CUR) < 0)
+              {
+                psd_set_error (feof (f), errno, error);
+                return -1;
+              }
+
             IFDBG(3) g_debug ("RLE decode - data");
             for (cidx = 0; cidx < total_channels; ++cidx)
               {
@@ -1812,7 +1830,8 @@ add_merged_image (gint32     image_id,
     }
 
   /* ----- Draw merged image ----- */
-  if (img_a->num_layers == 0)            /* Merged image - Photoshop 2 style */
+  if (img_a->merged_image_only ||
+      img_a->num_layers == 0)            /* Merged image - Photoshop 2 style */
     {
       image_type = get_gimp_image_type (img_a->base_type, img_a->transparency);
 
@@ -1836,6 +1855,7 @@ add_merged_image (gint32     image_id,
                                  100,
                                  gimp_image_get_default_new_layer_mode (image_id));
       gimp_image_insert_layer (image_id, layer_id, -1, 0);
+
       buffer = gimp_drawable_get_buffer (layer_id);
       gegl_buffer_set (buffer,
                        GEGL_RECTANGLE (0, 0,
@@ -1843,6 +1863,36 @@ add_merged_image (gint32     image_id,
                                        gegl_buffer_get_height (buffer)),
                        0, get_layer_format (img_a, img_a->transparency),
                        pixels, GEGL_AUTO_ROWSTRIDE);
+
+      /* Merged image data is blended against white.  Unblend it. */
+      if (img_a->transparency)
+        {
+          GeglBufferIterator *iter;
+
+          iter = gegl_buffer_iterator_new (buffer, NULL, 0,
+                                           babl_format ("R'G'B'A float"),
+                                           GEGL_ACCESS_READWRITE,
+                                           GEGL_ABYSS_NONE);
+
+          while (gegl_buffer_iterator_next (iter))
+            {
+              gfloat *data = iter->data[0];
+
+              for (i = 0; i < iter->length; i++)
+                {
+                  gint c;
+
+                  if (data[3])
+                    {
+                      for (c = 0; c < 3; c++)
+                        data[c] = (data[c] + data[3] - 1.0f) / data[3];
+                    }
+
+                  data += 4;
+                }
+            }
+        }
+
       g_object_unref (buffer);
       g_free (pixels);
     }
@@ -1854,9 +1904,19 @@ add_merged_image (gint32     image_id,
           g_free (chn_a[cidx].data);
     }
 
+  if (img_a->transparency)
+    {
+      /* Free "Transparency" channel name */
+      if (img_a->alpha_names)
+        {
+          alpha_name = g_ptr_array_index (img_a->alpha_names, 0);
+          if (alpha_name)
+            g_free (alpha_name);
+        }
+    }
+
   /* ----- Draw extra alpha channels ----- */
-  if ((extra_channels                   /* Extra alpha channels */
-      || img_a->transparency)           /* Transparency alpha channel */
+  if (extra_channels                   /* Extra alpha channels */
       && image_id > -1)
     {
       IFDBG(2) g_debug ("Add extra channels");
@@ -1864,17 +1924,7 @@ add_merged_image (gint32     image_id,
 
       /* Get channel resource data */
       if (img_a->transparency)
-        {
-          offset = 1;
-
-          /* Free "Transparency" channel name */
-          if (img_a->alpha_names)
-            {
-              alpha_name = g_ptr_array_index (img_a->alpha_names, 0);
-              if (alpha_name)
-                g_free (alpha_name);
-            }
-        }
+        offset = 1;
       else
         offset = 0;
 
diff --git a/plug-ins/file-psd/psd-load.h b/plug-ins/file-psd/psd-load.h
index 177d74fcac..f8b62c9fc7 100644
--- a/plug-ins/file-psd/psd-load.h
+++ b/plug-ins/file-psd/psd-load.h
@@ -23,6 +23,7 @@
 
 
 gint32  load_image (const gchar  *filename,
+                    gboolean      merged_image_only,
                     gboolean     *resolution_loaded,
                     GError      **error);
 
diff --git a/plug-ins/file-psd/psd.c b/plug-ins/file-psd/psd.c
index 0a52c0053a..971736c222 100644
--- a/plug-ins/file-psd/psd.c
+++ b/plug-ins/file-psd/psd.c
@@ -119,6 +119,27 @@ query (void)
                                     "",
                                     "0,string,8BPS");
 
+  /* File load (merged) */
+  gimp_install_procedure (LOAD_MERGED_PROC,
+                          "Loads merged images from the Photoshop PSD file format",
+                          "This plug-in loads the merged image data in Adobe "
+                          "Photoshop (TM) native PSD format.",
+                          "Ell",
+                          "Ell",
+                          "2018",
+                          N_("Photoshop image (merged)"),
+                          NULL,
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (load_args),
+                          G_N_ELEMENTS (load_return_vals),
+                          load_args, load_return_vals);
+
+  gimp_register_file_handler_mime (LOAD_MERGED_PROC, "image/x-psd");
+  gimp_register_magic_load_handler (LOAD_MERGED_PROC,
+                                    "psd",
+                                    "",
+                                    "0,string,8BPS");
+
   /* Thumbnail load */
   gimp_install_procedure (LOAD_THUMB_PROC,
                           "Loads thumbnails from the Photoshop PSD file format",
@@ -176,7 +197,8 @@ run (const gchar      *name,
   values[0].type          = GIMP_PDB_STATUS;
   values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
 
-  if (strcmp (name, LOAD_PROC) == 0)
+  if (strcmp (name, LOAD_PROC) == 0 ||
+      strcmp (name, LOAD_MERGED_PROC) == 0)
     {
       gboolean resolution_loaded = FALSE;
       gboolean interactive;
@@ -194,6 +216,7 @@ run (const gchar      *name,
         }
 
       image_ID = load_image (param[1].data.d_string,
+                             strcmp (name, LOAD_MERGED_PROC) == 0,
                              &resolution_loaded, &error);
 
       if (image_ID != -1)
diff --git a/plug-ins/file-psd/psd.h b/plug-ins/file-psd/psd.h
index f7320ac4cc..cb2d887505 100644
--- a/plug-ins/file-psd/psd.h
+++ b/plug-ins/file-psd/psd.h
@@ -32,6 +32,7 @@
 #define CONVERSION_WARNINGS             FALSE
 
 #define LOAD_PROC                       "file-psd-load"
+#define LOAD_MERGED_PROC                "file-psd-load-merged"
 #define LOAD_THUMB_PROC                 "file-psd-load-thumb"
 #define SAVE_PROC                       "file-psd-save"
 #define PLUG_IN_BINARY                  "file-psd"
@@ -642,6 +643,8 @@ typedef struct
 /* PSD File data structures */
 typedef struct
 {
+  gboolean              merged_image_only;      /* Whether to load only the merged image data */
+
   guint16               channels;               /* Number of channels: 1- 56 */
   gboolean              transparency;           /* Image has merged transparency alpha channel */
   guint32               rows;                   /* Number of rows: 1 - 30000 */


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