[gimp/gimp-2-10] plug-ins: improve PSD loading speed



commit 10bbdb323a8f66cf5e13e14c00efdbf16850b2ae
Author: Ell <ell_se yahoo com>
Date:   Tue Feb 18 18:39:49 2020 +0200

    plug-ins: improve PSD loading speed
    
    In file-psd, improve loading speed, mostly by eliminating excessive
    copies.
    
    (cherry picked from commit 52f5a9f65453f78b3f1e0e3b31962178f5aa4bfb)

 plug-ins/file-psd/psd-load.c | 190 +++++++++++++++++++++----------------------
 plug-ins/file-psd/psd-util.c |  65 ++++++---------
 2 files changed, 116 insertions(+), 139 deletions(-)
---
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
index 46a0c76d9f..cc1487c05e 100644
--- a/plug-ins/file-psd/psd-load.c
+++ b/plug-ins/file-psd/psd-load.c
@@ -1122,7 +1122,6 @@ add_layers (gint32     image_id,
   PSDchannel          **lyr_chn;
   GArray               *parent_group_stack;
   gint32                parent_group_id = -1;
-  guchar               *pixels;
   guint16               alpha_chn;
   guint16               user_mask_chn;
   guint16               layer_channels;
@@ -1137,15 +1136,12 @@ add_layers (gint32     image_id,
   gint32                lm_y;                  /* Layer mask y */
   gint32                lm_w;                  /* Layer mask width */
   gint32                lm_h;                  /* Layer mask height */
-  gint32                layer_size;
   gint32                layer_id = -1;
   gint32                mask_id = -1;
   gint32                active_layer_id = -1;
   gint                  lidx;                  /* Layer index */
   gint                  cidx;                  /* Channel index */
   gint                  rowi;                  /* Row index */
-  gint                  coli;                  /* Column index */
-  gint                  i;
   gboolean              alpha;
   gboolean              user_mask;
   gboolean              empty;
@@ -1530,29 +1526,66 @@ add_layers (gint32     image_id,
                     }
                   else
                     {
-                      layer_size = l_w * l_h;
+                      GeglBufferIterator *iter;
+
                       bps = img_a->bps / 8;
                       if (bps == 0)
                         bps++;
-                      pixels = g_malloc (layer_size * layer_channels * bps);
-                      for (cidx = 0; cidx < layer_channels; ++cidx)
+
+                      buffer = gimp_drawable_get_buffer (layer_id);
+
+                      iter = gegl_buffer_iterator_new (
+                        buffer, NULL, 0, get_layer_format (img_a, alpha),
+                        GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE, 1);
+
+                      while (gegl_buffer_iterator_next (iter))
                         {
-                          IFDBG(3) g_debug ("Start channel %d", channel_idx[cidx]);
-                          for (i = 0; i < layer_size; ++i)
-                            memcpy (&pixels[((i * layer_channels) + cidx) * bps],
-                                    &lyr_chn[channel_idx[cidx]]->data[i * bps], bps);
-                          g_free (lyr_chn[channel_idx[cidx]]->data);
+                          const GeglRectangle *roi      = &iter->items[0].roi;
+                          guint8              *dst0     = iter->items[0].data;
+                          gint                 src_step = bps;
+                          gint                 dst_step = bps * layer_channels;
+
+                          for (cidx = 0; cidx < layer_channels; ++cidx)
+                            {
+                              gint b;
+
+                              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;
+                                  gint    y;
+
+                                  dst = &dst0[cidx * bps + b];
+
+                                  for (y = 0; y < roi->height; y++)
+                                    {
+                                      const guint8 *src;
+                                      gint          x;
+
+                                      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;
+                                        }
+                                    }
+                                }
+                            }
                         }
 
-                      buffer = gimp_drawable_get_buffer (layer_id);
-                      gegl_buffer_set (buffer,
-                                       GEGL_RECTANGLE (0, 0,
-                                                       gegl_buffer_get_width (buffer),
-                                                       gegl_buffer_get_height (buffer)),
-                                       0, get_layer_format (img_a, alpha),
-                                       pixels, GEGL_AUTO_ROWSTRIDE);
+                      for (cidx = 0; cidx < layer_channels; ++cidx)
+                        g_free (lyr_chn[channel_idx[cidx]]->data);
+
                       g_object_unref (buffer);
-                      g_free (pixels);
                     }
                 }
 
@@ -1574,69 +1607,27 @@ add_layers (gint32     image_id,
                     }
                   else
                     {
+                      GeglRectangle mask_rect;
+
                       /* Load layer mask data */
                       lm_x = lyr_a[lidx]->layer_mask.left - l_x;
                       lm_y = lyr_a[lidx]->layer_mask.top - l_y;
                       lm_w = lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left;
                       lm_h = lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top;
                       IFDBG(3) g_debug ("Mask channel index %d", user_mask_chn);
-                      bps = (img_a->bps + 1) / 8;
-                      layer_size = lm_w * lm_h * bps;
-                      pixels = g_malloc (layer_size);
-                      IFDBG(3) g_debug ("Allocate Pixels %d", layer_size);
-                      /* Crop mask at layer boundary */
                       IFDBG(3) g_debug ("Original Mask %d %d %d %d", lm_x, lm_y, lm_w, lm_h);
-                      if (lm_x < 0
-                          || lm_y < 0
-                          || lm_w + lm_x > l_w
-                          || lm_h + lm_y > l_h)
-                        {
-                          if (CONVERSION_WARNINGS)
-                            g_message ("Warning\n"
-                                       "The layer mask is partly outside the "
-                                       "layer boundary. The mask will be "
-                                       "cropped which may result in data loss.");
-                          i = 0;
-                          for (rowi = 0; rowi < lm_h; ++rowi)
-                            {
-                              if (rowi + lm_y >= 0 && rowi + lm_y < l_h)
-                                {
-                                  for (coli = 0; coli < lm_w; ++coli)
-                                    {
-                                      if (coli + lm_x >= 0 && coli + lm_x < l_w)
-                                        {
-                                          memcpy (&pixels[i * bps], &lyr_chn[user_mask_chn]->data[(rowi * 
lm_w + coli) * bps], bps);
-                                          i++;
-                                        }
-                                    }
-                                }
-                            }
-                          if (lm_x < 0)
-                            {
-                              lm_w += lm_x;
-                              lm_x = 0;
-                            }
-                          if (lm_y < 0)
-                            {
-                              lm_h += lm_y;
-                              lm_y = 0;
-                            }
-                          if (lm_w + lm_x > l_w)
-                            lm_w = l_w - lm_x;
-                          if (lm_h + lm_y > l_h)
-                            lm_h = l_h - lm_y;
-                        }
-                      else
-                        {
-                          memcpy (pixels, lyr_chn[user_mask_chn]->data, layer_size);
-                          i = layer_size;
-                        }
-                      g_free (lyr_chn[user_mask_chn]->data);
-                      /* Draw layer mask data, if any */
-                      if (i > 0)
+                      /* Crop mask at layer boundary, and draw layer mask data,
+                       * if any
+                       */
+                      if (gegl_rectangle_intersect (
+                            &mask_rect,
+                            GEGL_RECTANGLE (0, 0, l_w, l_h),
+                            GEGL_RECTANGLE (lm_x, lm_y, lm_w, lm_h)))
                         {
                           IFDBG(3) g_debug ("Layer %d %d %d %d", l_x, l_y, l_w, l_h);
-                          IFDBG(3) g_debug ("Mask %d %d %d %d", lm_x, lm_y, lm_w, lm_h);
+                          IFDBG(3) g_debug ("Mask %d %d %d %d",
+                                            mask_rect.x,     mask_rect.y,
+                                            mask_rect.width, mask_rect.height);
 
                           if (lyr_a[lidx]->layer_mask.def_color == 255)
                             mask_id = gimp_layer_create_mask (layer_id,
@@ -1645,18 +1636,25 @@ add_layers (gint32     image_id,
                             mask_id = gimp_layer_create_mask (layer_id,
                                                               GIMP_ADD_MASK_BLACK);
 
+                          bps = img_a->bps / 8;
+                          if (bps == 0)
+                            bps++;
+
                           IFDBG(3) g_debug ("New layer mask %d", mask_id);
                           gimp_layer_add_mask (layer_id, mask_id);
                           buffer = gimp_drawable_get_buffer (mask_id);
                           gegl_buffer_set (buffer,
-                                           GEGL_RECTANGLE (lm_x, lm_y, lm_w, lm_h),
+                                           &mask_rect,
                                            0, get_mask_format (img_a),
-                                           pixels, GEGL_AUTO_ROWSTRIDE);
+                                           lyr_chn[user_mask_chn]->data + (
+                                             (mask_rect.y - lm_y)  * lm_w +
+                                             (mask_rect.x - lm_x)) * bps,
+                                           lm_w * bps);
                           g_object_unref (buffer);
                           gimp_layer_set_apply_mask (layer_id,
                                                      ! lyr_a[lidx]->layer_mask.mask_flags.disabled);
                         }
-                      g_free (pixels);
+                      g_free (lyr_chn[user_mask_chn]->data);
                     }
                 }
 
@@ -2122,7 +2120,6 @@ read_channel_data (PSDchannel     *channel,
 {
   gchar    *raw_data;
   gchar    *src;
-  gchar    *dst;
   guint32   readline_len;
   gint      i, j;
 
@@ -2157,8 +2154,7 @@ read_channel_data (PSDchannel     *channel,
       case PSD_COMP_RLE:
         for (i = 0; i < channel->rows; ++i)
           {
-            src = g_malloc (rle_pack_len[i]);
-            dst = g_malloc (readline_len);
+            src = gegl_scratch_alloc (rle_pack_len[i]);
 /*      FIXME check for over-run
             if (ftell (f) + rle_pack_len[i] > block_end)
               {
@@ -2169,15 +2165,13 @@ read_channel_data (PSDchannel     *channel,
             if (fread (src, rle_pack_len[i], 1, f) < 1)
               {
                 psd_set_error (feof (f), errno, error);
-                g_free (src);
-                g_free (dst);
+                gegl_scratch_free (src);
                 return -1;
               }
             /* FIXME check for errors returned from decode packbits */
-            decode_packbits (src, dst, rle_pack_len[i], readline_len);
-            g_free (src);
-            memcpy (raw_data + i * readline_len, dst, readline_len);
-            g_free (dst);
+            decode_packbits (src, raw_data + i * readline_len,
+                             rle_pack_len[i], readline_len);
+            gegl_scratch_free (src);
           }
         break;
       case PSD_COMP_ZIP:
@@ -2223,45 +2217,45 @@ read_channel_data (PSDchannel     *channel,
     {
     case 32:
       {
-        guint32 *src = (guint32*) raw_data;
-        guint32 *dst = g_malloc (channel->rows * channel->columns * 4);
+        guint32 *data = (guint32*) raw_data;
 
-        channel->data = (gchar*) dst;
+        channel->data = raw_data;
+        raw_data      = NULL;
 
         for (i = 0; i < channel->rows * channel->columns; ++i)
-          dst[i] = GUINT32_FROM_BE (src[i]);
+          data[i] = GUINT32_FROM_BE (data[i]);
 
         if (compression == PSD_COMP_ZIP_PRED)
           {
             for (i = 0; i < channel->rows; ++i)
               for (j = 1; j < channel->columns; ++j)
-                dst[i * channel->columns + j] += dst[i * channel->columns + j - 1];
+                data[i * channel->columns + j] += data[i * channel->columns + j - 1];
           }
         break;
       }
 
     case 16:
       {
-        guint16 *src = (guint16*) raw_data;
-        guint16 *dst = g_malloc (channel->rows * channel->columns * 2);
+        guint16 *data = (guint16*) raw_data;
 
-        channel->data = (gchar*) dst;
+        channel->data = raw_data;
+        raw_data      = NULL;
 
         for (i = 0; i < channel->rows * channel->columns; ++i)
-          dst[i] = GUINT16_FROM_BE (src[i]);
+          data[i] = GUINT16_FROM_BE (data[i]);
 
         if (compression == PSD_COMP_ZIP_PRED)
           {
             for (i = 0; i < channel->rows; ++i)
               for (j = 1; j < channel->columns; ++j)
-                dst[i * channel->columns + j] += dst[i * channel->columns + j - 1];
+                data[i * channel->columns + j] += data[i * channel->columns + j - 1];
           }
         break;
       }
 
       case 8:
-        channel->data = g_malloc (channel->rows * channel->columns * bps / 8 );
-        memcpy (channel->data, raw_data, (channel->rows * channel->columns * bps / 8));
+        channel->data = raw_data;
+        raw_data      = NULL;
 
         if (compression == PSD_COMP_ZIP_PRED)
           {
diff --git a/plug-ins/file-psd/psd-util.c b/plug-ins/file-psd/psd-util.c
index f71a57bdd6..5686bb7970 100644
--- a/plug-ins/file-psd/psd-util.c
+++ b/plug-ins/file-psd/psd-util.c
@@ -489,7 +489,6 @@ decode_packbits (const gchar *src,
    */
 
   gint    n;
-  gchar   dat;
   gint32  unpack_left = unpacked_len;
   gint32  pack_left = packed_len;
   gint32  error_code = 0;
@@ -508,67 +507,51 @@ decode_packbits (const gchar *src,
 
       if (n < 0)        /* replicate next gchar |n|+ 1 times */
         {
-          n  = 1 - n;
-          if (! pack_left)
+          n = 1 - n;
+          if (pack_left < 1)
             {
               IFDBG(2) g_debug ("Input buffer exhausted in replicate");
               error_code = 1;
               break;
             }
-          if (n > unpack_left)
+          if (unpack_left < n)
             {
               IFDBG(2) g_debug ("Overrun in packbits replicate of %d chars", n - unpack_left);
               error_code = 2;
             }
-          dat = *src;
-          for (; n > 0; --n)
-            {
-              if (! unpack_left)
-                break;
-              *dst = dat;
-              dst++;
-              unpack_left--;
-            }
-          if (unpack_left)
-            {
-              src++;
-              pack_left--;
-            }
+          memset (dst, *src, n);
+          src++;
+          pack_left--;
+          dst         += n;
+          unpack_left -= n;
         }
       else              /* copy next n+1 gchars literally */
         {
           n++;
-          for (; n > 0; --n)
+          if (pack_left < n)
+            {
+              IFDBG(2) g_debug ("Input buffer exhausted in copy");
+              error_code = 3;
+              break;
+            }
+          if (unpack_left < n)
             {
-              if (! pack_left)
-                {
-                  IFDBG(2) g_debug ("Input buffer exhausted in copy");
-                  error_code = 3;
-                  break;
-                }
-              if (! unpack_left)
-                {
-                  IFDBG(2) g_debug ("Output buffer exhausted in copy");
-                  error_code = 4;
-                  break;
-                }
-              *dst = *src;
-              dst++;
-              unpack_left--;
-              src++;
-              pack_left--;
+              IFDBG(2) g_debug ("Output buffer exhausted in copy");
+              error_code = 4;
+              break;
             }
+          memcpy (dst, src, n);
+          src         += n;
+          pack_left   -= n;
+          dst         += n;
+          unpack_left -= n;
         }
     }
 
   if (unpack_left > 0)
     {
       /* Pad with zeros to end of output buffer */
-      for (n = 0; n < pack_left; ++n)
-        {
-          *dst = 0;
-          dst++;
-        }
+      memset (dst, 0, unpack_left);
     }
 
   if (unpack_left)


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