gimp r26902 - in trunk: . plug-ins/file-psd



Author: neo
Date: Mon Sep  8 20:42:55 2008
New Revision: 26902
URL: http://svn.gnome.org/viewvc/gimp?rev=26902&view=rev

Log:
2008-09-08  Sven Neumann  <sven gimp org>

	* plug-ins/file-psd/psd-save.c: applied patch from Dennis Ranke 
as
	attached to bug #551231. Changes the PSD save plug-in to store
	transparency data in the image data section. Also fixes bug 
#551232
	(saving an indexed image with multiple layers as PSD modifies 
the
	image).



Modified:
   trunk/ChangeLog
   trunk/plug-ins/file-psd/psd-save.c

Modified: trunk/plug-ins/file-psd/psd-save.c
==============================================================================
--- trunk/plug-ins/file-psd/psd-save.c	(original)
+++ trunk/plug-ins/file-psd/psd-save.c	Mon Sep  8 20:42:55 2008
@@ -120,6 +120,9 @@
 
   GimpImageBaseType    baseType;
 
+  gint32               merged_layer;/* Merged image,
+                                       to be used for the image data section */
+
   gint                 nChannels;   /* Number of user channels in the image */
   gint32              *lChannels;   /* User channels in the image */
 
@@ -187,6 +190,8 @@
                                     glong         *ChanLenPosition,
                                     gint32         rowlenOffset);
 
+static gint32 create_merged_image  (gint32         imageID);
+
 
 const GimpPlugInInfo PLUG_IN_INFO =
 {
@@ -692,7 +697,8 @@
   write_gint32 (fd, 0, "reserved 1");      /* 6 for the 'reserved' field + 4 bytes for a long */
   write_gint16 (fd, 0, "reserved 1");      /* and 2 bytes for a short */
   write_gint16 (fd, (PSDImageData.nChannels +
-                     nChansLayer (PSDImageData.baseType, 0, 0)),
+                     nChansLayer (PSDImageData.baseType,
+                     gimp_drawable_has_alpha (PSDImageData.merged_layer), 0)),
                 "channels");
   write_gint32 (fd, PSDImageData.image_height, "rows");
   write_gint32 (fd, PSDImageData.image_width, "columns");
@@ -820,7 +826,8 @@
 
   /* --------------- Write Channel names --------------- */
 
-  if (PSDImageData.nChannels > 0)
+  if (PSDImageData.nChannels > 0 ||
+      gimp_drawable_has_alpha (PSDImageData.merged_layer))
     {
       xfwrite (fd, "8BIM", 4, "imageresources signature");
       write_gint16 (fd, 0x03EE, "0x03EE Id"); /* 1006 */
@@ -834,6 +841,10 @@
 
     /* Write all strings */
 
+    /* if the merged_image contains transparency, write a name for it first */
+    if (gimp_drawable_has_alpha (PSDImageData.merged_layer))
+      write_string (fd, "Transparency", "channel name");
+
     for (i = PSDImageData.nChannels - 1; i >= 0; i--)
     {
       char *chName = gimp_drawable_get_name (PSDImageData.lChannels[i]);
@@ -1047,7 +1058,10 @@
 
   /* Layer structure section */
 
-  write_gint16 (fd, PSDImageData.nLayers, "Layer structure count");
+  if (gimp_drawable_has_alpha (PSDImageData.merged_layer))
+    write_gint16 (fd, -PSDImageData.nLayers, "Layer structure count");
+  else
+    write_gint16 (fd, PSDImageData.nLayers, "Layer structure count");
 
   /* Layer records section */
   /* GIMP layers must be written in reverse order */
@@ -1254,6 +1268,7 @@
   if ( gimp_drawable_has_alpha  (drawableID) &&
       !gimp_drawable_is_indexed (drawableID))
     colors -= 1;
+
   gimp_tile_cache_ntiles (2* (drawable->width / gimp_tile_width () + 1));
 
   LengthsTable = g_new (gint16, height);
@@ -1267,21 +1282,26 @@
 
   for (i = 0; i < bytes; i++)
     {
-      int chan;
+      gint chan;
+
       len = 0;
-      if (bytes != colors) /* Need to write alpha channel first */
+
+      if (bytes != colors && ltable_offset == 0) /* Need to write alpha channel first, except in image data section */
         {
           if (i == 0)
             {
-              if (ltable_offset > 0)
-                continue;
               chan = bytes - 1;
             }
           else
-            chan = i - 1;
+            {
+              chan = i - 1;
+            }
         }
       else
-        chan = i;
+        {
+          chan = i;
+        }
+
       if (ChanLenPosition)
         {
           write_gint16 (fd, 1, "Compression type (RLE)");
@@ -1423,25 +1443,18 @@
 {
   gint ChanCount;
   gint i, j;
-  gint nChannel;
   gint32 imageHeight;                   /* Height of image */
   glong offset;                         /* offset in file of rle lengths */
   gint chan;
-  gint32 bottom_layer;
 
   IFDBG printf (" Function: save_data\n");
 
   ChanCount = (PSDImageData.nChannels +
-               nChansLayer (PSDImageData.baseType, 0, 0));
-
-  i = PSDImageData.nLayers - 1;  /* Layers to be written */
-  IFDBG printf ("\tProcessing %d layers\n", i);
+               nChansLayer (PSDImageData.baseType,
+               gimp_drawable_has_alpha (PSDImageData.merged_layer), 0));
 
   imageHeight = gimp_image_height (image_id);
 
-  nChannel = 0;
-
-
   write_gint16 (fd, 1, "RLE compression");
 
   /* All line lengths go before the rle pixel data */
@@ -1452,37 +1465,12 @@
     for (j = 0; j < imageHeight; j++)
       write_gint16 (fd, 0, "junk line lengths");
 
-  bottom_layer = PSDImageData.lLayers[PSDImageData.nLayers - 1];
-
-  if (PSDImageData.nLayers != 1 ||
-      gimp_drawable_width  (bottom_layer) != gimp_image_width  (image_id) ||
-      gimp_drawable_height (bottom_layer) != gimp_image_height (image_id))
-    {
-      gint32 flat_image;
-      gint32 flat_drawable;
-
-      IFDBG printf ("\t\tCreating flattened image\n");
-      flat_image = gimp_image_duplicate (image_id);
-      gimp_image_undo_disable (flat_image);
-      flat_drawable = gimp_image_flatten (flat_image);
-
-      /* gimp_image_flatten() may fail if there are no visible layers */
-      if (flat_drawable != -1)
-        {
-          IFDBG printf ("\t\tWriting compressed flattened image data\n");
-          write_pixel_data (fd, flat_drawable, NULL, offset);
-        }
-
-      gimp_image_delete (flat_image);
-    }
-  else
-    {
-      IFDBG printf ("\t\tWriting compressed image data\n");
-      write_pixel_data (fd, PSDImageData.lLayers[PSDImageData.nLayers - 1],
-                        NULL, offset);
-    }
+  IFDBG printf ("\t\tWriting compressed image data\n");
+  write_pixel_data (fd, PSDImageData.merged_layer,
+                    NULL, offset);
 
-  chan = nChansLayer (PSDImageData.baseType, 0, 0);
+  chan = nChansLayer (PSDImageData.baseType,
+                      gimp_drawable_has_alpha(PSDImageData.merged_layer), 0);
 
   for (i = PSDImageData.nChannels - 1; i >= 0; i--)
     {
@@ -1494,7 +1482,66 @@
     }
 }
 
+static gint32
+create_merged_image (gint32 image_id)
+{
+  gint32  merged_layer;
 
+  merged_layer = gimp_layer_new_from_visible (image_id, image_id, SAVE_PROC);
+
+  if (gimp_image_base_type (image_id) != GIMP_INDEXED)
+    {
+      GimpPixelRgn  region;
+      gboolean      transparency_found = FALSE;
+      gpointer      pr;
+
+      gimp_pixel_rgn_init (&region,
+                           gimp_drawable_get (merged_layer),
+                           0, 0,
+                           gimp_image_width (image_id),
+                           gimp_image_height (image_id),
+                           TRUE, FALSE);
+
+      for (pr = gimp_pixel_rgns_register (1, &region);
+           pr != NULL;
+           pr = gimp_pixel_rgns_process (pr))
+        {
+          guchar *data = region.data;
+          gint    y;
+
+          for (y = 0; y < region.h; y++)
+            {
+              guchar *d = data;
+              gint    x;
+
+              for (x = 0; x < region.w; x++)
+                {
+                  guint32 alpha = d[region.bpp - 1];
+
+                  if (alpha < 255)
+                    {
+                      gint i;
+
+                      transparency_found = TRUE;
+
+                      /* blend against white, photoshop does this. */
+                      for (i = 0; i < region.bpp - 1; i++)
+                        d[i] = ((guint32) d[i] * alpha) / 255 + 255 - alpha;
+                    }
+
+                  d += region.bpp;
+                }
+
+              data += region.rowstride;
+            }
+        }
+
+      if (! transparency_found)
+        gimp_layer_flatten (merged_layer);
+    }
+
+  return merged_layer;
+}
 
 static void
 get_image_data (FILE   *fd,
@@ -1513,18 +1560,14 @@
   PSDImageData.baseType = gimp_image_base_type (image_id);
   IFDBG printf ("\tGot base type: %d\n", PSDImageData.baseType);
 
-  /* PSD format does not support indexed layered images */
+  PSDImageData.merged_layer = create_merged_image (image_id);
 
-  if (PSDImageData.baseType == GIMP_INDEXED)
-    {
-      IFDBG printf ("\tFlattening indexed image\n");
-      gimp_image_flatten (image_id);
-    }
-
-  PSDImageData.lChannels = gimp_image_get_channels (image_id, &PSDImageData.nChannels);
+  PSDImageData.lChannels = gimp_image_get_channels (image_id,
+                                                    &PSDImageData.nChannels);
   IFDBG printf ("\tGot number of channels: %d\n", PSDImageData.nChannels);
 
-  PSDImageData.lLayers = gimp_image_get_layers (image_id, &PSDImageData.nLayers);
+  PSDImageData.lLayers = gimp_image_get_layers (image_id,
+                                                &PSDImageData.nLayers);
   IFDBG printf ("\tGot number of layers: %d\n", PSDImageData.nLayers);
 
   PSDImageData.layersDim = g_new (PSD_Layer_Dimension, PSDImageData.nLayers);
@@ -1606,6 +1649,10 @@
 
   save_data (fd, image_id);
 
+  /* Delete merged image now */
+
+  gimp_drawable_delete (PSDImageData.merged_layer);
+
   IFDBG printf ("----- Closing PSD file, done -----\n\n");
 
   fclose (fd);



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