/* GIMP - The GNU Image Manipulation Program
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* GIMP PSD Plug-in
* Copyright 2007 by John Marshall
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see .
*/
#include "config.h"
#include
#include
#include
#include
#include
#include "psd.h"
#include "psd-util.h"
#include "psd-image-res-load.h"
#include "psd-layer-res-load.h"
#include "psd-load.h"
#include "libgimp/stdplugins-intl.h"
#define COMP_MODE_SIZE sizeof(guint16)
/* Local function prototypes */
static gint read_header_block (PSDimage *img_a,
FILE *f,
GError **error);
static gint read_color_mode_block (PSDimage *img_a,
FILE *f,
GError **error);
static gint read_image_resource_block (PSDimage *img_a,
FILE *f,
GError **error);
static PSDlayer ** read_layer_block (PSDimage *img_a,
FILE *f,
GError **error);
static gint read_merged_image_block (PSDimage *img_a,
FILE *f,
GError **error);
static gint32 create_gimp_image (PSDimage *img_a,
const gchar *filename);
static gint add_color_map (gint32 image_id,
PSDimage *img_a);
static gint add_image_resources (gint32 image_id,
PSDimage *img_a,
FILE *f,
gboolean *resolution_loaded,
gboolean *profile_loaded,
GError **error);
static gint add_layers (gint32 image_id,
PSDimage *img_a,
PSDlayer **lyr_a,
FILE *f,
GError **error);
static gint add_merged_image (gint32 image_id,
PSDimage *img_a,
FILE *f,
GError **error);
/* Local utility function prototypes */
static gchar * get_psd_color_mode_name (PSDColorMode mode);
static void psd_to_gimp_color_map (guchar *map256);
static GimpImageType get_gimp_image_type (GimpImageBaseType image_base_type,
gboolean alpha);
static gint read_channel_data (PSDchannel *channel,
guint16 bps,
guint16 compression,
const guint16 *rle_pack_len,
FILE *f,
guint32 comp_len,
GError **error);
static void convert_1_bit (const gchar *src,
gchar *dst,
guint32 rows,
guint32 columns);
static const Babl* get_layer_format (PSDimage *img_a,
gboolean alpha);
static const Babl* get_channel_format (PSDimage *img_a);
static const Babl* get_mask_format (PSDimage *img_a);
/* Main file load function */
gint32
load_image (const gchar *filename,
gboolean merged_image_only,
gboolean *resolution_loaded,
gboolean *profile_loaded,
GError **load_error)
{
FILE *f;
GStatBuf st;
PSDimage img_a;
PSDlayer **lyr_a;
gint32 image_id = -1;
GError *error = NULL;
img_a.cmyk_transform = img_a.cmyk_transform_alpha = NULL;
img_a.cmyk_profile = NULL;
/* ----- Open PSD file ----- */
if (g_stat (filename, &st) == -1)
return -1;
gimp_progress_init_printf (_("Opening '%s'"),
gimp_filename_to_utf8 (filename));
IFDBG(1) g_debug ("Open file %s", gimp_filename_to_utf8 (filename));
f = g_fopen (filename, "rb");
if (f == NULL)
{
g_set_error (load_error, G_FILE_ERROR, g_file_error_from_errno (errno),
_("Could not open '%s' for reading: %s"),
gimp_filename_to_utf8 (filename), g_strerror (errno));
return -1;
}
img_a.merged_image_only = merged_image_only;
/* ----- Read the PSD file Header block ----- */
IFDBG(2) g_debug ("Read header block");
if (read_header_block (&img_a, f, &error) < 0)
goto load_error;
gimp_progress_update (0.1);
/* ----- Read the PSD file Color Mode block ----- */
IFDBG(2) g_debug ("Read color mode block");
if (read_color_mode_block (&img_a, f, &error) < 0)
goto load_error;
gimp_progress_update (0.2);
/* ----- Read the PSD file Image Resource block ----- */
IFDBG(2) g_debug ("Read image resource block");
if (read_image_resource_block (&img_a, f, &error) < 0)
goto load_error;
gimp_progress_update (0.3);
/* ----- Read the PSD file Layer & Mask block ----- */
IFDBG(2) g_debug ("Read layer & mask block");
lyr_a = read_layer_block (&img_a, f, &error);
if (! img_a.merged_image_only && img_a.num_layers != 0 && lyr_a == NULL)
goto load_error;
gimp_progress_update (0.4);
/* ----- Read the PSD file Merged Image Data block ----- */
IFDBG(2) g_debug ("Read merged image and extra alpha channel block");
if (read_merged_image_block (&img_a, f, &error) < 0)
goto load_error;
gimp_progress_update (0.5);
/* ----- Create GIMP image ----- */
IFDBG(2) g_debug ("Create GIMP image");
image_id = create_gimp_image (&img_a, filename);
if (image_id < 0)
goto load_error;
gimp_progress_update (0.6);
/* ----- Add color map ----- */
IFDBG(2) g_debug ("Add color map");
if (add_color_map (image_id, &img_a) < 0)
goto load_error;
gimp_progress_update (0.7);
/* ----- Add image resources ----- */
IFDBG(2) g_debug ("Add image resources");
if (add_image_resources (image_id, &img_a, f,
resolution_loaded, profile_loaded,
&error) < 0)
goto load_error;
gimp_progress_update (0.8);
/* ----- Add layers -----*/
IFDBG(2) g_debug ("Add layers");
if (add_layers (image_id, &img_a, lyr_a, f, &error) < 0)
goto load_error;
gimp_progress_update (0.9);
/* ----- Add merged image data and extra alpha channels ----- */
IFDBG(2) g_debug ("Add merged image data and extra alpha channels");
if (add_merged_image (image_id, &img_a, f, &error) < 0)
goto load_error;
gimp_progress_update (1.0);
IFDBG(2) g_debug ("Close file & return, image id: %d", image_id);
IFDBG(1) g_debug ("\n----------------------------------------"
"----------------------------------------\n");
gimp_image_clean_all (image_id);
gimp_image_undo_enable (image_id);
fclose (f);
return image_id;
/* ----- Process load errors ----- */
load_error:
if (error)
{
g_set_error (load_error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Error loading PSD file: %s"), error->message);
g_error_free (error);
}
/* Delete partially loaded image */
if (image_id > 0)
gimp_image_delete (image_id);
/* Close file if Open */
if (! (f == NULL))
fclose (f);
return -1;
}
/* Local functions */
static gint
read_header_block (PSDimage *img_a,
FILE *f,
GError **error)
{
guint16 version;
gchar sig[4];
gchar buf[6];
if (fread (sig, 4, 1, f) < 1
|| fread (&version, 2, 1, f) < 1
|| fread (buf, 6, 1, f) < 1
|| fread (&img_a->channels, 2, 1, f) < 1
|| fread (&img_a->rows, 4, 1, f) < 1
|| fread (&img_a->columns, 4, 1, f) < 1
|| fread (&img_a->bps, 2, 1, f) < 1
|| fread (&img_a->color_mode, 2, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
version = GUINT16_FROM_BE (version);
img_a->channels = GUINT16_FROM_BE (img_a->channels);
img_a->rows = GUINT32_FROM_BE (img_a->rows);
img_a->columns = GUINT32_FROM_BE (img_a->columns);
img_a->bps = GUINT16_FROM_BE (img_a->bps);
img_a->color_mode = GUINT16_FROM_BE (img_a->color_mode);
IFDBG(1) g_debug ("\n\n\tSig: %.4s\n\tVer: %d\n\tChannels: "
"%d\n\tSize: %dx%d\n\tBPS: %d\n\tMode: %d\n",
sig, version, img_a->channels,
img_a->columns, img_a->rows,
img_a->bps, img_a->color_mode);
if (memcmp (sig, "8BPS", 4) != 0)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Not a valid Photoshop document file"));
return -1;
}
if (version != 1)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported file format version: %d"), version);
return -1;
}
if (img_a->channels > MAX_CHANNELS)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Too many channels in file: %d"), img_a->channels);
return -1;
}
/* Photoshop CS (version 8) supports 300000 x 300000, but this
is currently larger than GIMP_MAX_IMAGE_SIZE */
if (img_a->rows < 1 || img_a->rows > GIMP_MAX_IMAGE_SIZE)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported or invalid image height: %d"),
img_a->rows);
return -1;
}
if (img_a->columns < 1 || img_a->columns > GIMP_MAX_IMAGE_SIZE)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported or invalid image width: %d"),
img_a->columns);
return -1;
}
/* img_a->rows is sanitized above, so a division by zero is avoided here */
if (img_a->columns > G_MAXINT32 / img_a->rows)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported or invalid image size: %dx%d"),
img_a->columns, img_a->rows);
return -1;
}
if (img_a->color_mode != PSD_BITMAP
&& img_a->color_mode != PSD_GRAYSCALE
&& img_a->color_mode != PSD_INDEXED
&& img_a->color_mode != PSD_RGB
&& img_a->color_mode != PSD_MULTICHANNEL
&& img_a->color_mode != PSD_CMYK
&& img_a->color_mode != PSD_DUOTONE)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported color mode: %s"),
get_psd_color_mode_name (img_a->color_mode));
return -1;
}
if (img_a->color_mode == PSD_CMYK)
{
if (img_a->bps != 8)
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported color mode: %s"),
get_psd_color_mode_name (img_a->color_mode));
return -1;
}
}
/* Warning for unsupported bit depth */
switch (img_a->bps)
{
case 32:
IFDBG(3) g_debug ("32 Bit Data");
break;
case 16:
IFDBG(3) g_debug ("16 Bit Data");
break;
case 8:
IFDBG(3) g_debug ("8 Bit Data");
break;
case 1:
IFDBG(3) g_debug ("1 Bit Data");
break;
default:
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported bit depth: %d"), img_a->bps);
return -1;
break;
}
return 0;
}
static gint
read_color_mode_block (PSDimage *img_a,
FILE *f,
GError **error)
{
static guchar cmap[] = { 0, 0, 0, 255, 255, 255 };
guint32 block_len;
img_a->color_map_entries = 0;
img_a->color_map_len = 0;
if (fread (&block_len, 4, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
block_len = GUINT32_FROM_BE (block_len);
IFDBG(1) g_debug ("Color map block size = %d", block_len);
if (block_len == 0)
{
if (img_a->color_mode == PSD_INDEXED ||
img_a->color_mode == PSD_DUOTONE )
{
IFDBG(1) g_debug ("No color block for indexed or duotone image");
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("The file is corrupt!"));
return -1;
}
}
else if (img_a->color_mode == PSD_INDEXED)
{
if (block_len != 768)
{
IFDBG(1) g_debug ("Invalid color block size for indexed image");
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("The file is corrupt!"));
return -1;
}
else
{
img_a->color_map_len = block_len;
img_a->color_map = g_malloc (img_a->color_map_len);
if (fread (img_a->color_map, block_len, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
else
{
psd_to_gimp_color_map (img_a->color_map);
img_a->color_map_entries = 256;
}
}
}
else if (img_a->color_mode == PSD_DUOTONE)
{
img_a->color_map_len = block_len;
img_a->color_map = g_malloc (img_a->color_map_len);
if (fread (img_a->color_map, block_len, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
}
/* Create color map for bitmap image */
if (img_a->color_mode == PSD_BITMAP)
{
img_a->color_map_len = 6;
img_a->color_map = g_malloc (img_a->color_map_len);
memcpy (img_a->color_map, cmap, img_a->color_map_len);
img_a->color_map_entries = 2;
}
IFDBG(2) g_debug ("Color map data length %d", img_a->color_map_len);
return 0;
}
static gint
read_image_resource_block (PSDimage *img_a,
FILE *f,
GError **error)
{
guint32 block_len;
guint32 block_end;
if (fread (&block_len, 4, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
img_a->image_res_len = GUINT32_FROM_BE (block_len);
IFDBG(1) g_debug ("Image resource block size = %d", (int)img_a->image_res_len);
img_a->image_res_start = ftell (f);
block_end = img_a->image_res_start + img_a->image_res_len;
if (fseek (f, block_end, SEEK_SET) < 0)
{
psd_set_error (feof (f), errno, error);
return -1;
}
return 0;
}
static PSDlayer **
read_layer_info (PSDimage *img_a,
FILE *f,
GError **error)
{
PSDlayer **lyr_a = NULL;
guint32 block_len;
guint32 block_rem;
gint32 read_len;
gint32 write_len;
gint lidx; /* Layer index */
gint cidx; /* Channel index */
/* 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->num_layers = GINT16_FROM_BE (img_a->num_layers);
IFDBG(2) g_debug ("Number of layers: %d", img_a->num_layers);
if (img_a->num_layers < 0)
{
img_a->transparency = TRUE;
img_a->num_layers = -img_a->num_layers;
}
if (! img_a->merged_image_only && img_a->num_layers)
{
/* Read layer records */
PSDlayerres res_a;
/* Create pointer array for the layer records */
lyr_a = g_new (PSDlayer *, img_a->num_layers);
for (lidx = 0; lidx < img_a->num_layers; ++lidx)
{
/* 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;
}
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);
lyr_a[lidx]->chn_info = g_new (ChannelLengthInfo, lyr_a[lidx]->num_channels);
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);
}
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]->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]->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)
{
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.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
|| 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)
{
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;
}
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;
}
IFDBG(2) g_debug ("Layer mask coords %d %d %d %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);
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)
{
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);
if (block_len > 0)
{
if (fseek (f, block_len, SEEK_CUR) < 0)
{
psd_set_error (feof (f), errno, error);
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);
/* Adjustment layer info */ /* FIXME */
while (block_rem > 7)
{
if (get_layer_resource_header (&res_a, f, error) < 0)
return NULL;
block_rem -= 12;
if (res_a.data_len % 2 != 0)
{
/* Warn the user about an invalid length value but
* try to recover graciously. See bug #771558.
*/
g_printerr ("psd-load: Layer extra data length should "
"be even, but it is %d.", 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,
_("The file is corrupt!"));
return NULL;
}
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;
}
}
}
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;
}
IFDBG(1) g_debug ("Layer image data block size %d",
img_a->layer_data_len);
}
return lyr_a;
}
static PSDlayer **
read_layer_block (PSDimage *img_a,
FILE *f,
GError **error)
{
PSDlayer **lyr_a = NULL;
guint32 block_len;
guint32 block_end;
if (fread (&block_len, 4, 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;
if (!img_a->mask_layer_len)
{
img_a->num_layers = 0;
return NULL;
}
else
{
guint32 total_len = img_a->mask_layer_len;
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);
total_len -= block_len;
}
else
{
img_a->num_layers = 0;
lyr_a = NULL;
}
/* 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)
{
psd_set_error (feof (f), errno, error);
return NULL;
}
}
return lyr_a;
}
static gint
read_merged_image_block (PSDimage *img_a,
FILE *f,
GError **error)
{
img_a->merged_image_start = ftell(f);
if (fseek (f, 0, SEEK_END) < 0)
{
psd_set_error (feof (f), errno, error);
return -1;
}
img_a->merged_image_len = ftell(f) - img_a->merged_image_start;
IFDBG(1) g_debug ("Merged image data block: Start: %d, len: %d",
img_a->merged_image_start, img_a->merged_image_len);
return 0;
}
static gint32
create_gimp_image (PSDimage *img_a,
const gchar *filename)
{
gint32 image_id = -1;
GimpPrecision precision;
switch (img_a->color_mode)
{
case PSD_MULTICHANNEL:
case PSD_GRAYSCALE:
case PSD_DUOTONE:
img_a->base_type = GIMP_GRAY;
break;
case PSD_BITMAP:
case PSD_INDEXED:
img_a->base_type = GIMP_INDEXED;
break;
case PSD_CMYK:
case PSD_RGB:
img_a->base_type = GIMP_RGB;
break;
default:
/* Color mode already validated - should not be here */
g_warning ("Invalid color mode");
return -1;
break;
}
switch (img_a->bps)
{
case 32:
precision = GIMP_PRECISION_U32_GAMMA;
break;
case 16:
precision = GIMP_PRECISION_U16_GAMMA;
break;
case 8:
case 1:
if (img_a->color_mode == PSD_CMYK)
precision = GIMP_PRECISION_FLOAT_GAMMA;
else
precision = GIMP_PRECISION_U8_GAMMA;
break;
default:
/* Precision not supported */
g_warning ("Invalid precision");
return -1;
break;
}
/* Create gimp image */
IFDBG(2) g_debug ("Create image");
image_id = gimp_image_new_with_precision (img_a->columns, img_a->rows,
img_a->base_type, precision);
gimp_image_set_filename (image_id, filename);
gimp_image_undo_disable (image_id);
return image_id;
}
static gint
add_color_map (gint32 image_id,
PSDimage *img_a)
{
GimpParasite *parasite;
if (img_a->color_map_len)
{
if (img_a->color_mode != PSD_DUOTONE)
{
gimp_image_set_colormap (image_id, img_a->color_map,
img_a->color_map_entries);
}
else
{
/* Add parasite for Duotone color data */
IFDBG(2) g_debug ("Add Duotone color data parasite");
parasite = gimp_parasite_new (PSD_PARASITE_DUOTONE_DATA, 0,
img_a->color_map_len, img_a->color_map);
gimp_image_attach_parasite (image_id, parasite);
gimp_parasite_free (parasite);
}
g_free (img_a->color_map);
}
return 0;
}
static gint
add_image_resources (gint32 image_id,
PSDimage *img_a,
FILE *f,
gboolean *resolution_loaded,
gboolean *profile_loaded,
GError **error)
{
PSDimageres res_a;
if (fseek (f, img_a->image_res_start, SEEK_SET) < 0)
{
psd_set_error (feof (f), errno, error);
return -1;
}
/* Initialise image resource variables */
img_a->no_icc = FALSE;
img_a->layer_state = 0;
img_a->alpha_names = NULL;
img_a->alpha_display_info = NULL;
img_a->alpha_display_count = 0;
img_a->alpha_id = NULL;
img_a->alpha_id_count = 0;
img_a->quick_mask_id = 0;
while (ftell (f) < img_a->image_res_start + img_a->image_res_len)
{
if (get_image_resource_header (&res_a, f, error) < 0)
return -1;
if (res_a.data_start + res_a.data_len >
img_a->image_res_start + img_a->image_res_len)
{
IFDBG(1) g_debug ("Unexpected end of image resource data");
return 0;
}
if (load_image_resource (&res_a, image_id, img_a, f,
resolution_loaded, profile_loaded,
error) < 0)
return -1;
}
return 0;
}
static guchar *
psd_convert_cmyk_to_srgb (PSDimage *img_a,
guchar *dst,
guchar *src,
gint width,
gint height,
gboolean alpha)
{
if (img_a->cmyk_profile)
{
if (alpha)
{
if (! img_a->cmyk_transform_alpha)
{
GimpColorProfile *srgb = gimp_color_profile_new_rgb_srgb ();
img_a->cmyk_transform_alpha = gimp_color_transform_new (img_a->cmyk_profile, babl_format ("cmykA u8"),
srgb, babl_format ("R'G'B'A float"),
0, 0);
g_object_unref (srgb);
}
gimp_color_transform_process_pixels (img_a->cmyk_transform_alpha,
babl_format ("cmykA u8"),
src,
babl_format ("R'G'B'A float"),
dst,
width * height);
}
else
{
if (! img_a->cmyk_transform)
{
GimpColorProfile *srgb = gimp_color_profile_new_rgb_srgb ();
img_a->cmyk_transform = gimp_color_transform_new (img_a->cmyk_profile, babl_format ("cmyk u8"),
srgb, babl_format ("R'G'B' float"),
0, 0);
g_object_unref (srgb);
}
gimp_color_transform_process_pixels (img_a->cmyk_transform_alpha,
babl_format ("cmyk u8"),
src,
babl_format ("R'G'B' float"),
dst,
width * height);
}
}
else
{
const Babl *fish;
if (alpha)
fish = babl_fish ("cmykA u8", "R'G'B'A float");
else
fish = babl_fish ("cmyk u8", "R'G'B' float");
babl_process (fish, src, dst, width * height);
}
return (guchar*) dst;
}
static gint
add_layers (gint32 image_id,
PSDimage *img_a,
PSDlayer **lyr_a,
FILE *f,
GError **error)
{
PSDchannel **lyr_chn;
GArray *parent_group_stack;
gint32 parent_group_id = -1;
guint16 alpha_chn;
guint16 user_mask_chn;
guint16 layer_channels;
guint16 channel_idx[MAX_CHANNELS];
guint16 *rle_pack_len;
guint16 bps;
gint32 l_x; /* Layer x */
gint32 l_y; /* Layer y */
gint32 l_w; /* Layer width */
gint32 l_h; /* Layer height */
gint32 lm_x; /* Layer mask x */
gint32 lm_y; /* Layer mask y */
gint32 lm_w; /* Layer mask width */
gint32 lm_h; /* Layer mask height */
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 */
gboolean alpha;
gboolean user_mask;
gboolean empty;
gboolean empty_mask;
GeglBuffer *buffer;
GimpImageType image_type;
LayerModeInfo mode_info;
IFDBG(2) g_debug ("Number of layers: %d", img_a->num_layers);
if (img_a->merged_image_only || img_a->num_layers == 0)
{
IFDBG(2) g_debug ("No layers to process");
return 0;
}
/* Layered image - Photoshop 3 style */
if (fseek (f, img_a->layer_data_start, SEEK_SET) < 0)
{
psd_set_error (feof (f), errno, error);
return -1;
}
/* set the root of the group hierarchy */
parent_group_stack = g_array_new (FALSE, FALSE, sizeof (gint32));
g_array_append_val (parent_group_stack, parent_group_id);
for (lidx = 0; lidx < img_a->num_layers; ++lidx)
{
IFDBG(2) g_debug ("Process Layer No %d.", lidx);
if (lyr_a[lidx]->drop)
{
IFDBG(2) g_debug ("Drop layer %d", lidx);
/* Step past layer data */
for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx)
{
if (fseek (f, lyr_a[lidx]->chn_info[cidx].data_len, SEEK_CUR) < 0)
{
psd_set_error (feof (f), errno, error);
return -1;
}
}
}
else
{
/* Empty layer */
if (lyr_a[lidx]->bottom - lyr_a[lidx]->top == 0
|| lyr_a[lidx]->right - lyr_a[lidx]->left == 0)
empty = TRUE;
else
empty = FALSE;
/* Empty mask */
if (lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top == 0
|| lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left == 0)
empty_mask = TRUE;
else
empty_mask = FALSE;
IFDBG(3) g_debug ("Empty mask %d, size %d %d", empty_mask,
lyr_a[lidx]->layer_mask.bottom - lyr_a[lidx]->layer_mask.top,
lyr_a[lidx]->layer_mask.right - lyr_a[lidx]->layer_mask.left);
/* Load layer channel data */
IFDBG(2) g_debug ("Number of channels: %d", lyr_a[lidx]->num_channels);
/* Create pointer array for the channel records */
lyr_chn = g_new (PSDchannel *, lyr_a[lidx]->num_channels);
for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx)
{
guint16 comp_mode = PSD_COMP_RAW;
/* Allocate channel record */
lyr_chn[cidx] = g_malloc (sizeof (PSDchannel) );
lyr_chn[cidx]->id = lyr_a[lidx]->chn_info[cidx].channel_id;
lyr_chn[cidx]->rows = lyr_a[lidx]->bottom - lyr_a[lidx]->top;
lyr_chn[cidx]->columns = lyr_a[lidx]->right - lyr_a[lidx]->left;
lyr_chn[cidx]->data = NULL;
if (lyr_chn[cidx]->id == PSD_CHANNEL_EXTRA_MASK)
{
if (fseek (f, lyr_a[lidx]->chn_info[cidx].data_len, SEEK_CUR) != 0)
{
psd_set_error (feof (f), errno, error);
return -1;
}
continue;
}
else if (lyr_chn[cidx]->id == PSD_CHANNEL_MASK)
{
/* Works around a bug in panotools psd files where the layer mask
size is given as 0 but data exists. Set mask size to layer size.
*/
if (empty_mask && lyr_a[lidx]->chn_info[cidx].data_len - 2 > 0)
{
empty_mask = FALSE;
if (lyr_a[lidx]->layer_mask.top == lyr_a[lidx]->layer_mask.bottom)
{
lyr_a[lidx]->layer_mask.top = lyr_a[lidx]->top;
lyr_a[lidx]->layer_mask.bottom = lyr_a[lidx]->bottom;
}
if (lyr_a[lidx]->layer_mask.right == lyr_a[lidx]->layer_mask.left)
{
lyr_a[lidx]->layer_mask.right = lyr_a[lidx]->right;
lyr_a[lidx]->layer_mask.left = lyr_a[lidx]->left;
}
}
lyr_chn[cidx]->rows = (lyr_a[lidx]->layer_mask.bottom -
lyr_a[lidx]->layer_mask.top);
lyr_chn[cidx]->columns = (lyr_a[lidx]->layer_mask.right -
lyr_a[lidx]->layer_mask.left);
}
IFDBG(3) g_debug ("Channel id %d, %dx%d",
lyr_chn[cidx]->id,
lyr_chn[cidx]->columns,
lyr_chn[cidx]->rows);
/* Only read channel data if there is any channel
* data. Note that the channel data can contain a
* compression method but no actual data.
*/
if (lyr_a[lidx]->chn_info[cidx].data_len >= COMP_MODE_SIZE)
{
if (fread (&comp_mode, COMP_MODE_SIZE, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
comp_mode = GUINT16_FROM_BE (comp_mode);
IFDBG(3) g_debug ("Compression mode: %d", comp_mode);
}
if (lyr_a[lidx]->chn_info[cidx].data_len > COMP_MODE_SIZE)
{
switch (comp_mode)
{
case PSD_COMP_RAW: /* Planar raw data */
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, 0,
error) < 1)
return -1;
break;
case PSD_COMP_RLE: /* Packbits */
IFDBG(3) g_debug ("RLE channel length %d, RLE length data: %d, "
"RLE data block: %d",
lyr_a[lidx]->chn_info[cidx].data_len - 2,
lyr_chn[cidx]->rows * 2,
(lyr_a[lidx]->chn_info[cidx].data_len - 2 -
lyr_chn[cidx]->rows * 2));
rle_pack_len = g_malloc (lyr_chn[cidx]->rows * 2);
for (rowi = 0; rowi < lyr_chn[cidx]->rows; ++rowi)
{
if (fread (&rle_pack_len[rowi], 2, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
g_free (rle_pack_len);
return -1;
}
rle_pack_len[rowi] = GUINT16_FROM_BE (rle_pack_len[rowi]);
}
IFDBG(3) g_debug ("RLE decode - data");
if (read_channel_data (lyr_chn[cidx], img_a->bps,
PSD_COMP_RLE, rle_pack_len, f, 0,
error) < 1)
return -1;
g_free (rle_pack_len);
break;
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);
return -1;
break;
}
}
}
/* Draw layer */
alpha = FALSE;
alpha_chn = -1;
user_mask = FALSE;
user_mask_chn = -1;
layer_channels = 0;
l_x = 0;
l_y = 0;
l_w = img_a->columns;
l_h = img_a->rows;
if (parent_group_stack->len > 0)
parent_group_id = g_array_index (parent_group_stack, gint32,
parent_group_stack->len - 1);
else
parent_group_id = -1; /* root */
IFDBG(3) g_debug ("Re-hash channel indices");
for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx)
{
if (lyr_chn[cidx]->id == PSD_CHANNEL_MASK)
{
user_mask = TRUE;
user_mask_chn = cidx;
}
else if (lyr_chn[cidx]->id == PSD_CHANNEL_ALPHA)
{
alpha = TRUE;
alpha_chn = cidx;
}
else if (lyr_chn[cidx]->data)
{
channel_idx[layer_channels] = cidx; /* Assumes in sane order */
layer_channels++; /* RGB, Lab, CMYK etc. */
}
}
if (alpha)
{
channel_idx[layer_channels] = alpha_chn;
layer_channels++;
}
/* Create the layer */
if (lyr_a[lidx]->group_type != 0)
{
if (lyr_a[lidx]->group_type == 3)
{
/* the marker layers are used to
* assemble the layer structure in a single pass
*/
IFDBG(2) g_debug ("Create placeholder group layer");
layer_id = gimp_layer_group_new (image_id);
/* add this group layer as the new parent */
g_array_append_val (parent_group_stack, layer_id);
}
else /* group-type == 1 || group_type == 2 */
{
if (parent_group_stack->len)
{
layer_id = g_array_index (parent_group_stack, gint32,
parent_group_stack->len - 1);
IFDBG(2) g_debug ("End group layer id %d.", layer_id);
/* since the layers are stored in reverse, the group
* layer start marker actually means we're done with
* that layer group
*/
g_array_remove_index (parent_group_stack,
parent_group_stack->len - 1);
gimp_drawable_offsets (layer_id, &l_x, &l_y);
l_w = gimp_drawable_width (layer_id);
l_h = gimp_drawable_height (layer_id);
}
else
{
IFDBG(1) g_debug ("WARNING: Unmatched group layer start marker.");
layer_id = -1;
}
}
}
else
{
if (empty)
{
IFDBG(2) g_debug ("Create blank layer");
}
else
{
IFDBG(2) g_debug ("Create normal layer");
l_x = lyr_a[lidx]->left;
l_y = lyr_a[lidx]->top;
l_w = lyr_a[lidx]->right - lyr_a[lidx]->left;
l_h = lyr_a[lidx]->bottom - lyr_a[lidx]->top;
}
image_type = get_gimp_image_type (img_a->base_type, TRUE);
IFDBG(3) g_debug ("Layer type %d", image_type);
layer_id = gimp_layer_new (image_id, lyr_a[lidx]->name,
l_w, l_h, image_type,
100, GIMP_LAYER_MODE_NORMAL);
}
if (layer_id != -1)
{
/* Set the layer name. Note that we do this even for group-end
* markers, to avoid having the default group name collide with
* subsequent layers; the real group name is set by the group
* start marker.
*/
gimp_item_set_name (layer_id, lyr_a[lidx]->name);
/* Set the layer properties (skip this for layer group end
* markers; we set their properties when processing the start
* marker.)
*/
if (lyr_a[lidx]->group_type != 3)
{
/* Mode */
psd_to_gimp_blend_mode (lyr_a[lidx]->blend_mode, &mode_info);
gimp_layer_set_mode (layer_id, mode_info.mode);
gimp_layer_set_blend_space (layer_id, mode_info.blend_space);
gimp_layer_set_composite_space (layer_id, mode_info.composite_space);
gimp_layer_set_composite_mode (layer_id, mode_info.composite_mode);
/* Opacity */
gimp_layer_set_opacity (layer_id,
lyr_a[lidx]->opacity * 100.0 / 255.0);
/* Flags */
gimp_layer_set_lock_alpha (layer_id, lyr_a[lidx]->layer_flags.trans_prot);
gimp_item_set_visible (layer_id, lyr_a[lidx]->layer_flags.visible);
#if 0
/* according to the spec, the 'irrelevant' flag indicates
* that the layer's "pixel data is irrelevant to the
* appearance of the document". what this seems to mean is
* not that the layer doesn't contribute to the image, but
* rather that its appearance can be entirely derived from
* sources other than the pixel data, such as vector data.
* in particular, this doesn't mean that the layer is
* invisible. since we only support raster layers atm, we can
* just ignore this flag.
*/
if (lyr_a[lidx]->layer_flags.irrelevant &&
lyr_a[lidx]->group_type == 0)
{
gimp_item_set_visible (layer_id, FALSE);
}
#endif
/* Position */
if (l_x != 0 || l_y != 0)
gimp_layer_set_offsets (layer_id, l_x, l_y);
/* Color tag */
gimp_item_set_color_tag (layer_id,
psd_to_gimp_layer_color_tag (lyr_a[lidx]->color_tag[0]));
/* Tattoo */
if (lyr_a[lidx]->id)
gimp_item_set_tattoo (layer_id, lyr_a[lidx]->id);
/* For layer groups, expand or collapse the group */
if (lyr_a[lidx]->group_type != 0)
{
gimp_item_set_expanded (layer_id,
lyr_a[lidx]->group_type == 1);
}
}
/* Remember the active layer ID */
if (lidx == img_a->layer_state)
{
active_layer_id = layer_id;
}
/* Set the layer data */
if (lyr_a[lidx]->group_type == 0)
{
IFDBG(3) g_debug ("Draw layer");
if (empty)
{
gimp_drawable_fill (layer_id, GIMP_FILL_TRANSPARENT);
}
else
{
GeglBufferIterator *iter;
bps = img_a->bps / 8;
if (bps == 0)
bps++;
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))
{
const GeglRectangle *roi = &iter->items[0].roi;
guint8 *dst0 = iter->items[0].data;
gint src_step = bps;
gint dst_step = bps * layer_channels;
if (img_a->color_mode == PSD_CMYK)
{
dst0 = gegl_scratch_alloc (layer_channels *
iter->length);
}
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;
}
}
}
}
if (img_a->color_mode == PSD_CMYK)
{
psd_convert_cmyk_to_srgb (
img_a,
iter->items[0].data, dst0,
roi->width, roi->height,
alpha);
gegl_scratch_free (dst0);
}
}
for (cidx = 0; cidx < layer_channels; ++cidx)
g_free (lyr_chn[channel_idx[cidx]]->data);
g_object_unref (buffer);
}
}
/* Layer mask */
if (user_mask && lyr_a[lidx]->group_type != 3)
{
if (empty_mask)
{
IFDBG(3) g_debug ("Create empty mask");
if (lyr_a[lidx]->layer_mask.def_color == 255)
mask_id = gimp_layer_create_mask (layer_id,
GIMP_ADD_MASK_WHITE);
else
mask_id = gimp_layer_create_mask (layer_id,
GIMP_ADD_MASK_BLACK);
gimp_layer_add_mask (layer_id, mask_id);
gimp_layer_set_apply_mask (layer_id,
! lyr_a[lidx]->layer_mask.mask_flags.disabled);
}
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);
IFDBG(3) g_debug ("Original Mask %d %d %d %d", lm_x, lm_y, lm_w, lm_h);
/* 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",
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,
GIMP_ADD_MASK_WHITE);
else
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,
&mask_rect,
0, get_mask_format (img_a),
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 (lyr_chn[user_mask_chn]->data);
}
}
/* Insert the layer */
if (lyr_a[lidx]->group_type == 0 || /* normal layer */
lyr_a[lidx]->group_type == 3 /* group layer end marker */)
{
gimp_image_insert_layer (image_id, layer_id, parent_group_id, 0);
}
}
for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx)
if (lyr_chn[cidx])
g_free (lyr_chn[cidx]);
g_free (lyr_chn);
}
g_free (lyr_a[lidx]->chn_info);
g_free (lyr_a[lidx]->name);
g_free (lyr_a[lidx]);
}
g_free (lyr_a);
g_array_free (parent_group_stack, FALSE);
/* Set the active layer */
if (active_layer_id >= 0)
gimp_image_set_active_layer (image_id, active_layer_id);
return 0;
}
static gint
add_merged_image (gint32 image_id,
PSDimage *img_a,
FILE *f,
GError **error)
{
PSDchannel chn_a[MAX_CHANNELS];
gchar *alpha_name;
guchar *pixels;
guint16 comp_mode;
guint16 base_channels;
guint16 extra_channels;
guint16 total_channels;
guint16 bps;
guint16 *rle_pack_len[MAX_CHANNELS];
guint32 alpha_id;
gint32 layer_size;
gint32 layer_id = -1;
gint32 channel_id = -1;
gint16 alpha_opacity;
gint cidx; /* Channel index */
gint rowi; /* Row index */
gint offset;
gint i;
gboolean alpha_visible;
GeglBuffer *buffer;
GimpImageType image_type;
GimpRGB alpha_rgb;
total_channels = img_a->channels;
extra_channels = 0;
bps = img_a->bps / 8;
if (bps == 0)
bps++;
if ((img_a->color_mode == PSD_BITMAP ||
img_a->color_mode == PSD_MULTICHANNEL ||
img_a->color_mode == PSD_GRAYSCALE ||
img_a->color_mode == PSD_DUOTONE ||
img_a->color_mode == PSD_INDEXED) &&
total_channels > 1)
{
extra_channels = total_channels - 1;
}
else if ((img_a->color_mode == PSD_RGB ||
img_a->color_mode == PSD_LAB) &&
total_channels > 3)
{
extra_channels = total_channels - 3;
}
else if ((img_a->color_mode == PSD_CMYK) &&
total_channels > 4)
{
extra_channels = total_channels - 4;
}
if (img_a->transparency && extra_channels > 0)
extra_channels--;
base_channels = total_channels - extra_channels;
if (img_a->merged_image_only)
{
extra_channels = 0;
total_channels = base_channels;
}
/* ----- Read merged image & extra channel pixel data ----- */
if (img_a->merged_image_only ||
img_a->num_layers == 0 ||
extra_channels > 0)
{
guint32 block_len;
guint32 block_start;
block_start = img_a->merged_image_start;
block_len = img_a->merged_image_len;
fseek (f, block_start, SEEK_SET);
if (fread (&comp_mode, COMP_MODE_SIZE, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
comp_mode = GUINT16_FROM_BE (comp_mode);
switch (comp_mode)
{
case PSD_COMP_RAW: /* Planar raw data */
IFDBG(3) g_debug ("Raw data length: %d", block_len);
for (cidx = 0; cidx < total_channels; ++cidx)
{
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, 0,
error) < 1)
return -1;
}
break;
case PSD_COMP_RLE: /* Packbits */
/* Image data is stored as packed scanlines in planar order
with all compressed length counters stored first */
IFDBG(3) g_debug ("RLE length data: %d, RLE data block: %d",
total_channels * img_a->rows * 2,
block_len - (total_channels * img_a->rows * 2));
for (cidx = 0; cidx < total_channels; ++cidx)
{
chn_a[cidx].columns = img_a->columns;
chn_a[cidx].rows = img_a->rows;
rle_pack_len[cidx] = g_malloc (img_a->rows * 2);
for (rowi = 0; rowi < img_a->rows; ++rowi)
{
if (fread (&rle_pack_len[cidx][rowi], 2, 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
rle_pack_len[cidx][rowi] = GUINT16_FROM_BE (rle_pack_len[cidx][rowi]);
}
}
/* Skip channel length data for unloaded channels */
if (fseek (f, (img_a->channels - total_channels) * img_a->rows * 2,
SEEK_CUR) < 0)
{
psd_set_error (feof (f), errno, error);
return -1;
}
IFDBG(3) g_debug ("RLE decode - data");
for (cidx = 0; cidx < total_channels; ++cidx)
{
if (read_channel_data (&chn_a[cidx], img_a->bps,
PSD_COMP_RLE, rle_pack_len[cidx], f, 0,
error) < 1)
return -1;
g_free (rle_pack_len[cidx]);
}
break;
case PSD_COMP_ZIP: /* ? */
case PSD_COMP_ZIP_PRED:
default:
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported compression mode: %d"), comp_mode);
return -1;
break;
}
}
/* ----- Draw merged image ----- */
if (img_a->merged_image_only ||
img_a->num_layers == 0) /* Merged image - Photoshop 2 style */
{
image_type = get_gimp_image_type (img_a->base_type, img_a->transparency);
layer_size = img_a->columns * img_a->rows;
pixels = g_malloc (layer_size * base_channels * bps);
for (cidx = 0; cidx < base_channels; ++cidx)
{
for (i = 0; i < layer_size; ++i)
{
memcpy (&pixels[((i * base_channels) + cidx) * bps],
&chn_a[cidx].data[i * bps], bps);
}
g_free (chn_a[cidx].data);
}
/* Add background layer */
IFDBG(2) g_debug ("Draw merged image");
layer_id = gimp_layer_new (image_id, _("Background"),
img_a->columns, img_a->rows,
image_type,
100,
gimp_image_get_default_new_layer_mode (image_id));
gimp_image_insert_layer (image_id, layer_id, -1, 0);
buffer = gimp_drawable_get_buffer (layer_id);
if (img_a->color_mode == PSD_CMYK)
img_a->color_mode = PSD_RGB;
gegl_buffer_set (buffer,
GEGL_RECTANGLE (0, 0,
gegl_buffer_get_width (buffer),
gegl_buffer_get_height (buffer)),
0, get_layer_format (img_a, (base_channels % 2) == 0),
pixels, GEGL_AUTO_ROWSTRIDE);
/* Merged image data is blended against white. Unblend it. */
if (img_a->transparency)
{
GeglBufferIterator *iter;
iter = gegl_buffer_iterator_new (buffer, NULL, 0,
babl_format ("R'G'B'A float"),
GEGL_ACCESS_READWRITE,
GEGL_ABYSS_NONE, 1);
while (gegl_buffer_iterator_next (iter))
{
gfloat *data = iter->items[0].data;
for (i = 0; i < iter->length; i++)
{
gint c;
if (data[3])
{
for (c = 0; c < 3; c++)
data[c] = (data[c] + data[3] - 1.0f) / data[3];
}
data += 4;
}
}
}
g_object_unref (buffer);
g_free (pixels);
}
else
{
/* Free merged image data for layered image */
if (extra_channels)
for (cidx = 0; cidx < base_channels; ++cidx)
g_free (chn_a[cidx].data);
}
if (img_a->transparency)
{
/* Free "Transparency" channel name */
if (img_a->alpha_names)
{
alpha_name = g_ptr_array_index (img_a->alpha_names, 0);
if (alpha_name)
g_free (alpha_name);
}
}
/* ----- Draw extra alpha channels ----- */
if (extra_channels /* Extra alpha channels */
&& image_id > -1)
{
IFDBG(2) g_debug ("Add extra channels");
pixels = g_malloc(0);
/* Get channel resource data */
if (img_a->transparency)
offset = 1;
else
offset = 0;
/* Draw channels */
IFDBG(2) g_debug ("Number of channels: %d", extra_channels);
for (i = 0; i < extra_channels; ++i)
{
/* Alpha channel name */
alpha_name = NULL;
alpha_visible = FALSE;
/* Quick mask channel*/
if (img_a->quick_mask_id)
if (i == img_a->quick_mask_id - base_channels + offset)
{
/* Free "Quick Mask" channel name */
alpha_name = g_ptr_array_index (img_a->alpha_names, i + offset);
if (alpha_name)
g_free (alpha_name);
alpha_name = g_strdup (GIMP_IMAGE_QUICK_MASK_NAME);
alpha_visible = TRUE;
}
if (! alpha_name && img_a->alpha_names)
if (offset < img_a->alpha_names->len
&& i + offset <= img_a->alpha_names->len)
alpha_name = g_ptr_array_index (img_a->alpha_names, i + offset);
if (! alpha_name)
alpha_name = g_strdup (_("Extra"));
if (offset < img_a->alpha_id_count &&
offset + i <= img_a->alpha_id_count)
alpha_id = img_a->alpha_id[i + offset];
else
alpha_id = 0;
if (offset < img_a->alpha_display_count &&
i + offset <= img_a->alpha_display_count)
{
alpha_rgb = img_a->alpha_display_info[i + offset]->gimp_color;
alpha_opacity = img_a->alpha_display_info[i + offset]->opacity;
}
else
{
gimp_rgba_set (&alpha_rgb, 1.0, 0.0, 0.0, 1.0);
alpha_opacity = 50;
}
cidx = base_channels + i;
pixels = g_realloc (pixels, chn_a[cidx].columns * chn_a[cidx].rows * bps);
memcpy (pixels, chn_a[cidx].data, chn_a[cidx].columns * chn_a[cidx].rows * bps);
channel_id = gimp_channel_new (image_id, alpha_name,
chn_a[cidx].columns, chn_a[cidx].rows,
alpha_opacity, &alpha_rgb);
gimp_image_insert_channel (image_id, channel_id, -1, i);
g_free (alpha_name);
buffer = gimp_drawable_get_buffer (channel_id);
if (alpha_id)
gimp_item_set_tattoo (channel_id, alpha_id);
gimp_item_set_visible (channel_id, alpha_visible);
gegl_buffer_set (buffer,
GEGL_RECTANGLE (0, 0,
gegl_buffer_get_width (buffer),
gegl_buffer_get_height (buffer)),
0, get_channel_format (img_a),
pixels, GEGL_AUTO_ROWSTRIDE);
g_object_unref (buffer);
g_free (chn_a[cidx].data);
}
g_free (pixels);
if (img_a->alpha_names)
g_ptr_array_free (img_a->alpha_names, TRUE);
if (img_a->alpha_id)
g_free (img_a->alpha_id);
if (img_a->alpha_display_info)
{
for (cidx = 0; cidx < img_a->alpha_display_count; ++cidx)
g_free (img_a->alpha_display_info[cidx]);
g_free (img_a->alpha_display_info);
}
}
/* FIXME gimp image tattoo state */
return 0;
}
/* Local utility functions */
static gchar *
get_psd_color_mode_name (PSDColorMode mode)
{
static gchar * const psd_color_mode_names[] =
{
"BITMAP",
"GRAYSCALE",
"INDEXED",
"RGB",
"CMYK",
"UNKNOWN (5)",
"UNKNOWN (6)",
"MULTICHANNEL",
"DUOTONE",
"LAB"
};
static gchar *err_name = NULL;
if (mode >= PSD_BITMAP && mode <= PSD_LAB)
return psd_color_mode_names[mode];
g_free (err_name);
err_name = g_strdup_printf ("UNKNOWN (%d)", mode);
return err_name;
}
static void
psd_to_gimp_color_map (guchar *map256)
{
guchar *tmpmap;
gint i;
tmpmap = g_malloc (3 * 256);
for (i = 0; i < 256; ++i)
{
tmpmap[i*3 ] = map256[i];
tmpmap[i*3+1] = map256[i+256];
tmpmap[i*3+2] = map256[i+512];
}
memcpy (map256, tmpmap, 3 * 256);
g_free (tmpmap);
}
static GimpImageType
get_gimp_image_type (GimpImageBaseType image_base_type,
gboolean alpha)
{
GimpImageType image_type;
switch (image_base_type)
{
case GIMP_GRAY:
image_type = (alpha) ? GIMP_GRAYA_IMAGE : GIMP_GRAY_IMAGE;
break;
case GIMP_INDEXED:
image_type = (alpha) ? GIMP_INDEXEDA_IMAGE : GIMP_INDEXED_IMAGE;
break;
case GIMP_RGB:
image_type = (alpha) ? GIMP_RGBA_IMAGE : GIMP_RGB_IMAGE;
break;
default:
image_type = -1;
break;
}
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,
guint32 comp_len,
GError **error)
{
gchar *raw_data;
gchar *src;
guint32 readline_len;
gint i, j;
if (bps == 1)
readline_len = ((channel->columns + 7) / 8);
else
readline_len = (channel->columns * bps / 8);
IFDBG(3) g_debug ("raw data size %d x %d = %d", readline_len,
channel->rows, readline_len * channel->rows);
/* sanity check, int overflow check (avoid divisions by zero) */
if ((channel->rows == 0) || (channel->columns == 0) ||
(channel->rows > G_MAXINT32 / channel->columns / MAX (bps / 8, 1)))
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Unsupported or invalid channel size"));
return -1;
}
raw_data = g_malloc (readline_len * channel->rows);
switch (compression)
{
case PSD_COMP_RAW:
if (fread (raw_data, readline_len, channel->rows, f) < 1)
{
psd_set_error (feof (f), errno, error);
return -1;
}
break;
case PSD_COMP_RLE:
for (i = 0; i < channel->rows; ++i)
{
src = gegl_scratch_alloc (rle_pack_len[i]);
/* FIXME check for over-run
if (ftell (f) + rle_pack_len[i] > block_end)
{
psd_set_error (TRUE, errno, error);
return -1;
}
*/
if (fread (src, rle_pack_len[i], 1, f) < 1)
{
psd_set_error (feof (f), errno, error);
gegl_scratch_free (src);
return -1;
}
/* FIXME check for errors returned from decode packbits */
decode_packbits (src, raw_data + i * readline_len,
rle_pack_len[i], readline_len);
gegl_scratch_free (src);
}
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
{
g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
_("Failed to decompress data"));
g_free (src);
return -1;
}
g_free (src);
break;
}
}
/* Convert channel data to GIMP format */
switch (bps)
{
case 32:
{
guint32 *data = (guint32*) raw_data;
channel->data = raw_data;
raw_data = NULL;
for (i = 0; i < channel->rows * channel->columns; ++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)
data[i * channel->columns + j] += data[i * channel->columns + j - 1];
}
break;
}
case 16:
{
guint16 *data = (guint16*) raw_data;
channel->data = raw_data;
raw_data = NULL;
for (i = 0; i < channel->rows * channel->columns; ++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)
data[i * channel->columns + j] += data[i * channel->columns + j - 1];
}
break;
}
case 8:
channel->data = raw_data;
raw_data = NULL;
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:
channel->data = (gchar *) g_malloc (channel->rows * channel->columns);
convert_1_bit (raw_data, channel->data, channel->rows, channel->columns);
break;
default:
return -1;
break;
}
g_free (raw_data);
return 1;
}
static void
convert_1_bit (const gchar *src,
gchar *dst,
guint32 rows,
guint32 columns)
{
/* Convert bits to bytes left to right by row.
Rows are padded out to a byte boundary.
*/
guint32 row_pos = 0;
gint i, j;
IFDBG(3) g_debug ("Start 1 bit conversion");
for (i = 0; i < rows * ((columns + 7) / 8); ++i)
{
guchar mask = 0x80;
for (j = 0; j < 8 && row_pos < columns; ++j)
{
*dst = (*src & mask) ? 0 : 1;
IFDBG(3) g_debug ("byte %d, bit %d, offset %d, src %d, dst %d",
i , j, row_pos, *src, *dst);
dst++;
mask >>= 1;
row_pos++;
}
if (row_pos >= columns)
row_pos = 0;
src++;
}
IFDBG(3) g_debug ("End 1 bit conversion");
}
static const Babl*
get_layer_format (PSDimage *img_a,
gboolean alpha)
{
const Babl *format = NULL;
switch (get_gimp_image_type (img_a->base_type, alpha))
{
case GIMP_GRAY_IMAGE:
switch (img_a->bps)
{
case 32:
format = babl_format ("Y' u32");
break;
case 16:
format = babl_format ("Y' u16");
break;
case 8:
case 1:
format = babl_format ("Y' u8");
break;
default:
return NULL;
break;
}
break;
case GIMP_GRAYA_IMAGE:
switch (img_a->bps)
{
case 32:
format = babl_format ("Y'A u32");
break;
case 16:
format = babl_format ("Y'A u16");
break;
case 8:
case 1:
format = babl_format ("Y'A u8");
break;
default:
return NULL;
break;
}
break;
case GIMP_RGB_IMAGE:
switch (img_a->bps)
{
case 32:
format = babl_format ("R'G'B' u32");
break;
case 16:
format = babl_format ("R'G'B' u16");
break;
case 8:
case 1:
format = babl_format (img_a->color_mode == PSD_CMYK ? "R'G'B' float" : "R'G'B' u8");
break;
default:
return NULL;
break;
}
break;
case GIMP_RGBA_IMAGE:
switch (img_a->bps)
{
case 32:
format = babl_format ("R'G'B'A u32");
break;
case 16:
format = babl_format ("R'G'B'A u16");
break;
case 8:
case 1:
format = babl_format (img_a->color_mode == PSD_CMYK ? "R'G'B'A float" : "R'G'B'A u8");
break;
default:
return NULL;
break;
}
break;
default:
return NULL;
break;
}
return format;
}
static const Babl*
get_channel_format (PSDimage *img_a)
{
const Babl *format = NULL;
switch (img_a->bps)
{
case 32:
format = babl_format ("Y u32");
break;
case 16:
format = babl_format ("Y u16");
break;
case 8:
case 1:
/* see gimp_image_get_channel_format() */
format = babl_format ("Y' u8");
break;
default:
break;
}
return format;
}
static const Babl*
get_mask_format (PSDimage *img_a)
{
const Babl *format = NULL;
switch (img_a->bps)
{
case 32:
format = babl_format ("Y u32");
break;
case 16:
format = babl_format ("Y u16");
break;
case 8:
case 1:
format = babl_format ("Y u8");
break;
default:
break;
}
return format;
}