[gimp/soc-2013-psd: 8/10] plug-ins: Support > 8 bit psd files properly.



commit 72a0b6830746cbfaf10361aa3ed00ee00674a82a
Author: Simon Lui <simonlui src gnome org>
Date:   Tue Sep 17 23:24:01 2013 -0400

    plug-ins: Support > 8 bit psd files properly.

 plug-ins/file-psd/psd-load.c |  141 +++++++++++++++++++++++++++++++-----------
 plug-ins/file-psd/psd.h      |    2 +-
 2 files changed, 106 insertions(+), 37 deletions(-)
---
diff --git a/plug-ins/file-psd/psd-load.c b/plug-ins/file-psd/psd-load.c
index 84da797..cb337a7 100644
--- a/plug-ins/file-psd/psd-load.c
+++ b/plug-ins/file-psd/psd-load.c
@@ -102,7 +102,7 @@ static void             convert_1_bit              (const gchar *src,
                                                     guint32      rows,
                                                     guint32      columns);
 
-static const Babl*      get_psd_pixel_format       (PSDimage    *img_a);
+static const Babl*      get_pixel_format           (PSDimage    *img_a);
 
 
 /* Main file load function */
@@ -324,7 +324,7 @@ read_header_block (PSDimage  *img_a,
       return -1;
     }
 
-  /* Warnings for format conversions */
+  /* Warning for unsupported bit depth */
   switch (img_a->bps)
     {
       case 32:
@@ -333,6 +333,11 @@ read_header_block (PSDimage  *img_a,
 
       case 16:
         IFDBG(3) g_debug ("16 Bit Data");
+       if (CONVERSION_WARNINGS)
+          g_message (_("Warning:\n"
+                       "The image you are loading has 16 bits per channel. GIMP "
+                       "can only handle 8 bit, so it will be converted for you. "
+                       "Information will be lost because of this conversion."));
         break;
 
       case 8:
@@ -481,6 +486,7 @@ read_layer_block (PSDimage  *img_a,
       img_a->num_layers = -1;
       return NULL;
     }
+
   img_a->mask_layer_len = GUINT32_FROM_BE (block_len);
 
   IFDBG(1) g_debug ("Layer and mask block size = %d", img_a->mask_layer_len);
@@ -522,6 +528,7 @@ read_layer_block (PSDimage  *img_a,
 
           /* Create pointer array for the layer records */
           lyr_a = g_new (PSDlayer *, img_a->num_layers);
+
           for (lidx = 0; lidx < img_a->num_layers; ++lidx)
             {
               /* Allocate layer record */
@@ -541,6 +548,7 @@ read_layer_block (PSDimage  *img_a,
                   psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
+
               lyr_a[lidx]->top = GINT32_FROM_BE (lyr_a[lidx]->top);
               lyr_a[lidx]->left = GINT32_FROM_BE (lyr_a[lidx]->left);
               lyr_a[lidx]->bottom = GINT32_FROM_BE (lyr_a[lidx]->bottom);
@@ -587,6 +595,7 @@ read_layer_block (PSDimage  *img_a,
                                  lyr_a[lidx]->num_channels);
 
               lyr_a[lidx]->chn_info = g_new (ChannelLengthInfo, lyr_a[lidx]->num_channels);
+
               for (cidx = 0; cidx < lyr_a[lidx]->num_channels; ++cidx)
                 {
                   if (fread (&lyr_a[lidx]->chn_info[cidx].channel_id, 2, 1, f) < 1
@@ -627,6 +636,7 @@ read_layer_block (PSDimage  *img_a,
 
               lyr_a[lidx]->layer_flags.trans_prot = lyr_a[lidx]->flags & 1 ? TRUE : FALSE;
               lyr_a[lidx]->layer_flags.visible = lyr_a[lidx]->flags & 2 ? FALSE : TRUE;
+
               if (lyr_a[lidx]->flags & 8)
                 lyr_a[lidx]->layer_flags.irrelevant = lyr_a[lidx]->flags & 16 ? TRUE : FALSE;
               else
@@ -799,9 +809,11 @@ read_layer_block (PSDimage  *img_a,
                   psd_set_error (feof (f), errno, error);
                   return NULL;
                 }
+
               block_len = GUINT32_FROM_BE (block_len);
               block_rem -= (block_len + 4);
               IFDBG(3) g_debug ("Remaining length %d", block_rem);
+
               if (block_len > 0)
                 {
                   if (fseek (f, block_len, SEEK_CUR) < 0)
@@ -815,6 +827,7 @@ read_layer_block (PSDimage  *img_a,
                                                        4, f, error);
               if (*error)
                 return NULL;
+
               block_rem -= read_len;
               IFDBG(3) g_debug ("Remaining length %d", block_rem);
 
@@ -824,8 +837,13 @@ read_layer_block (PSDimage  *img_a,
                 {
                   if (get_layer_resource_header (&res_a, f, error) < 0)
                     return NULL;
+
                   block_rem -= 12;
 
+                 //Round up to the nearest even byte
+                 while (res_a.data_len % 4 != 0)
+                   res_a.data_len++;
+
                   if (res_a.data_len > block_rem)
                     {
                       IFDBG(1) g_debug ("Unexpected end of layer resource data");
@@ -899,6 +917,7 @@ create_gimp_image (PSDimage    *img_a,
                    const gchar *filename)
 {
   gint32 image_id = -1;
+  GimpPrecision precision;
 
   switch (img_a->color_mode)
     {
@@ -923,10 +942,32 @@ create_gimp_image (PSDimage    *img_a,
         break;
     }
 
+    switch (img_a->bps)
+      {
+        case 32:
+          precision = GIMP_PRECISION_U32_LINEAR;
+         break;
+
+        case 16:
+          precision = GIMP_PRECISION_U16_LINEAR;
+         break;
+
+        case 8:
+        case 1:
+          precision = GIMP_PRECISION_U8_LINEAR;
+         break;
+
+        default:
+         /* Precision not supported */
+         g_warning ("Invalid precision");
+         return -1;
+         break;
+      }
+
   /* Create gimp image */
   IFDBG(2) g_debug ("Create image");
-  image_id = gimp_image_new (img_a->columns, img_a->rows, img_a->base_type);
-
+  image_id = gimp_image_new_with_precision (img_a->columns, img_a->rows,
+                                           img_a->base_type, precision);
   gimp_image_set_filename (image_id, filename);
   gimp_image_undo_disable (image_id);
 
@@ -1022,6 +1063,7 @@ add_layers (const gint32  image_id,
   guint16               layer_channels;
   guint16               channel_idx[MAX_CHANNELS];
   guint16              *rle_pack_len;
+  guint16               bps;
   gint32                l_x;                   /* Layer x */
   gint32                l_y;                   /* Layer y */
   gint32                l_w;                   /* Layer width */
@@ -1326,12 +1368,16 @@ add_layers (const gint32  image_id,
               image_type = get_gimp_image_type (img_a->base_type, alpha);
               IFDBG(3) g_debug ("Layer type %d", image_type);
               layer_size = l_w * l_h;
-              pixels = g_malloc (layer_size * layer_channels);
+             bps = img_a->bps / 8;
+             if (bps == 0)
+               bps++;
+              pixels = g_malloc (layer_size * layer_channels * bps);
               for (cidx = 0; cidx < layer_channels; ++cidx)
                 {
                   IFDBG(3) g_debug ("Start channel %d", channel_idx[cidx]);
                   for (i = 0; i < layer_size; ++i)
-                    pixels[(i * layer_channels) + cidx] = lyr_chn[channel_idx[cidx]]->data[i];
+                   memcpy (&pixels[((i * layer_channels) + cidx) * bps],
+                           &lyr_chn[channel_idx[cidx]]->data[i * bps], bps);
                   g_free (lyr_chn[channel_idx[cidx]]->data);
                 }
 
@@ -1346,7 +1392,7 @@ add_layers (const gint32  image_id,
               gimp_layer_set_lock_alpha  (layer_id, lyr_a[lidx]->layer_flags.trans_prot);
              buffer = gimp_drawable_get_buffer (layer_id);
              gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (buffer), 
gegl_buffer_get_height (buffer)),
-                              0, get_psd_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
+                              0, get_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
               gimp_item_set_visible (layer_id, lyr_a[lidx]->layer_flags.visible);
               if (lyr_a[lidx]->id)
                 gimp_item_set_tattoo (layer_id, lyr_a[lidx]->id);
@@ -1450,7 +1496,7 @@ add_layers (const gint32  image_id,
                   gimp_layer_add_mask (layer_id, mask_id);
                  buffer = gimp_drawable_get_buffer (mask_id);
                  gegl_buffer_set (buffer, GEGL_RECTANGLE (lm_x, lm_y, lm_w, lm_h), 0,
-                                  get_psd_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
+                                  get_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
                   g_object_unref (buffer);
                   gimp_layer_set_apply_mask (layer_id,
                     ! lyr_a[lidx]->layer_mask.mask_flags.disabled);
@@ -1483,6 +1529,7 @@ add_merged_image (const gint32  image_id,
   guint16               base_channels;
   guint16               extra_channels;
   guint16               total_channels;
+  guint16               bps;
   guint16              *rle_pack_len[MAX_CHANNELS];
   guint32               alpha_id;
   gint32                layer_size;
@@ -1503,6 +1550,9 @@ add_merged_image (const gint32  image_id,
 
   total_channels = img_a->channels;
   extra_channels = 0;
+  bps = img_a->bps / 8;
+  if (bps == 0)
+    bps++;
 
   if ((img_a->color_mode == PSD_BITMAP ||
        img_a->color_mode == PSD_GRAYSCALE ||
@@ -1608,12 +1658,13 @@ add_merged_image (const gint32  image_id,
       image_type = get_gimp_image_type (img_a->base_type, img_a->transparency);
 
       layer_size = img_a->columns * img_a->rows;
-      pixels = g_malloc (layer_size * base_channels);
+      pixels = g_malloc (layer_size * base_channels * bps);
       for (cidx = 0; cidx < base_channels; ++cidx)
         {
           for (i = 0; i < layer_size; ++i)
             {
-              pixels[(i * base_channels) + cidx] = chn_a[cidx].data[i];
+             memcpy (&pixels[((i * base_channels) + cidx) * bps],
+                     &chn_a[cidx].data[i * bps], bps);
             }
           g_free (chn_a[cidx].data);
         }
@@ -1627,7 +1678,7 @@ add_merged_image (const gint32  image_id,
       gimp_image_insert_layer (image_id, layer_id, -1, 0);
       buffer = gimp_drawable_get_buffer (layer_id);
       gegl_buffer_set (buffer, GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (buffer), gegl_buffer_get_height 
(buffer)),
-                      0, get_psd_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
+                      0, get_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
       g_object_unref (buffer);
       g_free (pixels);
     }
@@ -1719,7 +1770,7 @@ add_merged_image (const gint32  image_id,
           gimp_item_set_visible (channel_id, alpha_visible);
          gegl_buffer_set (buffer,
                           GEGL_RECTANGLE (0, 0, gegl_buffer_get_width (buffer), gegl_buffer_get_height 
(buffer)),
-                          0, get_psd_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
+                          0, get_pixel_format (img_a), pixels, GEGL_AUTO_ROWSTRIDE);
           g_object_unref (buffer);
           g_free (chn_a[cidx].data);
         }
@@ -1903,14 +1954,20 @@ read_channel_data (PSDchannel     *channel,
   /* Convert channel data to GIMP format */
   switch (bps)
     {
+      case 32:
+      case 16:
+      case 8:
+        channel->data = (gchar *) g_malloc (channel->rows * channel->columns * bps / 8 );
+        memcpy (channel->data, raw_data, (channel->rows * channel->columns * bps / 8));
+        break;
+
       case 1:
         channel->data = (gchar *) g_malloc (channel->rows * channel->columns);
         convert_1_bit (raw_data, channel->data, channel->rows, channel->columns);
         break;
 
       default:
-       channel->data = (gchar *) g_malloc (channel->rows * channel->columns);
-        memcpy (channel->data, raw_data, (channel->rows * channel->columns));
+       return -1;
         break;
     }
 
@@ -1953,7 +2010,7 @@ convert_1_bit (const gchar *src,
 }
 
 static const Babl*
-get_psd_pixel_format(PSDimage *img_a)
+get_pixel_format (PSDimage *img_a)
 {
   const Babl *format;
 
@@ -1962,18 +2019,21 @@ get_psd_pixel_format(PSDimage *img_a)
     case GIMP_GRAY_IMAGE:
       switch (img_a->bps)
        {
-        case 32:
-         format = babl_format ("Y' float");
+       case 32:
+          format = babl_format ("Y u32");
          break;
+
         case 16:
-          format = babl_format ("Y' u16");
+          format = babl_format ("Y u16");
          break;
+
         case 8:
         case 1:
-          format = babl_format ("Y' u8");
+          format = babl_format ("Y u8");
          break;
+
         default:
-         return NULL;
+          return NULL;
          break;
        }
       break;
@@ -1981,16 +2041,19 @@ get_psd_pixel_format(PSDimage *img_a)
     case GIMP_GRAYA_IMAGE:
       switch (img_a->bps)
        {
-        case 32:
-         format = babl_format ("Y'A float");
-          break;
+       case 32:
+          format = babl_format ("YA u32");
+         break;
+
         case 16:
-          format = babl_format ("Y'A u16");
+          format = babl_format ("YA u16");
           break;
+
         case 8:
         case 1:
-          format = babl_format ("Y'A u8");
+          format = babl_format ("YA u8");
           break;
+
         default:
          return NULL;
          break;
@@ -2001,16 +2064,19 @@ get_psd_pixel_format(PSDimage *img_a)
     case GIMP_INDEXED_IMAGE:
       switch (img_a->bps)
        {
-        case 32:
-         format = babl_format ("R'G'B' float");
-          break;
+       case 32:
+          format = babl_format ("RGB u32");
+         break;
+
         case 16:
-          format = babl_format ("R'G'B' u16");
+          format = babl_format ("RGB u16");
           break;
+
         case 8:
         case 1:
-          format = babl_format ("R'G'B' u8");
+          format = babl_format ("RGB u8");
           break;
+
         default:
          return NULL;
          break;
@@ -2021,16 +2087,19 @@ get_psd_pixel_format(PSDimage *img_a)
     case GIMP_INDEXEDA_IMAGE:
       switch (img_a->bps)
        {
-        case 32:
-         format = babl_format ("R'G'B'A float");
-          break;
+       case 32:
+          format = babl_format ("RGBA u32");
+         break;
+
         case 16:
-          format = babl_format ("R'G'B'A u16");
-          break;
+          format = babl_format ("RGBA u16");
+         break;
+
         case 8:
         case 1:
-          format = babl_format ("R'G'B'A u8");
+          format = babl_format ("RGBA u8");
           break;
+
         default:
          return NULL;
          break;
diff --git a/plug-ins/file-psd/psd.h b/plug-ins/file-psd/psd.h
index 794c742..f9a6a65 100644
--- a/plug-ins/file-psd/psd.h
+++ b/plug-ins/file-psd/psd.h
@@ -647,7 +647,7 @@ typedef struct
   gboolean              transparency;           /* Image has merged transparency alpha channel */
   guint32               rows;                   /* Number of rows: 1 - 30000 */
   guint32               columns;                /* Number of columns: 1 - 30000 */
-  guint16               bps;                    /* Bits per channel: 1, 8, 16, or 32 */
+  guint16               bps;                    /* Bits per sample: 1, 8, 16, or 32 */
   guint16               color_mode;             /* Image color mode: {PSDColorMode} */
   GimpImageBaseType     base_type;              /* Image base color mode: (GIMP) */
   guint16               comp_mode;              /* Merged image compression mode */


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]