Eine aufbereitete Darstellung der Quelle

 
     
 
 
Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 

Benutzer

Quelle  psd-image-res-load.c   Sprache: 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 <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 <libgimp/gimp.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 "libgimp/stdplugins-intl.h"

#define EXIF_HEADER_SIZE 8

/*  Local function prototypes  */
static gint     load_resource_unknown  (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_ps_only  (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1005     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1006     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1007     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1008     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1022     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1024     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1028     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1032     (const PSDimageres     *res_a,
                                        GimpImage             *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,
                                        GimpImage             *image,
                                        GFile                 *file,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1037     (const PSDimageres     *res_a,
                                        PSDimage              *img_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1039     (const PSDimageres     *res_a,
                                        PSDimage              *img_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1045     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1046     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1053     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1058     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1069     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_1077     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        PSDimage              *img_a,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_2000     (const PSDimageres     *res_a,
                                        GimpImage             *image,
                                        GInputStream          *input,
                                        GError               **error);

static gint     load_resource_2999     (const PSDimageres     *res_a,
                                        GimpImage             *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,
                     GimpImage    *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 GIMP
              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_GLOBAL_ANGLE:
            load_resource_1037 (res_a, img_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,
                         GimpImage     *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,
                       GimpImage          *image,
                       GInputStream       *input,
                       GError            **error)
{
  /* Unknown image resources attached as parasites to re-save later */
  GimpParasite  *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 = gimp_parasite_new (name, 0, res_a->data_len, data);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);
  g_free (data);
  g_free (name);

  return 0;
}

static gint
load_resource_ps_only (const PSDimageres  *res_a,
                       GimpImage          *image,
                       GInputStream       *input,
                       GError            **error)
{
  /* Save photoshop resources with no meaning for GIMP as image parasites
     to re-save later */

  GimpParasite  *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 = gimp_parasite_new (name, 0, res_a->data_len, data);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);
  g_free (data);
  g_free (name);

  return 0;
}

static gint
load_resource_1005 (const PSDimageres  *res_a,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  /* Load image resolution and unit of measure */

  /* FIXME  width unit and height unit unused at present */

  ResolutionInfo  res_info;
  GimpUnit       *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 */

  gimp_image_set_resolution (image,
                             res_info.hRes / 65536.0, res_info.vRes / 65536.0);

  /* GIMP only has one display unit so use ps horizontal resolution unit */
  switch (res_info.hResUnit)
    {
    case PSD_RES_INCH:
      image_unit = gimp_unit_inch ();
      break;
    case PSD_RES_CM:
      image_unit = gimp_unit_mm ();
      break;
    default:
      image_unit = gimp_unit_inch ();
    }

  gimp_image_set_unit (image, image_unit);

  return 0;
}

static gint
load_resource_1006 (const PSDimageres  *res_a,
                    GimpImage          *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;
    }

  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)
        {
          if (! img_a->alpha_names)
            img_a->alpha_names = g_ptr_array_new ();
          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,
                    GimpImage          *image,
                    PSDimage           *img_a,
                    GInputStream       *input,
                    GError            **error)
{
  /* Load alpha channel display info */

  DisplayInfo       dsp_info;
  CMColor           ps_color;
  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)
    {
      GeglColor *color;

      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);

      color = gegl_color_new ("red");

      switch (dsp_info.colorSpace)
        {
          case PSD_CS_RGB:
            /* TODO: which space should we use? */
            gegl_color_set_rgba_with_space (color,
                                            ps_color.rgb.red / 65535.0,
                                            ps_color.rgb.green / 65535.0,
                                            ps_color.rgb.blue / 65535.0,
                                            1.0, NULL);
            break;

          case PSD_CS_HSB:
            {
              gfloat hsv[3] =
                {
                  ps_color.hsv.hue / 65535.0f,
                  ps_color.hsv.saturation / 65535.0f,
                  ps_color.hsv.value / 65535.0f
                };

              gegl_color_set_pixel (color, babl_format ("HSV float"), hsv);
            }
          break;

          case PSD_CS_CMYK:
            /* TODO: again, which space? */
            gegl_color_set_cmyk (color,
                                 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,
                                 1.0, NULL);
            break;

          case PSD_CS_GRAYSCALE:
            {
              gdouble gray = ps_color.gray.gray / 10000.0;

              /* TODO: which space? */
              gegl_color_set_pixel (color, babl_format_with_space ("Y' double", NULL), &gray);
            }
            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);
        }

      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, opacity: %d, kind: %d",
                        dsp_info.colorSpace, dsp_info.opacity, dsp_info.kind);

      img_a->alpha_display_info[cidx] = g_malloc0 (sizeof (PSDchanneldata));
      img_a->alpha_display_info[cidx]->gimp_color = color;
      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,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  /* Load image caption */
  GimpParasite  *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 = gimp_parasite_new (GIMP_PARASITE_COMMENT, GIMP_PARASITE_PERSISTENT,
                                write_len, caption);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);
  g_free (caption);

  return 0;
}

static gint
load_resource_1022 (const PSDimageres  *res_a,
                    GimpImage          *image,
                    PSDimage           *img_a,
                    GInputStream       *input,
                    GError            **error)
{
  /* Load quick mask info */
  gboolean quick_mask_empty = TRUE; /* 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,
                    GimpImage          *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,
                    GimpImage          *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 */

  GimpParasite *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 GIMP IPTC parasite */
  IFDBG (2) g_debug ("Processing IPTC data as GIMP IPTC parasite");
  /* Serialize IPTC data */
  iptc_data_save (iptc_data, &iptc_buf, &iptc_buf_len);
  if (iptc_buf_len > 0)
    {
      parasite = gimp_parasite_new (GIMP_PARASITE_IPTC,
                                    GIMP_PARASITE_PERSISTENT,
                                    iptc_buf_len, iptc_buf);
      gimp_image_attach_parasite (image, parasite);
      gimp_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 = gimp_parasite_new (name, 0, res_a->data_len, res_data);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);
  g_free (name);

#endif /* HAVE_IPTCDATA */

  g_free (res_data);
  return 0;
}

static gint
load_resource_1032 (const PSDimageres  *res_a,
                    GimpImage          *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)
        gimp_image_add_vguide (image, guide.fLocation);
      else
        gimp_image_add_hguide (image, guide.fLocation);
    }

  return 0;
}

static gint
load_resource_1033 (const PSDimageres  *res_a,
                    GimpImage          *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;
  GimpLayer            *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 */
  gimp_image_resize (image, cinfo.output_width, cinfo.output_height, 0, 0);
  layer = gimp_layer_new (image, _("Background"),
                          cinfo.output_width,
                          cinfo.output_height,
                          GIMP_RGB_IMAGE,
                          100,
                          gimp_image_get_default_new_layer_mode (image));
  buffer = gimp_drawable_get_buffer (GIMP_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).
   */

  gimp_image_insert_layer (image, layer, NULL, 0);
  g_object_unref (buffer);

  return 0;
}

/* (Photoshop 5.0) Global Angle. 4 bytes that contain an integer between 0 and 359,
 * which is the global lighting angle for effects layer. If not present, assumed to be 30.
 * The above official text seems to be incorrect. I have seen a negative value,
 * which isn't a surprise since layer effect angles can be negative.
 */

static gint
load_resource_1037 (const PSDimageres  *res_a,
                    PSDimage           *img_a,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  gint32 global_angle = 30;

  IFDBG(2) g_debug ("Process image resource block: 1037: Global Lighting Angle");

  if (psd_read (input, &global_angle, 4, error) < 4)
    {
      psd_set_error (error);
      return -1;
    }
  img_a->global_light_angle = GINT32_FROM_BE (global_angle);

  IFDBG(3) g_debug ("Global angle: %d", img_a->global_light_angle);

  return 0;
}

static gint
load_resource_1039 (const PSDimageres  *res_a,
                    PSDimage           *img_a,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  /* Load ICC profile */
  GimpColorProfile *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 = gimp_color_profile_new_from_icc_profile ((guint8 *) icc_profile,
                                                     res_a->data_len,
                                                     NULL);
  if (profile)
    {
      if (img_a->color_mode == PSD_CMYK &&
          gimp_color_profile_is_cmyk (profile))
        {
          img_a->cmyk_profile = profile;
          /* Store CMYK profile in GimpImage if attached */
          gimp_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
        {
          gimp_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,
                    GimpImage          *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,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  /* Load indexed color table count */
  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)
    {
      GimpPalette *palette;

      palette = gimp_image_get_palette (image);
      if (palette)
        while (index_count < gimp_palette_get_color_count (palette))
          gimp_palette_delete_entry (palette, index_count);
    }
  return 0;
}

static gint
load_resource_1053 (const PSDimageres  *res_a,
                    GimpImage          *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,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  gchar        *name;

  GimpParasite *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 = gimp_parasite_new (name, 0, res_a->data_len, res_data);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);
  g_free (name);

  g_free (res_data);
  return 0;
}

static gint
load_resource_1069 (const PSDimageres  *res_a,
                    GimpImage          *image,
                    PSDimage           *img_a,
                    GInputStream       *input,
                    GError            **error)
{
  guint16 layer_count = 0;
  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 = 0;

      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,
                    GimpImage          *image,
                    PSDimage           *img_a,
                    GInputStream       *input,
                    GError            **error)
{
  /* Load alpha channel display info */

  DisplayInfoNew    dsp_info;
  CMColor           ps_color;
  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)
    {
      GeglColor *color;

      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);

      color = gegl_color_new ("red");

      switch (dsp_info.colorSpace)
        {
          case PSD_CS_RGB:
            /* TODO: which space? */
            gegl_color_set_rgba_with_space (color,
                                            ps_color.rgb.red / 65535.0,
                                            ps_color.rgb.green / 65535.0,
                                            ps_color.rgb.blue / 65535.0,
                                            1.0, NULL);
            break;

          case PSD_CS_HSB:
            {
              gfloat hsv[3] =
                {
                  ps_color.hsv.hue / 65535.0f,
                  ps_color.hsv.saturation / 65535.0f,
                  ps_color.hsv.value / 65535.0f
                };

              gegl_color_set_pixel (color, babl_format ("HSV float"), hsv);
            }
            break;

          case PSD_CS_CMYK:
            /* TODO: which space? */
            gegl_color_set_cmyk (color,
                                 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,
                                 1.0, NULL);
            break;

          case PSD_CS_GRAYSCALE:
            {
              gdouble gray = ps_color.gray.gray / 10000.0;

              /* TODO: which space? */
              gegl_color_set_pixel (color, babl_format_with_space ("Y' double", NULL), &gray);
            }
            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);
        }

      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, opacity: %d, mode: %d",
                        dsp_info.colorSpace, dsp_info.opacity, dsp_info.mode);

      img_a->alpha_display_info[cidx] = g_malloc0 (sizeof (PSDchanneldata));
      img_a->alpha_display_info[cidx]->gimp_color = color;
      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,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  gdouble   *controlpoints;
  gint32     x[3];
  gint32     y[3];
  GimpPath  *path      = NULL;
  gint16     type      = 0;
  gint16     init_fill = 0;
  gint16     num_rec;
  gint16     path_rec;
  gint       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 = gimp_image_get_width (image);
  image_height = gimp_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 */
      path = gimp_path_new (image, "Working Path");
    }
  else
    {
      /* Use the name stored in the PSD to name the path */
      path = gimp_path_new (image, res_a->name);
    }

  gimp_image_insert_path (image, path, 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 */
          gimp_path_stroke_new_from_points (path,
                                            GIMP_PATH_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,
                    GimpImage          *image,
                    GInputStream       *input,
                    GError            **error)
{
  gchar        *path_name;
  gint16        path_flatness_int   = 0;
  guint16       path_flatness_fixed = 0;
  gfloat        path_flatness;
  GimpParasite *parasite;
  gint32        read_len;
  gint32        write_len;

  path_name = fread_pascal_string (&read_len, &write_len, 1, input, error);
  if (*error || ! path_name)
    {
      g_printerr ("psd-load: Unable to read clipping path name.");
      return -1;
    }

  /* Convert from fixed to floating point */
  if (psd_read (input, &path_flatness_int, 2, error) < 2 ||
      psd_read (input, &path_flatness_fixed, 2, error) < 2)
    {
      psd_set_error (error);
      return -1;
    }
  path_flatness_fixed = GUINT16_FROM_BE (path_flatness_fixed);
  path_flatness_int   = GINT16_FROM_BE (path_flatness_int);

  /* 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 = gimp_parasite_new (PSD_PARASITE_CLIPPING_PATH, 0,
                                read_len, path_name);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);

  parasite = gimp_parasite_new (PSD_PARASITE_PATH_FLATNESS, 0,
                                sizeof (gfloat), &path_flatness);
  gimp_image_attach_parasite (image, parasite);
  gimp_parasite_free (parasite);

  /* Adobe says they ignore the last two bytes, the fill rule */
  if (psd_read (input, &path_flatness_fixed, 2, error) < 2)
    {
      psd_set_error (error);
      return -1;
    }

  g_free (path_name);

  return 0;
}

Messung
CHZG
839510092

¤ Dauer der Verarbeitung: 0.42 Sekunden  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

PVS Prover

Isabelle Prover


Cephes Mathematical Library

Vienna Development Method

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Open Source Software

     Quellcodebibliothek
     Eigene Quellcodes
     Fremde Quellcodes
     Suchen

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Statistik
#Sources=1104842
#Domains=499168