[gimp] Implement saving and loading of layer trees in the XCF



commit c6fa4f7206daa28a374ba12820bb82755c87919e
Author: Michael Natterer <mitch gimp org>
Date:   Sun Aug 30 21:28:59 2009 +0200

    Implement saving and loading of layer trees in the XCF
    
    * app/xcf/xcf-private.h: add properties PROP_GROUP_ITEM and
      PROP_ITEM_PATH
    
    * app/xcf/xcf-save.c: when saving a group layer, save a
      PROP_GROUP_ITEM.  When saving a child item, save a PROP_ITEM_PATH
      which contains the path indices returned by gimp_item_get_path().
    
    * app/xcf/xcf-load.c: when loading a PROP_GROUP_ITEM, replace the
      layer that is being loaded by a GimpGroupLayer, also ignore that
      layer's hierarchy (it makes no sense to load the tiles of a layer
      that's generated from its children). When loading a PROP_ITEM_PATH,
      pass the loaded path up to xcf_load_image() so it can add the loaded
      layer at the right place in the tree.

 app/xcf/xcf-load.c    |  103 +++++++++++++++++++++++++++++++++++++++++--------
 app/xcf/xcf-private.h |    4 +-
 app/xcf/xcf-save.c    |   35 +++++++++++++++++
 3 files changed, 124 insertions(+), 18 deletions(-)
---
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index fcc0899..21ccf8f 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -37,12 +37,13 @@
 #include "core/gimpcontainer.h"
 #include "core/gimpdrawable-private.h" /* eek */
 #include "core/gimpgrid.h"
+#include "core/gimpgrouplayer.h"
 #include "core/gimpimage.h"
 #include "core/gimpimage-colormap.h"
 #include "core/gimpimage-grid.h"
 #include "core/gimpimage-guides.h"
 #include "core/gimpimage-sample-points.h"
-#include "core/gimplayer.h"
+#include "core/gimpitemstack.h"
 #include "core/gimplayer-floating-sel.h"
 #include "core/gimplayermask.h"
 #include "core/gimpparasitelist.h"
@@ -75,6 +76,7 @@ static gboolean        xcf_load_image_props   (XcfInfo      *info,
 static gboolean        xcf_load_layer_props   (XcfInfo      *info,
                                                GimpImage    *image,
                                                GimpLayer   **layer,
+                                               GList       **item_path,
                                                gboolean     *apply_mask,
                                                gboolean     *edit_mask,
                                                gboolean     *show_mask,
@@ -86,7 +88,8 @@ static gboolean        xcf_load_prop          (XcfInfo      *info,
                                                PropType     *prop_type,
                                                guint32      *prop_size);
 static GimpLayer     * xcf_load_layer         (XcfInfo      *info,
-                                               GimpImage    *image);
+                                               GimpImage    *image,
+                                               GList       **item_path);
 static GimpChannel   * xcf_load_channel       (XcfInfo      *info,
                                                GimpImage    *image);
 static GimpLayerMask * xcf_load_layer_mask    (XcfInfo      *info,
@@ -169,6 +172,7 @@ xcf_load_image (Gimp     *gimp,
   while (TRUE)
     {
       GimpLayer *layer;
+      GList     *item_path = NULL;
 
       /* read in the offset of the next layer */
       info->cp += xcf_read_int32 (info->fp, &offset, 1);
@@ -189,7 +193,7 @@ xcf_load_image (Gimp     *gimp,
         goto error;
 
       /* read in the layer */
-      layer = xcf_load_layer (info, image);
+      layer = xcf_load_layer (info, image, &item_path);
       if (!layer)
         goto error;
 
@@ -199,10 +203,31 @@ xcf_load_image (Gimp     *gimp,
 
       /* add the layer to the image if its not the floating selection */
       if (layer != info->floating_sel)
-        gimp_image_add_layer (image, layer,
-                              NULL, /* FIXME tree */
-                              gimp_container_get_n_children (image->layers),
-                              FALSE);
+        {
+          GimpContainer *layers = gimp_image_get_layers (image);
+          GimpContainer *container;
+          GimpLayer     *parent;
+
+          if (item_path)
+            {
+              parent = GIMP_LAYER
+                (gimp_item_stack_get_parent_by_path (GIMP_ITEM_STACK (layers),
+                                                     item_path,
+                                                     NULL));
+
+              container = gimp_viewable_get_children (GIMP_VIEWABLE (parent));
+            }
+          else
+            {
+              parent    = NULL;
+              container = layers;
+            }
+
+          gimp_image_add_layer (image, layer,
+                                parent,
+                                gimp_container_get_n_children (container),
+                                FALSE);
+        }
 
       /* restore the saved position so we'll be ready to
        *  read the next offset.
@@ -614,6 +639,7 @@ static gboolean
 xcf_load_layer_props (XcfInfo    *info,
                       GimpImage  *image,
                       GimpLayer **layer,
+                      GList     **item_path,
                       gboolean   *apply_mask,
                       gboolean   *edit_mask,
                       gboolean   *show_mask,
@@ -758,6 +784,42 @@ xcf_load_layer_props (XcfInfo    *info,
           info->cp += xcf_read_int32 (info->fp, text_layer_flags, 1);
           break;
 
+        case PROP_GROUP_ITEM:
+          {
+            GimpLayer *group;
+
+            group = gimp_group_layer_new (image);
+
+            gimp_object_set_name (GIMP_OBJECT (group),
+                                  gimp_object_get_name (*layer));
+
+            GIMP_DRAWABLE (group)->type =
+              gimp_drawable_type (GIMP_DRAWABLE (*layer));
+
+            g_object_ref_sink (*layer);
+            g_object_unref (*layer);
+            *layer = group;
+          }
+          break;
+
+        case PROP_ITEM_PATH:
+          {
+            glong  base = info->cp;
+            GList *path = NULL;
+
+            while (info->cp - base < prop_size)
+              {
+                guint32 index;
+
+                info->cp += xcf_read_int32 (info->fp, &index, 1);
+
+                path = g_list_append (path, GUINT_TO_POINTER (index));
+              }
+
+            *item_path = path;
+          }
+          break;
+
         default:
 #ifdef GIMP_UNSTABLE
           g_printerr ("unexpected/unknown layer property: %d (skipping)\n",
@@ -961,8 +1023,9 @@ xcf_load_prop (XcfInfo  *info,
 }
 
 static GimpLayer *
-xcf_load_layer (XcfInfo   *info,
-                GimpImage *image)
+xcf_load_layer (XcfInfo    *info,
+                GimpImage  *image,
+                GList     **item_path)
 {
   GimpLayer     *layer;
   GimpLayerMask *layer_mask;
@@ -999,7 +1062,7 @@ xcf_load_layer (XcfInfo   *info,
     return NULL;
 
   /* read in the layer properties */
-  if (! xcf_load_layer_props (info, image, &layer,
+  if (! xcf_load_layer_props (info, image, &layer, item_path,
                               &apply_mask, &edit_mask, &show_mask,
                               &text_layer_flags))
     goto error;
@@ -1025,15 +1088,21 @@ xcf_load_layer (XcfInfo   *info,
   info->cp += xcf_read_int32 (info->fp, &hierarchy_offset, 1);
   info->cp += xcf_read_int32 (info->fp, &layer_mask_offset, 1);
 
-  /* read in the hierarchy */
-  if (! xcf_seek_pos (info, hierarchy_offset, NULL))
-    goto error;
+  /* read in the hierarchy (ignore it for group layers, both as an
+   * optimization and because the hierarchy's extents don't match
+   * the group layer's tiles)
+   */
+  if (! gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
+    {
+      if (! xcf_seek_pos (info, hierarchy_offset, NULL))
+        goto error;
 
-  if (! xcf_load_hierarchy (info,
-                            gimp_drawable_get_tiles (GIMP_DRAWABLE (layer))))
-    goto error;
+      if (! xcf_load_hierarchy (info,
+                                gimp_drawable_get_tiles (GIMP_DRAWABLE (layer))))
+        goto error;
 
-  xcf_progress_update (info);
+      xcf_progress_update (info);
+    }
 
   /* read in the layer mask */
   if (layer_mask_offset != 0)
diff --git a/app/xcf/xcf-private.h b/app/xcf/xcf-private.h
index 8fa9161..b539d31 100644
--- a/app/xcf/xcf-private.h
+++ b/app/xcf/xcf-private.h
@@ -49,7 +49,9 @@ typedef enum
   PROP_VECTORS            = 25,
   PROP_TEXT_LAYER_FLAGS   = 26,
   PROP_SAMPLE_POINTS      = 27,
-  PROP_LOCK_CONTENT       = 28
+  PROP_LOCK_CONTENT       = 28,
+  PROP_GROUP_ITEM         = 29,
+  PROP_ITEM_PATH          = 30
 } PropType;
 
 typedef enum
diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c
index 79eb39c..88031b8 100644
--- a/app/xcf/xcf-save.c
+++ b/app/xcf/xcf-save.c
@@ -453,6 +453,19 @@ xcf_save_layer_props (XcfInfo    *info,
   gint          offset_x;
   gint          offset_y;
 
+  if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
+    xcf_check_error (xcf_save_prop (info, image, PROP_GROUP_ITEM, error));
+
+  if (gimp_viewable_get_parent (GIMP_VIEWABLE (layer)))
+    {
+      GList *path;
+
+      path = gimp_item_get_path (GIMP_ITEM (layer));
+      xcf_check_error (xcf_save_prop (info, image, PROP_ITEM_PATH, error,
+                                      path));
+      g_list_free (path);
+    }
+
   if (layer == gimp_image_get_active_layer (image))
     xcf_check_error (xcf_save_prop (info, image, PROP_ACTIVE_LAYER, error));
 
@@ -617,6 +630,7 @@ xcf_save_prop (XcfInfo    *info,
     case PROP_ACTIVE_LAYER:
     case PROP_ACTIVE_CHANNEL:
     case PROP_SELECTION:
+    case PROP_GROUP_ITEM:
       size = 0;
 
       xcf_write_prop_type_check_error (info, prop_type);
@@ -1071,6 +1085,27 @@ xcf_save_prop (XcfInfo    *info,
         xcf_write_int32_check_error (info, &flags, 1);
       }
       break;
+
+    case PROP_ITEM_PATH:
+      {
+        GList *path;
+
+        path = va_arg (args, GList *);
+        size = 4 * g_list_length (path);
+
+        xcf_write_prop_type_check_error (info, prop_type);
+        xcf_write_int32_check_error (info, &size, 1);
+
+        while (path)
+          {
+            guint32 index = GPOINTER_TO_UINT (path->data);
+
+            xcf_write_int32_check_error (info, &index, 1);
+
+            path = g_list_next (path);
+          }
+      }
+      break;
     }
 
   va_end (args);



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