[gimp] file-psd: improve high bit depth and compression support



commit b07cf7fbeea6ff1e5018f25cdf93b947c7c85143
Author: Massimo Valentini <mvalentini src gnome org>
Date:   Sat Jun 13 18:33:00 2015 +0200

    file-psd: improve high bit depth and compression support
    
    see:
    Bug 750729 - Importing *.PSDs with greater than
     8-bit depth lose their masks and appear funny

 plug-ins/file-psd/Makefile.am |    1 +
 plug-ins/file-psd/psd-load.c  |  845 ++++++++++++++++++++++++-----------------
 2 files changed, 499 insertions(+), 347 deletions(-)
---
diff --git a/plug-ins/file-psd/Makefile.am b/plug-ins/file-psd/Makefile.am
index a190667..1386754 100644
--- a/plug-ins/file-psd/Makefile.am
+++ b/plug-ins/file-psd/Makefile.am
@@ -67,4 +67,5 @@ file_psd_LDADD = \
        $(IPTCDATA_LIBS)        \
        $(RT_LIBS)              \
        $(INTLLIBS)             \
+       $(Z_LIBS)               \
        $(file_psd_RC)
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
index d2e4e0e..1f7c29d 100644
--- a/plug-ins/file-psd/psd-load.c
+++ b/plug-ins/file-psd/psd-load.c
@@ -24,6 +24,7 @@
 #include <errno.h>
 
 #include <glib/gstdio.h>
+#include <zlib.h>
 #include <libgimp/gimp.h>
 
 #include "psd.h"
@@ -95,6 +96,7 @@ static gint             read_channel_data          (PSDchannel     *channel,
                                                     guint16         compression,
                                                     const guint16  *rle_pack_len,
                                                     FILE           *f,
+                                                    guint16         comp_len,
                                                     GError        **error);
 
 static void             convert_1_bit              (const gchar *src,
@@ -465,419 +467,469 @@ read_image_resource_block (PSDimage  *img_a,
 }
 
 static PSDlayer **
-read_layer_block (PSDimage  *img_a,
-                  FILE      *f,
-                  GError   **error)
+read_layer_info (PSDimage  *img_a,
+                 FILE      *f,
+                 GError   **error)
 {
-  PSDlayer **lyr_a;
+  PSDlayer **lyr_a = NULL;
   guint32    block_len;
-  guint32    block_end;
   guint32    block_rem;
   gint32     read_len;
   gint32     write_len;
   gint       lidx;                  /* Layer index */
   gint       cidx;                  /* Channel index */
 
-  if (fread (&block_len, 4, 1, f) < 1)
+  /* Get number of layers */
+  if (fread (&img_a->num_layers, 2, 1, f) < 1)
     {
       psd_set_error (feof (f), errno, error);
       img_a->num_layers = -1;
       return NULL;
     }
 
-  img_a->mask_layer_len = GUINT32_FROM_BE (block_len);
-
-  IFDBG(1) g_debug ("Layer and mask block size = %d", img_a->mask_layer_len);
-
-  img_a->transparency = FALSE;
-  img_a->layer_data_len = 0;
+  img_a->num_layers = GINT16_FROM_BE (img_a->num_layers);
+  IFDBG(2) g_debug ("Number of layers: %d", img_a->num_layers);
 
-  if (!img_a->mask_layer_len)
+  if (img_a->num_layers < 0)
     {
-      img_a->num_layers = 0;
-      return NULL;
+      img_a->transparency = TRUE;
+      img_a->num_layers = -img_a->num_layers;
     }
-  else
+
+  if (img_a->num_layers)
     {
-      img_a->mask_layer_start = ftell (f);
-      block_end = img_a->mask_layer_start + img_a->mask_layer_len;
+      /* Read layer records */
+      PSDlayerres           res_a;
 
-      /* Get number of layers */
-      if (fread (&block_len, 4, 1, f) < 1
-          || fread (&img_a->num_layers, 2, 1, f) < 1)
-        {
-          psd_set_error (feof (f), errno, error);
-          img_a->num_layers = -1;
-          return NULL;
-        }
-      img_a->num_layers = GINT16_FROM_BE (img_a->num_layers);
-      IFDBG(2) g_debug ("Number of layers: %d", img_a->num_layers);
+      /* Create pointer array for the layer records */
+      lyr_a = g_new (PSDlayer *, img_a->num_layers);
 
-      if (img_a->num_layers < 0)
+      for (lidx = 0; lidx < img_a->num_layers; ++lidx)
         {
-          img_a->transparency = TRUE;
-          img_a->num_layers = -img_a->num_layers;
-        }
+          /* Allocate layer record */
+          lyr_a[lidx] = (PSDlayer *) g_malloc (sizeof (PSDlayer) );
+
+          /* Initialise record */
+          lyr_a[lidx]->drop = FALSE;
+          lyr_a[lidx]->id = 0;
+          lyr_a[lidx]->group_type = 0;
+
+          if (fread (&lyr_a[lidx]->top, 4, 1, f) < 1
+              || fread (&lyr_a[lidx]->left, 4, 1, f) < 1
+              || fread (&lyr_a[lidx]->bottom, 4, 1, f) < 1
+              || fread (&lyr_a[lidx]->right, 4, 1, f) < 1
+              || fread (&lyr_a[lidx]->num_channels, 2, 1, f) < 1)
+            {
+              psd_set_error (feof (f), errno, error);
+              return NULL;
+            }
 
-      if (img_a->num_layers)
-        {
-          /* Read layer records */
-          PSDlayerres           res_a;
+          lyr_a[lidx]->top = GINT32_FROM_BE (lyr_a[lidx]->top);
+          lyr_a[lidx]->left = GINT32_FROM_BE (lyr_a[lidx]->left);
+          lyr_a[lidx]->bottom = GINT32_FROM_BE (lyr_a[lidx]->bottom);
+          lyr_a[lidx]->right = GINT32_FROM_BE (lyr_a[lidx]->right);
+          lyr_a[lidx]->num_channels = GUINT16_FROM_BE (lyr_a[lidx]->num_channels);
+
+          if (lyr_a[lidx]->num_channels > MAX_CHANNELS)
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("Too many channels in layer: %d"),
+                           lyr_a[lidx]->num_channels);
+              return NULL;
+            }
+          if (lyr_a[lidx]->bottom < lyr_a[lidx]->top ||
+              lyr_a[lidx]->bottom - lyr_a[lidx]->top > GIMP_MAX_IMAGE_SIZE)
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("Unsupported or invalid layer height: %d"),
+                           lyr_a[lidx]->bottom - lyr_a[lidx]->top);
+              return NULL;
+            }
+          if (lyr_a[lidx]->right < lyr_a[lidx]->left ||
+              lyr_a[lidx]->right - lyr_a[lidx]->left > GIMP_MAX_IMAGE_SIZE)
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("Unsupported or invalid layer width: %d"),
+                           lyr_a[lidx]->right - lyr_a[lidx]->left);
+              return NULL;
+            }
+
+          if ((lyr_a[lidx]->right - lyr_a[lidx]->left) >
+              G_MAXINT32 / MAX (lyr_a[lidx]->bottom - lyr_a[lidx]->top, 1))
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("Unsupported or invalid layer size: %dx%d"),
+                           lyr_a[lidx]->right - lyr_a[lidx]->left,
+                           lyr_a[lidx]->bottom - lyr_a[lidx]->top);
+              return NULL;
+            }
+
+          IFDBG(2) g_debug ("Layer %d, Coords %d %d %d %d, channels %d, ",
+                            lidx, lyr_a[lidx]->left, lyr_a[lidx]->top,
+                            lyr_a[lidx]->right, lyr_a[lidx]->bottom,
+                            lyr_a[lidx]->num_channels);
 
-          /* Create pointer array for the layer records */
-          lyr_a = g_new (PSDlayer *, img_a->num_layers);
+          lyr_a[lidx]->chn_info = g_new (ChannelLengthInfo, lyr_a[lidx]->num_channels);
 
-          for (lidx = 0; lidx < img_a->num_layers; ++lidx)
+          for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx)
             {
-              /* Allocate layer record */
-              lyr_a[lidx] = (PSDlayer *) g_malloc (sizeof (PSDlayer) );
-
-              /* Initialise record */
-              lyr_a[lidx]->drop = FALSE;
-              lyr_a[lidx]->id = 0;
-              lyr_a[lidx]->group_type = 0;
-
-              if (fread (&lyr_a[lidx]->top, 4, 1, f) < 1
-                  || fread (&lyr_a[lidx]->left, 4, 1, f) < 1
-                  || fread (&lyr_a[lidx]->bottom, 4, 1, f) < 1
-                  || fread (&lyr_a[lidx]->right, 4, 1, f) < 1
-                  || fread (&lyr_a[lidx]->num_channels, 2, 1, f) < 1)
+              if (fread (&lyr_a[lidx]->chn_info[cidx].channel_id, 2, 1, f) < 1
+                  || fread (&lyr_a[lidx]->chn_info[cidx].data_len, 4, 1, f) < 1)
                 {
                   psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
+              lyr_a[lidx]->chn_info[cidx].channel_id =
+                GINT16_FROM_BE (lyr_a[lidx]->chn_info[cidx].channel_id);
+              lyr_a[lidx]->chn_info[cidx].data_len =
+                GUINT32_FROM_BE (lyr_a[lidx]->chn_info[cidx].data_len);
+              img_a->layer_data_len += lyr_a[lidx]->chn_info[cidx].data_len;
+              IFDBG(3) g_debug ("Channel ID %d, data len %d",
+                                lyr_a[lidx]->chn_info[cidx].channel_id,
+                                lyr_a[lidx]->chn_info[cidx].data_len);
+            }
+
+          if (fread (lyr_a[lidx]->mode_key, 4, 1, f) < 1
+              || fread (lyr_a[lidx]->blend_mode, 4, 1, f) < 1
+              || fread (&lyr_a[lidx]->opacity, 1, 1, f) < 1
+              || fread (&lyr_a[lidx]->clipping, 1, 1, f) < 1
+              || fread (&lyr_a[lidx]->flags, 1, 1, f) < 1
+              || fread (&lyr_a[lidx]->filler, 1, 1, f) < 1
+              || fread (&lyr_a[lidx]->extra_len, 4, 1, f) < 1)
+            {
+              psd_set_error (feof (f), errno, error);
+              return NULL;
+            }
+          if (memcmp (lyr_a[lidx]->mode_key, "8BIM", 4) != 0)
+            {
+              IFDBG(1) g_debug ("Incorrect layer mode signature %.4s",
+                                lyr_a[lidx]->mode_key);
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("The file is corrupt!"));
+              return NULL;
+            }
 
-              lyr_a[lidx]->top = GINT32_FROM_BE (lyr_a[lidx]->top);
-              lyr_a[lidx]->left = GINT32_FROM_BE (lyr_a[lidx]->left);
-              lyr_a[lidx]->bottom = GINT32_FROM_BE (lyr_a[lidx]->bottom);
-              lyr_a[lidx]->right = GINT32_FROM_BE (lyr_a[lidx]->right);
-              lyr_a[lidx]->num_channels = GUINT16_FROM_BE (lyr_a[lidx]->num_channels);
+          lyr_a[lidx]->layer_flags.trans_prot = lyr_a[lidx]->flags & 1 ? TRUE : FALSE;
+          lyr_a[lidx]->layer_flags.visible = lyr_a[lidx]->flags & 2 ? FALSE : TRUE;
 
-              if (lyr_a[lidx]->num_channels > MAX_CHANNELS)
+          if (lyr_a[lidx]->flags & 8)
+            lyr_a[lidx]->layer_flags.irrelevant = lyr_a[lidx]->flags & 16 ? TRUE : FALSE;
+          else
+            lyr_a[lidx]->layer_flags.irrelevant = FALSE;
+
+          lyr_a[lidx]->extra_len = GUINT32_FROM_BE (lyr_a[lidx]->extra_len);
+          block_rem = lyr_a[lidx]->extra_len;
+          IFDBG(2) g_debug ("\n\tLayer mode sig: %.4s\n\tBlend mode: %.4s\n\t"
+                            "Opacity: %d\n\tClipping: %d\n\tExtra data len: %d\n\t"
+                            "Alpha lock: %d\n\tVisible: %d\n\tIrrelevant: %d",
+                            lyr_a[lidx]->mode_key,
+                            lyr_a[lidx]->blend_mode,
+                            lyr_a[lidx]->opacity,
+                            lyr_a[lidx]->clipping,
+                            lyr_a[lidx]->extra_len,
+                            lyr_a[lidx]->layer_flags.trans_prot,
+                            lyr_a[lidx]->layer_flags.visible,
+                            lyr_a[lidx]->layer_flags.irrelevant);
+          IFDBG(3) g_debug ("Remaining length %d", block_rem);
+
+          /* Layer mask data */
+          if (fread (&block_len, 4, 1, f) < 1)
+            {
+              psd_set_error (feof (f), errno, error);
+              return NULL;
+            }
+          block_len = GUINT32_FROM_BE (block_len);
+          block_rem -= (block_len + 4);
+          IFDBG(3) g_debug ("Remaining length %d", block_rem);
+
+          lyr_a[lidx]->layer_mask_extra.top = 0;
+          lyr_a[lidx]->layer_mask_extra.left = 0;
+          lyr_a[lidx]->layer_mask_extra.bottom = 0;
+          lyr_a[lidx]->layer_mask_extra.right = 0;
+          lyr_a[lidx]->layer_mask.top = 0;
+          lyr_a[lidx]->layer_mask.left = 0;
+          lyr_a[lidx]->layer_mask.bottom = 0;
+          lyr_a[lidx]->layer_mask.right = 0;
+          lyr_a[lidx]->layer_mask.def_color = 0;
+          lyr_a[lidx]->layer_mask.extra_def_color = 0;
+          lyr_a[lidx]->layer_mask.mask_flags.relative_pos = FALSE;
+          lyr_a[lidx]->layer_mask.mask_flags.disabled = FALSE;
+          lyr_a[lidx]->layer_mask.mask_flags.invert = FALSE;
+
+          switch (block_len)
+            {
+            case 0:
+              break;
+
+            case 20:
+              if (fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1)
                 {
-                  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                              _("Too many channels in layer: %d"),
-                              lyr_a[lidx]->num_channels);
+                  psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
-              if (lyr_a[lidx]->bottom < lyr_a[lidx]->top ||
-                  lyr_a[lidx]->bottom - lyr_a[lidx]->top > GIMP_MAX_IMAGE_SIZE)
+              lyr_a[lidx]->layer_mask.top =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
+              lyr_a[lidx]->layer_mask.left =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
+              lyr_a[lidx]->layer_mask.bottom =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
+              lyr_a[lidx]->layer_mask.right =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
+              lyr_a[lidx]->layer_mask.mask_flags.relative_pos =
+                lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE;
+              lyr_a[lidx]->layer_mask.mask_flags.disabled =
+                lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE;
+              lyr_a[lidx]->layer_mask.mask_flags.invert =
+                lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE;
+              break;
+            case 36: /* If we have a 36 byte mask record assume second data set is correct */
+              if (fread (&lyr_a[lidx]->layer_mask_extra.top, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask_extra.left, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask_extra.bottom, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask_extra.right, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1
+                  || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1)
                 {
-                  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                              _("Unsupported or invalid layer height: %d"),
-                              lyr_a[lidx]->bottom - lyr_a[lidx]->top);
+                  psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
-              if (lyr_a[lidx]->right < lyr_a[lidx]->left ||
-                  lyr_a[lidx]->right - lyr_a[lidx]->left > GIMP_MAX_IMAGE_SIZE)
+              lyr_a[lidx]->layer_mask_extra.top =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.top);
+              lyr_a[lidx]->layer_mask_extra.left =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.left);
+              lyr_a[lidx]->layer_mask_extra.bottom =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.bottom);
+              lyr_a[lidx]->layer_mask_extra.right =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.right);
+              lyr_a[lidx]->layer_mask.top =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
+              lyr_a[lidx]->layer_mask.left =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
+              lyr_a[lidx]->layer_mask.bottom =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
+              lyr_a[lidx]->layer_mask.right =
+                GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
+              lyr_a[lidx]->layer_mask.mask_flags.relative_pos =
+                lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE;
+              lyr_a[lidx]->layer_mask.mask_flags.disabled =
+                lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE;
+              lyr_a[lidx]->layer_mask.mask_flags.invert =
+                lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE;
+              break;
+
+            default:
+              IFDBG(1) g_debug ("Unknown layer mask record size ... skipping");
+              if (fseek (f, block_len, SEEK_CUR) < 0)
                 {
-                  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                              _("Unsupported or invalid layer width: %d"),
-                              lyr_a[lidx]->right - lyr_a[lidx]->left);
+                  psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
+            }
 
-              if ((lyr_a[lidx]->right - lyr_a[lidx]->left) >
-                  G_MAXINT32 / MAX (lyr_a[lidx]->bottom - lyr_a[lidx]->top, 1))
-                {
-                  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                               _("Unsupported or invalid layer size: %dx%d"),
-                               lyr_a[lidx]->right - lyr_a[lidx]->left,
-                               lyr_a[lidx]->bottom - lyr_a[lidx]->top);
-                  return NULL;
-                }
+          /* sanity checks */
+          if (lyr_a[lidx]->layer_mask.bottom < lyr_a[lidx]->layer_mask.top ||
+              lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top > GIMP_MAX_IMAGE_SIZE)
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("Unsupported or invalid layer mask height: %d"),
+                           lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top);
+              return NULL;
+            }
+          if (lyr_a[lidx]->layer_mask.right < lyr_a[lidx]->layer_mask.left ||
+              lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left > GIMP_MAX_IMAGE_SIZE)
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("Unsupported or invalid layer mask width: %d"),
+                           lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left);
+              return NULL;
+            }
 
-              IFDBG(2) g_debug ("Layer %d, Coords %d %d %d %d, channels %d, ",
-                                 lidx, lyr_a[lidx]->left, lyr_a[lidx]->top,
-                                 lyr_a[lidx]->right, lyr_a[lidx]->bottom,
-                                 lyr_a[lidx]->num_channels);
+          if ((lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left) >
+              G_MAXINT32 / MAX (lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top, 1))
+            {
+              g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
+                           _("Unsupported or invalid layer mask size: %dx%d"),
+                           lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left,
+                           lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top);
+              return NULL;
+            }
 
-              lyr_a[lidx]->chn_info = g_new (ChannelLengthInfo, lyr_a[lidx]->num_channels);
+          IFDBG(2) g_debug ("Layer mask coords %d %d %d %d, Rel pos %d",
+                            lyr_a[lidx]->layer_mask.left,
+                            lyr_a[lidx]->layer_mask.top,
+                            lyr_a[lidx]->layer_mask.right,
+                            lyr_a[lidx]->layer_mask.bottom,
+                            lyr_a[lidx]->layer_mask.mask_flags.relative_pos);
 
-              for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx)
-                {
-                  if (fread (&lyr_a[lidx]->chn_info[cidx].channel_id, 2, 1, f) < 1
-                      || fread (&lyr_a[lidx]->chn_info[cidx].data_len, 4, 1, f) < 1)
-                    {
-                      psd_set_error (feof (f), errno, error);
-                      return NULL;
-                    }
-                  lyr_a[lidx]->chn_info[cidx].channel_id =
-                    GINT16_FROM_BE (lyr_a[lidx]->chn_info[cidx].channel_id);
-                  lyr_a[lidx]->chn_info[cidx].data_len =
-                    GUINT32_FROM_BE (lyr_a[lidx]->chn_info[cidx].data_len);
-                  img_a->layer_data_len += lyr_a[lidx]->chn_info[cidx].data_len;
-                  IFDBG(3) g_debug ("Channel ID %d, data len %d",
-                                     lyr_a[lidx]->chn_info[cidx].channel_id,
-                                     lyr_a[lidx]->chn_info[cidx].data_len);
-                }
+          IFDBG(3) g_debug ("Default mask color, %d, %d",
+                            lyr_a[lidx]->layer_mask.def_color,
+                            lyr_a[lidx]->layer_mask.extra_def_color);
 
-              if (fread (lyr_a[lidx]->mode_key, 4, 1, f) < 1
-                  || fread (lyr_a[lidx]->blend_mode, 4, 1, f) < 1
-                  || fread (&lyr_a[lidx]->opacity, 1, 1, f) < 1
-                  || fread (&lyr_a[lidx]->clipping, 1, 1, f) < 1
-                  || fread (&lyr_a[lidx]->flags, 1, 1, f) < 1
-                  || fread (&lyr_a[lidx]->filler, 1, 1, f) < 1
-                  || fread (&lyr_a[lidx]->extra_len, 4, 1, f) < 1)
-                {
-                  psd_set_error (feof (f), errno, error);
-                  return NULL;
-                }
-              if (memcmp (lyr_a[lidx]->mode_key, "8BIM", 4) != 0)
-                {
-                  IFDBG(1) g_debug ("Incorrect layer mode signature %.4s",
-                                    lyr_a[lidx]->mode_key);
-                  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                              _("The file is corrupt!"));
-                  return NULL;
-                }
+          /* Layer blending ranges */           /* FIXME  */
+          if (fread (&block_len, 4, 1, f) < 1)
+            {
+              psd_set_error (feof (f), errno, error);
+              return NULL;
+            }
 
-              lyr_a[lidx]->layer_flags.trans_prot = lyr_a[lidx]->flags & 1 ? TRUE : FALSE;
-              lyr_a[lidx]->layer_flags.visible = lyr_a[lidx]->flags & 2 ? FALSE : TRUE;
+          block_len = GUINT32_FROM_BE (block_len);
+          block_rem -= (block_len + 4);
+          IFDBG(3) g_debug ("Remaining length %d", block_rem);
 
-              if (lyr_a[lidx]->flags & 8)
-                lyr_a[lidx]->layer_flags.irrelevant = lyr_a[lidx]->flags & 16 ? TRUE : FALSE;
-              else
-                lyr_a[lidx]->layer_flags.irrelevant = FALSE;
-
-              lyr_a[lidx]->extra_len = GUINT32_FROM_BE (lyr_a[lidx]->extra_len);
-              block_rem = lyr_a[lidx]->extra_len;
-              IFDBG(2) g_debug ("\n\tLayer mode sig: %.4s\n\tBlend mode: %.4s\n\t"
-                                "Opacity: %d\n\tClipping: %d\n\tExtra data len: %d\n\t"
-                                "Alpha lock: %d\n\tVisible: %d\n\tIrrelevant: %d",
-                                    lyr_a[lidx]->mode_key,
-                                    lyr_a[lidx]->blend_mode,
-                                    lyr_a[lidx]->opacity,
-                                    lyr_a[lidx]->clipping,
-                                    lyr_a[lidx]->extra_len,
-                                    lyr_a[lidx]->layer_flags.trans_prot,
-                                    lyr_a[lidx]->layer_flags.visible,
-                                    lyr_a[lidx]->layer_flags.irrelevant);
-              IFDBG(3) g_debug ("Remaining length %d", block_rem);
-
-              /* Layer mask data */
-              if (fread (&block_len, 4, 1, f) < 1)
+          if (block_len > 0)
+            {
+              if (fseek (f, block_len, SEEK_CUR) < 0)
                 {
                   psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
-              block_len = GUINT32_FROM_BE (block_len);
-              block_rem -= (block_len + 4);
-              IFDBG(3) g_debug ("Remaining length %d", block_rem);
-
-              lyr_a[lidx]->layer_mask_extra.top = 0;
-              lyr_a[lidx]->layer_mask_extra.left = 0;
-              lyr_a[lidx]->layer_mask_extra.bottom = 0;
-              lyr_a[lidx]->layer_mask_extra.right = 0;
-              lyr_a[lidx]->layer_mask.top = 0;
-              lyr_a[lidx]->layer_mask.left = 0;
-              lyr_a[lidx]->layer_mask.bottom = 0;
-              lyr_a[lidx]->layer_mask.right = 0;
-              lyr_a[lidx]->layer_mask.def_color = 0;
-              lyr_a[lidx]->layer_mask.extra_def_color = 0;
-              lyr_a[lidx]->layer_mask.mask_flags.relative_pos = FALSE;
-              lyr_a[lidx]->layer_mask.mask_flags.disabled = FALSE;
-              lyr_a[lidx]->layer_mask.mask_flags.invert = FALSE;
-
-              switch (block_len)
-                {
-                  case 0:
-                    break;
-
-                  case 20:
-                    if (fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1)
-                      {
-                        psd_set_error (feof (f), errno, error);
-                        return NULL;
-                      }
-                    lyr_a[lidx]->layer_mask.top =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
-                    lyr_a[lidx]->layer_mask.left =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
-                    lyr_a[lidx]->layer_mask.bottom =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
-                    lyr_a[lidx]->layer_mask.right =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
-                    lyr_a[lidx]->layer_mask.mask_flags.relative_pos =
-                      lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE;
-                    lyr_a[lidx]->layer_mask.mask_flags.disabled =
-                      lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE;
-                    lyr_a[lidx]->layer_mask.mask_flags.invert =
-                      lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE;
-                    break;
-                  case 36: /* If we have a 36 byte mask record assume second data set is correct */
-                    if (fread (&lyr_a[lidx]->layer_mask_extra.top, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask_extra.left, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask_extra.bottom, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask_extra.right, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.extra_def_color, 1, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.extra_flags, 1, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.def_color, 1, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.flags, 1, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.top, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.left, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.bottom, 4, 1, f) < 1
-                        || fread (&lyr_a[lidx]->layer_mask.right, 4, 1, f) < 1)
-                      {
-                        psd_set_error (feof (f), errno, error);
-                        return NULL;
-                      }
-                    lyr_a[lidx]->layer_mask_extra.top =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.top);
-                    lyr_a[lidx]->layer_mask_extra.left =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.left);
-                    lyr_a[lidx]->layer_mask_extra.bottom =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.bottom);
-                    lyr_a[lidx]->layer_mask_extra.right =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask_extra.right);
-                    lyr_a[lidx]->layer_mask.top =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.top);
-                    lyr_a[lidx]->layer_mask.left =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.left);
-                    lyr_a[lidx]->layer_mask.bottom =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.bottom);
-                    lyr_a[lidx]->layer_mask.right =
-                      GINT32_FROM_BE (lyr_a[lidx]->layer_mask.right);
-                    lyr_a[lidx]->layer_mask.mask_flags.relative_pos =
-                      lyr_a[lidx]->layer_mask.flags & 1 ? TRUE : FALSE;
-                    lyr_a[lidx]->layer_mask.mask_flags.disabled =
-                      lyr_a[lidx]->layer_mask.flags & 2 ? TRUE : FALSE;
-                    lyr_a[lidx]->layer_mask.mask_flags.invert =
-                      lyr_a[lidx]->layer_mask.flags & 4 ? TRUE : FALSE;
-                    break;
-
-                  default:
-                    IFDBG(1) g_debug ("Unknown layer mask record size ... skipping");
-                    if (fseek (f, block_len, SEEK_CUR) < 0)
-                      {
-                        psd_set_error (feof (f), errno, error);
-                        return NULL;
-                      }
-                }
+            }
 
-              /* sanity checks */
-              if (lyr_a[lidx]->layer_mask.bottom < lyr_a[lidx]->layer_mask.top ||
-                  lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top > GIMP_MAX_IMAGE_SIZE)
-                {
-                  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                               _("Unsupported or invalid layer mask height: %d"),
-                               lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top);
-                  return NULL;
-                }
-              if (lyr_a[lidx]->layer_mask.right < lyr_a[lidx]->layer_mask.left ||
-                  lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left > GIMP_MAX_IMAGE_SIZE)
-                {
-                  g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                               _("Unsupported or invalid layer mask width: %d"),
-                               lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left);
-                  return NULL;
-                }
+          lyr_a[lidx]->name = fread_pascal_string (&read_len, &write_len,
+                                                   4, f, error);
+          if (*error)
+            return NULL;
+
+          block_rem -= read_len;
+          IFDBG(3) g_debug ("Remaining length %d", block_rem);
 
-              if ((lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left) >
-                  G_MAXINT32 / MAX (lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top, 1))
+          /* Adjustment layer info */           /* FIXME */
+
+          while (block_rem > 7)
+            {
+              if (get_layer_resource_header (&res_a, f, error) < 0)
+                return NULL;
+
+              block_rem -= 12;
+
+              //Round up to the nearest even byte
+              while (res_a.data_len % 4 != 0)
+                res_a.data_len++;
+
+              if (res_a.data_len > block_rem)
                 {
+                  IFDBG(1) g_debug ("Unexpected end of layer resource data");
                   g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                               _("Unsupported or invalid layer mask size: %dx%d"),
-                               lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left,
-                               lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top);
+                               _("The file is corrupt!"));
                   return NULL;
                 }
 
-              IFDBG(2) g_debug ("Layer mask coords %d %d %d %d, Rel pos %d",
-                                lyr_a[lidx]->layer_mask.left,
-                                lyr_a[lidx]->layer_mask.top,
-                                lyr_a[lidx]->layer_mask.right,
-                                lyr_a[lidx]->layer_mask.bottom,
-                                lyr_a[lidx]->layer_mask.mask_flags.relative_pos);
-
-              IFDBG(3) g_debug ("Default mask color, %d, %d",
-                                lyr_a[lidx]->layer_mask.def_color,
-                                lyr_a[lidx]->layer_mask.extra_def_color);
-
-              /* Layer blending ranges */           /* FIXME  */
-              if (fread (&block_len, 4, 1, f) < 1)
+              if (load_layer_resource (&res_a, lyr_a[lidx], f, error) < 0)
+                return NULL;
+              block_rem -= res_a.data_len;
+            }
+          if (block_rem > 0)
+            {
+              if (fseek (f, block_rem, SEEK_CUR) < 0)
                 {
                   psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
+            }
+        }
 
-              block_len = GUINT32_FROM_BE (block_len);
-              block_rem -= (block_len + 4);
-              IFDBG(3) g_debug ("Remaining length %d", block_rem);
+      img_a->layer_data_start = ftell(f);
+      if (fseek (f, img_a->layer_data_len, SEEK_CUR) < 0)
+        {
+          psd_set_error (feof (f), errno, error);
+          return NULL;
+        }
 
-              if (block_len > 0)
-                {
-                  if (fseek (f, block_len, SEEK_CUR) < 0)
-                    {
-                      psd_set_error (feof (f), errno, error);
-                      return NULL;
-                    }
-                }
+      IFDBG(1) g_debug ("Layer image data block size %d",
+                        img_a->layer_data_len);
+    }
 
-              lyr_a[lidx]->name = fread_pascal_string (&read_len, &write_len,
-                                                       4, f, error);
-              if (*error)
-                return NULL;
+  return lyr_a;
+}
 
-              block_rem -= read_len;
-              IFDBG(3) g_debug ("Remaining length %d", block_rem);
 
-              /* Adjustment layer info */           /* FIXME */
+static PSDlayer **
+read_layer_block (PSDimage  *img_a,
+                  FILE      *f,
+                  GError   **error)
+{
+  PSDlayer **lyr_a = NULL;
+  guint32    block_len;
+  guint32    block_end;
 
-              while (block_rem > 7)
-                {
-                  if (get_layer_resource_header (&res_a, f, error) < 0)
-                    return NULL;
+  if (fread (&block_len, 4, 1, f) < 1)
+    {
+      psd_set_error (feof (f), errno, error);
+      img_a->num_layers = -1;
+      return NULL;
+    }
 
-                  block_rem -= 12;
+  img_a->mask_layer_len = GUINT32_FROM_BE (block_len);
 
-                  //Round up to the nearest even byte
-                  while (res_a.data_len % 4 != 0)
-                    res_a.data_len++;
+  IFDBG(1) g_debug ("Layer and mask block size = %d", img_a->mask_layer_len);
 
-                  if (res_a.data_len > block_rem)
-                    {
-                      IFDBG(1) g_debug ("Unexpected end of layer resource data");
-                      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                                  _("The file is corrupt!"));
-                      return NULL;
-                    }
+  img_a->transparency = FALSE;
+  img_a->layer_data_len = 0;
 
-                  if (load_layer_resource (&res_a, lyr_a[lidx], f, error) < 0)
-                    return NULL;
-                  block_rem -= res_a.data_len;
-                }
-              if (block_rem > 0)
-                {
-                  if (fseek (f, block_rem, SEEK_CUR) < 0)
-                    {
-                      psd_set_error (feof (f), errno, error);
-                      return NULL;
-                    }
-                }
-            }
+  if (!img_a->mask_layer_len)
+    {
+      img_a->num_layers = 0;
+      return NULL;
+    }
+  else
+    {
+      guint32 total_len = img_a->mask_layer_len;
 
-          img_a->layer_data_start = ftell(f);
-          if (fseek (f, img_a->layer_data_len, SEEK_CUR) < 0)
-            {
-              psd_set_error (feof (f), errno, error);
-              return NULL;
-            }
+      img_a->mask_layer_start = ftell (f);
+      block_end = img_a->mask_layer_start + img_a->mask_layer_len;
+
+      /* Layer info */
+      if (fread (&block_len, 4, 1, f) == 1 && block_len)
+        {
+          block_len = GUINT32_FROM_BE (block_len);
+          IFDBG(1) g_debug ("Layer info size = %d", block_len);
+
+          lyr_a = read_layer_info (img_a, f, error);
 
-          IFDBG(1) g_debug ("Layer image data block size %d",
-                             img_a->layer_data_len);
+          total_len -= block_len;
         }
       else
-        lyr_a = NULL;
+        {
+          img_a->num_layers = 0;
+          lyr_a = NULL;
+        }
 
-      /* Read global layer mask record */       /* FIXME */
+      /* Global layer mask info */
+      if (fread (&block_len, 4, 1, f) == 1 && block_len)
+        {
+          block_len = GUINT32_FROM_BE (block_len);
+          IFDBG(1) g_debug ("Global layer mask info size = %d", block_len);
+
+          /* read_global_layer_mask_info (img_a, f, error); */
+          fseek (f, block_len, SEEK_CUR);
+
+          total_len -= block_len;
+        }
+
+      /* Additional Layer Information */
+      if (total_len > 12)
+        {
+          gchar signature_key[8];
+
+          if (fread (&signature_key, 4, 2, f) == 2 &&
+              (memcmp (signature_key, "8BIMLr16", 8) == 0 ||
+               memcmp (signature_key, "8BIMLr32", 8) == 0) &&
+              fread (&block_len, 4, 1, f) == 1 && block_len)
+            lyr_a = read_layer_info (img_a, f, error);
+        }
 
       /* Skip to end of block */
       if (fseek (f, block_end, SEEK_SET) < 0)
@@ -1242,7 +1294,7 @@ add_layers (gint32     image_id,
                         IFDBG(3) g_debug ("Raw data length: %d",
                                           lyr_a[lidx]->chn_info[cidx].data_len - 2);
                         if (read_channel_data (lyr_chn[cidx], img_a->bps,
-                                               PSD_COMP_RAW, NULL, f,
+                                               PSD_COMP_RAW, NULL, f, 0,
                                                error) < 1)
                           return -1;
                         break;
@@ -1268,7 +1320,7 @@ add_layers (gint32     image_id,
 
                         IFDBG(3) g_debug ("RLE decode - data");
                         if (read_channel_data (lyr_chn[cidx], img_a->bps,
-                                               PSD_COMP_RLE, rle_pack_len, f,
+                                               PSD_COMP_RLE, rle_pack_len, f, 0,
                                                error) < 1)
                           return -1;
 
@@ -1277,6 +1329,13 @@ add_layers (gint32     image_id,
 
                       case PSD_COMP_ZIP:                 /* ? */
                       case PSD_COMP_ZIP_PRED:
+                        if (read_channel_data (lyr_chn[cidx], img_a->bps,
+                                               comp_mode, NULL, f,
+                                               lyr_a[lidx]->chn_info[cidx].data_len - 2,
+                                               error) < 1)
+                          return -1;
+                        break;
+
                       default:
                         g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
                                     _("Unsupported compression mode: %d"), comp_mode);
@@ -1456,7 +1515,8 @@ add_layers (gint32     image_id,
                   IFDBG(3) g_debug ("Mask channel index %d", user_mask_chn);
                   IFDBG(3) g_debug ("Relative pos %d",
                                     lyr_a[lidx]->layer_mask.mask_flags.relative_pos);
-                  layer_size = lm_w * lm_h;
+                  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 */
@@ -1480,8 +1540,7 @@ add_layers (gint32     image_id,
                                 {
                                   if (coli + lm_x >= 0 && coli + lm_x < l_w)
                                     {
-                                      pixels[i] =
-                                        lyr_chn[user_mask_chn]->data[(rowi * lm_w) + coli];
+                                      memcpy (&pixels[i * bps], &lyr_chn[user_mask_chn]->data[(rowi * lm_w + 
coli) * bps], bps);
                                       i++;
                                     }
                                 }
@@ -1637,7 +1696,7 @@ add_merged_image (gint32     image_id,
                 chn_a[cidx].columns = img_a->columns;
                 chn_a[cidx].rows = img_a->rows;
                 if (read_channel_data (&chn_a[cidx], img_a->bps,
-                                       PSD_COMP_RAW, NULL, f,
+                                       PSD_COMP_RAW, NULL, f, 0,
                                        error) < 1)
                   return -1;
               }
@@ -1669,7 +1728,7 @@ add_merged_image (gint32     image_id,
             for (cidx = 0; cidx < total_channels; ++cidx)
               {
                 if (read_channel_data (&chn_a[cidx], img_a->bps,
-                                       PSD_COMP_RLE, rle_pack_len[cidx], f,
+                                       PSD_COMP_RLE, rle_pack_len[cidx], f, 0,
                                        error) < 1)
                   return -1;
                 g_free (rle_pack_len[cidx]);
@@ -1922,19 +1981,33 @@ get_gimp_image_type (GimpImageBaseType image_base_type,
   return image_type;
 }
 
+static voidpf
+zzalloc (voidpf opaque, uInt items, uInt size)
+{
+  /* overflow check missing */
+  return g_malloc (items * size);
+}
+
+static void
+zzfree (voidpf opaque, voidpf address)
+{
+  g_free (address);
+}
+
 static gint
 read_channel_data (PSDchannel     *channel,
                    guint16         bps,
                    guint16         compression,
                    const guint16  *rle_pack_len,
                    FILE           *f,
+                   guint16         comp_len,
                    GError        **error)
 {
   gchar    *raw_data;
   gchar    *src;
   gchar    *dst;
   guint32   readline_len;
-  gint      i;
+  gint      i, j;
 
   if (bps == 1)
     readline_len = ((channel->columns + 7) / 8);
@@ -1990,16 +2063,94 @@ read_channel_data (PSDchannel     *channel,
             g_free (dst);
           }
         break;
+      case PSD_COMP_ZIP:
+      case PSD_COMP_ZIP_PRED:
+        {
+          z_stream zs;
+
+          src = g_malloc (comp_len);
+          if (fread (src, comp_len, 1, f) < 1)
+            {
+              psd_set_error (feof (f), errno, error);
+              g_free (src);
+              return -1;
+            }
+
+          zs.next_in = (guchar*) src;
+          zs.avail_in = comp_len;
+          zs.next_out = (guchar*) raw_data;
+          zs.avail_out = readline_len * channel->rows;
+          zs.zalloc = zzalloc;
+          zs.zfree = zzfree;
+
+          if (inflateInit (&zs) == Z_OK &&
+              inflate (&zs, Z_FINISH) == Z_STREAM_END)
+            {
+              inflateEnd (&zs);
+            }
+          else
+            {
+              psd_set_error (feof (f), errno, error);
+              g_free (src);
+              return -1;
+            }
+
+          g_free (src);
+          break;
+        }
     }
 
   /* Convert channel data to GIMP format */
   switch (bps)
     {
-      case 32:
-      case 16:
+    case 32:
+      {
+        guint32 *src = (guint32*) raw_data;
+        guint32 *dst = g_malloc (channel->rows * channel->columns * 4);
+
+        channel->data = (gchar*) dst;
+
+        for (i = 0; i < channel->rows * channel->columns; ++i)
+          dst[i] = GUINT32_FROM_BE (src[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];
+          }
+        break;
+      }
+
+    case 16:
+      {
+        guint16 *src = (guint16*) raw_data;
+        guint16 *dst = g_malloc (channel->rows * channel->columns * 2);
+
+        channel->data = (gchar*) dst;
+
+        for (i = 0; i < channel->rows * channel->columns; ++i)
+          dst[i] = GUINT16_FROM_BE (src[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];
+          }
+        break;
+      }
+
       case 8:
-        channel->data = (gchar *) g_malloc (channel->rows * channel->columns * bps / 8 );
+        channel->data = g_malloc (channel->rows * channel->columns * bps / 8 );
         memcpy (channel->data, raw_data, (channel->rows * channel->columns * bps / 8));
+
+        if (compression == PSD_COMP_ZIP_PRED)
+          {
+            for (i = 0; i < channel->rows; ++i)
+              for (j = 1; j < channel->columns; ++j)
+                channel->data[i * channel->columns + j] += channel->data[i * channel->columns + j - 1];
+          }
         break;
 
       case 1:



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