mirror of https://github.com/GNOME/gimp.git
489 lines
18 KiB
C
489 lines
18 KiB
C
/* 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 <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
/* ----- Known Layer Resource Block Types -----
|
|
All layer resources not otherwise handled, including unknown types
|
|
are dropped with a warning.
|
|
|
|
* Adjustment layer IDs *
|
|
PSD_LADJ_LEVEL "levl" Drop Layer * Adjustment layer - levels (PS4) *
|
|
PSD_LADJ_CURVE "curv" Drop Layer * Adjustment layer - curves (PS4) *
|
|
PSD_LADJ_BRIGHTNESS "brit" Drop Layer * Adjustment layer - brightness contrast (PS4) *
|
|
PSD_LADJ_BALANCE "blnc" Drop Layer * Adjustment layer - color balance (PS4) *
|
|
PSD_LADJ_BLACK_WHITE "blwh" Drop Layer * Adjustment layer - black & white (PS10) *
|
|
PSD_LADJ_HUE "hue " Drop Layer * Adjustment layer - old hue saturation (PS4) *
|
|
PSD_LADJ_HUE2 "hue2" Drop Layer * Adjustment layer - hue saturation (PS5) *
|
|
PSD_LADJ_SELECTIVE "selc" Drop Layer * Adjustment layer - selective color (PS4) *
|
|
PSD_LADJ_MIXER "mixr" Drop Layer * Adjustment layer - channel mixer (PS9) *
|
|
PSD_LADJ_GRAD_MAP "grdm" Drop Layer * Adjustment layer - gradient map (PS9) *
|
|
PSD_LADJ_PHOTO_FILT "phfl" Drop Layer * Adjustment layer - photo filter (PS9) *
|
|
PSD_LADJ_EXPOSURE "expA" Drop Layer * Adjustment layer - exposure (PS10) *
|
|
PSD_LADJ_INVERT "nvrt" Drop Layer * Adjustment layer - invert (PS4) *
|
|
PSD_LADJ_THRESHOLD "thrs" Drop Layer * Adjustment layer - threshold (PS4) *
|
|
PSD_LADJ_POSTERIZE "post" Drop Layer * Adjustment layer - posterize (PS4) *
|
|
|
|
* Fill Layer IDs *
|
|
PSD_LFIL_SOLID "SoCo" - * Solid color sheet setting (PS6) *
|
|
PSD_LFIL_PATTERN "PtFl" - * Pattern fill setting (PS6) *
|
|
PSD_LFIL_GRADIENT "GdFl" - * Gradient fill setting (PS6) *
|
|
|
|
* Effects Layer IDs *
|
|
PSD_LFX_FX "lrFX" - * Effects layer info (PS5) *
|
|
PSD_LFX_FX2 "lfx2" - * Object based effects layer info (PS6) *
|
|
|
|
* Type Tool Layers *
|
|
PSD_LTYP_TYPE "tySh" - * Type tool layer (PS5) *
|
|
PSD_LTYP_TYPE2 "TySh" - * Type tool object setting (PS6) *
|
|
|
|
* Layer Properties *
|
|
PSD_LPRP_UNICODE "luni" Loaded * Unicode layer name (PS5) *
|
|
PSD_LPRP_SOURCE "lnsr" Loaded * Layer name source setting (PS6) *
|
|
PSD_LPRP_ID "lyid" Loaded * Layer ID (PS5) *
|
|
PSD_LPRP_BLEND_CLIP "clbl" - * Blend clipping elements (PS6) *
|
|
PSD_LPRP_BLEND_INT "infx" - * Blend interior elements (PS6) *
|
|
PSD_LPRP_KNOCKOUT "knko" - * Knockout setting (PS6) *
|
|
PSD_LPRP_PROTECT "lspf" - * Protected setting (PS6) *
|
|
PSD_LPRP_COLOR "lclr" - * Sheet color setting (PS6) *
|
|
PSD_LPRP_REF_POINT "fxrp" - * Reference point (PS6) *
|
|
|
|
* Vector mask *
|
|
PSD_LMSK_VMASK "vmsk" - * Vector mask setting (PS6) *
|
|
|
|
* Parasites *
|
|
PSD_LPAR_ANNOTATE "Anno" - * Annotation (PS6) *
|
|
|
|
* Other *
|
|
PSD_LOTH_PATTERN "Patt" - * Patterns (PS6) *
|
|
PSD_LOTH_GRADIENT "grdm" - * Gradient settings (PS6) *
|
|
PSD_LOTH_SECTION "lsct" Drop Layer * Section divider setting (PS6) (Layer Groups) *
|
|
PSD_LOTH_RESTRICT "brst" - * Channel blending restirction setting (PS6) *
|
|
PSD_LOTH_FOREIGN_FX "ffxi" - * Foreign effect ID (PS6) *
|
|
PSD_LOTH_PATT_DATA "shpa" - * Pattern data (PS6) *
|
|
PSD_LOTH_META_DATA "shmd" - * Meta data setting (PS6) *
|
|
PSD_LOTH_LAYER_DATA "layr" - * Layer data (PS6) *
|
|
|
|
* Effects layer resource IDs *
|
|
PSD_LFX_COMMON "cmnS" - * Effects layer - common state (PS5) *
|
|
PSD_LFX_DROP_SDW "dsdw" - * Effects layer - drop shadow (PS5) *
|
|
PSD_LFX_INNER_SDW "isdw" - * Effects layer - inner shadow (PS5) *
|
|
PSD_LFX_OUTER_GLW "oglw" - * Effects layer - outer glow (PS5) *
|
|
PSD_LFX_INNER_GLW "iglw" - * Effects layer - inner glow (PS5) *
|
|
PSD_LFX_BEVEL "bevl" - * Effects layer - bevel (PS5) *
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
|
|
#include <glib/gstdio.h>
|
|
#include <libgimp/gimp.h>
|
|
|
|
#include "psd.h"
|
|
#include "psd-util.h"
|
|
#include "psd-layer-res-load.h"
|
|
|
|
#include "libgimp/stdplugins-intl.h"
|
|
|
|
/* Local function prototypes */
|
|
static gint load_resource_unknown (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
static gint load_resource_ladj (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
static gint load_resource_lfil (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
static gint load_resource_lfx (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
static gint load_resource_ltyp (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
static gint load_resource_luni (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
static gint load_resource_lyid (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
static gint load_resource_lsct (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error);
|
|
|
|
|
|
/* Public Functions */
|
|
gint
|
|
get_layer_resource_header (PSDlayerres *res_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
if (fread (res_a->sig, 4, 1, f) < 1
|
|
|| fread (res_a->key, 4, 1, f) < 1
|
|
|| fread (&res_a->data_len, 4, 1, f) < 1)
|
|
{
|
|
psd_set_error (feof (f), errno, error);
|
|
return -1;
|
|
}
|
|
res_a->data_len = GUINT32_FROM_BE (res_a->data_len);
|
|
res_a->data_start = ftell (f);
|
|
|
|
IFDBG(2) g_debug ("Sig: %.4s, key: %.4s, start: %d, len: %d",
|
|
res_a->sig, res_a->key, res_a->data_start, res_a->data_len);
|
|
|
|
return 0;
|
|
}
|
|
|
|
gint
|
|
load_layer_resource (PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Set file position to start of layer resource data block */
|
|
if (fseek (f, res_a->data_start, SEEK_SET) < 0)
|
|
{
|
|
psd_set_error (feof (f), errno, error);
|
|
return -1;
|
|
}
|
|
|
|
/* Process layer resource blocks */
|
|
if (memcmp (res_a->sig, "8BIM", 4) != 0)
|
|
{
|
|
IFDBG(1) g_debug ("Unknown layer resource signature %.4s", res_a->sig);
|
|
}
|
|
else
|
|
{
|
|
if (memcmp (res_a->key, PSD_LADJ_LEVEL, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_CURVE, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_BRIGHTNESS, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_BALANCE, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_BLACK_WHITE, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_HUE, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_HUE2, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_SELECTIVE, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_MIXER, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_GRAD_MAP, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_PHOTO_FILT, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_EXPOSURE, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_THRESHOLD, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_INVERT, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LADJ_POSTERIZE, 4) == 0)
|
|
load_resource_ladj (res_a, lyr_a, f, error);
|
|
|
|
else if (memcmp (res_a->key, PSD_LFIL_SOLID, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LFIL_PATTERN, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LFIL_GRADIENT, 4) == 0)
|
|
load_resource_lfil (res_a, lyr_a, f, error);
|
|
|
|
else if (memcmp (res_a->key, PSD_LFX_FX, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LFX_FX2, 4) == 0)
|
|
load_resource_lfx (res_a, lyr_a, f, error);
|
|
|
|
else if (memcmp (res_a->key, PSD_LTYP_TYPE, 4) == 0
|
|
|| memcmp (res_a->key, PSD_LTYP_TYPE2, 4) == 0)
|
|
load_resource_ltyp (res_a, lyr_a, f, error);
|
|
|
|
else if (memcmp (res_a->key, PSD_LPRP_UNICODE, 4) == 0)
|
|
load_resource_luni (res_a, lyr_a, f, error);
|
|
|
|
else if (memcmp (res_a->key, PSD_LPRP_ID, 4) == 0)
|
|
load_resource_lyid (res_a, lyr_a, f, error);
|
|
|
|
else if (memcmp (res_a->key, PSD_LOTH_SECTION, 4) == 0)
|
|
load_resource_lsct (res_a, lyr_a, f, error);
|
|
|
|
else
|
|
load_resource_unknown (res_a, lyr_a, f, error);
|
|
}
|
|
|
|
/* Set file position to end of layer resource block */
|
|
if (fseek (f, res_a->data_start + res_a->data_len, SEEK_SET) < 0)
|
|
{
|
|
psd_set_error (feof (f), errno, error);
|
|
return -1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* Private Functions */
|
|
|
|
static gint
|
|
load_resource_unknown (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
IFDBG(2) g_debug ("Process unknown layer resource block: %.4s", res_a->key);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
load_resource_ladj (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Load adjustment layer */
|
|
static gboolean msg_flag = FALSE;
|
|
|
|
IFDBG(2) g_debug ("Process layer resource block %.4s: Adjustment layer", res_a->key);
|
|
lyr_a->drop = TRUE;
|
|
if (! msg_flag && CONVERSION_WARNINGS)
|
|
{
|
|
g_message ("Warning:\n"
|
|
"The image file contains adjustment layers. "
|
|
"These are not supported by the GIMP and will "
|
|
"be dropped.");
|
|
msg_flag = TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
load_resource_lfil (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Load fill layer */
|
|
static gboolean msg_flag = FALSE;
|
|
|
|
IFDBG(2) g_debug ("Process layer resource block %.4s: Fill layer", res_a->key);
|
|
if (! msg_flag && CONVERSION_WARNINGS)
|
|
{
|
|
g_message ("Warning:\n"
|
|
"The image file contains fill layers. "
|
|
"These are not supported by the GIMP and will "
|
|
"be rasterized.");
|
|
msg_flag = TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
load_resource_lfx (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Load layer effects */
|
|
static gboolean msg_flag = FALSE;
|
|
|
|
IFDBG(2) g_debug ("Process layer resource block %.4s: Layer effects", res_a->key);
|
|
if (! msg_flag && CONVERSION_WARNINGS)
|
|
{
|
|
g_message ("Warning:\n"
|
|
"The image file contains layer effects. "
|
|
"These are not supported by the GIMP and will "
|
|
"be dropped.");
|
|
msg_flag = TRUE;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
load_resource_ltyp (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Load type tool layer */
|
|
gint16 version;
|
|
gint16 text_desc_vers;
|
|
gint32 desc_version;
|
|
guint64 t_xx;
|
|
guint64 t_xy;
|
|
guint64 t_yx;
|
|
guint64 t_yy;
|
|
guint64 t_tx;
|
|
guint64 t_ty;
|
|
gdouble transform_xx;
|
|
gdouble transform_xy;
|
|
gdouble transform_yx;
|
|
gdouble transform_yy;
|
|
gdouble transform_tx;
|
|
gdouble transform_ty;
|
|
|
|
static gboolean msg_flag = FALSE;
|
|
|
|
IFDBG(2) g_debug ("Process layer resource block %.4s: Type tool layer", res_a->key);
|
|
if (! msg_flag && CONVERSION_WARNINGS)
|
|
{
|
|
g_message ("Warning:\n"
|
|
"The image file contains type tool layers. "
|
|
"These are not supported by the GIMP and will "
|
|
"be dropped.");
|
|
msg_flag = TRUE;
|
|
}
|
|
|
|
/* New style type tool layers (ps6) */
|
|
if (memcmp (res_a->key, PSD_LTYP_TYPE2, 4) == 0)
|
|
{
|
|
if (fread (&version, 2, 1, f) < 1
|
|
|| fread (&t_xx, 8, 1, f) < 1
|
|
|| fread (&t_xy, 8, 1, f) < 1
|
|
|| fread (&t_yx, 8, 1, f) < 1
|
|
|| fread (&t_yy, 8, 1, f) < 1
|
|
|| fread (&t_tx, 8, 1, f) < 1
|
|
|| fread (&t_ty, 8, 1, f) < 1
|
|
|| fread (&text_desc_vers, 2, 1, f) < 1
|
|
|| fread (&desc_version, 4, 1, f) < 1)
|
|
{
|
|
psd_set_error (feof (f), errno, error);
|
|
return -1;
|
|
}
|
|
|
|
version = GINT16_FROM_BE (version);
|
|
text_desc_vers = GINT16_FROM_BE (text_desc_vers);
|
|
desc_version = GINT32_FROM_BE (desc_version);
|
|
// t_xx = GUINT64_FROM_BE (t_xx);
|
|
// t_xy = GUINT64_FROM_BE (t_xy);
|
|
// t_yx = GUINT64_FROM_BE (t_yx);
|
|
// t_yy = GUINT64_FROM_BE (t_yy);
|
|
// t_tx = GUINT64_FROM_BE (t_tx);
|
|
// t_ty = GUINT64_FROM_BE (t_ty);
|
|
|
|
transform_xx = t_xx >> 11;
|
|
transform_xy = t_xy >> 11;
|
|
transform_yx = t_yx >> 11;
|
|
transform_yy = t_yy >> 11;
|
|
transform_tx = t_tx >> 11;
|
|
transform_ty = t_ty >> 11;
|
|
|
|
IFDBG(2) g_debug ("Version: %d, Text desc. vers.: %d, Desc. vers.: %d",
|
|
version, text_desc_vers, desc_version);
|
|
|
|
IFDBG(2) g_debug ("Transform\n\txx: %f\n\txy: %f\n\tyx: %f"
|
|
"\n\tyy: %f\n\ttx: %f\n\tty: %f",
|
|
transform_xx, transform_xy, transform_yx,
|
|
transform_yy, transform_tx, transform_ty);
|
|
|
|
// classID = fread_unicode_string (&read_len, &write_len, 4, f);
|
|
// IFDBG(2) g_debug ("Unicode name: %s", classID);
|
|
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
load_resource_luni (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Load layer name in unicode (length padded to multiple of 4 bytes) */
|
|
gint32 read_len;
|
|
gint32 write_len;
|
|
|
|
IFDBG(2) g_debug ("Process layer resource block luni: Unicode Name");
|
|
if (lyr_a->name)
|
|
g_free (lyr_a->name);
|
|
|
|
lyr_a->name = fread_unicode_string (&read_len, &write_len, 4, f, error);
|
|
if (*error)
|
|
return -1;
|
|
IFDBG(3) g_debug ("Unicode name: %s", lyr_a->name);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
load_resource_lyid (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Load layer id (tattoo) */
|
|
|
|
IFDBG(2) g_debug ("Process layer resource block lyid: Layer ID");
|
|
if (fread (&lyr_a->id, 4, 1, f) < 1)
|
|
{
|
|
psd_set_error (feof (f), errno, error);
|
|
return -1;
|
|
}
|
|
lyr_a->id = GUINT32_FROM_BE (lyr_a->id);
|
|
IFDBG(3) g_debug ("Layer id: %i", lyr_a->id);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static gint
|
|
load_resource_lsct (const PSDlayerres *res_a,
|
|
PSDlayer *lyr_a,
|
|
FILE *f,
|
|
GError **error)
|
|
{
|
|
/* Load adjustment layer */
|
|
static gboolean msg_flag = FALSE;
|
|
guint32 type;
|
|
|
|
IFDBG(2) g_debug ("Process layer resource block %.4s: Section divider", res_a->key);
|
|
if (fread (&type, 4, 1, f) < 1)
|
|
{
|
|
psd_set_error (feof (f), errno, error);
|
|
return -1;
|
|
}
|
|
type = GUINT32_FROM_BE (type);
|
|
IFDBG(3) g_debug ("Section divider type: %i", type);
|
|
|
|
if (type == 1 || /* Layer group start - open folder */
|
|
type == 2) /* Layer group start - closed folder */
|
|
{
|
|
lyr_a->drop = TRUE;
|
|
if (! msg_flag && CONVERSION_WARNINGS)
|
|
{
|
|
g_message ("Warning:\n"
|
|
"The image file contains layer groups. "
|
|
"These are not supported by the GIMP and will "
|
|
"be dropped.");
|
|
msg_flag = TRUE;
|
|
}
|
|
}
|
|
|
|
if (type == 3) /* End of layer group - hidden in UI */
|
|
lyr_a->drop = TRUE;
|
|
|
|
|
|
return 0;
|
|
}
|
|
|