PIKApp/plug-ins/file-psd/psd-image-res-load.c

1764 lines
60 KiB
C

/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
*
* PIKA 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 <https://www.gnu.org/licenses/>.
*/
/* ----- Known Image Resource Block Types -----
All image resources not otherwise handled, including unknown types
are added as image parasites.
The data is attached as-is from the file (i.e. in big endian order).
PSD_PS2_IMAGE_INFO = 1000, Dropped * 0x03e8 - Obsolete - ps 2.0 image info *
PSD_MAC_PRINT_INFO = 1001, PS Only * 0x03e9 - Optional - Mac print manager print info record *
PSD_PS2_COLOR_TAB = 1003, Dropped * 0x03eb - Obsolete - ps 2.0 indexed color table *
PSD_RESN_INFO = 1005, Loaded * 0x03ed - ResolutionInfo structure *
PSD_ALPHA_NAMES = 1006, Loaded * 0x03ee - Alpha channel names *
PSD_DISPLAY_INFO = 1007, Loaded * 0x03ef - DisplayInfo structure *
PSD_CAPTION = 1008, Loaded * 0x03f0 - Optional - Caption string *
PSD_BORDER_INFO = 1009, * 0x03f1 - Border info *
PSD_BACKGROUND_COL = 1010, * 0x03f2 - Background color *
PSD_PRINT_FLAGS = 1011, * 0x03f3 - Print flags *
PSD_GREY_HALFTONE = 1012, * 0x03f4 - Greyscale and multichannel halftoning info *
PSD_COLOR_HALFTONE = 1013, * 0x03f5 - Color halftoning info *
PSD_DUOTONE_HALFTONE = 1014, * 0x03f6 - Duotone halftoning info *
PSD_GREY_XFER = 1015, * 0x03f7 - Greyscale and multichannel transfer functions *
PSD_COLOR_XFER = 1016, * 0x03f8 - Color transfer functions *
PSD_DUOTONE_XFER = 1017, * 0x03f9 - Duotone transfer functions *
PSD_DUOTONE_INFO = 1018, * 0x03fa - Duotone image information *
PSD_EFFECTIVE_BW = 1019, * 0x03fb - Effective black & white values for dot range *
PSD_OBSOLETE_01 = 1020, Dropped * 0x03fc - Obsolete *
PSD_EPS_OPT = 1021, * 0x03fd - EPS options *
PSD_QUICK_MASK = 1022, Loaded * 0x03fe - Quick mask info *
PSD_OBSOLETE_02 = 1023, Dropped * 0x03ff - Obsolete *
PSD_LAYER_STATE = 1024, Loaded * 0x0400 - Layer state info *
PSD_WORKING_PATH = 1025, * 0x0401 - Working path (not saved) *
PSD_LAYER_GROUP = 1026, * 0x0402 - Layers group info *
PSD_OBSOLETE_03 = 1027, Dropped * 0x0403 - Obsolete *
PSD_IPTC_NAA_DATA = 1028, Loaded * 0x0404 - IPTC-NAA record (IMV4.pdf) *
PSD_IMAGE_MODE_RAW = 1029, * 0x0405 - Image mode for raw format files *
PSD_JPEG_QUAL = 1030, PS Only * 0x0406 - JPEG quality *
PSD_GRID_GUIDE = 1032, Loaded * 0x0408 - Grid & guide info *
PSD_THUMB_RES = 1033, Special * 0x0409 - Thumbnail resource *
PSD_COPYRIGHT_FLG = 1034, * 0x040a - Copyright flag *
PSD_URL = 1035, * 0x040b - URL string *
PSD_THUMB_RES2 = 1036, Special * 0x040c - Thumbnail resource *
PSD_GLOBAL_ANGLE = 1037, * 0x040d - Global angle *
PSD_COLOR_SAMPLER = 1038, * 0x040e - Color samplers resource *
PSD_ICC_PROFILE = 1039, Loaded * 0x040f - ICC Profile *
PSD_WATERMARK = 1040, * 0x0410 - Watermark *
PSD_ICC_UNTAGGED = 1041, * 0x0411 - Do not use ICC profile flag *
PSD_EFFECTS_VISIBLE = 1042, * 0x0412 - Show hide all effects layers *
PSD_SPOT_HALFTONE = 1043, * 0x0413 - Spot halftone *
PSD_DOC_IDS = 1044, * 0x0414 - Document specific IDs *
PSD_ALPHA_NAMES_UNI = 1045, Loaded * 0x0415 - Unicode alpha names *
PSD_IDX_COL_TAB_CNT = 1046, Loaded * 0x0416 - Indexed color table count *
PSD_IDX_TRANSPARENT = 1047, * 0x0417 - Index of transparent color (if any) *
PSD_GLOBAL_ALT = 1049, * 0x0419 - Global altitude *
PSD_SLICES = 1050, * 0x041a - Slices *
PSD_WORKFLOW_URL_UNI = 1051, * 0x041b - Workflow URL - Unicode string *
PSD_JUMP_TO_XPEP = 1052, * 0x041c - Jump to XPEP (?) *
PSD_ALPHA_ID = 1053, Loaded * 0x041d - Alpha IDs *
PSD_URL_LIST_UNI = 1054, * 0x041e - URL list - unicode *
PSD_VERSION_INFO = 1057, * 0x0421 - Version info *
PSD_EXIF_DATA = 1058, Loaded * 0x0422 - Exif data block 1 *
PSD_EXIF_DATA_3 = 1059 * 0X0423 - Exif data block 3 (?) *
PSD_XMP_DATA = 1060, Loaded * 0x0424 - XMP data block *
PSD_CAPTION_DIGEST = 1061, * 0x0425 - Caption digest *
PSD_PRINT_SCALE = 1062, * 0x0426 - Print scale *
PSD_PIXEL_AR = 1064, * 0x0428 - Pixel aspect ratio *
PSD_LAYER_COMPS = 1065, * 0x0429 - Layer comps *
PSD_ALT_DUOTONE_COLOR = 1066, * 0x042A - Alternative Duotone colors *
PSD_ALT_SPOT_COLOR = 1067, * 0x042B - Alternative Spot colors *
PSD_LAYER_SELECT_ID = 1069, * 0x042D - Layer selection ID *
PSD_HDR_TONING_INFO = 1070, * 0x042E - HDR toning information *
PSD_PRINT_INFO_SCALE = 1071, * 0x042F - Print scale *
PSD_LAYER_GROUP_E_ID = 1072, * 0x0430 - Layer group(s) enabled ID *
PSD_COLOR_SAMPLER_NEW = 1073, * 0x0431 - Color sampler resource for ps CS3 and higher PSD files *
PSD_MEASURE_SCALE = 1074, * 0x0432 - Measurement scale *
PSD_TIMELINE_INFO = 1075, * 0x0433 - Timeline information *
PSD_SHEET_DISCLOSE = 1076, * 0x0434 - Sheet discloser *
PSD_DISPLAY_INFO_NEW = 1077, Loaded * 0x0435 - DisplayInfo structure for ps CS3 and higher PSD files *
PSD_ONION_SKINS = 1078, * 0x0436 - Onion skins *
PSD_COUNT_INFO = 1080, * 0x0438 - Count information*
PSD_PRINT_INFO = 1082, * 0x043A - Print information added in ps CS5*
PSD_PRINT_STYLE = 1083, * 0x043B - Print style *
PSD_MAC_NSPRINTINFO = 1084, * 0x043C - Mac NSPrintInfo*
PSD_WIN_DEVMODE = 1085, * 0x043D - Windows DEVMODE *
PSD_AUTO_SAVE_PATH = 1086, * 0x043E - Auto save file path *
PSD_AUTO_SAVE_FORMAT = 1087, * 0x043F - Auto save format *
PSD_PATH_INFO_FIRST = 2000, Loaded * 0x07d0 - First path info block *
PSD_PATH_INFO_LAST = 2998, Loaded * 0x0bb6 - Last path info block *
PSD_CLIPPING_PATH = 2999, * 0x0bb7 - Name of clipping path *
PSD_PLUGIN_R_FIRST = 4000, * 0x0FA0 - First plugin resource *
PSD_PLUGIN_R_LAST = 4999, * 0x1387 - Last plugin resource *
PSD_IMAGEREADY_VARS = 7000, PS Only * 0x1B58 - Imageready variables *
PSD_IMAGEREADY_DATA = 7001, PS Only * 0x1B59 - Imageready data sets *
PSD_LIGHTROOM_WORK = 8000, PS Only * 0x1F40 - Lightroom workflow *
PSD_PRINT_FLAGS_2 = 10000 * 0x2710 - Print flags *
*/
#include "config.h"
#include <string.h>
#include <errno.h>
#include <glib/gstdio.h>
#include <libpika/pika.h>
#include <jpeglib.h>
#include <jerror.h>
#ifdef HAVE_IPTCDATA
#include <libiptcdata/iptc-data.h>
#endif /* HAVE_IPTCDATA */
#include "psd.h"
#include "psd-util.h"
#include "psd-image-res-load.h"
#include "libpika/stdplugins-intl.h"
#define EXIF_HEADER_SIZE 8
/* Local function prototypes */
static gint load_resource_unknown (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_ps_only (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_1005 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_1006 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_1007 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_1008 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_1022 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_1024 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_1028 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_1032 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
/* 1033 - Thumbnail needs special handling since it calls the jpeg library
* which needs a classic FILE. */
static gint load_resource_1033 (const PSDimageres *res_a,
PikaImage *image,
GFile *file,
GInputStream *input,
GError **error);
static gint load_resource_1039 (const PSDimageres *res_a,
PSDimage *img_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_1045 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_1046 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_1053 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_1058 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_1069 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_1077 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error);
static gint load_resource_2000 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
static gint load_resource_2999 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error);
/* Public Functions */
gint
get_image_resource_header (PSDimageres *res_a,
GInputStream *input,
GError **error)
{
gint32 read_len;
gint32 write_len;
gchar *name;
if (psd_read (input, &res_a->type, 4, error) < 4 ||
psd_read (input, &res_a->id, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
res_a->id = GUINT16_FROM_BE (res_a->id);
name = fread_pascal_string (&read_len, &write_len, 2, input, error);
if (*error)
return -1;
if (name != NULL)
g_strlcpy (res_a->name, name, write_len + 1);
else
res_a->name[0] = 0x0;
g_free (name);
if (psd_read (input, &res_a->data_len, 4, error) < 4)
{
psd_set_error (error);
return -1;
}
res_a->data_len = GUINT32_FROM_BE (res_a->data_len);
res_a->data_start = g_seekable_tell (G_SEEKABLE (input));
IFDBG(2) g_debug ("Type: %.4s, id: %d, start: %" G_GOFFSET_FORMAT ", len: %" G_GSIZE_FORMAT,
res_a->type, res_a->id, res_a->data_start, res_a->data_len);
return 0;
}
gint
load_image_resource (PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
gboolean *resolution_loaded,
gboolean *profile_loaded,
GError **error)
{
gint pad;
/* Set file position to start of image resource data block */
if (! psd_seek (input, res_a->data_start, G_SEEK_SET, error))
{
psd_set_error (error);
return -1;
}
/* Process image resource blocks */
if (memcmp (res_a->type, "8BIM", 4) != 0 &&
memcmp (res_a->type, "MeSa", 4) !=0)
{
IFDBG(1) g_debug ("Unknown image resource type signature %.4s",
res_a->type);
}
else
{
switch (res_a->id)
{
case PSD_PS2_IMAGE_INFO:
case PSD_PS2_COLOR_TAB:
case PSD_OBSOLETE_01:
case PSD_OBSOLETE_02:
case PSD_OBSOLETE_03:
/* Drop obsolete image resource blocks */
IFDBG(2) g_debug ("Obsolete image resource block: %d",
res_a->id);
break;
case PSD_THUMB_RES:
case PSD_THUMB_RES2:
/* Drop thumbnails from standard file load */
IFDBG(2) g_debug ("Thumbnail resource block: %d",
res_a->id);
break;
case PSD_MAC_PRINT_INFO:
case PSD_JPEG_QUAL:
/* Save photoshop resources with no meaning for PIKA
as image parasites */
load_resource_ps_only (res_a, image, input, error);
break;
case PSD_RESN_INFO:
if (! load_resource_1005 (res_a, image, input, error))
*resolution_loaded = TRUE;
break;
case PSD_ALPHA_NAMES:
load_resource_1006 (res_a, image, img_a, input, error);
break;
case PSD_DISPLAY_INFO:
load_resource_1007 (res_a, image, img_a, input, error);
break;
case PSD_CAPTION:
load_resource_1008 (res_a, image, input, error);
break;
case PSD_QUICK_MASK:
if (! img_a->merged_image_only)
load_resource_1022 (res_a, image, img_a, input, error);
break;
case PSD_LAYER_STATE:
if (! img_a->merged_image_only)
load_resource_1024 (res_a, image, img_a, input, error);
break;
case PSD_WORKING_PATH:
if (! img_a->merged_image_only)
load_resource_2000 (res_a, image, input, error);
break;
case PSD_IPTC_NAA_DATA:
load_resource_1028 (res_a, image, input, error);
break;
case PSD_GRID_GUIDE:
if (! img_a->merged_image_only)
load_resource_1032 (res_a, image, input, error);
break;
case PSD_ICC_PROFILE:
if (! load_resource_1039 (res_a, img_a, image, input, error))
*profile_loaded = TRUE;
break;
case PSD_ALPHA_NAMES_UNI:
load_resource_1045 (res_a, image, img_a, input, error);
break;
case PSD_IDX_COL_TAB_CNT:
load_resource_1046 (res_a, image, input, error);
break;
case PSD_ALPHA_ID:
if (! img_a->merged_image_only)
load_resource_1053 (res_a, image, img_a, input, error);
break;
case PSD_EXIF_DATA:
load_resource_1058 (res_a, image, input, error);
break;
case PSD_LAYER_SELECT_ID:
if (! img_a->merged_image_only)
load_resource_1069 (res_a, image, img_a, input, error);
break;
case PSD_XMP_DATA:
break;
case PSD_DISPLAY_INFO_NEW:
load_resource_1077 (res_a, image, img_a, input, error);
break;
case PSD_CLIPPING_PATH:
load_resource_2999 (res_a, image, input, error);
break;
case PSD_LAYER_COMPS:
img_a->unsupported_features->layer_comp = TRUE;
img_a->unsupported_features->show_gui = TRUE;
load_resource_unknown (res_a, image, input, error);
break;
default:
if (res_a->id >= 2000 &&
res_a->id < 2999)
load_resource_2000 (res_a, image, input, error);
else
load_resource_unknown (res_a, image, input, error);
}
}
/* Image blocks are null padded to even length */
if (res_a->data_len % 2 == 0)
pad = 0;
else
pad = 1;
/* Set file position to end of image resource block */
if (! psd_seek (input, res_a->data_start + res_a->data_len + pad, G_SEEK_SET, error))
{
psd_set_error (error);
return -1;
}
return 0;
}
gint
load_thumbnail_resource (PSDimageres *res_a,
PikaImage *image,
GFile *file,
GInputStream *input,
GError **error)
{
gint rtn = 0;
gint pad;
/* Set file position to start of image resource data block */
if (! psd_seek (input, res_a->data_start, G_SEEK_SET, error))
{
psd_set_error (error);
return -1;
}
/* Process image resource blocks */
if (res_a->id == PSD_THUMB_RES
|| res_a->id == PSD_THUMB_RES2)
{
/* Load thumbnails from standard file load */
load_resource_1033 (res_a, image, file, input, error);
rtn = 1;
}
/* Image blocks are null padded to even length */
if (res_a->data_len % 2 == 0)
pad = 0;
else
pad = 1;
/* Set file position to end of image resource block */
if (psd_seek (input, res_a->data_start + res_a->data_len + pad, G_SEEK_SET, error))
{
psd_set_error (error);
return -1;
}
return rtn;
}
/* Private Functions */
static gint
load_resource_unknown (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Unknown image resources attached as parasites to re-save later */
PikaParasite *parasite;
gchar *data;
gchar *name;
IFDBG(2) g_debug ("Process unknown image resource block: %d", res_a->id);
data = g_malloc (res_a->data_len);
if (res_a->data_len > 0 && psd_read (input, data, res_a->data_len, error) < res_a->data_len)
{
psd_set_error (error);
g_free (data);
return -1;
}
name = g_strdup_printf ("psd-image-resource-%.4s-%.4x",
res_a->type, res_a->id);
IFDBG(2) g_debug ("Parasite name: %s", name);
parasite = pika_parasite_new (name, 0, res_a->data_len, data);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
g_free (data);
g_free (name);
return 0;
}
static gint
load_resource_ps_only (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Save photoshop resources with no meaning for PIKA as image parasites
to re-save later */
PikaParasite *parasite;
gchar *data;
gchar *name;
IFDBG(3) g_debug ("Process image resource block: %d", res_a->id);
data = g_malloc (res_a->data_len);
if (psd_read (input, data, res_a->data_len, error) < res_a->data_len)
{
psd_set_error (error);
g_free (data);
return -1;
}
name = g_strdup_printf ("psd-image-resource-%.4s-%.4x",
res_a->type, res_a->id);
IFDBG(2) g_debug ("Parasite name: %s", name);
parasite = pika_parasite_new (name, 0, res_a->data_len, data);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
g_free (data);
g_free (name);
return 0;
}
static gint
load_resource_1005 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Load image resolution and unit of measure */
/* FIXME width unit and height unit unused at present */
ResolutionInfo res_info;
PikaUnit image_unit;
IFDBG(2) g_debug ("Process image resource block 1005: Resolution Info");
if (psd_read (input, &res_info.hRes, 4, error) < 4 ||
psd_read (input, &res_info.hResUnit, 2, error) < 2 ||
psd_read (input, &res_info.widthUnit, 2, error) < 2 ||
psd_read (input, &res_info.vRes, 4, error) < 4 ||
psd_read (input, &res_info.vResUnit, 2, error) < 2 ||
psd_read (input, &res_info.heightUnit, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
res_info.hRes = GINT32_FROM_BE (res_info.hRes);
res_info.hResUnit = GINT16_FROM_BE (res_info.hResUnit);
res_info.widthUnit = GINT16_FROM_BE (res_info.widthUnit);
res_info.vRes = GINT32_FROM_BE (res_info.vRes);
res_info.vResUnit = GINT16_FROM_BE (res_info.vResUnit);
res_info.heightUnit = GINT16_FROM_BE (res_info.heightUnit);
IFDBG(3) g_debug ("Resolution: %d, %d, %d, %d, %d, %d",
res_info.hRes,
res_info.hResUnit,
res_info.widthUnit,
res_info.vRes,
res_info.vResUnit,
res_info.heightUnit);
/* Resolution always recorded as pixels / inch in a fixed point implied
decimal int32 with 16 bits before point and 16 after (i.e. cast as
double and divide resolution by 2^16 */
pika_image_set_resolution (image,
res_info.hRes / 65536.0, res_info.vRes / 65536.0);
/* PIKA only has one display unit so use ps horizontal resolution unit */
switch (res_info.hResUnit)
{
case PSD_RES_INCH:
image_unit = PIKA_UNIT_INCH;
break;
case PSD_RES_CM:
image_unit = PIKA_UNIT_MM;
break;
default:
image_unit = PIKA_UNIT_INCH;
}
pika_image_set_unit (image, image_unit);
return 0;
}
static gint
load_resource_1006 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
/* Load alpha channel names stored as a series of pascal strings
unpadded between strings */
gchar *str;
gint32 block_rem;
gint32 read_len;
gint32 write_len;
IFDBG(2) g_debug ("Process image resource block 1006: Alpha Channel Names");
if (img_a->alpha_names)
{
IFDBG(3) g_debug ("Alpha names loaded from unicode resource block");
return 0;
}
img_a->alpha_names = g_ptr_array_new ();
block_rem = res_a->data_len;
while (block_rem > 1)
{
str = fread_pascal_string (&read_len, &write_len, 1, input, error);
if (*error)
return -1;
IFDBG(3) g_debug ("String: %s, %d, %d", str, read_len, write_len);
if (write_len >= 0)
{
g_ptr_array_add (img_a->alpha_names, (gpointer) str);
}
block_rem -= read_len;
}
return 0;
}
static gint
load_resource_1007 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
/* Load alpha channel display info */
DisplayInfo dsp_info;
CMColor ps_color;
PikaRGB pika_rgb;
PikaHSV pika_hsv;
PikaCMYK pika_cmyk;
gint16 tot_rec;
gint cidx;
IFDBG(2) g_debug ("Process image resource block 1007: Display Info");
tot_rec = res_a->data_len / 14;
if (tot_rec == 0)
return 0;
img_a->alpha_display_info = g_new (PSDchanneldata *, tot_rec);
img_a->alpha_display_count = tot_rec;
for (cidx = 0; cidx < tot_rec; ++cidx)
{
if (psd_read (input, &dsp_info.colorSpace, 2, error) < 2 ||
psd_read (input, &dsp_info.color, 8, error) < 8 ||
psd_read (input, &dsp_info.opacity, 2, error) < 2 ||
psd_read (input, &dsp_info.kind, 1, error) < 1 ||
psd_read (input, &dsp_info.padding, 1, error) < 1)
{
psd_set_error (error);
return -1;
}
dsp_info.colorSpace = GINT16_FROM_BE (dsp_info.colorSpace);
ps_color.cmyk.cyan = GUINT16_FROM_BE (dsp_info.color[0]);
ps_color.cmyk.magenta = GUINT16_FROM_BE (dsp_info.color[1]);
ps_color.cmyk.yellow = GUINT16_FROM_BE (dsp_info.color[2]);
ps_color.cmyk.black = GUINT16_FROM_BE (dsp_info.color[3]);
dsp_info.opacity = GINT16_FROM_BE (dsp_info.opacity);
switch (dsp_info.colorSpace)
{
case PSD_CS_RGB:
pika_rgb_set (&pika_rgb, ps_color.rgb.red / 65535.0,
ps_color.rgb.green / 65535.0,
ps_color.rgb.blue / 65535.0);
break;
case PSD_CS_HSB:
pika_hsv_set (&pika_hsv, ps_color.hsv.hue / 65535.0,
ps_color.hsv.saturation / 65535.0,
ps_color.hsv.value / 65535.0);
pika_hsv_to_rgb (&pika_hsv, &pika_rgb);
break;
case PSD_CS_CMYK:
pika_cmyk_set (&pika_cmyk, 1.0 - ps_color.cmyk.cyan / 65535.0,
1.0 - ps_color.cmyk.magenta / 65535.0,
1.0 - ps_color.cmyk.yellow / 65535.0,
1.0 - ps_color.cmyk.black / 65535.0);
pika_cmyk_to_rgb (&pika_cmyk, &pika_rgb);
break;
case PSD_CS_GRAYSCALE:
pika_rgb_set (&pika_rgb, ps_color.gray.gray / 10000.0,
ps_color.gray.gray / 10000.0,
ps_color.gray.gray / 10000.0);
break;
case PSD_CS_FOCOLTONE:
case PSD_CS_TRUMATCH:
case PSD_CS_HKS:
case PSD_CS_LAB:
case PSD_CS_PANTONE:
case PSD_CS_TOYO:
case PSD_CS_DIC:
case PSD_CS_ANPA:
default:
if (CONVERSION_WARNINGS)
g_message ("Unsupported color space: %d",
dsp_info.colorSpace);
pika_rgb_set (&pika_rgb, 1.0, 0.0, 0.0);
}
pika_rgb_set_alpha (&pika_rgb, 1.0);
IFDBG(2) g_debug ("PS cSpace: %d, col: %d %d %d %d, opacity: %d, kind: %d",
dsp_info.colorSpace, ps_color.cmyk.cyan, ps_color.cmyk.magenta,
ps_color.cmyk.yellow, ps_color.cmyk.black, dsp_info.opacity,
dsp_info.kind);
IFDBG(2) g_debug ("cSpace: %d, col: %g %g %g, opacity: %d, kind: %d",
dsp_info.colorSpace, pika_rgb.r * 255 , pika_rgb.g * 255,
pika_rgb.b * 255, dsp_info.opacity, dsp_info.kind);
img_a->alpha_display_info[cidx] = g_malloc0 (sizeof (PSDchanneldata));
img_a->alpha_display_info[cidx]->pika_color = pika_rgb;
img_a->alpha_display_info[cidx]->opacity = dsp_info.opacity;
img_a->alpha_display_info[cidx]->ps_kind = dsp_info.kind;
img_a->alpha_display_info[cidx]->ps_cspace = dsp_info.colorSpace;
img_a->alpha_display_info[cidx]->ps_color = ps_color;
}
return 0;
}
static gint
load_resource_1008 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Load image caption */
PikaParasite *parasite;
gchar *caption;
gint32 read_len;
gint32 write_len;
IFDBG(2) g_debug ("Process image resource block: 1008: Caption");
caption = fread_pascal_string (&read_len, &write_len, 1, input, error);
if (*error)
return -1;
IFDBG(3) g_debug ("Caption: %s", caption);
parasite = pika_parasite_new (PIKA_PARASITE_COMMENT, PIKA_PARASITE_PERSISTENT,
write_len, caption);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
g_free (caption);
return 0;
}
static gint
load_resource_1022 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
/* Load quick mask info */
gboolean quick_mask_empty; /* Quick mask initially empty */
IFDBG(2) g_debug ("Process image resource block: 1022: Quick Mask");
if (psd_read (input, &img_a->quick_mask_id, 2, error) < 2 ||
psd_read (input, &quick_mask_empty, 1, error) < 1)
{
psd_set_error (error);
return -1;
}
img_a->quick_mask_id = GUINT16_FROM_BE (img_a->quick_mask_id);
IFDBG(3) g_debug ("Quick mask channel: %d, empty: %d",
img_a->quick_mask_id,
quick_mask_empty);
return 0;
}
static gint
load_resource_1024 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
/* Load image layer state - current active layer counting from bottom up */
IFDBG(2) g_debug ("Process image resource block: 1024: Layer State");
if (psd_read (input, &img_a->layer_state, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
img_a->layer_state = GUINT16_FROM_BE (img_a->layer_state);
return 0;
}
static gint
load_resource_1028 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Load IPTC data block */
#ifdef HAVE_IPTCDATA
IptcData *iptc_data;
guchar *iptc_buf;
guint iptc_buf_len;
#else
gchar *name;
#endif /* HAVE_IPTCDATA */
PikaParasite *parasite;
gchar *res_data;
IFDBG(2) g_debug ("Process image resource block: 1028: IPTC data");
res_data = g_malloc (res_a->data_len);
if (psd_read (input, res_data, res_a->data_len, error) < res_a->data_len)
{
psd_set_error (error);
g_free (res_data);
return -1;
}
#ifdef HAVE_IPTCDATA
/* Load IPTC data structure */
iptc_data = iptc_data_new_from_data (res_data, res_a->data_len);
IFDBG (3) iptc_data_dump (iptc_data, 0);
/* Store resource data as a PIKA IPTC parasite */
IFDBG (2) g_debug ("Processing IPTC data as PIKA IPTC parasite");
/* Serialize IPTC data */
iptc_data_save (iptc_data, &iptc_buf, &iptc_buf_len);
if (iptc_buf_len > 0)
{
parasite = pika_parasite_new (PIKA_PARASITE_IPTC,
PIKA_PARASITE_PERSISTENT,
iptc_buf_len, iptc_buf);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
}
iptc_data_unref (iptc_data);
g_free (iptc_buf);
#else
/* Store resource data as a standard psd parasite */
IFDBG (2) g_debug ("Processing IPTC data as psd parasite");
name = g_strdup_printf ("psd-image-resource-%.4s-%.4x",
res_a->type, res_a->id);
IFDBG(3) g_debug ("Parasite name: %s", name);
parasite = pika_parasite_new (name, 0, res_a->data_len, res_data);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
g_free (name);
#endif /* HAVE_IPTCDATA */
g_free (res_data);
return 0;
}
static gint
load_resource_1032 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Load grid and guides */
/* Grid info is not used (CS2 or earlier) */
GuideHeader hdr;
GuideResource guide;
gint i;
IFDBG(2) g_debug ("Process image resource block 1032: Grid and Guide Info");
if (psd_read (input, &hdr.fVersion, 4, error) < 4 ||
psd_read (input, &hdr.fGridCycleV, 4, error) < 4 ||
psd_read (input, &hdr.fGridCycleH, 4, error) < 4 ||
psd_read (input, &hdr.fGuideCount, 4, error) < 4)
{
psd_set_error (error);
return -1;
}
hdr.fVersion = GUINT32_FROM_BE (hdr.fVersion);
hdr.fGridCycleV = GUINT32_FROM_BE (hdr.fGridCycleV);
hdr.fGridCycleH = GUINT32_FROM_BE (hdr.fGridCycleH);
hdr.fGuideCount = GUINT32_FROM_BE (hdr.fGuideCount);
IFDBG(3) g_debug ("Grids & Guides: %d, %d, %d, %d",
hdr.fVersion,
hdr.fGridCycleV,
hdr.fGridCycleH,
hdr.fGuideCount);
for (i = 0; i < hdr.fGuideCount; ++i)
{
if (psd_read (input, &guide.fLocation, 4, error) < 4 ||
psd_read (input, &guide.fDirection, 1, error) < 1)
{
psd_set_error (error);
return -1;
}
guide.fLocation = GUINT32_FROM_BE (guide.fLocation);
guide.fLocation /= 32;
IFDBG(3) g_debug ("Guide: %d px, %d",
guide.fLocation,
guide.fDirection);
if (guide.fDirection == PSD_VERTICAL)
pika_image_add_vguide (image, guide.fLocation);
else
pika_image_add_hguide (image, guide.fLocation);
}
return 0;
}
static gint
load_resource_1033 (const PSDimageres *res_a,
PikaImage *image,
GFile *file,
GInputStream *input,
GError **error)
{
/* Load thumbnail image */
struct jpeg_decompress_struct cinfo;
struct jpeg_error_mgr jerr;
FILE *f;
ThumbnailInfo thumb_info;
GeglBuffer *buffer;
const Babl *format;
PikaLayer *layer;
guchar *buf;
guchar *rgb_buf;
guchar **rowbuf;
gint i;
IFDBG(2) g_debug ("Process image resource block %d: Thumbnail Image", res_a->id);
/* Read thumbnail resource header info */
if (psd_read (input, &thumb_info.format, 4, error) < 4 ||
psd_read (input, &thumb_info.width, 4, error) < 4 ||
psd_read (input, &thumb_info.height, 4, error) < 4 ||
psd_read (input, &thumb_info.widthbytes, 4, error) < 4 ||
psd_read (input, &thumb_info.size, 4, error) < 4 ||
psd_read (input, &thumb_info.compressedsize, 4, error) < 4 ||
psd_read (input, &thumb_info.bitspixel, 2, error) < 2 ||
psd_read (input, &thumb_info.planes, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
thumb_info.format = GINT32_FROM_BE (thumb_info.format);
thumb_info.width = GINT32_FROM_BE (thumb_info.width);
thumb_info.height = GINT32_FROM_BE (thumb_info.height);
thumb_info.widthbytes = GINT32_FROM_BE (thumb_info.widthbytes);
thumb_info.size = GINT32_FROM_BE (thumb_info.size);
thumb_info.compressedsize = GINT32_FROM_BE (thumb_info.compressedsize);
thumb_info.bitspixel = GINT16_FROM_BE (thumb_info.bitspixel);
thumb_info.planes = GINT16_FROM_BE (thumb_info.planes);
IFDBG(2) g_debug ("\nThumbnail:\n"
"\tFormat: %d\n"
"\tDimensions: %d x %d\n",
thumb_info.format,
thumb_info.width,
thumb_info.height);
if (thumb_info.format != 1)
{
IFDBG(1) g_debug ("Unknown thumbnail format %d", thumb_info.format);
return -1;
}
/* Load Jpeg RGB thumbnail info */
/* Open input also as a FILE. */
f = g_fopen (g_file_peek_path (file), "rb");
if (! f)
return -1;
/* Now seek to the same position as we have in input. */
fseek(f, g_seekable_tell (G_SEEKABLE (input)), SEEK_SET);
/* Step 1: Allocate and initialize JPEG decompression object */
cinfo.err = jpeg_std_error (&jerr);
jpeg_create_decompress (&cinfo);
/* Step 2: specify data source (eg, a file) */
jpeg_stdio_src(&cinfo, f);
/* Step 3: read file parameters with jpeg_read_header() */
jpeg_read_header (&cinfo, TRUE);
/* Step 4: set parameters for decompression */
/* Step 5: Start decompressor */
jpeg_start_decompress (&cinfo);
/* temporary buffers */
buf = g_new (guchar, cinfo.output_height * cinfo.output_width
* cinfo.output_components);
if (res_a->id == PSD_THUMB_RES)
rgb_buf = g_new (guchar, cinfo.output_height * cinfo.output_width
* cinfo.output_components);
else
rgb_buf = NULL;
rowbuf = g_new (guchar *, cinfo.output_height);
for (i = 0; i < cinfo.output_height; ++i)
rowbuf[i] = buf + cinfo.output_width * cinfo.output_components * i;
/* Create image layer */
pika_image_resize (image, cinfo.output_width, cinfo.output_height, 0, 0);
layer = pika_layer_new (image, _("Background"),
cinfo.output_width,
cinfo.output_height,
PIKA_RGB_IMAGE,
100,
pika_image_get_default_new_layer_mode (image));
buffer = pika_drawable_get_buffer (PIKA_DRAWABLE (layer));
format = babl_format ("R'G'B' u8");
/* Step 6: while (scan lines remain to be read) */
/* jpeg_read_scanlines(...); */
while (cinfo.output_scanline < cinfo.output_height)
{
jpeg_read_scanlines (&cinfo,
(JSAMPARRAY) &rowbuf[cinfo.output_scanline], 1);
}
if (res_a->id == PSD_THUMB_RES) /* Order is BGR for resource 1033 */
{
guchar *dst = rgb_buf;
guchar *src = buf;
for (i = 0; i < gegl_buffer_get_width (buffer) * gegl_buffer_get_height (buffer); ++i)
{
guchar r, g, b;
r = *(src++);
g = *(src++);
b = *(src++);
*(dst++) = b;
*(dst++) = g;
*(dst++) = r;
}
}
gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0,
gegl_buffer_get_width (buffer),
gegl_buffer_get_height (buffer)),
0, format, rgb_buf ? rgb_buf : buf, GEGL_AUTO_ROWSTRIDE);
/* Step 7: Finish decompression */
jpeg_finish_decompress (&cinfo);
/* We can ignore the return value since suspension is not possible
* with the stdio data source.
*/
/* Step 8: Release JPEG decompression object */
jpeg_destroy_decompress (&cinfo);
/* free up the temporary buffers */
g_free (rowbuf);
g_free (buf);
g_free (rgb_buf);
/* Close FILE */
fclose (f);
/* At this point you may want to check to see whether any
* corrupt-data warnings occurred (test whether
* jerr.num_warnings is nonzero).
*/
pika_image_insert_layer (image, layer, NULL, 0);
g_object_unref (buffer);
return 0;
}
static gint
load_resource_1039 (const PSDimageres *res_a,
PSDimage *img_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Load ICC profile */
PikaColorProfile *profile;
gchar *icc_profile;
IFDBG(2) g_debug ("Process image resource block: 1039: ICC Profile");
icc_profile = g_malloc (res_a->data_len);
if (psd_read (input, icc_profile, res_a->data_len, error) < res_a->data_len)
{
psd_set_error (error);
g_free (icc_profile);
return -1;
}
profile = pika_color_profile_new_from_icc_profile ((guint8 *) icc_profile,
res_a->data_len,
NULL);
if (profile)
{
if (img_a->color_mode == PSD_CMYK &&
pika_color_profile_is_cmyk (profile))
{
img_a->cmyk_profile = profile;
/* Store CMYK profile in PikaImage if attached */
pika_image_set_simulation_profile (image, img_a->cmyk_profile);
}
else if (img_a->color_mode == PSD_LAB)
{
g_debug ("LAB color profile ignored.");
g_object_unref (profile);
}
else
{
pika_image_set_color_profile (image, profile);
g_object_unref (profile);
}
}
g_free (icc_profile);
return 0;
}
static gint
load_resource_1045 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
/* Load alpha channel names stored as a series of unicode strings
in a GPtrArray */
gchar *str;
gint32 block_rem;
gint32 read_len;
gint32 write_len;
IFDBG(2) g_debug ("Process image resource block 1045: Unicode Alpha Channel Names");
if (img_a->alpha_names)
{
gint i;
IFDBG(3) g_debug ("Deleting localised alpha channel names");
for (i = 0; i < img_a->alpha_names->len; ++i)
{
str = g_ptr_array_index (img_a->alpha_names, i);
g_free (str);
}
g_ptr_array_free (img_a->alpha_names, TRUE);
}
img_a->alpha_names = g_ptr_array_new ();
block_rem = res_a->data_len;
while (block_rem > 1)
{
str = fread_unicode_string (&read_len, &write_len, 1, FALSE, input,
error);
if (*error)
return -1;
IFDBG(3) g_debug ("String: %s, %d, %d", str, read_len, write_len);
if (write_len >= 0)
{
g_ptr_array_add (img_a->alpha_names, (gpointer) str);
}
block_rem -= read_len;
}
return 0;
}
static gint
load_resource_1046 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
/* Load indexed color table count */
guchar *cmap;
gint32 cmap_count = 0;
gint16 index_count = 0;
IFDBG(2) g_debug ("Process image resource block: 1046: Indexed Color Table Count");
if (psd_read (input, &index_count, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
index_count = GINT16_FROM_BE (index_count);
IFDBG(3) g_debug ("Indexed color table count: %d", index_count);
/* FIXME - check that we have indexed image */
if (index_count && index_count < 256)
{
cmap = pika_image_get_colormap (image, NULL, &cmap_count);
if (cmap && index_count < cmap_count)
pika_image_set_colormap (image, cmap, index_count);
g_free (cmap);
}
return 0;
}
static gint
load_resource_1053 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
/* Load image alpha channel ids (tattoos) */
gint16 tot_rec;
gint16 cidx;
IFDBG(2) g_debug ("Process image resource block: 1053: Channel ID");
tot_rec = res_a->data_len / 4;
if (tot_rec ==0)
return 0;
img_a->alpha_id = g_malloc (sizeof (img_a->alpha_id) * tot_rec);
img_a->alpha_id_count = tot_rec;
for (cidx = 0; cidx < tot_rec; ++cidx)
{
if (psd_read (input, &img_a->alpha_id[cidx], 4, error) < 4)
{
psd_set_error (error);
return -1;
}
img_a->alpha_id[cidx] = GUINT32_FROM_BE (img_a->alpha_id[cidx]);
IFDBG(3) g_debug ("Channel id: %d", img_a->alpha_id[cidx]);
}
return 0;
}
static gint
load_resource_1058 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
gchar *name;
PikaParasite *parasite;
gchar *res_data;
IFDBG(2) g_debug ("Process image resource block: 1058: Exif data");
res_data = g_malloc (res_a->data_len);
if (psd_read (input, res_data, res_a->data_len, error) < res_a->data_len)
{
psd_set_error (error);
g_free (res_data);
return -1;
}
/* Store resource data as a standard psd parasite */
IFDBG (2) g_debug ("Processing exif data as psd parasite");
name = g_strdup_printf ("psd-image-resource-%.4s-%.4x",
res_a->type, res_a->id);
IFDBG(3) g_debug ("Parasite name: %s", name);
parasite = pika_parasite_new (name, 0, res_a->data_len, res_data);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
g_free (name);
g_free (res_data);
return 0;
}
static gint
load_resource_1069 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
guint16 layer_count;
gint i;
IFDBG(2) g_debug ("Process image resource block: 1069: Layer Selection ID(s)");
if (psd_read (input, &layer_count, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
layer_count = GUINT16_FROM_BE (layer_count);
/* This should probably not happen, but just in case the block is
* duplicated, let's just free the previous selection.
*/
g_list_free (img_a->layer_selection);
img_a->layer_selection = NULL;
for (i = 0; i < layer_count; i++)
{
guint32 layer_id;
if (psd_read (input, &layer_id, 4, error) < 4)
{
psd_set_error (error);
return -1;
}
layer_id = GUINT32_FROM_BE (layer_id);
img_a->layer_selection = g_list_prepend (img_a->layer_selection, GINT_TO_POINTER (layer_id));
}
return 0;
}
static gint
load_resource_1077 (const PSDimageres *res_a,
PikaImage *image,
PSDimage *img_a,
GInputStream *input,
GError **error)
{
/* Load alpha channel display info */
DisplayInfoNew dsp_info;
CMColor ps_color;
PikaRGB pika_rgb;
PikaHSV pika_hsv;
PikaCMYK pika_cmyk;
gint16 tot_rec;
gint cidx;
IFDBG(2) g_debug ("Process image resource block 1077: Display Info New");
/* For now, skip first 4 bytes since intention is unclear. Seems to be
a version number that is always one, but who knows. */
if (! psd_seek (input, 4, G_SEEK_CUR, error))
return -1;
tot_rec = res_a->data_len / 13;
if (tot_rec == 0)
return 0;
img_a->alpha_display_info = g_new (PSDchanneldata *, tot_rec);
img_a->alpha_display_count = tot_rec;
for (cidx = 0; cidx < tot_rec; ++cidx)
{
if (psd_read (input, &dsp_info.colorSpace, 2, error) < 2 ||
psd_read (input, &dsp_info.color, 8, error) < 8 ||
psd_read (input, &dsp_info.opacity, 2, error) < 2 ||
psd_read (input, &dsp_info.mode, 1, error) < 1)
{
psd_set_error (error);
return -1;
}
dsp_info.colorSpace = GINT16_FROM_BE (dsp_info.colorSpace);
ps_color.cmyk.cyan = GUINT16_FROM_BE (dsp_info.color[0]);
ps_color.cmyk.magenta = GUINT16_FROM_BE (dsp_info.color[1]);
ps_color.cmyk.yellow = GUINT16_FROM_BE (dsp_info.color[2]);
ps_color.cmyk.black = GUINT16_FROM_BE (dsp_info.color[3]);
dsp_info.opacity = GINT16_FROM_BE (dsp_info.opacity);
switch (dsp_info.colorSpace)
{
case PSD_CS_RGB:
pika_rgb_set (&pika_rgb, ps_color.rgb.red / 65535.0,
ps_color.rgb.green / 65535.0,
ps_color.rgb.blue / 65535.0);
break;
case PSD_CS_HSB:
pika_hsv_set (&pika_hsv, ps_color.hsv.hue / 65535.0,
ps_color.hsv.saturation / 65535.0,
ps_color.hsv.value / 65535.0);
pika_hsv_to_rgb (&pika_hsv, &pika_rgb);
break;
case PSD_CS_CMYK:
pika_cmyk_set (&pika_cmyk, 1.0 - ps_color.cmyk.cyan / 65535.0,
1.0 - ps_color.cmyk.magenta / 65535.0,
1.0 - ps_color.cmyk.yellow / 65535.0,
1.0 - ps_color.cmyk.black / 65535.0);
pika_cmyk_to_rgb (&pika_cmyk, &pika_rgb);
break;
case PSD_CS_GRAYSCALE:
pika_rgb_set (&pika_rgb, ps_color.gray.gray / 10000.0,
ps_color.gray.gray / 10000.0,
ps_color.gray.gray / 10000.0);
break;
case PSD_CS_FOCOLTONE:
case PSD_CS_TRUMATCH:
case PSD_CS_HKS:
case PSD_CS_LAB:
case PSD_CS_PANTONE:
case PSD_CS_TOYO:
case PSD_CS_DIC:
case PSD_CS_ANPA:
default:
if (CONVERSION_WARNINGS)
g_message ("Unsupported color space: %d",
dsp_info.colorSpace);
pika_rgb_set (&pika_rgb, 1.0, 0.0, 0.0);
}
pika_rgb_set_alpha (&pika_rgb, 1.0);
IFDBG(2) g_debug ("PS cSpace: %d, col: %d %d %d %d, opacity: %d, mode: %d",
dsp_info.colorSpace, ps_color.cmyk.cyan, ps_color.cmyk.magenta,
ps_color.cmyk.yellow, ps_color.cmyk.black, dsp_info.opacity,
dsp_info.mode);
IFDBG(2) g_debug ("cSpace: %d, col: %g %g %g, opacity: %d, mode: %d",
dsp_info.colorSpace, pika_rgb.r * 255 , pika_rgb.g * 255,
pika_rgb.b * 255, dsp_info.opacity, dsp_info.mode);
img_a->alpha_display_info[cidx] = g_malloc0 (sizeof (PSDchanneldata));
img_a->alpha_display_info[cidx]->pika_color = pika_rgb;
img_a->alpha_display_info[cidx]->opacity = dsp_info.opacity;
img_a->alpha_display_info[cidx]->ps_mode = dsp_info.mode;
img_a->alpha_display_info[cidx]->ps_cspace = dsp_info.colorSpace;
img_a->alpha_display_info[cidx]->ps_color = ps_color;
}
return 0;
}
static gint
load_resource_2000 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
gdouble *controlpoints;
gint32 x[3];
gint32 y[3];
PikaVectors *vectors = NULL;
gint16 type;
gint16 init_fill;
gint16 num_rec;
gint16 path_rec;
gint16 cntr;
gint image_width;
gint image_height;
gint i;
gboolean closed;
/* Load path data from image resources 2000-2998 */
IFDBG(2) g_debug ("Process image resource block: %d :Path data", res_a->id);
path_rec = res_a->data_len / 26;
if (path_rec ==0)
return 0;
if (psd_read (input, &type, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
type = GINT16_FROM_BE (type);
if (type != PSD_PATH_FILL_RULE)
{
IFDBG(1) g_debug ("Unexpected path record type: %d", type);
return -1;
}
if (! psd_seek (input, 24, G_SEEK_CUR, error))
{
psd_set_error (error);
return -1;
}
path_rec--;
if (path_rec ==0)
return 0;
image_width = pika_image_get_width (image);
image_height = pika_image_get_height (image);
/* Create path */
if (res_a->id == PSD_WORKING_PATH)
{
/* use "Working Path" for the path name to match the Photoshop display */
vectors = pika_vectors_new (image, "Working Path");
}
else
{
/* Use the name stored in the PSD to name the path */
vectors = pika_vectors_new (image, res_a->name);
}
pika_image_insert_vectors (image, vectors, NULL, -1);
while (path_rec > 0)
{
if (psd_read (input, &type, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
type = GINT16_FROM_BE (type);
IFDBG(3) g_debug ("Path record type %d", type);
if (type == PSD_PATH_FILL_RULE)
{
if (! psd_seek (input, 24, G_SEEK_CUR, error))
{
psd_set_error (error);
return -1;
}
}
else if (type == PSD_PATH_FILL_INIT)
{
if (psd_read (input, &init_fill, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
if (! psd_seek (input, 22, G_SEEK_CUR, error))
{
psd_set_error (error);
return -1;
}
}
else if (type == PSD_PATH_CL_LEN
|| type == PSD_PATH_OP_LEN)
{
if (psd_read (input, &num_rec, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
num_rec = GINT16_FROM_BE (num_rec);
IFDBG(3) g_debug ("Num path records %d", num_rec);
if (num_rec > path_rec)
{
psd_set_error (error);
return - 1;
}
if (type == PSD_PATH_CL_LEN)
closed = TRUE;
else
closed = FALSE;
cntr = 0;
controlpoints = g_malloc (sizeof (gdouble) * num_rec * 6);
if (! psd_seek (input, 22, G_SEEK_CUR, error))
{
psd_set_error (error);
g_free (controlpoints);
return -1;
}
while (num_rec > 0)
{
if (psd_read (input, &type, 2, error) < 2)
{
psd_set_error (error);
return -1;
}
type = GINT16_FROM_BE (type);
IFDBG(3) g_debug ("Path record type %d", type);
if (type == PSD_PATH_CL_LNK
|| type == PSD_PATH_CL_UNLNK
|| type == PSD_PATH_OP_LNK
|| type == PSD_PATH_OP_UNLNK)
{
if (psd_read (input, &y[0], 4, error) < 4 ||
psd_read (input, &x[0], 4, error) < 4 ||
psd_read (input, &y[1], 4, error) < 4 ||
psd_read (input, &x[1], 4, error) < 4 ||
psd_read (input, &y[2], 4, error) < 4 ||
psd_read (input, &x[2], 4, error) < 4)
{
psd_set_error (error);
return -1;
}
for (i = 0; i < 3; ++i)
{
x[i] = GINT32_FROM_BE (x[i]);
controlpoints[cntr] = x[i] / 16777216.0 * image_width;
cntr++;
y[i] = GINT32_FROM_BE (y[i]);
controlpoints[cntr] = y[i] / 16777216.0 * image_height;
cntr++;
}
IFDBG(3) g_debug ("Path points (%d,%d), (%d,%d), (%d,%d)",
x[0], y[0], x[1], y[1], x[2], y[2]);
}
else
{
IFDBG(1) g_debug ("Unexpected path type record %d", type);
if (! psd_seek (input, 24, G_SEEK_CUR, error))
{
psd_set_error (error);
return -1;
}
}
path_rec--;
num_rec--;
}
/* Add sub-path */
pika_vectors_stroke_new_from_points (vectors,
PIKA_VECTORS_STROKE_TYPE_BEZIER,
cntr, controlpoints, closed);
g_free (controlpoints);
}
else
{
if (! psd_seek (input, 24, G_SEEK_CUR, error))
{
psd_set_error (error);
return -1;
}
}
path_rec--;
}
return 0;
}
static gint
load_resource_2999 (const PSDimageres *res_a,
PikaImage *image,
GInputStream *input,
GError **error)
{
gchar *path_name;
gint16 path_flatness_int;
gint16 path_flatness_fixed;
gfloat path_flatness;
PikaParasite *parasite;
gint32 read_len;
gint32 write_len;
path_name = fread_pascal_string (&read_len, &write_len, 2, input, error);
if (*error)
return -1;
/* Convert from fixed to floating point */
if (psd_read (input, &path_flatness_int, 1, error) < 1 ||
psd_read (input, &path_flatness_fixed, 1, error) < 1)
{
psd_set_error (error);
return -1;
}
path_flatness_fixed = GINT16_FROM_BE (path_flatness_fixed);
/* Converting from Adobe fixed point value to float */
path_flatness = (path_flatness_fixed - 0.5f) / 65536.0;
path_flatness += path_flatness_int;
/* Adobe path flatness range is 0.2 to 100.0 */
path_flatness = CLAMP (path_flatness, 0.2f, 100.0f);
/* Save to image parasite */
parasite = pika_parasite_new (PSD_PARASITE_CLIPPING_PATH, 0,
read_len, path_name);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
parasite = pika_parasite_new (PSD_PARASITE_PATH_FLATNESS, 0,
sizeof (gfloat), &path_flatness);
pika_image_attach_parasite (image, parasite);
pika_parasite_free (parasite);
/* Adobe says they ignore the last two bytes, the fill rule */
if (psd_read (input, &path_flatness_fixed, 1, error) < 1)
{
psd_set_error (error);
return -1;
}
g_free (path_name);
return 0;
}