[gimp] file-psd: improve high bit depth and compression support
- From: Massimo Valentini <mvalentini src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp] file-psd: improve high bit depth and compression support
- Date: Sat, 13 Jun 2015 16:35:38 +0000 (UTC)
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]