[gimp/gimp-attributes-wip: 1/2] introducing gimp-attributes Instead of gexiv2-metadata, two new classes are introduced, GimpAttribut



commit 6c0f0ad5c3f42d84a90057a2fbdc71b8805ebcbd
Author: Hartmut Kuhse <hk_priv gmx de>
Date:   Tue Sep 30 20:50:44 2014 +0200

    introducing gimp-attributes
    Instead of gexiv2-metadata, two new classes are introduced, GimpAttribute
    and GimpAttributes, which stores GimpAttribute objects.
    The aim is more internal flexibility for metadata/attributes.
    
    GimpMetadata still exist as an interface between GExiv2, reading the metadata
    from an image, and GimpAttribute, storing the metadata and more.
    
    GimpAttributes are stored for GimpImage (as the older metadata object)
    and GimpItem (GimpLayer / GimpChannel)
    
    A new dialog for attributes as a plug-in for images(<Image>/Image/Image Attributes),
    layers (<Layers>/Layer Attributes) and channels (<Channels>/Channel Attributes).
    
    A dialog for editing IPTC Attributes for images, layers and channel (at the same places).
    This dialog is older and will not be enhanced.
    
    A dialog for editing image copyright and description whats o ever.
    As IPTC is (or will be) dead and xmp shall be the common standard, with the relevant
    IPTC tags mapped in xmp, i decided to take the tags from Adobe Lightroom 's "IPTC Extension"
    tags for dealing with digital rights (<Image>/Image/Digital Rights).
    I am very proud of this dialog, it was very hard work and is still in progress.

 app/core/Makefile.am                    |    2 +
 app/core/core-enums.c                   |    8 +-
 app/core/core-enums.h                   |    4 +-
 app/core/core-types.h                   |    1 +
 app/core/gimpchannel.c                  |   14 +
 app/core/gimpimage-duplicate.c          |   20 +-
 app/core/gimpimage-merge.c              |   23 +-
 app/core/gimpimage-metadata.c           |  163 +-
 app/core/gimpimage-metadata.h           |    8 +-
 app/core/gimpimage-undo-push.c          |   21 +-
 app/core/gimpimage-undo-push.h          |    6 +-
 app/core/gimpimage.c                    |   70 +-
 app/core/gimpimageundo.c                |   30 +-
 app/core/gimpimageundo.h                |    2 +-
 app/core/gimpitem-metadata.c            |   73 +
 app/core/gimpitem-metadata.h            |   28 +
 app/core/gimpitemundo.c                 |   74 +-
 app/core/gimpitemundo.h                 |    2 +
 app/core/gimplayer.c                    |   12 +-
 app/core/gimpviewable.c                 |   46 +-
 app/core/gimpviewable.h                 |    9 +-
 app/core/gimpviewableundo.c             |  175 ++
 app/core/gimpviewableundo.h             |   51 +
 app/file/file-open.c                    |    2 +-
 app/pdb/image-cmds.c                    |  118 +-
 app/pdb/internal-procs.c                |    2 +-
 app/pdb/item-cmds.c                     |  122 ++
 app/xcf/xcf-load.c                      |  164 +-
 app/xcf/xcf-save.c                      |   70 +-
 libgimp/Makefile.am                     |    3 +
 libgimp/gimp.def                        |    6 +-
 libgimp/gimp.h                          |    1 +
 libgimp/gimpimage.c                     |   52 +-
 libgimp/gimpimage.h                     |    5 +
 libgimp/gimpimage_pdb.c                 |   48 +-
 libgimp/gimpimage_pdb.h                 |    6 +-
 libgimp/gimpitem.c                      |   86 +
 libgimp/gimpitem.h                      |   40 +
 libgimp/gimpitem_pdb.c                  |   62 +
 libgimp/gimpitem_pdb.h                  |   83 +-
 libgimp/gimpmetadata.c                  |  368 ++--
 libgimp/gimpmetadata.h                  |    5 +-
 libgimp/gimpviewable.c                  |   84 +
 libgimp/gimpviewable_pdb.c              |  100 +
 libgimpbase/Makefile.am                 |   12 +
 libgimpbase/gimpattribute.c             | 1858 ++++++++++++++++
 libgimpbase/gimpattribute.h             |   95 +
 libgimpbase/gimpattributes-image.c      |  282 +++
 libgimpbase/gimpattributes-image.h      |   47 +
 libgimpbase/gimpattributes.c            | 1657 ++++++++++++++
 libgimpbase/gimpattributes.h            |   74 +
 libgimpbase/gimpbase.def                |   50 +-
 libgimpbase/gimpbase.h                  |    3 +
 libgimpbase/gimpbasetypes.h             |    2 +
 libgimpbase/gimpmetadata.c              |  501 +-----
 libgimpbase/gimpmetadata.h              |   21 -
 libgimpbase/gimprational.c              |  301 +++
 libgimpbase/gimprational.h              |   68 +
 plug-ins/Makefile.am                    |    1 +
 plug-ins/common/Makefile.am             |   61 +-
 plug-ins/common/attributes.c            |  876 ++++++++
 plug-ins/common/file-jp2-load.c         |    8 +-
 plug-ins/common/file-png.c              |   38 +-
 plug-ins/common/file-tiff-load.c        |    8 +-
 plug-ins/common/file-tiff-save.c        |   24 +-
 plug-ins/common/gimprc.common           |    3 +-
 plug-ins/common/iptc.c                  |  513 +++++
 plug-ins/file-jpeg/jpeg-load.c          |   13 +-
 plug-ins/file-jpeg/jpeg-load.h          |    1 +
 plug-ins/file-jpeg/jpeg-save.c          |    3 +-
 plug-ins/file-jpeg/jpeg.c               |   22 +-
 plug-ins/file-psd/psd-save.c            |   15 +-
 plug-ins/file-psd/psd.c                 |    2 +-
 plug-ins/metainfo/Makefile.am           |   61 +
 plug-ins/metainfo/interface.c           |  236 ++
 plug-ins/metainfo/interface.h           |   49 +
 plug-ins/metainfo/metainfo-helper.c     |  272 +++
 plug-ins/metainfo/metainfo-helper.h     |  102 +
 plug-ins/metainfo/metainfo.c            |  156 ++
 plug-ins/metainfo/metainfo.h            |   29 +
 plug-ins/metainfo/page-administration.c | 1039 +++++++++
 plug-ins/metainfo/page-administration.h |   33 +
 plug-ins/metainfo/page-artwork.c        | 1067 +++++++++
 plug-ins/metainfo/page-artwork.h        |   33 +
 plug-ins/metainfo/page-description.c    |  927 ++++++++
 plug-ins/metainfo/page-description.h    |   33 +
 plug-ins/metainfo/page-rights.c         | 1117 ++++++++++
 plug-ins/metainfo/page-rights.h         |   33 +
 plug-ins/ui/Makefile.am                 |    5 +-
 plug-ins/ui/plug-in-attributes.ui       |  346 +++
 plug-ins/ui/plug-in-iptc.ui             |  779 +++++++
 plug-ins/ui/plug-in-metadata.ui         |  908 --------
 plug-ins/ui/plug-in-metainfo.ui         | 3556 +++++++++++++++++++++++++++++++
 po-plug-ins/POTFILES.in                 |   10 +-
 tools/pdbgen/pdb/image.pdb              |   40 +-
 tools/pdbgen/pdb/item.pdb               |   78 +-
 tools/pdbgen/pdb/viewable.pdb           |  109 +
 97 files changed, 17744 insertions(+), 2102 deletions(-)
---
diff --git a/app/core/Makefile.am b/app/core/Makefile.am
index e5b44d8..0d105bf 100644
--- a/app/core/Makefile.am
+++ b/app/core/Makefile.am
@@ -266,6 +266,8 @@ libappcore_a_sources = \
        gimpitem-exclusive.h                    \
        gimpitem-linked.c                       \
        gimpitem-linked.h                       \
+       gimpitem-metadata.c                     \
+       gimpitem-metadata.h                     \
        gimpitem-preview.c                      \
        gimpitem-preview.h                      \
        gimpitempropundo.c                      \
diff --git a/app/core/core-enums.c b/app/core/core-enums.c
index c6dcc62..5d97822 100644
--- a/app/core/core-enums.c
+++ b/app/core/core-enums.c
@@ -866,13 +866,14 @@ gimp_undo_type_get_type (void)
     { GIMP_UNDO_IMAGE_SIZE, "GIMP_UNDO_IMAGE_SIZE", "image-size" },
     { GIMP_UNDO_IMAGE_RESOLUTION, "GIMP_UNDO_IMAGE_RESOLUTION", "image-resolution" },
     { GIMP_UNDO_IMAGE_GRID, "GIMP_UNDO_IMAGE_GRID", "image-grid" },
-    { GIMP_UNDO_IMAGE_METADATA, "GIMP_UNDO_IMAGE_METADATA", "image-metadata" },
     { GIMP_UNDO_IMAGE_COLORMAP, "GIMP_UNDO_IMAGE_COLORMAP", "image-colormap" },
+    { GIMP_UNDO_IMAGE_ATTRIBUTES, "GIMP_UNDO_IMAGE_ATTRIBUTES", "image-attributes" },
     { GIMP_UNDO_GUIDE, "GIMP_UNDO_GUIDE", "guide" },
     { GIMP_UNDO_SAMPLE_POINT, "GIMP_UNDO_SAMPLE_POINT", "sample-point" },
     { GIMP_UNDO_DRAWABLE, "GIMP_UNDO_DRAWABLE", "drawable" },
     { GIMP_UNDO_DRAWABLE_MOD, "GIMP_UNDO_DRAWABLE_MOD", "drawable-mod" },
     { GIMP_UNDO_MASK, "GIMP_UNDO_MASK", "mask" },
+    { GIMP_UNDO_ITEM_ATTRIBUTES, "GIMP_UNDO_ITEM_ATTRIBUTES", "item-attributes" },
     { GIMP_UNDO_ITEM_REORDER, "GIMP_UNDO_ITEM_REORDER", "item-reorder" },
     { GIMP_UNDO_ITEM_RENAME, "GIMP_UNDO_ITEM_RENAME", "item-rename" },
     { GIMP_UNDO_ITEM_DISPLACE, "GIMP_UNDO_ITEM_DISPLACE", "item-displace" },
@@ -908,6 +909,7 @@ gimp_undo_type_get_type (void)
     { GIMP_UNDO_FOREGROUND_SELECT, "GIMP_UNDO_FOREGROUND_SELECT", "foreground-select" },
     { GIMP_UNDO_PARASITE_ATTACH, "GIMP_UNDO_PARASITE_ATTACH", "parasite-attach" },
     { GIMP_UNDO_PARASITE_REMOVE, "GIMP_UNDO_PARASITE_REMOVE", "parasite-remove" },
+    { GIMP_UNDO_VIEWABLE_ATTRIBUTES, "GIMP_UNDO_VIEWABLE_ATTRIBUTES", "viewable-attributes" },
     { GIMP_UNDO_CANT, "GIMP_UNDO_CANT", "cant" },
     { 0, NULL, NULL }
   };
@@ -957,13 +959,14 @@ gimp_undo_type_get_type (void)
     { GIMP_UNDO_IMAGE_SIZE, NC_("undo-type", "Image size"), NULL },
     { GIMP_UNDO_IMAGE_RESOLUTION, NC_("undo-type", "Image resolution change"), NULL },
     { GIMP_UNDO_IMAGE_GRID, NC_("undo-type", "Grid"), NULL },
-    { GIMP_UNDO_IMAGE_METADATA, NC_("undo-type", "Change metadata"), NULL },
     { GIMP_UNDO_IMAGE_COLORMAP, NC_("undo-type", "Change indexed palette"), NULL },
+    { GIMP_UNDO_IMAGE_ATTRIBUTES, NC_("undo-type", "Changed attributes"), NULL },
     { GIMP_UNDO_GUIDE, NC_("undo-type", "Guide"), NULL },
     { GIMP_UNDO_SAMPLE_POINT, NC_("undo-type", "Sample Point"), NULL },
     { GIMP_UNDO_DRAWABLE, NC_("undo-type", "Layer/Channel"), NULL },
     { GIMP_UNDO_DRAWABLE_MOD, NC_("undo-type", "Layer/Channel modification"), NULL },
     { GIMP_UNDO_MASK, NC_("undo-type", "Selection mask"), NULL },
+    { GIMP_UNDO_ITEM_ATTRIBUTES, NC_("undo-type", "Changed attributes"), NULL },
     { GIMP_UNDO_ITEM_REORDER, NC_("undo-type", "Reorder item"), NULL },
     { GIMP_UNDO_ITEM_RENAME, NC_("undo-type", "Rename item"), NULL },
     { GIMP_UNDO_ITEM_DISPLACE, NC_("undo-type", "Move item"), NULL },
@@ -999,6 +1002,7 @@ gimp_undo_type_get_type (void)
     { GIMP_UNDO_FOREGROUND_SELECT, NC_("undo-type", "Select foreground"), NULL },
     { GIMP_UNDO_PARASITE_ATTACH, NC_("undo-type", "Attach parasite"), NULL },
     { GIMP_UNDO_PARASITE_REMOVE, NC_("undo-type", "Remove parasite"), NULL },
+    { GIMP_UNDO_VIEWABLE_ATTRIBUTES, "GIMP_UNDO_VIEWABLE_ATTRIBUTES", NULL },
     { GIMP_UNDO_CANT, NC_("undo-type", "Not undoable"), NULL },
     { 0, NULL, NULL }
   };
diff --git a/app/core/core-enums.h b/app/core/core-enums.h
index 81e20f8..9f75c22 100644
--- a/app/core/core-enums.h
+++ b/app/core/core-enums.h
@@ -426,13 +426,14 @@ typedef enum /*< pdb-skip >*/
   GIMP_UNDO_IMAGE_SIZE,               /*< desc="Image size"                  >*/
   GIMP_UNDO_IMAGE_RESOLUTION,         /*< desc="Image resolution change"     >*/
   GIMP_UNDO_IMAGE_GRID,               /*< desc="Grid"                        >*/
-  GIMP_UNDO_IMAGE_METADATA,           /*< desc="Change metadata"             >*/
   GIMP_UNDO_IMAGE_COLORMAP,           /*< desc="Change indexed palette"      >*/
+  GIMP_UNDO_IMAGE_ATTRIBUTES,         /*< desc="Change attributes            >*/
   GIMP_UNDO_GUIDE,                    /*< desc="Guide"                       >*/
   GIMP_UNDO_SAMPLE_POINT,             /*< desc="Sample Point"                >*/
   GIMP_UNDO_DRAWABLE,                 /*< desc="Layer/Channel"               >*/
   GIMP_UNDO_DRAWABLE_MOD,             /*< desc="Layer/Channel modification"  >*/
   GIMP_UNDO_MASK,                     /*< desc="Selection mask"              >*/
+  GIMP_UNDO_ITEM_ATTRIBUTES,          /*< desc="Change attributes            >*/
   GIMP_UNDO_ITEM_REORDER,             /*< desc="Reorder item"                >*/
   GIMP_UNDO_ITEM_RENAME,              /*< desc="Rename item"                 >*/
   GIMP_UNDO_ITEM_DISPLACE,            /*< desc="Move item"                   >*/
@@ -468,6 +469,7 @@ typedef enum /*< pdb-skip >*/
   GIMP_UNDO_FOREGROUND_SELECT,        /*< desc="Select foreground"           >*/
   GIMP_UNDO_PARASITE_ATTACH,          /*< desc="Attach parasite"             >*/
   GIMP_UNDO_PARASITE_REMOVE,          /*< desc="Remove parasite"             >*/
+  GIMP_UNDO_VIEWABLE_ATTRIBUTES,      /*< desc="Change attributes            >*/
 
   GIMP_UNDO_CANT                      /*< desc="Not undoable"                >*/
 } GimpUndoType;
diff --git a/app/core/core-types.h b/app/core/core-types.h
index d1c077b..5634349 100644
--- a/app/core/core-types.h
+++ b/app/core/core-types.h
@@ -166,6 +166,7 @@ typedef struct _GimpSamplePointUndo   GimpSamplePointUndo;
 typedef struct _GimpFloatingSelUndo   GimpFloatingSelUndo;
 typedef struct _GimpUndoStack         GimpUndoStack;
 typedef struct _GimpUndoAccumulator   GimpUndoAccumulator;
+typedef struct _GimpViewableUndo      GimpViewableUndo;
 
 
 /*  misc objects  */
diff --git a/app/core/gimpchannel.c b/app/core/gimpchannel.c
index 0e70915..7e239dc 100644
--- a/app/core/gimpchannel.c
+++ b/app/core/gimpchannel.c
@@ -23,6 +23,7 @@
 #include <gegl.h>
 #include <gdk-pixbuf/gdk-pixbuf.h>
 
+#include "libgimpbase/gimpbase.h"
 #include "libgimpmath/gimpmath.h"
 #include "libgimpcolor/gimpcolor.h"
 
@@ -44,6 +45,7 @@
 #include "gimpimage-quick-mask.h"
 #include "gimpimage-undo.h"
 #include "gimpimage-undo-push.h"
+#include "gimpitem-metadata.h"
 #include "gimpchannel.h"
 #include "gimpchannel-select.h"
 #include "gimpcontext.h"
@@ -493,6 +495,9 @@ gimp_channel_duplicate (GimpItem *item,
 
   if (GIMP_IS_CHANNEL (new_item))
     {
+      GimpAttributes *attributes;
+      GimpAttributes *new_attributes;
+
       GimpChannel *channel     = GIMP_CHANNEL (item);
       GimpChannel *new_channel = GIMP_CHANNEL (new_item);
 
@@ -506,6 +511,15 @@ gimp_channel_duplicate (GimpItem *item,
       new_channel->y1           = channel->y1;
       new_channel->x2           = channel->x2;
       new_channel->y2           = channel->y2;
+
+      attributes = gimp_item_get_attributes (item);
+      if (attributes)
+        {
+          new_attributes = gimp_attributes_duplicate (attributes);
+          gimp_item_set_attributes (new_item, new_attributes, FALSE);
+          g_object_unref (new_attributes);
+        }
+
     }
 
   return new_item;
diff --git a/app/core/gimpimage-duplicate.c b/app/core/gimpimage-duplicate.c
index da4469b..5a48e5c 100644
--- a/app/core/gimpimage-duplicate.c
+++ b/app/core/gimpimage-duplicate.c
@@ -72,7 +72,7 @@ static void          gimp_image_duplicate_sample_points    (GimpImage *image,
                                                             GimpImage *new_image);
 static void          gimp_image_duplicate_grid             (GimpImage *image,
                                                             GimpImage *new_image);
-static void          gimp_image_duplicate_metadata         (GimpImage *image,
+static void          gimp_image_duplicate_attributes       (GimpImage *image,
                                                             GimpImage *new_image);
 static void          gimp_image_duplicate_quick_mask       (GimpImage *image,
                                                             GimpImage *new_image);
@@ -147,8 +147,8 @@ gimp_image_duplicate (GimpImage *image)
   /*  Copy the grid  */
   gimp_image_duplicate_grid (image, new_image);
 
-  /*  Copy the metadata  */
-  gimp_image_duplicate_metadata (image, new_image);
+  /*  Copy the attributes  */
+  gimp_image_duplicate_attributes (image, new_image);
 
   /*  Copy the quick mask info  */
   gimp_image_duplicate_quick_mask (image, new_image);
@@ -474,16 +474,16 @@ gimp_image_duplicate_grid (GimpImage *image,
 }
 
 static void
-gimp_image_duplicate_metadata (GimpImage *image,
-                               GimpImage *new_image)
+gimp_image_duplicate_attributes (GimpImage *image,
+                                 GimpImage *new_image)
 {
-  GimpMetadata *metadata = gimp_image_get_metadata (image);
+  GimpAttributes *attributes = gimp_image_get_attributes (image);
 
-  if (metadata)
+  if (attributes)
     {
-      metadata = gimp_metadata_duplicate (metadata);
-      gimp_image_set_metadata (new_image, metadata, FALSE);
-      g_object_unref (metadata);
+      attributes = gimp_attributes_duplicate (attributes);
+      gimp_image_set_attributes (new_image, attributes, FALSE);
+      g_object_unref (attributes);
     }
 }
 
diff --git a/app/core/gimpimage-merge.c b/app/core/gimpimage-merge.c
index aec9c75..a779966 100644
--- a/app/core/gimpimage-merge.c
+++ b/app/core/gimpimage-merge.c
@@ -40,8 +40,10 @@
 #include "gimpgrouplayer.h"
 #include "gimpimage.h"
 #include "gimpimage-merge.h"
+#include "gimpimage-metadata.h"
 #include "gimpimage-undo.h"
 #include "gimpitemstack.h"
+#include "gimpitem-metadata.h"
 #include "gimplayer-floating-sel.h"
 #include "gimplayermask.h"
 #include "gimpmarshal.h"
@@ -426,6 +428,7 @@ gimp_image_merge_layers (GimpImage     *image,
   GimpLayer        *layer;
   GimpLayer        *bottom_layer;
   GimpParasiteList *parasites;
+  GimpAttributes   *attributes;
   gint              count;
   gint              x1, y1, x2, y2;
   gint              off_x, off_y;
@@ -520,8 +523,8 @@ gimp_image_merge_layers (GimpImage     *image,
       (gimp_drawable_is_indexed (GIMP_DRAWABLE (layer)) &&
        ! gimp_drawable_has_alpha (GIMP_DRAWABLE (layer))))
     {
-      GeglColor *color;
-      GimpRGB    bg;
+      GeglColor      *color;
+      GimpRGB         bg;
 
       merge_layer = gimp_layer_new (image, (x2 - x1), (y2 - y1),
                                     gimp_image_get_layer_format (image, FALSE),
@@ -581,6 +584,22 @@ gimp_image_merge_layers (GimpImage     *image,
 
   bottom_layer = layer;
 
+  /* Copy the attributes of the bottom layer to the new layer */
+
+  attributes = gimp_item_get_attributes (GIMP_ITEM (bottom_layer));
+
+  if (!attributes)
+    attributes = gimp_image_get_attributes (image);
+
+  if (attributes)
+    {
+      GimpAttributes *new_attributes;
+
+      new_attributes = gimp_attributes_duplicate (attributes);
+      gimp_item_set_attributes (GIMP_ITEM (merge_layer), new_attributes, TRUE);
+      g_object_unref (new_attributes);
+    }
+
   /* Copy the tattoo and parasites of the bottom layer to the new layer */
   gimp_item_set_tattoo (GIMP_ITEM (merge_layer),
                         gimp_item_get_tattoo (GIMP_ITEM (bottom_layer)));
diff --git a/app/core/gimpimage-metadata.c b/app/core/gimpimage-metadata.c
index 459dac1..c244952 100644
--- a/app/core/gimpimage-metadata.c
+++ b/app/core/gimpimage-metadata.c
@@ -33,75 +33,136 @@
 /* public functions */
 
 
-GimpMetadata *
-gimp_image_get_metadata (GimpImage *image)
-{
-  GimpImagePrivate *private;
-
-  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
-
-  private = GIMP_IMAGE_GET_PRIVATE (image);
-
-  return private->metadata;
-}
+//void
+//gimp_image_set_metadata (GimpImage    *image,
+//                         GimpMetadata *metadata,
+//                         gboolean      push_undo)
+//{
+//  GimpImagePrivate *private;
+//
+//  g_return_if_fail (GIMP_IS_IMAGE (image));
+//
+//  private = GIMP_IMAGE_GET_PRIVATE (image);
+//
+//  if (metadata != private->metadata)
+//    {
+//      if (push_undo)
+//        gimp_image_undo_push_image_metadata (image, NULL);
+//
+//      if (private->metadata)
+//        g_object_unref (private->metadata);
+//
+//      private->metadata = metadata;
+//
+//      if (private->metadata)
+//        {
+//          gdouble xres, yres;
+//
+//          g_object_ref (private->metadata);
+//
+//          gimp_metadata_set_pixel_size (metadata,
+//                                        gimp_image_get_width  (image),
+//                                        gimp_image_get_height (image));
+//
+//          switch (gimp_image_get_component_type (image))
+//            {
+//            case GIMP_COMPONENT_TYPE_U8:
+//              gimp_metadata_set_bits_per_sample (metadata, 8);
+//              break;
+//
+//            case GIMP_COMPONENT_TYPE_U16:
+//            case GIMP_COMPONENT_TYPE_HALF:
+//              gimp_metadata_set_bits_per_sample (metadata, 16);
+//              break;
+//
+//            case GIMP_COMPONENT_TYPE_U32:
+//            case GIMP_COMPONENT_TYPE_FLOAT:
+//              gimp_metadata_set_bits_per_sample (metadata, 32);
+//              break;
+//
+//            case GIMP_COMPONENT_TYPE_DOUBLE:
+//              gimp_metadata_set_bits_per_sample (metadata, 64);
+//              break;
+//            }
+//
+//          gimp_image_get_resolution (image, &xres, &yres);
+//          gimp_metadata_set_resolution (metadata, xres, yres,
+//                                        gimp_image_get_unit (image));
+//        }
+//
+//      g_object_notify (G_OBJECT (image), "metadata");
+//    }
+//}
 
 void
-gimp_image_set_metadata (GimpImage    *image,
-                         GimpMetadata *metadata,
-                         gboolean      push_undo)
+gimp_image_set_attributes (GimpImage      *image,
+                           GimpAttributes *attributes,
+                           gboolean        push_undo)
 {
-  GimpImagePrivate *private;
+  GimpViewable *viewable;
+  gdouble xres, yres;
 
   g_return_if_fail (GIMP_IS_IMAGE (image));
 
-  private = GIMP_IMAGE_GET_PRIVATE (image);
+  if (! attributes)
+    return;
+
+  if (push_undo)
+    gimp_image_undo_push_image_attributes (image, NULL);
 
-  if (metadata != private->metadata)
+  viewable = GIMP_VIEWABLE (image);
+
+  if (viewable)
     {
-      if (push_undo)
-        gimp_image_undo_push_image_metadata (image, NULL);
 
-      if (private->metadata)
-        g_object_unref (private->metadata);
+      gimp_attributes_set_pixel_size (attributes,
+                                      gimp_image_get_width  (image),
+                                      gimp_image_get_height (image));
 
-      private->metadata = metadata;
+      switch (gimp_image_get_component_type (image))
+      {
+        case GIMP_COMPONENT_TYPE_U8:
+          gimp_attributes_set_bits_per_sample (attributes, 8);
+          break;
 
-      if (private->metadata)
-        {
-          gdouble xres, yres;
+        case GIMP_COMPONENT_TYPE_U16:
+        case GIMP_COMPONENT_TYPE_HALF:
+          gimp_attributes_set_bits_per_sample (attributes, 16);
+          break;
 
-          g_object_ref (private->metadata);
+        case GIMP_COMPONENT_TYPE_U32:
+        case GIMP_COMPONENT_TYPE_FLOAT:
+          gimp_attributes_set_bits_per_sample (attributes, 32);
+          break;
 
-          gimp_metadata_set_pixel_size (metadata,
-                                        gimp_image_get_width  (image),
-                                        gimp_image_get_height (image));
+        case GIMP_COMPONENT_TYPE_DOUBLE:
+          gimp_attributes_set_bits_per_sample (attributes, 64);
+          break;
+      }
 
-          switch (gimp_image_get_component_type (image))
-            {
-            case GIMP_COMPONENT_TYPE_U8:
-              gimp_metadata_set_bits_per_sample (metadata, 8);
-              break;
+      gimp_image_get_resolution (image, &xres, &yres);
+      gimp_attributes_set_resolution (attributes, xres, yres,
+                                      gimp_image_get_unit (image));
 
-            case GIMP_COMPONENT_TYPE_U16:
-            case GIMP_COMPONENT_TYPE_HALF:
-              gimp_metadata_set_bits_per_sample (metadata, 16);
-              break;
+      gimp_viewable_set_attributes (viewable, attributes);
+    }
+}
 
-            case GIMP_COMPONENT_TYPE_U32:
-            case GIMP_COMPONENT_TYPE_FLOAT:
-              gimp_metadata_set_bits_per_sample (metadata, 32);
-              break;
+GimpAttributes *
+gimp_image_get_attributes (GimpImage *image)
+{
+  GimpViewable   *viewable;
+  GimpAttributes *attributes;
 
-            case GIMP_COMPONENT_TYPE_DOUBLE:
-              gimp_metadata_set_bits_per_sample (metadata, 64);
-              break;
-            }
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
 
-          gimp_image_get_resolution (image, &xres, &yres);
-          gimp_metadata_set_resolution (metadata, xres, yres,
-                                        gimp_image_get_unit (image));
-        }
+  viewable = GIMP_VIEWABLE (image);
 
-      g_object_notify (G_OBJECT (image), "metadata");
+  if (viewable)
+    {
+      attributes = gimp_viewable_get_attributes (viewable);
+      return attributes;
     }
+
+  return NULL;
 }
diff --git a/app/core/gimpimage-metadata.h b/app/core/gimpimage-metadata.h
index 1f90d34..77bb083 100644
--- a/app/core/gimpimage-metadata.h
+++ b/app/core/gimpimage-metadata.h
@@ -19,10 +19,10 @@
 #define __GIMP_IMAGE_METADATA_H__
 
 
-GimpMetadata * gimp_image_get_metadata (GimpImage    *image);
-void           gimp_image_set_metadata (GimpImage    *image,
-                                        GimpMetadata *metadata,
-                                        gboolean      push_undo);
+void              gimp_image_set_attributes  (GimpImage      *image,
+                                              GimpAttributes *attributes,
+                                              gboolean        push_undo);
+GimpAttributes *  gimp_image_get_attributes  (GimpImage      *image);
 
 
 #endif /* __GIMP_IMAGE_METADATA_H__ */
diff --git a/app/core/gimpimage-undo-push.c b/app/core/gimpimage-undo-push.c
index 066f35a..26f7042 100644
--- a/app/core/gimpimage-undo-push.c
+++ b/app/core/gimpimage-undo-push.c
@@ -49,6 +49,8 @@
 #include "gimpsamplepoint.h"
 #include "gimpsamplepointundo.h"
 #include "gimpselection.h"
+#include "gimpviewable.h"
+#include "gimpviewableundo.h"
 
 #include "text/gimptextlayer.h"
 #include "text/gimptextundo.h"
@@ -149,17 +151,32 @@ gimp_image_undo_push_image_colormap (GimpImage   *image,
 }
 
 GimpUndo *
-gimp_image_undo_push_image_metadata (GimpImage   *image,
+gimp_image_undo_push_image_attributes (GimpImage   *image,
                                      const gchar *undo_desc)
 {
   g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
 
   return gimp_image_undo_push (image, GIMP_TYPE_IMAGE_UNDO,
-                               GIMP_UNDO_IMAGE_METADATA, undo_desc,
+                               GIMP_UNDO_IMAGE_ATTRIBUTES, undo_desc,
                                GIMP_DIRTY_IMAGE_META,
                                NULL);
 }
 
+
+GimpUndo *
+gimp_image_undo_push_item_attributes (GimpImage    *image,
+                                      const gchar  *undo_desc,
+                                      GimpItem     *item)
+{
+  g_return_val_if_fail (GIMP_IS_IMAGE (image), NULL);
+
+  return gimp_image_undo_push (image, GIMP_TYPE_ITEM_UNDO,
+                               GIMP_UNDO_ITEM_ATTRIBUTES, undo_desc,
+                               GIMP_DIRTY_IMAGE_META,
+                               "item", item,
+                               NULL);
+}
+
 GimpUndo *
 gimp_image_undo_push_image_parasite (GimpImage          *image,
                                      const gchar        *undo_desc,
diff --git a/app/core/gimpimage-undo-push.h b/app/core/gimpimage-undo-push.h
index 28d463d..390ba73 100644
--- a/app/core/gimpimage-undo-push.h
+++ b/app/core/gimpimage-undo-push.h
@@ -38,7 +38,7 @@ GimpUndo * gimp_image_undo_push_image_grid          (GimpImage     *image,
                                                      GimpGrid      *grid);
 GimpUndo * gimp_image_undo_push_image_colormap      (GimpImage     *image,
                                                      const gchar   *undo_desc);
-GimpUndo * gimp_image_undo_push_image_metadata      (GimpImage     *image,
+GimpUndo * gimp_image_undo_push_image_attributes    (GimpImage     *image,
                                                      const gchar   *undo_desc);
 GimpUndo * gimp_image_undo_push_image_parasite      (GimpImage     *image,
                                                      const gchar   *undo_desc,
@@ -113,6 +113,9 @@ GimpUndo * gimp_image_undo_push_item_parasite_remove(GimpImage     *image,
                                                      const gchar   *undo_desc,
                                                      GimpItem      *item,
                                                      const gchar   *name);
+GimpUndo * gimp_image_undo_push_item_attributes     (GimpImage     *image,
+                                                     const gchar   *undo_desc,
+                                                     GimpItem      *item);
 
 
 /*  layer undos  */
@@ -229,5 +232,4 @@ GimpUndo * gimp_image_undo_push_fs_to_layer         (GimpImage     *image,
 GimpUndo * gimp_image_undo_push_cantundo            (GimpImage     *image,
                                                      const gchar   *undo_desc);
 
-
 #endif  /* __GIMP_IMAGE_UNDO_PUSH_H__ */
diff --git a/app/core/gimpimage.c b/app/core/gimpimage.c
index 3a45bb0..bf6a937 100644
--- a/app/core/gimpimage.c
+++ b/app/core/gimpimage.c
@@ -848,7 +848,6 @@ gimp_image_set_property (GObject      *object,
     case PROP_PRECISION:
       private->precision = g_value_get_enum (value);
       break;
-    case PROP_METADATA:
     case PROP_BUFFER:
     default:
       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
@@ -885,9 +884,6 @@ gimp_image_get_property (GObject    *object,
     case PROP_PRECISION:
       g_value_set_enum (value, private->precision);
       break;
-    case PROP_METADATA:
-      g_value_set_object (value, gimp_image_get_metadata (image));
-      break;
     case PROP_BUFFER:
       g_value_set_object (value, gimp_image_get_buffer (GIMP_PICKABLE (image)));
       break;
@@ -1191,10 +1187,10 @@ gimp_image_get_size (GimpViewable *viewable,
 static void
 gimp_image_size_changed (GimpViewable *viewable)
 {
-  GimpImage    *image = GIMP_IMAGE (viewable);
-  GimpMetadata *metadata;
-  GList        *all_items;
-  GList        *list;
+  GimpImage      *image = GIMP_IMAGE (viewable);
+  GimpAttributes *attributes;
+  GList          *all_items;
+  GList          *list;
 
   if (GIMP_VIEWABLE_CLASS (parent_class)->size_changed)
     GIMP_VIEWABLE_CLASS (parent_class)->size_changed (viewable);
@@ -1219,12 +1215,15 @@ gimp_image_size_changed (GimpViewable *viewable)
 
   gimp_viewable_size_changed (GIMP_VIEWABLE (gimp_image_get_mask (image)));
 
-  metadata = gimp_image_get_metadata (image);
-  if (metadata)
-    gimp_metadata_set_pixel_size (metadata,
-                                  gimp_image_get_width  (image),
-                                  gimp_image_get_height (image));
+  attributes = gimp_image_get_attributes (image);
 
+  if (attributes)
+    {
+      gimp_attributes_set_pixel_size (attributes,
+                                      gimp_image_get_width  (image),
+                                      gimp_image_get_height (image));
+
+    }
   gimp_projectable_structure_changed (GIMP_PROJECTABLE (image));
 }
 
@@ -1251,31 +1250,32 @@ gimp_image_real_mode_changed (GimpImage *image)
 static void
 gimp_image_real_precision_changed (GimpImage *image)
 {
-  GimpMetadata *metadata;
+  GimpAttributes *attributes;
 
-  metadata = gimp_image_get_metadata (image);
-  if (metadata)
+  attributes = gimp_image_get_attributes (image);
+
+  if (attributes)
     {
       switch (gimp_image_get_component_type (image))
-        {
+      {
         case GIMP_COMPONENT_TYPE_U8:
-          gimp_metadata_set_bits_per_sample (metadata, 8);
+          gimp_attributes_set_bits_per_sample (attributes, 8);
           break;
 
         case GIMP_COMPONENT_TYPE_U16:
         case GIMP_COMPONENT_TYPE_HALF:
-          gimp_metadata_set_bits_per_sample (metadata, 16);
+          gimp_attributes_set_bits_per_sample (attributes, 16);
           break;
 
         case GIMP_COMPONENT_TYPE_U32:
         case GIMP_COMPONENT_TYPE_FLOAT:
-          gimp_metadata_set_bits_per_sample (metadata, 32);
+          gimp_attributes_set_bits_per_sample (attributes, 32);
           break;
 
         case GIMP_COMPONENT_TYPE_DOUBLE:
-          gimp_metadata_set_bits_per_sample (metadata, 64);
+          gimp_attributes_set_bits_per_sample (attributes, 64);
           break;
-        }
+      }
     }
 
   gimp_projectable_structure_changed (GIMP_PROJECTABLE (image));
@@ -1284,16 +1284,17 @@ gimp_image_real_precision_changed (GimpImage *image)
 static void
 gimp_image_real_resolution_changed (GimpImage *image)
 {
-  GimpMetadata *metadata;
+  GimpAttributes *attributes;
 
-  metadata = gimp_image_get_metadata (image);
-  if (metadata)
+  attributes = gimp_image_get_attributes (image);
+
+  if (attributes)
     {
       gdouble xres, yres;
 
       gimp_image_get_resolution (image, &xres, &yres);
-      gimp_metadata_set_resolution (metadata, xres, yres,
-                                    gimp_image_get_unit (image));
+      gimp_attributes_set_resolution (attributes, xres, yres,
+                                      gimp_image_get_unit (image));
     }
 }
 
@@ -1314,16 +1315,17 @@ gimp_image_real_size_changed_detailed (GimpImage *image,
 static void
 gimp_image_real_unit_changed (GimpImage *image)
 {
-  GimpMetadata *metadata;
+  GimpAttributes *attributes;
+
+  attributes = gimp_image_get_attributes (image);
 
-  metadata = gimp_image_get_metadata (image);
-  if (metadata)
+  if (attributes)
     {
       gdouble xres, yres;
 
       gimp_image_get_resolution (image, &xres, &yres);
-      gimp_metadata_set_resolution (metadata, xres, yres,
-                                    gimp_image_get_unit (image));
+      gimp_attributes_set_resolution (attributes, xres, yres,
+                                      gimp_image_get_unit (image));
     }
 }
 
@@ -2322,10 +2324,6 @@ gimp_image_get_xcf_version (GimpImage    *image,
         version = MAX (3, version);
     }
 
-  /* need version 6 for new metadata */
-  if (gimp_image_get_metadata (image))
-    version = MAX (6, version);
-
   /* need version 7 for high bit depth images */
   if (gimp_image_get_precision (image) != GIMP_PRECISION_U8_GAMMA)
     version = MAX (7, version);
diff --git a/app/core/gimpimageundo.c b/app/core/gimpimageundo.c
index dea3570..ce1cca7 100644
--- a/app/core/gimpimageundo.c
+++ b/app/core/gimpimageundo.c
@@ -188,9 +188,9 @@ gimp_image_undo_constructed (GObject *object)
                                          GIMP_IMAGE_COLORMAP_SIZE);
       break;
 
-    case GIMP_UNDO_IMAGE_METADATA:
-      image_undo->metadata =
-        gimp_metadata_duplicate (gimp_image_get_metadata (image));
+    case GIMP_UNDO_IMAGE_ATTRIBUTES:
+      image_undo->attributes =
+        gimp_attributes_duplicate (gimp_image_get_attributes (image));
       break;
 
     case GIMP_UNDO_PARASITE_ATTACH:
@@ -291,8 +291,8 @@ gimp_image_undo_get_memsize (GimpObject *object,
   if (image_undo->colormap)
     memsize += GIMP_IMAGE_COLORMAP_SIZE;
 
-  if (image_undo->metadata)
-    memsize += gimp_g_object_get_memsize (G_OBJECT (image_undo->metadata));
+  if (image_undo->attributes)
+    memsize += gimp_g_object_get_memsize (G_OBJECT (image_undo->attributes));
 
   memsize += gimp_object_get_memsize (GIMP_OBJECT (image_undo->grid),
                                       gui_size);
@@ -457,17 +457,17 @@ gimp_image_undo_pop (GimpUndo            *undo,
       }
       break;
 
-    case GIMP_UNDO_IMAGE_METADATA:
+    case GIMP_UNDO_IMAGE_ATTRIBUTES:
       {
-        GimpMetadata *metadata;
+        GimpAttributes *attributes;
 
-        metadata = gimp_metadata_duplicate (gimp_image_get_metadata (image));
+        attributes = gimp_attributes_duplicate (gimp_image_get_attributes (image));
 
-        gimp_image_set_metadata (image, image_undo->metadata, FALSE);
+        gimp_image_set_attributes (image, image_undo->attributes, FALSE);
 
-        if (image_undo->metadata)
-          g_object_unref (image_undo->metadata);
-        image_undo->metadata = metadata;
+        if (image_undo->attributes)
+          g_object_unref (image_undo->attributes);
+        image_undo->attributes = attributes;
       }
       break;
 
@@ -519,10 +519,10 @@ gimp_image_undo_free (GimpUndo     *undo,
       image_undo->colormap = NULL;
     }
 
-  if (image_undo->metadata)
+  if (image_undo->attributes)
     {
-      g_object_unref (image_undo->metadata);
-      image_undo->metadata = NULL;
+      g_object_unref (image_undo->attributes);
+      image_undo->attributes = NULL;
     }
 
   if (image_undo->parasite_name)
diff --git a/app/core/gimpimageundo.h b/app/core/gimpimageundo.h
index b6a9b01..3bc52e8 100644
--- a/app/core/gimpimageundo.h
+++ b/app/core/gimpimageundo.h
@@ -50,7 +50,7 @@ struct _GimpImageUndo
   GimpGrid          *grid;
   gint               num_colors;
   guchar            *colormap;
-  GimpMetadata      *metadata;
+  GimpAttributes    *attributes;
   gchar             *parasite_name;
   GimpParasite      *parasite;
 };
diff --git a/app/core/gimpitem-metadata.c b/app/core/gimpitem-metadata.c
new file mode 100644
index 0000000..ee9bfbd
--- /dev/null
+++ b/app/core/gimpitem-metadata.c
@@ -0,0 +1,73 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "core-types.h"
+
+#include "gimpimage.h"
+#include "gimpitem.h"
+#include "gimpitem-metadata.h"
+
+
+/* public functions */
+
+void
+gimp_item_set_attributes (GimpItem *item,
+                          GimpAttributes *attributes,
+                          gboolean        push_undo)
+{
+  GimpViewable *viewable;
+
+  g_return_if_fail (GIMP_IS_ITEM (item));
+
+  if (push_undo)
+    gimp_image_undo_push_item_attributes (gimp_item_get_image (item),
+                                          NULL,
+                                          item);
+
+  viewable = GIMP_VIEWABLE (item);
+
+  if (viewable)
+    {
+      gimp_viewable_set_attributes (viewable, attributes);
+    }
+}
+
+GimpAttributes *
+gimp_item_get_attributes (GimpItem *item)
+{
+  GimpViewable   *viewable;
+  GimpAttributes *attributes;
+
+  g_return_val_if_fail (GIMP_IS_ITEM (item), NULL);
+
+  viewable = GIMP_VIEWABLE (item);
+
+  if (viewable)
+    {
+      attributes = gimp_viewable_get_attributes (viewable);
+      return attributes;
+    }
+
+  return NULL;
+}
diff --git a/app/core/gimpitem-metadata.h b/app/core/gimpitem-metadata.h
new file mode 100644
index 0000000..df2d0b1
--- /dev/null
+++ b/app/core/gimpitem-metadata.h
@@ -0,0 +1,28 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_ITEM_METADATA_H__
+#define __GIMP_ITEM_METADATA_H__
+
+
+void              gimp_item_set_attributes  (GimpItem       *item,
+                                             GimpAttributes *attributes,
+                                             gboolean        push_undo);
+GimpAttributes *  gimp_item_get_attributes  (GimpItem       *item);
+
+
+#endif /* __GIMP_ITEM_METADATA_H__ */
diff --git a/app/core/gimpitemundo.c b/app/core/gimpitemundo.c
index 34c9539..aceb6c7 100644
--- a/app/core/gimpitemundo.c
+++ b/app/core/gimpitemundo.c
@@ -22,8 +22,11 @@
 
 #include "core-types.h"
 
+#include "libgimpbase/gimpbase.h"
+
 #include "gimpimage.h"
 #include "gimpitem.h"
+#include "gimpitem-metadata.h"
 #include "gimpitemundo.h"
 
 
@@ -34,18 +37,21 @@ enum
 };
 
 
-static void   gimp_item_undo_constructed  (GObject      *object);
-static void   gimp_item_undo_set_property (GObject      *object,
-                                           guint         property_id,
-                                           const GValue *value,
-                                           GParamSpec   *pspec);
-static void   gimp_item_undo_get_property (GObject      *object,
-                                           guint         property_id,
-                                           GValue       *value,
-                                           GParamSpec   *pspec);
+static void   gimp_item_undo_constructed  (GObject             *object);
+static void   gimp_item_undo_set_property (GObject             *object,
+                                           guint                property_id,
+                                           const GValue        *value,
+                                           GParamSpec          *pspec);
+static void   gimp_item_undo_get_property (GObject             *object,
+                                           guint                property_id,
+                                           GValue              *value,
+                                           GParamSpec          *pspec);
 
-static void   gimp_item_undo_free         (GimpUndo     *undo,
-                                           GimpUndoMode  undo_mode);
+static void   gimp_item_undo_free         (GimpUndo            *undo,
+                                           GimpUndoMode         undo_mode);
+static void   gimp_item_undo_pop          (GimpUndo            *undo,
+                                           GimpUndoMode         undo_mode,
+                                           GimpUndoAccumulator *accum);
 
 
 G_DEFINE_TYPE (GimpItemUndo, gimp_item_undo, GIMP_TYPE_UNDO)
@@ -63,6 +69,7 @@ gimp_item_undo_class_init (GimpItemUndoClass *klass)
   object_class->set_property = gimp_item_undo_set_property;
   object_class->get_property = gimp_item_undo_get_property;
 
+  undo_class->pop            = gimp_item_undo_pop;
   undo_class->free           = gimp_item_undo_free;
 
   g_object_class_install_property (object_class, PROP_ITEM,
@@ -84,7 +91,14 @@ gimp_item_undo_constructed (GObject *object)
 
   G_OBJECT_CLASS (parent_class)->constructed (object);
 
-  g_assert (GIMP_IS_ITEM (item_undo->item));
+  switch (GIMP_UNDO (object)->undo_type)
+  {
+    case GIMP_UNDO_ITEM_ATTRIBUTES:
+      item_undo->attributes =
+          gimp_attributes_duplicate (gimp_item_get_attributes (item_undo->item));
+      break;
+  }
+
 }
 
 static void
@@ -139,5 +153,41 @@ gimp_item_undo_free (GimpUndo     *undo,
       item_undo->item = NULL;
     }
 
+  if (item_undo->attributes)
+    {
+      g_object_unref (item_undo->attributes);
+      item_undo->attributes = NULL;
+    }
+
   GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode);
 }
+
+static void
+gimp_item_undo_pop     (GimpUndo            *undo,
+                        GimpUndoMode         undo_mode,
+                        GimpUndoAccumulator *accum)
+{
+  GimpItemUndo   *item_undo  = GIMP_ITEM_UNDO (undo);
+  GimpItem       *item       = GIMP_ITEM_UNDO (undo)->item;
+
+  switch (undo->undo_type)
+    {
+    case GIMP_UNDO_ITEM_ATTRIBUTES:
+      {
+        GimpAttributes *attributes;
+
+        attributes = gimp_attributes_duplicate (gimp_item_get_attributes (item));
+
+        gimp_item_set_attributes (item, item_undo->attributes, FALSE);
+
+        if (item_undo->attributes)
+          g_object_unref (item_undo->attributes);
+        item_undo->attributes = attributes;
+      }
+      break;
+
+    default:
+      g_assert_not_reached ();
+
+    }
+}
diff --git a/app/core/gimpitemundo.h b/app/core/gimpitemundo.h
index 2c137b4..4b002d9 100644
--- a/app/core/gimpitemundo.h
+++ b/app/core/gimpitemundo.h
@@ -37,6 +37,8 @@ struct _GimpItemUndo
   GimpUndo  parent_instance;
 
   GimpItem *item;  /* the item this undo is for */
+  GimpAttributes    *attributes; 
+
 };
 
 struct _GimpItemUndoClass
diff --git a/app/core/gimplayer.c b/app/core/gimplayer.c
index af47dd0..5ca547f 100644
--- a/app/core/gimplayer.c
+++ b/app/core/gimplayer.c
@@ -705,7 +705,9 @@ static GimpItem *
 gimp_layer_duplicate (GimpItem *item,
                       GType     new_type)
 {
-  GimpItem *new_item;
+  GimpItem       *new_item;
+  GimpAttributes *attributes;
+  GimpAttributes *new_attributes;
 
   g_return_val_if_fail (g_type_is_a (new_type, GIMP_TYPE_DRAWABLE), NULL);
 
@@ -736,6 +738,14 @@ gimp_layer_duplicate (GimpItem *item,
           new_layer->edit_mask  = layer->edit_mask;
           new_layer->show_mask  = layer->show_mask;
         }
+
+      attributes = gimp_viewable_get_attributes (GIMP_VIEWABLE (layer));
+      if (attributes)
+        {
+          new_attributes = gimp_attributes_duplicate (attributes);
+          gimp_viewable_set_attributes (GIMP_VIEWABLE (new_layer), new_attributes);
+          g_object_unref (new_attributes);
+        }
     }
 
   return new_item;
diff --git a/app/core/gimpviewable.c b/app/core/gimpviewable.c
index 319a284..2d357cf 100644
--- a/app/core/gimpviewable.c
+++ b/app/core/gimpviewable.c
@@ -26,6 +26,7 @@
 #include <gdk-pixbuf/gdk-pixbuf.h>
 #include <gegl.h>
 
+#include "libgimpbase/gimpbase.h"
 #include "libgimpcolor/gimpcolor.h"
 #include "libgimpmath/gimpmath.h"
 #include "libgimpconfig/gimpconfig.h"
@@ -125,7 +126,6 @@ static gboolean gimp_viewable_deserialize_property   (GimpConfig       *config,
                                                       GScanner         *scanner,
                                                       GTokenType       *expected);
 
-
 G_DEFINE_TYPE_WITH_CODE (GimpViewable, gimp_viewable, GIMP_TYPE_OBJECT,
                          G_IMPLEMENT_INTERFACE (GIMP_TYPE_CONFIG,
                                                 gimp_viewable_config_iface_init))
@@ -210,6 +210,7 @@ gimp_viewable_class_init (GimpViewableClass *klass)
 static void
 gimp_viewable_init (GimpViewable *viewable)
 {
+  viewable->attributes = NULL;
 }
 
 static void
@@ -222,6 +223,7 @@ gimp_viewable_config_iface_init (GimpConfigInterface *iface)
 static void
 gimp_viewable_finalize (GObject *object)
 {
+  GimpViewable        *viewable = GIMP_VIEWABLE (object);
   GimpViewablePrivate *private = GET_PRIVATE (object);
 
   if (private->icon_name)
@@ -247,6 +249,11 @@ gimp_viewable_finalize (GObject *object)
       g_object_unref (private->preview_pixbuf);
       private->preview_pixbuf = NULL;
     }
+  if (viewable->attributes)
+    {
+      g_object_unref (viewable->attributes);
+      viewable->attributes = NULL;
+    }
 
   G_OBJECT_CLASS (parent_class)->finalize (object);
 }
@@ -575,8 +582,23 @@ gimp_viewable_invalidate_preview (GimpViewable *viewable)
 void
 gimp_viewable_size_changed (GimpViewable *viewable)
 {
+  GimpAttributes *attributes = NULL;
+  gint width, height;
+
   g_return_if_fail (GIMP_IS_VIEWABLE (viewable));
 
+  gimp_viewable_get_size (viewable, &width, &height);
+
+  attributes = gimp_viewable_get_attributes (viewable);
+
+  if (attributes)
+    {
+      gimp_attributes_set_pixel_size (attributes,
+                                      width,
+                                      height);
+
+    }
+
   g_signal_emit (viewable, viewable_signals[SIZE_CHANGED], 0);
 }
 
@@ -1300,6 +1322,28 @@ gimp_viewable_set_expanded (GimpViewable *viewable,
     GIMP_VIEWABLE_GET_CLASS (viewable)->set_expanded (viewable, expanded);
 }
 
+void 
+gimp_viewable_set_attributes (GimpViewable   *viewable,
+                              GimpAttributes *attributes)
+{
+  g_return_if_fail (GIMP_IS_VIEWABLE (viewable));
+
+  if (attributes)
+    {
+
+      viewable->attributes = attributes;
+      g_object_ref (viewable->attributes);
+    }
+}
+
+GimpAttributes *
+gimp_viewable_get_attributes (GimpViewable  *viewable)
+{
+  g_return_val_if_fail (GIMP_IS_VIEWABLE (viewable), NULL);
+
+  return viewable->attributes;
+}
+
 gboolean
 gimp_viewable_is_ancestor (GimpViewable *ancestor,
                            GimpViewable *descendant)
diff --git a/app/core/gimpviewable.h b/app/core/gimpviewable.h
index cb55175..b8a1332 100644
--- a/app/core/gimpviewable.h
+++ b/app/core/gimpviewable.h
@@ -43,7 +43,8 @@ typedef struct _GimpViewableClass GimpViewableClass;
 
 struct _GimpViewable
 {
-  GimpObject  parent_instance;
+  GimpObject       parent_instance;
+  GimpAttributes  *attributes;
 };
 
 struct _GimpViewableClass
@@ -97,6 +98,7 @@ struct _GimpViewableClass
   void            (* set_expanded)       (GimpViewable  *viewable,
                                           gboolean       expand);
   gboolean        (* get_expanded)       (GimpViewable  *viewable);
+
 };
 
 
@@ -179,7 +181,10 @@ GimpContainer * gimp_viewable_get_children       (GimpViewable  *viewable);
 gboolean        gimp_viewable_get_expanded       (GimpViewable  *viewable);
 void            gimp_viewable_set_expanded       (GimpViewable  *viewable,
                                                   gboolean       expanded);
-
+void            gimp_viewable_set_attributes     (GimpViewable  *viewable,
+                                                  GimpAttributes *attributes);
+GimpAttributes *
+                gimp_viewable_get_attributes     (GimpViewable  *viewable);
 gboolean        gimp_viewable_is_ancestor        (GimpViewable  *ancestor,
                                                   GimpViewable  *descendant);
 
diff --git a/app/core/gimpviewableundo.c b/app/core/gimpviewableundo.c
new file mode 100644
index 0000000..a62e92c
--- /dev/null
+++ b/app/core/gimpviewableundo.c
@@ -0,0 +1,175 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gdk-pixbuf/gdk-pixbuf.h>
+#include <gegl.h>
+
+#include "libgimpbase/gimpbase.h"
+
+#include "core-types.h"
+
+#include "gimpviewable.h"
+#include "gimpviewableundo.h"
+
+
+enum
+{
+  PROP_0,
+  PROP_VIEWABLE
+};
+
+
+static void   gimp_viewable_undo_constructed  (GObject      *object);
+static void   gimp_viewable_undo_set_property (GObject      *object,
+                                           guint         property_id,
+                                           const GValue *value,
+                                           GParamSpec   *pspec);
+static void   gimp_viewable_undo_get_property (GObject      *object,
+                                           guint         property_id,
+                                           GValue       *value,
+                                           GParamSpec   *pspec);
+
+static void   gimp_viewable_undo_free         (GimpUndo     *undo,
+                                           GimpUndoMode  undo_mode);
+
+
+G_DEFINE_TYPE (GimpViewableUndo, gimp_viewable_undo, GIMP_TYPE_UNDO)
+
+#define parent_class gimp_viewable_undo_parent_class
+
+
+static void
+gimp_viewable_undo_class_init (GimpViewableUndoClass *klass)
+{
+  GObjectClass  *object_class = G_OBJECT_CLASS (klass);
+  GimpUndoClass *undo_class   = GIMP_UNDO_CLASS (klass);
+
+  object_class->constructed  = gimp_viewable_undo_constructed;
+  object_class->set_property = gimp_viewable_undo_set_property;
+  object_class->get_property = gimp_viewable_undo_get_property;
+
+  undo_class->pop            = gimp_viewable_undo_pop;
+  undo_class->free           = gimp_viewable_undo_free;
+
+  g_object_class_install_property (object_class, PROP_VIEWABLE,
+                                   g_param_spec_object ("viewable", NULL, NULL,
+                                                        GIMP_TYPE_VIEWABLE,
+                                                        GIMP_PARAM_READWRITE |
+                                                        G_PARAM_CONSTRUCT_ONLY));
+}
+
+static void
+gimp_viewable_undo_init (GimpViewableUndo *undo)
+{
+}
+
+static void
+gimp_viewable_undo_constructed (GObject *object)
+{
+  GimpViewableUndo *viewable_undo = GIMP_VIEWABLE_UNDO (object);
+
+  G_OBJECT_CLASS (parent_class)->constructed (object);
+
+  g_assert (GIMP_IS_VIEWABLE (viewable_undo->viewable));
+}
+
+static void
+gimp_viewable_undo_set_property (GObject      *object,
+                             guint         property_id,
+                             const GValue *value,
+                             GParamSpec   *pspec)
+{
+  GimpViewableUndo *viewable_undo = GIMP_VIEWABLE_UNDO (object);
+
+  switch (property_id)
+    {
+    case PROP_VIEWABLE:
+      viewable_undo->viewable = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_viewable_undo_get_property (GObject    *object,
+                             guint       property_id,
+                             GValue     *value,
+                             GParamSpec *pspec)
+{
+  GimpViewableUndo *viewable_undo = GIMP_VIEWABLE_UNDO (object);
+
+  switch (property_id)
+    {
+    case PROP_VIEWABLE:
+      g_value_set_object (value, viewable_undo->viewable);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+      break;
+    }
+}
+
+static void
+gimp_viewable_undo_free (GimpUndo     *undo,
+                     GimpUndoMode  undo_mode)
+{
+  GimpViewableUndo *viewable_undo = GIMP_VIEWABLE_UNDO (undo);
+
+  if (viewable_undo->viewable)
+    {
+      g_object_unref (viewable_undo->viewable);
+      viewable_undo->viewable = NULL;
+    }
+
+  GIMP_UNDO_CLASS (parent_class)->free (undo, undo_mode);
+}
+
+static void
+gimp_viewable_undo_pop (GimpUndo            *undo,
+                        GimpUndoMode         undo_mode,
+                        GimpUndoAccumulator *accum)
+{
+  GimpViewableUndo *viewable_undo  = GIMP_VIEWABLE_UNDO (undo);
+  GimpViewable     *viewable       = GIMP_VIEWABLE_UNDO (undo)->viewable;
+
+  switch (undo->undo_type)
+    {
+    case GIMP_UNDO_IMAGE_ATTRIBUTES:
+      {
+        GimpAttributes *attributes;
+
+        attributes = gimp_attributes_duplicate (gimp_image_get_attributes (image));
+
+        gimp_image_set_attributes (image, image_undo->attributes, FALSE);
+
+        if (image_undo->attributes)
+          g_object_unref (image_undo->attributes);
+        image_undo->attributes = attributes;
+      }
+      break;
+
+    default:
+      g_assert_not_reached ();
+
+    }
+}
\ No newline at end of file
diff --git a/app/core/gimpviewableundo.h b/app/core/gimpviewableundo.h
new file mode 100644
index 0000000..848098c
--- /dev/null
+++ b/app/core/gimpviewableundo.h
@@ -0,0 +1,51 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GIMP_VIEWABLE_UNDO_H__
+#define __GIMP_VIEWABLE_UNDO_H__
+
+
+#include "gimpundo.h"
+
+
+#define GIMP_TYPE_VIEWABLE_UNDO            (gimp_viewable_undo_get_type ())
+#define GIMP_VIEWABLE_UNDO(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_VIEWABLE_UNDO, 
GimpViewableUndo))
+#define GIMP_VIEWABLE_UNDO_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_VIEWABLE_UNDO, 
GimpViewableUndoClass))
+#define GIMP_IS_VIEWABLE_UNDO(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_VIEWABLE_UNDO))
+#define GIMP_IS_VIEWABLE_UNDO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_VIEWABLE_UNDO))
+#define GIMP_VIEWABLE_UNDO_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_VIEWABLE_UNDO, 
GimpViewableUndoClass))
+
+
+typedef struct _GimpViewableUndoClass GimpViewableUndoClass;
+
+struct _GimpViewableUndo
+{
+  GimpUndo  parent_instance;
+
+  GimpViewable *viewable;  /* the viewable this undo is for */
+};
+
+struct _GimpViewableUndoClass
+{
+  GimpUndoClass  parent_class;
+};
+
+
+GType   gimp_viewable_undo_get_type (void) G_GNUC_CONST;
+
+
+#endif /* __GIMP_VIEWABLE_UNDO_H__ */
diff --git a/app/file/file-open.c b/app/file/file-open.c
index 59f0000..39c6d93 100644
--- a/app/file/file-open.c
+++ b/app/file/file-open.c
@@ -139,7 +139,7 @@ file_open_image (Gimp                *gimp,
                                                G_FILE_ATTRIBUTE_ACCESS_CAN_READ))
         {
           g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_FAILED,
-                               _("Premission denied"));
+                               _("Permission denied"));
           return NULL;
         }
     }
diff --git a/app/pdb/image-cmds.c b/app/pdb/image-cmds.c
index 1633473..ecd63f0 100644
--- a/app/pdb/image-cmds.c
+++ b/app/pdb/image-cmds.c
@@ -1707,64 +1707,64 @@ image_set_colormap_invoker (GimpProcedure         *procedure,
 }
 
 static GimpValueArray *
-image_get_metadata_invoker (GimpProcedure         *procedure,
-                            Gimp                  *gimp,
-                            GimpContext           *context,
-                            GimpProgress          *progress,
-                            const GimpValueArray  *args,
-                            GError               **error)
+image_set_attributes_invoker (GimpProcedure         *procedure,
+                              Gimp                  *gimp,
+                              GimpContext           *context,
+                              GimpProgress          *progress,
+                              const GimpValueArray  *args,
+                              GError               **error)
 {
   gboolean success = TRUE;
-  GimpValueArray *return_vals;
   GimpImage *image;
-  gchar *metadata_string = NULL;
+  const gchar *attributes_string;
 
   image = gimp_value_get_image (gimp_value_array_index (args, 0), gimp);
+  attributes_string = g_value_get_string (gimp_value_array_index (args, 1));
 
   if (success)
     {
-      GimpMetadata *metadata = gimp_image_get_metadata (image);
+      GimpAttributes *attributes = gimp_attributes_deserialize (attributes_string);
 
-      if (metadata)
-        metadata_string = gimp_metadata_serialize (metadata);
-    }
-
-  return_vals = gimp_procedure_get_return_values (procedure, success,
-                                                  error ? *error : NULL);
+      gimp_image_set_attributes (image, attributes, TRUE);
 
-  if (success)
-    g_value_take_string (gimp_value_array_index (return_vals, 1), metadata_string);
+      if (attributes)
+        g_object_unref (attributes);
+    }
 
-  return return_vals;
+  return gimp_procedure_get_return_values (procedure, success,
+                                           error ? *error : NULL);
 }
 
 static GimpValueArray *
-image_set_metadata_invoker (GimpProcedure         *procedure,
-                            Gimp                  *gimp,
-                            GimpContext           *context,
-                            GimpProgress          *progress,
-                            const GimpValueArray  *args,
-                            GError               **error)
+image_get_attributes_invoker (GimpProcedure         *procedure,
+                              Gimp                  *gimp,
+                              GimpContext           *context,
+                              GimpProgress          *progress,
+                              const GimpValueArray  *args,
+                              GError               **error)
 {
   gboolean success = TRUE;
+  GimpValueArray *return_vals;
   GimpImage *image;
-  const gchar *metadata_string;
+  gchar *attributes_string = NULL;
 
   image = gimp_value_get_image (gimp_value_array_index (args, 0), gimp);
-  metadata_string = g_value_get_string (gimp_value_array_index (args, 1));
 
   if (success)
     {
-      GimpMetadata *metadata = gimp_metadata_deserialize (metadata_string);
-
-      gimp_image_set_metadata (image, metadata, TRUE);
+      GimpAttributes *attributes = gimp_image_get_attributes (image);
 
-      if (metadata)
-        g_object_unref (metadata);
+      if (attributes)
+        attributes_string = gimp_attributes_serialize (attributes);
     }
 
-  return gimp_procedure_get_return_values (procedure, success,
-                                           error ? *error : NULL);
+  return_vals = gimp_procedure_get_return_values (procedure, success,
+                                                  error ? *error : NULL);
+
+  if (success)
+    g_value_take_string (gimp_value_array_index (return_vals, 1), attributes_string);
+
+  return return_vals;
 }
 
 static GimpValueArray *
@@ -4622,15 +4622,15 @@ register_image_procs (GimpPDB *pdb)
   g_object_unref (procedure);
 
   /*
-   * gimp-image-get-metadata
+   * gimp-image-set-attributes
    */
-  procedure = gimp_procedure_new (image_get_metadata_invoker);
+  procedure = gimp_procedure_new (image_set_attributes_invoker);
   gimp_object_set_static_name (GIMP_OBJECT (procedure),
-                               "gimp-image-get-metadata");
+                               "gimp-image-set-attributes");
   gimp_procedure_set_static_strings (procedure,
-                                     "gimp-image-get-metadata",
-                                     "Returns the image's metadata.",
-                                     "Returns exif/iptc/xmp metadata from the image.",
+                                     "gimp-image-set-attributes",
+                                     "Set the image's attributes.",
+                                     "Sets attributes on the image.",
                                      "Spencer Kimball & Peter Mattis",
                                      "Spencer Kimball & Peter Mattis",
                                      "1995-1996",
@@ -4641,26 +4641,26 @@ register_image_procs (GimpPDB *pdb)
                                                          "The image",
                                                          pdb->gimp, FALSE,
                                                          GIMP_PARAM_READWRITE));
-  gimp_procedure_add_return_value (procedure,
-                                   gimp_param_spec_string ("metadata-string",
-                                                           "metadata string",
-                                                           "The exif/ptc/xmp metadata as a string",
-                                                           FALSE, FALSE, FALSE,
-                                                           NULL,
-                                                           GIMP_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_string ("attributes-string",
+                                                       "attributes string",
+                                                       "The attributes as a xml string",
+                                                       FALSE, FALSE, FALSE,
+                                                       NULL,
+                                                       GIMP_PARAM_READWRITE));
   gimp_pdb_register_procedure (pdb, procedure);
   g_object_unref (procedure);
 
   /*
-   * gimp-image-set-metadata
+   * gimp-image-get-attributes
    */
-  procedure = gimp_procedure_new (image_set_metadata_invoker);
+  procedure = gimp_procedure_new (image_get_attributes_invoker);
   gimp_object_set_static_name (GIMP_OBJECT (procedure),
-                               "gimp-image-set-metadata");
+                               "gimp-image-get-attributes");
   gimp_procedure_set_static_strings (procedure,
-                                     "gimp-image-set-metadata",
-                                     "Set the image's metadata.",
-                                     "Sets exif/iptc/xmp metadata on the image.",
+                                     "gimp-image-get-attributes",
+                                     "Returns the image's attributes.",
+                                     "Returns attributes from the image.",
                                      "Spencer Kimball & Peter Mattis",
                                      "Spencer Kimball & Peter Mattis",
                                      "1995-1996",
@@ -4671,13 +4671,13 @@ register_image_procs (GimpPDB *pdb)
                                                          "The image",
                                                          pdb->gimp, FALSE,
                                                          GIMP_PARAM_READWRITE));
-  gimp_procedure_add_argument (procedure,
-                               gimp_param_spec_string ("metadata-string",
-                                                       "metadata string",
-                                                       "The exif/ptc/xmp metadata as a string",
-                                                       FALSE, FALSE, FALSE,
-                                                       NULL,
-                                                       GIMP_PARAM_READWRITE));
+  gimp_procedure_add_return_value (procedure,
+                                   gimp_param_spec_string ("attributes-string",
+                                                           "attributes string",
+                                                           "The attributes as a xml string",
+                                                           FALSE, FALSE, FALSE,
+                                                           NULL,
+                                                           GIMP_PARAM_READWRITE));
   gimp_pdb_register_procedure (pdb, procedure);
   g_object_unref (procedure);
 
diff --git a/app/pdb/internal-procs.c b/app/pdb/internal-procs.c
index 1639970..872acab 100644
--- a/app/pdb/internal-procs.c
+++ b/app/pdb/internal-procs.c
@@ -28,7 +28,7 @@
 #include "internal-procs.h"
 
 
-/* 732 procedures registered total */
+/* 734 procedures registered total */
 
 void
 internal_procs_init (GimpPDB *pdb)
diff --git a/app/pdb/item-cmds.c b/app/pdb/item-cmds.c
index 6194593..762fc74 100644
--- a/app/pdb/item-cmds.c
+++ b/app/pdb/item-cmds.c
@@ -30,6 +30,7 @@
 #include "pdb-types.h"
 
 #include "core/gimpimage.h"
+#include "core/gimpitem-metadata.h"
 #include "core/gimpitem.h"
 #include "core/gimplayermask.h"
 #include "core/gimplist.h"
@@ -769,6 +770,67 @@ item_set_tattoo_invoker (GimpProcedure         *procedure,
 }
 
 static GimpValueArray *
+item_get_attributes_invoker (GimpProcedure         *procedure,
+                             Gimp                  *gimp,
+                             GimpContext           *context,
+                             GimpProgress          *progress,
+                             const GimpValueArray  *args,
+                             GError               **error)
+{
+  gboolean success = TRUE;
+  GimpValueArray *return_vals;
+  GimpItem *item;
+  gchar *attributes_string = NULL;
+
+  item = gimp_value_get_item (gimp_value_array_index (args, 0), gimp);
+
+  if (success)
+    {
+      GimpAttributes *attributes = gimp_item_get_attributes (item);
+
+      if (attributes)
+        attributes_string = gimp_attributes_serialize (attributes);
+    }
+
+  return_vals = gimp_procedure_get_return_values (procedure, success,
+                                                  error ? *error : NULL);
+
+  if (success)
+    g_value_take_string (gimp_value_array_index (return_vals, 1), attributes_string);
+
+  return return_vals;
+}
+
+static GimpValueArray *
+item_set_attributes_invoker (GimpProcedure         *procedure,
+                             Gimp                  *gimp,
+                             GimpContext           *context,
+                             GimpProgress          *progress,
+                             const GimpValueArray  *args,
+                             GError               **error)
+{
+  gboolean success = TRUE;
+  GimpItem *item;
+  const gchar *attributes_string;
+
+  item = gimp_value_get_item (gimp_value_array_index (args, 0), gimp);
+  attributes_string = g_value_get_string (gimp_value_array_index (args, 1));
+
+  if (success)
+    {
+      GimpAttributes *attributes = gimp_attributes_deserialize (attributes_string);
+
+      gimp_item_set_attributes (item, attributes, TRUE);
+
+      if (attributes)
+        g_object_unref (attributes);
+    }
+
+  return gimp_procedure_get_return_values (procedure, success,
+                                           error ? *error : NULL);
+}
+
+static GimpValueArray *
 item_attach_parasite_invoker (GimpProcedure         *procedure,
                               Gimp                  *gimp,
                               GimpContext           *context,
@@ -1618,6 +1680,66 @@ register_item_procs (GimpPDB *pdb)
   g_object_unref (procedure);
 
   /*
+   * gimp-item-get-attributes
+   */
+  procedure = gimp_procedure_new (item_get_attributes_invoker);
+  gimp_object_set_static_name (GIMP_OBJECT (procedure),
+                               "gimp-item-get-attributes");
+  gimp_procedure_set_static_strings (procedure,
+                                     "gimp-item-get-attributes",
+                                     "Returns the item's attributes.",
+                                     "Returns attributes from the item.",
+                                     "Spencer Kimball & Peter Mattis",
+                                     "Spencer Kimball & Peter Mattis",
+                                     "1995-1996",
+                                     NULL);
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_item_id ("item",
+                                                        "item",
+                                                        "The item",
+                                                        pdb->gimp, FALSE,
+                                                        GIMP_PARAM_READWRITE));
+  gimp_procedure_add_return_value (procedure,
+                                   gimp_param_spec_string ("attributes-string",
+                                                           "attributes string",
+                                                           "The attributes as a xml string",
+                                                           FALSE, FALSE, FALSE,
+                                                           NULL,
+                                                           GIMP_PARAM_READWRITE));
+  gimp_pdb_register_procedure (pdb, procedure);
+  g_object_unref (procedure);
+
+  /*
+   * gimp-item-set-attributes
+   */
+  procedure = gimp_procedure_new (item_set_attributes_invoker);
+  gimp_object_set_static_name (GIMP_OBJECT (procedure),
+                               "gimp-item-set-attributes");
+  gimp_procedure_set_static_strings (procedure,
+                                     "gimp-item-set-attributes",
+                                     "Set the item's attributes.",
+                                     "Sets attributes on the item.",
+                                     "Spencer Kimball & Peter Mattis",
+                                     "Spencer Kimball & Peter Mattis",
+                                     "1995-1996",
+                                     NULL);
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_item_id ("item",
+                                                        "item",
+                                                        "The item",
+                                                        pdb->gimp, FALSE,
+                                                        GIMP_PARAM_READWRITE));
+  gimp_procedure_add_argument (procedure,
+                               gimp_param_spec_string ("attributes-string",
+                                                       "attributes string",
+                                                       "The attributes as a xml string",
+                                                       FALSE, FALSE, FALSE,
+                                                       NULL,
+                                                       GIMP_PARAM_READWRITE));
+  gimp_pdb_register_procedure (pdb, procedure);
+  g_object_unref (procedure);
+
+  /*
    * gimp-item-attach-parasite
    */
   procedure = gimp_procedure_new (item_attach_parasite_invoker);
diff --git a/app/xcf/xcf-load.c b/app/xcf/xcf-load.c
index f9f1e6a..e2473d9 100644
--- a/app/xcf/xcf-load.c
+++ b/app/xcf/xcf-load.c
@@ -47,6 +47,7 @@
 #include "core/gimpimage-sample-points.h"
 #include "core/gimpimage-undo.h"
 #include "core/gimpitemstack.h"
+#include "core/gimpitem-metadata.h"
 #include "core/gimplayer-floating-sel.h"
 #include "core/gimplayermask.h"
 #include "core/gimpparasitelist.h"
@@ -244,30 +245,39 @@ xcf_load_image (Gimp     *gimp,
         }
     }
 
-  /* check for a metadata parasite */
+  /* check for an attributes parasite */
   parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
-                                       "gimp-image-metadata");
+                                       "gimp-image-attributes");
   if (parasite)
     {
       GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
-      GimpMetadata     *metadata;
-      const gchar      *meta_string;
+      GimpAttributes   *attributes;
+      const gchar      *attributes_string;
 
-      meta_string = (gchar *) gimp_parasite_data (parasite);
-      metadata = gimp_metadata_deserialize (meta_string);
+      attributes_string = (gchar *) gimp_parasite_data (parasite);
+      attributes = gimp_attributes_deserialize (attributes_string);
 
-      if (metadata)
+      if (attributes)
         {
-          has_metadata = TRUE;
-
-          gimp_image_set_metadata (image, metadata, FALSE);
-          g_object_unref (metadata);
+          gimp_image_set_attributes (image, attributes, FALSE);
+          g_object_unref (attributes);
         }
 
       gimp_parasite_list_remove (private->parasites,
                                  gimp_parasite_name (parasite));
     }
 
+  /* check for a metadata parasite */
+  parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
+                                       "gimp-image-metadata");
+  if (parasite)
+    {
+      GimpImagePrivate *private = GIMP_IMAGE_GET_PRIVATE (image);
+
+      gimp_parasite_list_remove (private->parasites,
+                                 gimp_parasite_name (parasite));
+    }
+
   /* migrate the old "exif-data" parasite */
   parasite = gimp_image_parasite_find (GIMP_IMAGE (image),
                                        "exif-data");
@@ -283,13 +293,11 @@ xcf_load_image (Gimp     *gimp,
         }
       else
         {
-          GimpMetadata *metadata = gimp_image_get_metadata (image);
-          GError       *my_error = NULL;
+          GimpMetadata   *metadata = NULL;
+          GimpAttributes *attributes = NULL;
+          GError         *my_error = NULL;
 
-          if (metadata)
-            g_object_ref (metadata);
-          else
-            metadata = gimp_metadata_new ();
+          metadata = gimp_metadata_new ();
 
           if (! gimp_metadata_set_from_exif (metadata,
                                              gimp_parasite_data (parasite),
@@ -305,7 +313,12 @@ xcf_load_image (Gimp     *gimp,
             }
           else
             {
-              gimp_image_set_metadata (image, metadata, FALSE);
+              attributes = gimp_attributes_new ();
+              attributes = gimp_attributes_from_metadata (attributes, metadata);
+
+              gimp_image_set_attributes (image, attributes, FALSE);
+
+              g_object_unref (attributes);
             }
 
           g_object_unref (metadata);
@@ -330,13 +343,11 @@ xcf_load_image (Gimp     *gimp,
         }
       else
         {
-          GimpMetadata *metadata = gimp_image_get_metadata (image);
-          GError       *my_error = NULL;
+          GimpMetadata   *metadata = NULL;
+          GimpAttributes *attributes = NULL;
+          GError         *my_error = NULL;
 
-          if (metadata)
-            g_object_ref (metadata);
-          else
-            metadata = gimp_metadata_new ();
+          metadata = gimp_metadata_new ();
 
           if (! gimp_metadata_set_from_xmp (metadata,
                                             gimp_parasite_data (parasite),
@@ -352,7 +363,12 @@ xcf_load_image (Gimp     *gimp,
             }
           else
             {
-              gimp_image_set_metadata (image, metadata, FALSE);
+              attributes = gimp_attributes_new ();
+              attributes = gimp_attributes_from_metadata (attributes, metadata);
+
+              gimp_image_set_attributes (image, attributes, FALSE);
+
+              g_object_unref (attributes);
             }
 
           g_object_unref (metadata);
@@ -1350,25 +1366,26 @@ xcf_load_layer (XcfInfo    *info,
                 GimpImage  *image,
                 GList     **item_path)
 {
-  GimpLayer         *layer;
-  GimpLayerMask     *layer_mask;
-  guint32            hierarchy_offset;
-  guint32            layer_mask_offset;
-  gboolean           apply_mask = TRUE;
-  gboolean           edit_mask  = FALSE;
-  gboolean           show_mask  = FALSE;
-  gboolean           active;
-  gboolean           floating;
-  guint32            group_layer_flags = 0;
-  guint32            text_layer_flags = 0;
-  gint               width;
-  gint               height;
-  gint               type;
-  GimpImageBaseType  base_type;
-  gboolean           has_alpha;
-  const Babl        *format;
-  gboolean           is_fs_drawable;
-  gchar             *name;
+  GimpLayer          *layer;
+  GimpLayerMask      *layer_mask;
+  const GimpParasite *parasite;
+  guint32             hierarchy_offset;
+  guint32             layer_mask_offset;
+  gboolean            apply_mask = TRUE;
+  gboolean            edit_mask  = FALSE;
+  gboolean            show_mask  = FALSE;
+  gboolean            active;
+  gboolean            floating;
+  guint32             group_layer_flags = 0;
+  guint32             text_layer_flags = 0;
+  gint                width;
+  gint                height;
+  gint                type;
+  GimpImageBaseType   base_type;
+  gboolean            has_alpha;
+  const Babl         *format;
+  gboolean            is_fs_drawable;
+  gchar              *name;
 
   /* check and see if this is the drawable the floating selection
    *  is attached to. if it is then we'll do the attachment in our caller.
@@ -1445,6 +1462,29 @@ xcf_load_layer (XcfInfo    *info,
 
   GIMP_LOG (XCF, "layer props loaded");
 
+  parasite = gimp_item_parasite_find (GIMP_ITEM (layer),
+                                       "gimp-item-attributes");
+  if (parasite)
+    {
+      GimpAttributes   *attributes;
+      const gchar      *attributes_string;
+
+      attributes_string = (gchar *) gimp_parasite_data (parasite);
+      attributes = gimp_attributes_deserialize (attributes_string);
+
+      if (attributes)
+        {
+          gimp_item_set_attributes (GIMP_ITEM (layer), attributes, FALSE);
+          g_object_unref (attributes);
+        }
+
+      gimp_item_parasite_detach (GIMP_ITEM (layer),
+                                 "gimp-item-attributes",
+                                 FALSE);
+    }
+
+  GIMP_LOG (XCF, "layer attributes loaded");
+
   xcf_progress_update (info);
 
   /* call the evil text layer hack that might change our layer pointer */
@@ -1534,13 +1574,14 @@ static GimpChannel *
 xcf_load_channel (XcfInfo   *info,
                   GimpImage *image)
 {
-  GimpChannel *channel;
-  guint32      hierarchy_offset;
-  gint         width;
-  gint         height;
-  gboolean     is_fs_drawable;
-  gchar       *name;
-  GimpRGB      color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
+  GimpChannel        *channel;
+  const GimpParasite *parasite;
+  guint32             hierarchy_offset;
+  gint                width;
+  gint                height;
+  gboolean            is_fs_drawable;
+  gchar              *name;
+  GimpRGB             color = { 0.0, 0.0, 0.0, GIMP_OPACITY_OPAQUE };
 
   /* check and see if this is the drawable the floating selection
    *  is attached to. if it is then we'll do the attachment in our caller.
@@ -1565,6 +1606,27 @@ xcf_load_channel (XcfInfo   *info,
   if (!xcf_load_channel_props (info, image, &channel))
     goto error;
 
+  parasite = gimp_item_parasite_find (GIMP_ITEM (channel),
+                                       "gimp-item-attributes");
+  if (parasite)
+    {
+      GimpAttributes   *attributes;
+      const gchar      *attributes_string;
+
+      attributes_string = (gchar *) gimp_parasite_data (parasite);
+      attributes = gimp_attributes_deserialize (attributes_string);
+
+      if (attributes)
+        {
+          gimp_item_set_attributes (GIMP_ITEM (channel), attributes, FALSE);
+          g_object_unref (attributes);
+        }
+
+      gimp_item_parasite_detach (GIMP_ITEM (channel),
+                                 "gimp-item-attributes",
+                                 FALSE);
+    }
+
   xcf_progress_update (info);
 
   /* read the hierarchy and layer mask offsets */
diff --git a/app/xcf/xcf-save.c b/app/xcf/xcf-save.c
index 1ceb521..0bf88c2 100644
--- a/app/xcf/xcf-save.c
+++ b/app/xcf/xcf-save.c
@@ -45,6 +45,7 @@
 #include "core/gimpimage-metadata.h"
 #include "core/gimpimage-private.h"
 #include "core/gimpimage-sample-points.h"
+#include "core/gimpitem-metadata.h"
 #include "core/gimplayer.h"
 #include "core/gimplayermask.h"
 #include "core/gimpparasitelist.h"
@@ -355,10 +356,11 @@ xcf_save_image_props (XcfInfo    *info,
                       GimpImage  *image,
                       GError    **error)
 {
-  GimpImagePrivate *private       = GIMP_IMAGE_GET_PRIVATE (image);
-  GimpParasite     *grid_parasite = NULL;
-  GimpParasite     *meta_parasite = NULL;
-  GimpUnit          unit          = gimp_image_get_unit (image);
+  GimpImagePrivate *private             = GIMP_IMAGE_GET_PRIVATE (image);
+  GimpParasite     *grid_parasite       = NULL;
+  GimpParasite     *meta_parasite       = NULL;
+  GimpParasite     *attributes_parasite = NULL;
+  GimpUnit          unit                = gimp_image_get_unit (image);
   gdouble           xres;
   gdouble           yres;
 
@@ -410,21 +412,21 @@ xcf_save_image_props (XcfInfo    *info,
       gimp_parasite_list_add (private->parasites, grid_parasite);
     }
 
-  if (gimp_image_get_metadata (image))
+  if (gimp_image_get_attributes (image))
     {
-      GimpMetadata *metadata = gimp_image_get_metadata (image);
-      gchar        *meta_string;
+      GimpAttributes *attributes = gimp_image_get_attributes (image);
+      gchar          *attributes_string;
 
-      meta_string = gimp_metadata_serialize (metadata);
+      attributes_string = gimp_attributes_serialize (attributes);
 
-      if (meta_string)
+      if (attributes_string)
         {
-          meta_parasite = gimp_parasite_new ("gimp-image-metadata",
-                                             GIMP_PARASITE_PERSISTENT,
-                                             strlen (meta_string) + 1,
-                                             meta_string);
-          gimp_parasite_list_add (private->parasites, meta_parasite);
-          g_free (meta_string);
+          attributes_parasite = gimp_parasite_new ("gimp-image-attributes",
+                                                   GIMP_PARASITE_PERSISTENT,
+                                                   strlen (attributes_string) + 1,
+                                                   attributes_string);
+          gimp_parasite_list_add (private->parasites, attributes_parasite);
+          g_free (attributes_string);
         }
     }
 
@@ -462,6 +464,25 @@ xcf_save_layer_props (XcfInfo    *info,
   GimpParasiteList *parasites;
   gint              offset_x;
   gint              offset_y;
+  GimpParasite     *attributes_parasite = NULL;
+
+  if (gimp_item_get_attributes (GIMP_ITEM (layer)))
+    {
+      GimpAttributes *attributes = gimp_item_get_attributes (GIMP_ITEM (layer));
+      gchar          *attributes_string;
+
+      attributes_string = gimp_attributes_serialize (attributes);
+
+      if (attributes_string)
+        {
+          attributes_parasite = gimp_parasite_new ("gimp-item-attributes",
+                                                   GIMP_PARASITE_PERSISTENT,
+                                                   strlen (attributes_string) + 1,
+                                                   attributes_string);
+          gimp_item_parasite_attach (GIMP_ITEM (layer), attributes_parasite, FALSE);
+          g_free (attributes_string);
+        }
+    }
 
   if (gimp_viewable_get_children (GIMP_VIEWABLE (layer)))
     xcf_check_error (xcf_save_prop (info, image, PROP_GROUP_ITEM, error));
@@ -573,6 +594,25 @@ xcf_save_channel_props (XcfInfo      *info,
 {
   GimpParasiteList *parasites;
   guchar            col[3];
+  GimpParasite     *attributes_parasite = NULL;
+
+  if (gimp_item_get_attributes (GIMP_ITEM (channel)))
+    {
+      GimpAttributes *attributes = gimp_item_get_attributes (GIMP_ITEM (channel));
+      gchar          *attributes_string;
+
+      attributes_string = gimp_attributes_serialize (attributes);
+
+      if (attributes_string)
+        {
+          attributes_parasite = gimp_parasite_new ("gimp-item-attributes",
+                                                   GIMP_PARASITE_PERSISTENT,
+                                                   strlen (attributes_string) + 1,
+                                                   attributes_string);
+          gimp_item_parasite_attach (GIMP_ITEM (channel), attributes_parasite, FALSE);
+          g_free (attributes_string);
+        }
+    }
 
   if (channel == gimp_image_get_active_channel (image))
     xcf_check_error (xcf_save_prop (info, image, PROP_ACTIVE_CHANNEL, error));
diff --git a/libgimp/Makefile.am b/libgimp/Makefile.am
index d1540d4..0d5a47a 100644
--- a/libgimp/Makefile.am
+++ b/libgimp/Makefile.am
@@ -206,6 +206,8 @@ libgimp_sources = \
        gimpgradientselect.h    \
        gimpimage.c             \
        gimpimage.h             \
+       gimpitem.c              \
+       gimpitem.h              \
        gimplayer.c             \
        gimplayer.h             \
        gimppalette.c           \
@@ -327,6 +329,7 @@ gimpinclude_HEADERS = \
        gimpgradients.h                 \
        gimpgradientselect.h            \
        gimpimage.h                     \
+       gimpitem.h                      \
        gimplayer.h                     \
        gimppalette.h                   \
        gimppalettes.h                  \
diff --git a/libgimp/gimp.def b/libgimp/gimp.def
index 111f76e..daf7c96 100644
--- a/libgimp/gimp.def
+++ b/libgimp/gimp.def
@@ -389,6 +389,7 @@ EXPORTS
        gimp_image_get_active_drawable
        gimp_image_get_active_layer
        gimp_image_get_active_vectors
+       gimp_image_get_attributes
        gimp_image_get_channel_by_name
        gimp_image_get_channel_by_tattoo
        gimp_image_get_channel_position
@@ -408,7 +409,6 @@ EXPORTS
        gimp_image_get_layer_by_tattoo
        gimp_image_get_layer_position
        gimp_image_get_layers
-       gimp_image_get_metadata
        gimp_image_get_name
        gimp_image_get_parasite
        gimp_image_get_parasite_list
@@ -485,12 +485,12 @@ EXPORTS
        gimp_image_set_active_channel
        gimp_image_set_active_layer
        gimp_image_set_active_vectors
+       gimp_image_set_attributes
        gimp_image_set_cmap
        gimp_image_set_colormap
        gimp_image_set_component_active
        gimp_image_set_component_visible
        gimp_image_set_filename
-       gimp_image_set_metadata
        gimp_image_set_resolution
        gimp_image_set_tattoo_state
        gimp_image_set_unit
@@ -510,6 +510,7 @@ EXPORTS
        gimp_item_attach_parasite
        gimp_item_delete
        gimp_item_detach_parasite
+       gimp_item_get_attributes
        gimp_item_get_children
        gimp_item_get_image
        gimp_item_get_linked
@@ -530,6 +531,7 @@ EXPORTS
        gimp_item_is_text_layer
        gimp_item_is_valid
        gimp_item_is_vectors
+       gimp_item_set_attributes
        gimp_item_set_linked
        gimp_item_set_lock_content
        gimp_item_set_lock_position
diff --git a/libgimp/gimp.h b/libgimp/gimp.h
index 5a05e4e..eb78f6f 100644
--- a/libgimp/gimp.h
+++ b/libgimp/gimp.h
@@ -44,6 +44,7 @@
 #include <libgimp/gimpgradients.h>
 #include <libgimp/gimpgradientselect.h>
 #include <libgimp/gimpimage.h>
+#include <libgimp/gimpitem.h>
 #include <libgimp/gimplayer.h>
 #include <libgimp/gimppalette.h>
 #include <libgimp/gimppalettes.h>
diff --git a/libgimp/gimpimage.c b/libgimp/gimpimage.c
index 2c324ad..246aed4 100644
--- a/libgimp/gimpimage.c
+++ b/libgimp/gimpimage.c
@@ -101,61 +101,61 @@ gimp_image_get_thumbnail_data (gint32  image_ID,
 }
 
 /**
- * gimp_image_get_metadata:
+ * gimp_image_get_attributes:
  * @image_ID: The image.
  *
- * Returns the image's metadata.
+ * Returns the image's attributes.
  *
- * Returns exif/iptc/xmp metadata from the image.
+ * Returns attributes from the image.
  *
- * Returns: The exif/ptc/xmp metadata, or %NULL if there is none.
+ * Returns: The attributes, or %NULL if there is none.
  *
  * Since: GIMP 2.10
  **/
-GimpMetadata *
-gimp_image_get_metadata (gint32 image_ID)
+GimpAttributes *
+gimp_image_get_attributes (gint32 image_ID)
 {
-  GimpMetadata *metadata = NULL;
-  gchar        *metadata_string;
+  GimpAttributes *attributes        = NULL;
+  gchar          *attributes_string = NULL;
 
-  metadata_string = _gimp_image_get_metadata (image_ID);
-  if (metadata_string)
+  attributes_string = _gimp_image_get_attributes (image_ID);
+  if (attributes_string)
     {
-      metadata = gimp_metadata_deserialize (metadata_string);
-      g_free (metadata_string);
+      attributes = gimp_attributes_deserialize (attributes_string);
+      g_free (attributes_string);
     }
 
-  return metadata;
+  return attributes;
 }
 
 /**
- * gimp_image_set_metadata:
+ * gimp_image_set_attributes:
  * @image_ID: The image.
- * @metadata: The exif/ptc/xmp metadata.
+ * @metadata: The GimpAttributes object.
  *
- * Set the image's metadata.
+ * Set the image's attributes.
  *
- * Sets exif/iptc/xmp metadata on the image, or deletes it if
- * @metadata is %NULL.
+ * Sets attributes on the image, or deletes it if
+ * @attributes is %NULL.
  *
  * Returns: TRUE on success.
  *
  * Since: GIMP 2.10
  **/
 gboolean
-gimp_image_set_metadata (gint32        image_ID,
-                         GimpMetadata *metadata)
+gimp_image_set_attributes (gint32          image_ID,
+                           GimpAttributes *attributes)
 {
-  gchar    *metadata_string = NULL;
+  gchar    *attributes_string = NULL;
   gboolean  success;
 
-  if (metadata)
-    metadata_string = gimp_metadata_serialize (metadata);
+  if (attributes)
+    attributes_string = gimp_attributes_serialize (attributes);
 
-  success = _gimp_image_set_metadata (image_ID, metadata_string);
+  success = _gimp_image_set_attributes (image_ID, attributes_string);
 
-  if (metadata_string)
-    g_free (metadata_string);
+  if (attributes_string)
+    g_free (attributes_string);
 
   return success;
 }
diff --git a/libgimp/gimpimage.h b/libgimp/gimpimage.h
index 376b033..4995154 100644
--- a/libgimp/gimpimage.h
+++ b/libgimp/gimpimage.h
@@ -44,6 +44,11 @@ guchar       * gimp_image_get_thumbnail_data      (gint32              image_ID,
 GimpMetadata * gimp_image_get_metadata            (gint32              image_ID);
 gboolean       gimp_image_set_metadata            (gint32              image_ID,
                                                    GimpMetadata       *metadata);
+                                                   
+
+gboolean       gimp_image_set_attributes          (gint32              image_ID,
+                                                   GimpAttributes     *attributes);
+GimpAttributes *gimp_image_get_attributes         (gint32              image_ID);
 
 GIMP_DEPRECATED_FOR(gimp_image_get_colormap)
 guchar       * gimp_image_get_cmap                (gint32              image_ID,
diff --git a/libgimp/gimpimage_pdb.c b/libgimp/gimpimage_pdb.c
index 638f65a..0428f3e 100644
--- a/libgimp/gimpimage_pdb.c
+++ b/libgimp/gimpimage_pdb.c
@@ -1800,65 +1800,65 @@ _gimp_image_set_colormap (gint32        image_ID,
 }
 
 /**
- * _gimp_image_get_metadata:
+ * _gimp_image_set_attributes:
  * @image_ID: The image.
+ * @attributes_string: The attributes as a xml string.
  *
- * Returns the image's metadata.
+ * Set the image's attributes.
  *
- * Returns exif/iptc/xmp metadata from the image.
+ * Sets attributes on the image.
  *
- * Returns: The exif/ptc/xmp metadata as a string.
+ * Returns: TRUE on success.
  **/
-gchar *
-_gimp_image_get_metadata (gint32 image_ID)
+gboolean
+_gimp_image_set_attributes (gint32       image_ID,
+                            const gchar *attributes_string)
 {
   GimpParam *return_vals;
   gint nreturn_vals;
-  gchar *metadata_string = NULL;
+  gboolean success = TRUE;
 
-  return_vals = gimp_run_procedure ("gimp-image-get-metadata",
+  return_vals = gimp_run_procedure ("gimp-image-set-attributes",
                                     &nreturn_vals,
                                     GIMP_PDB_IMAGE, image_ID,
+                                    GIMP_PDB_STRING, attributes_string,
                                     GIMP_PDB_END);
 
-  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
-    metadata_string = g_strdup (return_vals[1].data.d_string);
+  success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS;
 
   gimp_destroy_params (return_vals, nreturn_vals);
 
-  return metadata_string;
+  return success;
 }
 
 /**
- * _gimp_image_set_metadata:
+ * _gimp_image_get_attributes:
  * @image_ID: The image.
- * @metadata_string: The exif/ptc/xmp metadata as a string.
  *
- * Set the image's metadata.
+ * Returns the image's attributes.
  *
- * Sets exif/iptc/xmp metadata on the image.
+ * Returns attributes from the image.
  *
- * Returns: TRUE on success.
+ * Returns: The attributes as a xml string.
  **/
-gboolean
-_gimp_image_set_metadata (gint32       image_ID,
-                          const gchar *metadata_string)
+gchar *
+_gimp_image_get_attributes (gint32 image_ID)
 {
   GimpParam *return_vals;
   gint nreturn_vals;
-  gboolean success = TRUE;
+  gchar *attributes_string = NULL;
 
-  return_vals = gimp_run_procedure ("gimp-image-set-metadata",
+  return_vals = gimp_run_procedure ("gimp-image-get-attributes",
                                     &nreturn_vals,
                                     GIMP_PDB_IMAGE, image_ID,
-                                    GIMP_PDB_STRING, metadata_string,
                                     GIMP_PDB_END);
 
-  success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS;
+  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
+    attributes_string = g_strdup (return_vals[1].data.d_string);
 
   gimp_destroy_params (return_vals, nreturn_vals);
 
-  return success;
+  return attributes_string;
 }
 
 /**
diff --git a/libgimp/gimpimage_pdb.h b/libgimp/gimpimage_pdb.h
index e5a2466..642edb2 100644
--- a/libgimp/gimpimage_pdb.h
+++ b/libgimp/gimpimage_pdb.h
@@ -148,9 +148,9 @@ G_GNUC_INTERNAL guint8*  _gimp_image_get_colormap            (gint32
 G_GNUC_INTERNAL gboolean _gimp_image_set_colormap            (gint32                  image_ID,
                                                               gint                    num_bytes,
                                                               const guint8           *colormap);
-G_GNUC_INTERNAL gchar*   _gimp_image_get_metadata            (gint32                  image_ID);
-G_GNUC_INTERNAL gboolean _gimp_image_set_metadata            (gint32                  image_ID,
-                                                              const gchar            *metadata_string);
+G_GNUC_INTERNAL gboolean _gimp_image_set_attributes          (gint32                  image_ID,
+                                                              const gchar            *attributes_string);
+G_GNUC_INTERNAL gchar*   _gimp_image_get_attributes          (gint32                  image_ID);
 gboolean                 gimp_image_clean_all                (gint32                  image_ID);
 gboolean                 gimp_image_is_dirty                 (gint32                  image_ID);
 G_GNUC_INTERNAL gboolean _gimp_image_thumbnail               (gint32                  image_ID,
diff --git a/libgimp/gimpitem.c b/libgimp/gimpitem.c
new file mode 100644
index 0000000..60a3ea6
--- /dev/null
+++ b/libgimp/gimpitem.c
@@ -0,0 +1,86 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
+ *
+ * gimpitem.c
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gimp.h"
+#include "gimpitem.h"
+
+
+/**
+ * gimp_item_get_attributes:
+ * @item_ID: The item.
+ *
+ * Returns the item's attributes.
+ *
+ * Returns attributes from the item.
+ *
+ * Returns: The attributes, or %NULL if there is none.
+ *
+ * Since: GIMP 2.10
+ **/
+GimpAttributes *
+gimp_item_get_attributes (gint32 item_ID)
+{
+  GimpAttributes *attributes = NULL;
+  gchar          *attributes_string;
+
+  attributes_string = _gimp_item_get_attributes (item_ID);
+  if (attributes_string)
+    {
+      attributes = gimp_attributes_deserialize (attributes_string);
+      g_free (attributes_string);
+    }
+
+  return attributes;
+}
+
+/**
+ * gimp_item_set_attributes:
+ * @item_ID: The item.
+ * @metadata: The GimpAttributes object.
+ *
+ * Set the item's attributes.
+ *
+ * Sets attributes on the item, or deletes it if
+ * @attributes is %NULL.
+ *
+ * Returns: TRUE on success.
+ *
+ * Since: GIMP 2.10
+ **/
+gboolean
+gimp_item_set_attributes (gint32          item_ID,
+                          GimpAttributes *attributes)
+{
+  gchar    *attributes_string = NULL;
+  gboolean  success;
+
+  if (attributes)
+    attributes_string = gimp_attributes_serialize (attributes);
+
+  success = _gimp_item_set_attributes (item_ID, attributes_string);
+
+  if (attributes_string)
+    g_free (attributes_string);
+
+  return success;
+}
+
diff --git a/libgimp/gimpitem.h b/libgimp/gimpitem.h
new file mode 100644
index 0000000..cfbc7dc
--- /dev/null
+++ b/libgimp/gimpitem.h
@@ -0,0 +1,40 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
+ *
+ * gimpitem.h
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#if !defined (__GIMP_H_INSIDE__) && !defined (GIMP_COMPILATION)
+#error "Only <libgimp/gimp.h> can be included directly."
+#endif
+
+#ifndef __GIMP_ITEM_H__
+#define __GIMP_ITEM_H__
+
+G_BEGIN_DECLS
+
+/* For information look into the C source or the html documentation */
+
+
+gboolean       gimp_item_set_attributes          (gint32              item_ID,
+                                                  GimpAttributes     *attributes);
+GimpAttributes *gimp_item_get_attributes         (gint32              item_ID);
+
+
+G_END_DECLS
+
+#endif /* __GIMP_ITEM_H__ */
diff --git a/libgimp/gimpitem_pdb.c b/libgimp/gimpitem_pdb.c
index c0f5939..09ba1eb 100644
--- a/libgimp/gimpitem_pdb.c
+++ b/libgimp/gimpitem_pdb.c
@@ -869,6 +869,68 @@ gimp_item_set_tattoo (gint32 item_ID,
 }
 
 /**
+ * _gimp_item_get_attributes:
+ * @item_ID: The item.
+ *
+ * Returns the item's attributes.
+ *
+ * Returns attributes from the item.
+ *
+ * Returns: The attributes as a xml string.
+ **/
+gchar *
+_gimp_item_get_attributes (gint32 item_ID)
+{
+  GimpParam *return_vals;
+  gint nreturn_vals;
+  gchar *attributes_string = NULL;
+
+  return_vals = gimp_run_procedure ("gimp-item-get-attributes",
+                                    &nreturn_vals,
+                                    GIMP_PDB_ITEM, item_ID,
+                                    GIMP_PDB_END);
+
+  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
+    attributes_string = g_strdup (return_vals[1].data.d_string);
+
+  gimp_destroy_params (return_vals, nreturn_vals);
+
+  return attributes_string;
+}
+
+/**
+ * _gimp_item_set_attributes:
+ * @item_ID: The item.
+ * @attributes_string: The attributes as a xml string.
+ *
+ * Set the item's attributes.
+ *
+ * Sets attributes on the item.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+_gimp_item_set_attributes (gint32       item_ID,
+                           const gchar *attributes_string)
+{
+  GimpParam *return_vals;
+  gint nreturn_vals;
+  gboolean success = TRUE;
+
+  return_vals = gimp_run_procedure ("gimp-item-set-attributes",
+                                    &nreturn_vals,
+                                    GIMP_PDB_ITEM, item_ID,
+                                    GIMP_PDB_STRING, attributes_string,
+                                    GIMP_PDB_END);
+
+  success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS;
+
+  gimp_destroy_params (return_vals, nreturn_vals);
+
+  return success;
+}
+
+/**
  * gimp_item_attach_parasite:
  * @item_ID: The item.
  * @parasite: The parasite to attach to the item.
diff --git a/libgimp/gimpitem_pdb.h b/libgimp/gimpitem_pdb.h
index c564f0f..8508f43 100644
--- a/libgimp/gimpitem_pdb.h
+++ b/libgimp/gimpitem_pdb.h
@@ -32,46 +32,49 @@ G_BEGIN_DECLS
 /* For information look into the C source or the html documentation */
 
 
-gboolean      gimp_item_is_valid          (gint32              item_ID);
-gint32        gimp_item_get_image         (gint32              item_ID);
-gboolean      gimp_item_delete            (gint32              item_ID);
-gboolean      gimp_item_is_drawable       (gint32              item_ID);
-gboolean      gimp_item_is_layer          (gint32              item_ID);
-gboolean      gimp_item_is_text_layer     (gint32              item_ID);
-gboolean      gimp_item_is_channel        (gint32              item_ID);
-gboolean      gimp_item_is_layer_mask     (gint32              item_ID);
-gboolean      gimp_item_is_selection      (gint32              item_ID);
-gboolean      gimp_item_is_vectors        (gint32              item_ID);
-gboolean      gimp_item_is_group          (gint32              item_ID);
-gint32        gimp_item_get_parent        (gint32              item_ID);
-gint*         gimp_item_get_children      (gint32              item_ID,
-                                           gint               *num_children);
-gchar*        gimp_item_get_name          (gint32              item_ID);
-gboolean      gimp_item_set_name          (gint32              item_ID,
-                                           const gchar        *name);
-gboolean      gimp_item_get_visible       (gint32              item_ID);
-gboolean      gimp_item_set_visible       (gint32              item_ID,
-                                           gboolean            visible);
-gboolean      gimp_item_get_linked        (gint32              item_ID);
-gboolean      gimp_item_set_linked        (gint32              item_ID,
-                                           gboolean            linked);
-gboolean      gimp_item_get_lock_content  (gint32              item_ID);
-gboolean      gimp_item_set_lock_content  (gint32              item_ID,
-                                           gboolean            lock_content);
-gboolean      gimp_item_get_lock_position (gint32              item_ID);
-gboolean      gimp_item_set_lock_position (gint32              item_ID,
-                                           gboolean            lock_position);
-gint          gimp_item_get_tattoo        (gint32              item_ID);
-gboolean      gimp_item_set_tattoo        (gint32              item_ID,
-                                           gint                tattoo);
-gboolean      gimp_item_attach_parasite   (gint32              item_ID,
-                                           const GimpParasite *parasite);
-gboolean      gimp_item_detach_parasite   (gint32              item_ID,
-                                           const gchar        *name);
-GimpParasite* gimp_item_get_parasite      (gint32              item_ID,
-                                           const gchar        *name);
-gchar**       gimp_item_get_parasite_list (gint32              item_ID,
-                                           gint               *num_parasites);
+gboolean                 gimp_item_is_valid          (gint32              item_ID);
+gint32                   gimp_item_get_image         (gint32              item_ID);
+gboolean                 gimp_item_delete            (gint32              item_ID);
+gboolean                 gimp_item_is_drawable       (gint32              item_ID);
+gboolean                 gimp_item_is_layer          (gint32              item_ID);
+gboolean                 gimp_item_is_text_layer     (gint32              item_ID);
+gboolean                 gimp_item_is_channel        (gint32              item_ID);
+gboolean                 gimp_item_is_layer_mask     (gint32              item_ID);
+gboolean                 gimp_item_is_selection      (gint32              item_ID);
+gboolean                 gimp_item_is_vectors        (gint32              item_ID);
+gboolean                 gimp_item_is_group          (gint32              item_ID);
+gint32                   gimp_item_get_parent        (gint32              item_ID);
+gint*                    gimp_item_get_children      (gint32              item_ID,
+                                                      gint               *num_children);
+gchar*                   gimp_item_get_name          (gint32              item_ID);
+gboolean                 gimp_item_set_name          (gint32              item_ID,
+                                                      const gchar        *name);
+gboolean                 gimp_item_get_visible       (gint32              item_ID);
+gboolean                 gimp_item_set_visible       (gint32              item_ID,
+                                                      gboolean            visible);
+gboolean                 gimp_item_get_linked        (gint32              item_ID);
+gboolean                 gimp_item_set_linked        (gint32              item_ID,
+                                                      gboolean            linked);
+gboolean                 gimp_item_get_lock_content  (gint32              item_ID);
+gboolean                 gimp_item_set_lock_content  (gint32              item_ID,
+                                                      gboolean            lock_content);
+gboolean                 gimp_item_get_lock_position (gint32              item_ID);
+gboolean                 gimp_item_set_lock_position (gint32              item_ID,
+                                                      gboolean            lock_position);
+gint                     gimp_item_get_tattoo        (gint32              item_ID);
+gboolean                 gimp_item_set_tattoo        (gint32              item_ID,
+                                                      gint                tattoo);
+G_GNUC_INTERNAL gchar*   _gimp_item_get_attributes   (gint32              item_ID);
+G_GNUC_INTERNAL gboolean _gimp_item_set_attributes   (gint32              item_ID,
+                                                      const gchar        *attributes_string);
+gboolean                 gimp_item_attach_parasite   (gint32              item_ID,
+                                                      const GimpParasite *parasite);
+gboolean                 gimp_item_detach_parasite   (gint32              item_ID,
+                                                      const gchar        *name);
+GimpParasite*            gimp_item_get_parasite      (gint32              item_ID,
+                                                      const gchar        *name);
+gchar**                  gimp_item_get_parasite_list (gint32              item_ID,
+                                                      gint               *num_parasites);
 
 
 G_END_DECLS
diff --git a/libgimp/gimpmetadata.c b/libgimp/gimpmetadata.c
index b3dd0ea..3e61fd1 100644
--- a/libgimp/gimpmetadata.c
+++ b/libgimp/gimpmetadata.c
@@ -28,6 +28,7 @@
 #include "gimp.h"
 #include "gimpui.h"
 #include "gimpmetadata.h"
+#include "libgimpbase/gimpbase.h"
 
 #include "libgimp-intl.h"
 
@@ -44,7 +45,6 @@ static gboolean    gimp_image_metadata_rotate_dialog (gint32             image_I
                                                       GExiv2Orientation  orientation,
                                                       const gchar       *parasite_name);
 
-
 /*  public functions  */
 
 /**
@@ -122,60 +122,78 @@ gimp_image_metadata_load_prepare (gint32        image_ID,
  */
 void
 gimp_image_metadata_load_finish (gint32                 image_ID,
+                                 gint32                 layer_ID,
                                  const gchar           *mime_type,
                                  GimpMetadata          *metadata,
                                  GimpMetadataLoadFlags  flags,
                                  gboolean               interactive)
 {
+  GimpAttributes *attributes = NULL;
+
   g_return_if_fail (image_ID > 0);
   g_return_if_fail (mime_type != NULL);
   g_return_if_fail (GEXIV2_IS_METADATA (metadata));
 
-  if (flags & GIMP_METADATA_LOAD_COMMENT)
+  if (flags & GIMP_METADATA_LOAD_ORIENTATION)
     {
-      gchar *comment;
+      gimp_image_metadata_rotate_query (image_ID, mime_type,
+                                        metadata, interactive);
+    }
 
-      comment = gexiv2_metadata_get_tag_interpreted_string (metadata,
-                                                            "Exif.Photo.UserComment");
-      if (! comment)
-        comment = gexiv2_metadata_get_tag_interpreted_string (metadata,
-                                                              "Exif.Image.ImageDescription");
+  attributes = gimp_attributes_from_metadata (attributes, metadata);
 
-      if (comment)
+  if (attributes)
+    {
+      if (flags & GIMP_METADATA_LOAD_COMMENT)
         {
-          GimpParasite *parasite;
+          GimpAttribute *attribute = NULL;
+          gchar         *comment   = NULL;
+
+          attribute = gimp_attributes_get_attribute (attributes, "Exif.Photo.UserComment");
+          if (attribute)
+            comment = gimp_attribute_get_string (attribute);
+          else
+            {
+              attribute = gimp_attributes_get_attribute (attributes, "Exif.Image.ImageDescription");
+              if (attribute)
+                comment = gimp_attribute_get_string (attribute);
+            }
 
-          parasite = gimp_parasite_new ("gimp-comment",
-                                        GIMP_PARASITE_PERSISTENT,
-                                        strlen (comment) + 1,
-                                        comment);
-          g_free (comment);
+          if (comment)
+            {
+              GimpParasite *parasite;
 
-          gimp_image_attach_parasite (image_ID, parasite);
-          gimp_parasite_free (parasite);
+              parasite = gimp_parasite_new ("gimp-comment",
+                                            GIMP_PARASITE_PERSISTENT,
+                                            strlen (comment) + 1,
+                                            comment);
+              g_free (comment);
+
+              gimp_image_attach_parasite (image_ID, parasite);
+              gimp_parasite_free (parasite);
+            }
         }
-    }
+      if (flags & GIMP_METADATA_LOAD_RESOLUTION)
+        {
+          gdouble   xres;
+          gdouble   yres;
+          GimpUnit  unit;
 
-  if (flags & GIMP_METADATA_LOAD_RESOLUTION)
-    {
-      gdouble   xres;
-      gdouble   yres;
-      GimpUnit  unit;
+          if (gimp_attributes_get_resolution (attributes, &xres, &yres, &unit))
+            {
+              gimp_image_set_resolution (image_ID, xres, yres);
+              gimp_image_set_unit (image_ID, unit);
+            }
+        }
 
-      if (gimp_metadata_get_resolution (metadata, &xres, &yres, &unit))
+      gimp_image_set_attributes (image_ID, attributes);
+      if (layer_ID > 0)
         {
-          gimp_image_set_resolution (image_ID, xres, yres);
-          gimp_image_set_unit (image_ID, unit);
+          gimp_item_set_attributes (layer_ID, attributes);
         }
-    }
+      g_object_unref (attributes);
 
-  if (flags & GIMP_METADATA_LOAD_ORIENTATION)
-    {
-      gimp_image_metadata_rotate_query (image_ID, mime_type,
-                                        metadata, interactive);
     }
-
-  gimp_image_set_metadata (image_ID, metadata);
 }
 
 /**
@@ -197,12 +215,12 @@ gimp_image_metadata_load_finish (gint32                 image_ID,
  *
  * Since: GIMP 2.10
  */
-GimpMetadata *
+GimpAttributes *
 gimp_image_metadata_save_prepare (gint32                 image_ID,
                                   const gchar           *mime_type,
                                   GimpMetadataSaveFlags *suggested_flags)
 {
-  GimpMetadata *metadata;
+  GimpAttributes *attributes = NULL;
 
   g_return_val_if_fail (image_ID > 0, NULL);
   g_return_val_if_fail (mime_type != NULL, NULL);
@@ -210,128 +228,27 @@ gimp_image_metadata_save_prepare (gint32                 image_ID,
 
   *suggested_flags = GIMP_METADATA_SAVE_ALL;
 
-  metadata = gimp_image_get_metadata (image_ID);
+  attributes = gimp_image_get_attributes (image_ID);
 
-  if (metadata)
+  if (attributes)
     {
-      GDateTime          *datetime;
-      const GimpParasite *comment_parasite;
-      const gchar        *comment = NULL;
-      gint                image_width;
-      gint                image_height;
-      gdouble             xres;
-      gdouble             yres;
-      gchar               buffer[32];
-
-      image_width  = gimp_image_width  (image_ID);
-      image_height = gimp_image_height (image_ID);
-
-      datetime = g_date_time_new_now_local ();
-
-      comment_parasite = gimp_image_get_parasite (image_ID, "gimp-comment");
-      if (comment_parasite)
-        comment = gimp_parasite_data (comment_parasite);
-
       /* Exif */
 
-      if (! gexiv2_metadata_has_exif (metadata))
+      if (! gimp_attributes_has_tag_type (attributes, TAG_EXIF))
         *suggested_flags &= ~GIMP_METADATA_SAVE_EXIF;
 
-      if (comment)
-        {
-          gexiv2_metadata_set_tag_string (metadata,
-                                          "Exif.Photo.UserComment",
-                                          comment);
-          gexiv2_metadata_set_tag_string (metadata,
-                                          "Exif.Image.ImageDescription",
-                                          comment);
-        }
-
-      g_snprintf (buffer, sizeof (buffer),
-                  "%d:%02d:%02d %02d:%02d:%02d",
-                  g_date_time_get_year (datetime),
-                  g_date_time_get_month (datetime),
-                  g_date_time_get_day_of_month (datetime),
-                  g_date_time_get_hour (datetime),
-                  g_date_time_get_minute (datetime),
-                  g_date_time_get_second (datetime));
-      gexiv2_metadata_set_tag_string (metadata,
-                                      "Exif.Image.DateTime",
-                                      buffer);
-
-      gexiv2_metadata_set_tag_string (metadata,
-                                      "Exif.Image.Software",
-                                      PACKAGE_STRING);
-
-      gimp_metadata_set_pixel_size (metadata,
-                                    image_width, image_height);
-
-      gimp_image_get_resolution (image_ID, &xres, &yres);
-      gimp_metadata_set_resolution (metadata, xres, yres,
-                                    gimp_image_get_unit (image_ID));
 
       /* XMP */
 
-      if (! gexiv2_metadata_has_xmp (metadata))
+      if (! gimp_attributes_has_tag_type (attributes, TAG_XMP))
         *suggested_flags &= ~GIMP_METADATA_SAVE_XMP;
 
-      gexiv2_metadata_set_tag_string (metadata,
-                                      "Xmp.dc.Format",
-                                      mime_type);
-
-      if (! g_strcmp0 (mime_type, "image/tiff"))
-        {
-          /* TIFF specific XMP data */
-
-          g_snprintf (buffer, sizeof (buffer), "%d", image_width);
-          gexiv2_metadata_set_tag_string (metadata,
-                                          "Xmp.tiff.ImageWidth",
-                                          buffer);
-
-          g_snprintf (buffer, sizeof (buffer), "%d", image_height);
-          gexiv2_metadata_set_tag_string (metadata,
-                                          "Xmp.tiff.ImageLength",
-                                          buffer);
-
-          g_snprintf (buffer, sizeof (buffer),
-                      "%d:%02d:%02d %02d:%02d:%02d",
-                      g_date_time_get_year (datetime),
-                      g_date_time_get_month (datetime),
-                      g_date_time_get_day_of_month (datetime),
-                      g_date_time_get_hour (datetime),
-                      g_date_time_get_minute (datetime),
-                      g_date_time_get_second (datetime));
-          gexiv2_metadata_set_tag_string (metadata,
-                                          "Xmp.tiff.DateTime",
-                                          buffer);
-        }
 
       /* IPTC */
 
-      if (! gexiv2_metadata_has_iptc (metadata))
+      if (! gimp_attributes_has_tag_type (attributes, TAG_IPTC))
         *suggested_flags &= ~GIMP_METADATA_SAVE_IPTC;
 
-      g_snprintf (buffer, sizeof (buffer),
-                  "%d-%d-%d",
-                  g_date_time_get_year (datetime),
-                  g_date_time_get_month (datetime),
-                  g_date_time_get_day_of_month (datetime));
-      gexiv2_metadata_set_tag_string (metadata,
-                                      "Iptc.Application2.DateCreated",
-                                      buffer);
-
-      g_snprintf (buffer, sizeof (buffer),
-                  "%02d:%02d:%02d-%02d:%02d",
-                  g_date_time_get_hour (datetime),
-                  g_date_time_get_minute (datetime),
-                  g_date_time_get_second (datetime),
-                  g_date_time_get_hour (datetime),
-                  g_date_time_get_minute (datetime));
-      gexiv2_metadata_set_tag_string (metadata,
-                                      "Iptc.Application2.TimeCreated",
-                                      buffer);
-
-      g_date_time_unref (datetime);
 
       /* Thumbnail */
 
@@ -339,7 +256,7 @@ gimp_image_metadata_save_prepare (gint32                 image_ID,
         *suggested_flags &= ~GIMP_METADATA_SAVE_THUMBNAIL;
     }
 
-  return metadata;
+  return attributes;
 }
 
 /**
@@ -362,22 +279,25 @@ gimp_image_metadata_save_prepare (gint32                 image_ID,
 gboolean
 gimp_image_metadata_save_finish (gint32                  image_ID,
                                  const gchar            *mime_type,
-                                 GimpMetadata           *metadata,
+                                 GimpAttributes         *attributes,
                                  GimpMetadataSaveFlags   flags,
                                  GFile                  *file,
                                  GError                **error)
 {
   GExiv2Metadata *new_metadata;
-  gboolean        support_exif;
-  gboolean        support_xmp;
-  gboolean        support_iptc;
-  gchar          *value;
   gboolean        success = FALSE;
-  gint            i;
+  gchar               buffer[32];
+  GDateTime          *datetime;
+  const GimpParasite *comment_parasite;
+  const gchar        *comment = NULL;
+  gint                image_width;
+  gint                image_height;
+  gdouble             xres;
+  gdouble             yres;
 
   g_return_val_if_fail (image_ID > 0, FALSE);
   g_return_val_if_fail (mime_type != NULL, FALSE);
-  g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), FALSE);
+  g_return_val_if_fail (attributes != NULL, FALSE);
   g_return_val_if_fail (G_IS_FILE (file), FALSE);
   g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
 
@@ -387,74 +307,138 @@ gimp_image_metadata_save_finish (gint32                  image_ID,
                   GIMP_METADATA_SAVE_THUMBNAIL)))
     return TRUE;
 
+  image_width  = gimp_image_width  (image_ID);
+  image_height = gimp_image_height (image_ID);
+
+  datetime = g_date_time_new_now_local ();
+
+  comment_parasite = gimp_image_get_parasite (image_ID, "gimp-comment");
+  if (comment_parasite)
+    comment = gimp_parasite_data (comment_parasite);
+
   /* read metadata from saved file */
   new_metadata = gimp_metadata_load_from_file (file, error);
 
   if (! new_metadata)
     return FALSE;
 
-  support_exif = gexiv2_metadata_get_supports_exif (new_metadata);
-  support_xmp  = gexiv2_metadata_get_supports_xmp  (new_metadata);
-  support_iptc = gexiv2_metadata_get_supports_iptc (new_metadata);
+  /* Exif */
 
-  if ((flags & GIMP_METADATA_SAVE_EXIF) && support_exif)
+  if (flags & GIMP_METADATA_SAVE_EXIF)
     {
-      gchar **exif_data = gexiv2_metadata_get_exif_tags (metadata);
 
-      for (i = 0; exif_data[i] != NULL; i++)
+      if (comment)
         {
-          if (! gexiv2_metadata_has_tag (new_metadata, exif_data[i]) &&
-              gimp_metadata_is_tag_supported (exif_data[i], mime_type))
-            {
-              value = gexiv2_metadata_get_tag_string (metadata, exif_data[i]);
-              gexiv2_metadata_set_tag_string (new_metadata, exif_data[i],
-                                              value);
-              g_free (value);
-            }
+          gimp_attributes_new_attribute (attributes,
+                                         "Exif.Photo.UserComment",
+                                         (gchar *) comment,
+                                         TYPE_UNICODE);
+          gimp_attributes_new_attribute (attributes,
+                                         "Exif.Image.ImageDescription",
+                                         (gchar *) comment,
+                                         TYPE_ASCII);
         }
 
-      g_strfreev (exif_data);
+      g_snprintf (buffer, sizeof (buffer),
+                  "%d:%02d:%02d %02d:%02d:%02d",
+                  g_date_time_get_year (datetime),
+                  g_date_time_get_month (datetime),
+                  g_date_time_get_day_of_month (datetime),
+                  g_date_time_get_hour (datetime),
+                  g_date_time_get_minute (datetime),
+                  g_date_time_get_second (datetime));
+      gimp_attributes_new_attribute (attributes,
+                                     "Exif.Image.DateTime",
+                                     buffer,
+                                     TYPE_ASCII);
+
+      gimp_attributes_new_attribute (attributes,
+                                     "Exif.Image.Software",
+                                     buffer,
+                                     TYPE_ASCII);
+
+      gimp_attributes_set_pixel_size (attributes,
+                                      image_width, image_height);
+
+      gimp_image_get_resolution (image_ID, &xres, &yres);
+      gimp_attributes_set_resolution (attributes, xres, yres,
+                                      gimp_image_get_unit (image_ID));
     }
 
-  if ((flags & GIMP_METADATA_SAVE_XMP) && support_xmp)
+  /* XMP */
+
+  if (flags & GIMP_METADATA_SAVE_XMP)
     {
-      gchar **xmp_data = gexiv2_metadata_get_xmp_tags (metadata);
+      gimp_attributes_new_attribute (attributes,
+                                     "Xmp.dc.Format",
+                                     (gchar *) mime_type,
+                                     TYPE_ASCII);
 
-      for (i = 0; xmp_data[i] != NULL; i++)
+      if (! g_strcmp0 (mime_type, "image/tiff"))
         {
-          if (! gexiv2_metadata_has_tag (new_metadata, xmp_data[i]) &&
-              gimp_metadata_is_tag_supported (xmp_data[i], mime_type))
-            {
-              value = gexiv2_metadata_get_tag_string (metadata, xmp_data[i]);
-              gexiv2_metadata_set_tag_string (new_metadata, xmp_data[i],
-                                              value);
-              g_free (value);
-            }
-        }
+          /* TIFF specific XMP data */
+
+          g_snprintf (buffer, sizeof (buffer), "%d", image_width);
+          gimp_attributes_new_attribute (attributes,
+                                         "Xmp.tiff.ImageWidth",
+                                         buffer,
+                                         TYPE_ASCII);
 
-      g_strfreev (xmp_data);
+          g_snprintf (buffer, sizeof (buffer), "%d", image_height);
+          gimp_attributes_new_attribute (attributes,
+                                         "Xmp.tiff.ImageLength",
+                                         buffer,
+                                         TYPE_ASCII);
+
+          g_snprintf (buffer, sizeof (buffer),
+                      "%d:%02d:%02d %02d:%02d:%02d",
+                      g_date_time_get_year (datetime),
+                      g_date_time_get_month (datetime),
+                      g_date_time_get_day_of_month (datetime),
+                      g_date_time_get_hour (datetime),
+                      g_date_time_get_minute (datetime),
+                      g_date_time_get_second (datetime));
+          gimp_attributes_new_attribute (attributes,
+                                         "Xmp.tiff.DateTime",
+                                         buffer,
+                                         TYPE_ASCII);
+        }
     }
 
-  if ((flags & GIMP_METADATA_SAVE_IPTC) && support_iptc)
+  /* IPTC */
+
+  if (flags & GIMP_METADATA_SAVE_IPTC)
     {
-      gchar **iptc_data = gexiv2_metadata_get_iptc_tags (metadata);
 
-      for (i = 0; iptc_data[i] != NULL; i++)
-        {
-          if (! gexiv2_metadata_has_tag (new_metadata, iptc_data[i]) &&
-              gimp_metadata_is_tag_supported (iptc_data[i], mime_type))
-            {
-              value = gexiv2_metadata_get_tag_string (metadata, iptc_data[i]);
-              gexiv2_metadata_set_tag_string (new_metadata, iptc_data[i],
-                                              value);
-              g_free (value);
-            }
-        }
+      g_snprintf (buffer, sizeof (buffer),
+                  "%d-%d-%d",
+                  g_date_time_get_year (datetime),
+                  g_date_time_get_month (datetime),
+                  g_date_time_get_day_of_month (datetime));
+      gimp_attributes_new_attribute (attributes,
+                                     "Iptc.Application2.DateCreated",
+                                     buffer,
+                                     TYPE_ASCII);
+
+      g_snprintf (buffer, sizeof (buffer),
+                  "%02d:%02d:%02d",
+                  g_date_time_get_hour (datetime),
+                  g_date_time_get_minute (datetime),
+                  g_date_time_get_second (datetime));
+      gimp_attributes_new_attribute (attributes,
+                                     "Iptc.Application2.TimeCreated",
+                                     buffer,
+                                     TYPE_ASCII);
+
+      g_date_time_unref (datetime);
 
-      g_strfreev (iptc_data);
     }
 
-  if (flags & GIMP_METADATA_SAVE_THUMBNAIL)
+  gimp_attributes_to_metadata (attributes, new_metadata, mime_type);
+
+  /* Thumbnail */
+
+  if ((flags & GIMP_METADATA_SAVE_THUMBNAIL) && g_strcmp0 (mime_type, "image/tiff"))
     {
       GdkPixbuf *thumb_pixbuf;
       gchar     *thumb_buffer;
diff --git a/libgimp/gimpmetadata.h b/libgimp/gimpmetadata.h
index 7cd4674..b7261e3 100644
--- a/libgimp/gimpmetadata.h
+++ b/libgimp/gimpmetadata.h
@@ -35,17 +35,18 @@ GimpMetadata * gimp_image_metadata_load_prepare (gint32                 image_ID
                                                  GFile                 *file,
                                                  GError               **error);
 void           gimp_image_metadata_load_finish  (gint32                 image_ID,
+                                                 gint32                 layer_ID,
                                                  const gchar           *mime_type,
                                                  GimpMetadata          *metadata,
                                                  GimpMetadataLoadFlags  flags,
                                                  gboolean               interactive);
 
-GimpMetadata * gimp_image_metadata_save_prepare (gint32                 image_ID,
+GimpAttributes * gimp_image_metadata_save_prepare (gint32                 image_ID,
                                                  const gchar           *mime_type,
                                                  GimpMetadataSaveFlags *suggested_flags);
 gboolean       gimp_image_metadata_save_finish  (gint32                 image_ID,
                                                  const gchar           *mime_type,
-                                                 GimpMetadata          *metadata,
+                                                 GimpAttributes        *attributes,
                                                  GimpMetadataSaveFlags  flags,
                                                  GFile                 *file,
                                                  GError               **error);
diff --git a/libgimp/gimpviewable.c b/libgimp/gimpviewable.c
new file mode 100644
index 0000000..47b9e5c
--- /dev/null
+++ b/libgimp/gimpviewable.c
@@ -0,0 +1,84 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2000 Peter Mattis and Spencer Kimball
+ *
+ * gimpimage.c
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gimp.h"
+#include "gimpimage.h"
+
+/**
+ * gimp_viewable_get_attributes:
+ * @object_ID: The viewable object.
+ *
+ * Returns the viewable's attributes.
+ *
+ * Returns attributes from the viewable.
+ *
+ * Returns: The attributes, or %NULL if there is none.
+ *
+ * Since: GIMP 2.10
+ **/
+GimpAttributes *
+gimp_viewable_get_attributes (gint32 object_ID)
+{
+  GimpAttributes *attributes = NULL;
+  gchar          *attributes_string;
+
+  attributes_string = _gimp_viewable_get_attributes (object_ID);
+  if (attributes_string)
+    {
+      attributes = gimp_attributes_deserialize (NULL, attributes_string);
+      g_free (attributes_string);
+    }
+
+  return attributes;
+}
+
+/**
+ * gimp_viewable_set_attributes:
+ * @object_ID: The viewable object.
+ * @attributes: The GimpAttributes object.
+ *
+ * Set the viewable's attributes.
+ *
+ * Sets attributes on the viewable, or deletes it if
+ * @attributes is %NULL.
+ *
+ * Returns: TRUE on success.
+ *
+ * Since: GIMP 2.10
+ **/
+gboolean
+gimp_viewable_set_attributes (gint32          object_ID,
+                              GimpAttributes *attributes)
+{
+  gchar    *attributes_string = NULL;
+  gboolean  success;
+
+  if (attributes)
+    attributes_string = gimp_attributes_serialize (attributes);
+
+  success = _gimp_viewable_set_attributes (object_ID, attributes_string);
+
+  if (attributes_string)
+    g_free (attributes_string);
+
+  return success;
+}
diff --git a/libgimp/gimpviewable_pdb.c b/libgimp/gimpviewable_pdb.c
new file mode 100644
index 0000000..9d1fddc
--- /dev/null
+++ b/libgimp/gimpviewable_pdb.c
@@ -0,0 +1,100 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-2003 Peter Mattis and Spencer Kimball
+ *
+ * gimpimage_pdb.c
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+/* NOTE: This file is auto-generated by pdbgen.pl */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "gimp.h"
+
+
+/**
+ * SECTION: gimpimage
+ * @title: gimpimage
+ * @short_description: Operations on complete images.
+ *
+ * Operations on complete images: creation, resizing/rescaling, and
+ * operations involving multiple layers.
+ **/
+
+/**
+ * _gimp_viewable_get_attributes:
+ * @object_ID: The viewable object.
+ *
+ * Returns the viewable's attributes.
+ *
+ * Returns attributes from the viewable.
+ *
+ * Returns: The attributes as a xml string.
+ **/
+gchar *
+_gimp_viewable_get_attributes (gint32 object_ID)
+{
+  GimpParam *return_vals;
+  gint nreturn_vals;
+  gchar *attributes_string = NULL;
+
+  return_vals = gimp_run_procedure ("gimp-viewable-get-attributes",
+                                    &nreturn_vals,
+                                    GIMP_PDB_IMAGE, object_ID,
+                                    GIMP_PDB_END);
+
+  if (return_vals[0].data.d_status == GIMP_PDB_SUCCESS)
+    attributes_string = g_strdup (return_vals[1].data.d_string);
+
+  gimp_destroy_params (return_vals, nreturn_vals);
+
+  return attributes_string;
+}
+
+/**
+ * _gimp_viewable_set_attributes:
+ * @object_ID: The viewable object.
+ * @attributes_string: The attributes as a string.
+ *
+ * Set the viewable's attributes.
+ *
+ * Sets attributes on the viewable.
+ *
+ * Returns: TRUE on success.
+ **/
+gboolean
+_gimp_image_set_attributes (gint32       object_ID,
+                            const gchar *attributes_string)
+{
+  GimpParam *return_vals;
+  gint nreturn_vals;
+  gboolean success = TRUE;
+
+  return_vals = gimp_run_procedure ("gimp-viewable-set-attributes",
+                                    &nreturn_vals,
+                                    GIMP_PDB_IMAGE, object_ID,
+                                    GIMP_PDB_STRING, attributes_string,
+                                    GIMP_PDB_END);
+
+  success = return_vals[0].data.d_status == GIMP_PDB_SUCCESS;
+
+  gimp_destroy_params (return_vals, nreturn_vals);
+
+  return success;
+}
+
diff --git a/libgimpbase/Makefile.am b/libgimpbase/Makefile.am
index c97e68f..bf60920 100644
--- a/libgimpbase/Makefile.am
+++ b/libgimpbase/Makefile.am
@@ -90,6 +90,12 @@ libgimpbase_sources = \
        gimpparam.h             \
        gimpversion.h           \
        \
+       gimpattribute.c \
+       gimpattribute.h \
+       gimpattributes.c        \
+       gimpattributes.h        \
+       gimpattributes-image.c  \
+       gimpattributes-image.h  \
        gimpbase-private.c      \
        gimpbase-private.h      \
        gimpchecks.c            \
@@ -110,6 +116,8 @@ libgimpbase_sources = \
        gimpparasiteio.h        \
        gimpprotocol.c          \
        gimpprotocol.h          \
+       gimprational.c          \
+       gimprational.h          \
        gimprectangle.c         \
        gimprectangle.h         \
        gimpreloc.c             \
@@ -143,6 +151,9 @@ libgimpbaseinclude_HEADERS = \
        gimpparam.h             \
        gimpversion.h           \
        \
+       gimpattribute.h         \
+       gimpattributes.h                \
+       gimpattributes-image.h  \
        gimpchecks.h            \
        gimpdatafiles.h         \
        gimpenv.h               \
@@ -150,6 +161,7 @@ libgimpbaseinclude_HEADERS = \
        gimpmetadata.h          \
        gimpparasite.h          \
        gimpparasiteio.h        \
+       gimprational.h          \
        gimprectangle.h         \
        gimpsignal.h            \
        gimpunit.h              \
diff --git a/libgimpbase/gimpattribute.c b/libgimpbase/gimpattribute.c
new file mode 100644
index 0000000..c1645d0
--- /dev/null
+++ b/libgimpbase/gimpattribute.c
@@ -0,0 +1,1858 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpattribute.c
+ * Copyright (C) 2014  Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib-object.h>
+
+#ifdef G_OS_WIN32
+#endif
+
+#include "gimpbasetypes.h"
+#include "gimpattribute.h"
+#include "gimprational.h"
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL)))
+#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
+
+typedef struct _TagTime TagTime;
+typedef struct _TagDate TagDate;
+
+struct _TagTime {
+    int tag_time_sec;
+    int tag_time_min;
+    int tag_time_hour;
+    int tag_tz_hour;
+    int tag_tz_min;
+  };
+
+struct _TagDate {
+    int tag_year;
+    int tag_month;
+    int tag_day;
+  };
+
+
+typedef struct _GimpAttributeClass GimpAttributeClass;
+typedef struct _GimpAttributePrivate GimpAttributePrivate;
+
+struct _GimpAttribute {
+  GObject               parent_instance;
+  GimpAttributePrivate *priv;
+};
+
+struct _GimpAttributeClass {
+  GObjectClass parent_class;
+};
+
+struct _GimpAttributePrivate {
+  gchar                      *name;
+
+  gchar                      *tag_value;
+  gchar                      *interpreted_value;
+
+  gchar                      *exif_type;
+
+  GimpAttributeValueType      value_type;
+  GimpAttributeTagType        tag_type;
+
+  gchar                      *attribute_type;
+  gchar                      *attribute_ifd;
+  gchar                      *attribute_tag;
+  gboolean                    is_new_name_space;
+
+  gboolean                    has_structure;
+  GimpAttributeStructureType  structure_type;
+  GSList                     *attribute_structure;
+
+};
+
+enum  {
+  PROP_0,
+  PROP_NAME,
+  PROP_LONG_VALUE,
+  PROP_SLONG_VALUE,
+  PROP_SHORT_VALUE,
+  PROP_SSHORT_VALUE,
+  PROP_DATE_VALUE,
+  PROP_TIME_VALUE,
+  PROP_ASCII_VALUE,
+  PROP_BYTE_VALUE,
+  PROP_MULTIPLE_VALUE,
+  PROP_RATIONAL_VALUE,
+  PROP_SRATIONAL_VALUE
+};
+
+static const gchar *xmp_namespaces[] =
+{
+    "dc",
+    "xmp",
+    "xmpRights",
+    "xmpMM",
+    "xmpBJ",
+    "xmpTPg",
+    "xmpDM",
+    "pdf",
+    "photoshop",
+    "crs",
+    "tiff",
+    "exif",
+    "aux",
+    "plus",
+    "digiKam",
+    "iptc",
+    "iptcExt",
+    "Iptc4xmpCore",
+    "Iptc4xmpExt",
+    "MicrosoftPhoto",
+    "kipi",
+    "mediapro",
+    "expressionmedia",
+    "MP",
+    "MPRI",
+    "MPReg",
+    "mwg-rs"
+};
+
+
+static gpointer gimp_attribute_parent_class = NULL;
+static gint counter = 0;
+
+
+static GimpAttribute*          gimp_attribute_construct              (GType                object_type,
+                                                                      const gchar         *name);
+static void                    gimp_attribute_finalize               (GObject             *obj);
+static void                    gimp_attribute_get_property           (GObject             *object,
+                                                                      guint                property_id,
+                                                                      GValue              *value,
+                                                                      GParamSpec          *pspec);
+static void                    gimp_attribute_set_property           (GObject             *object,
+                                                                      guint                property_id,
+                                                                      const GValue        *value,
+                                                                      GParamSpec          *pspec);
+static void                    gimp_attribute_set_name               (GimpAttribute       *attribute,
+                                                                      const gchar         *value);
+static gboolean                get_tag_time                          (gchar               *input,
+                                                                      TagTime             *tm);
+static gboolean                get_tag_date                          (gchar               *input,
+                                                                      TagDate             *dt);
+static gchar *                 gimp_attribute_escape_value           (gchar               *name,
+                                                                      gchar               *value,
+                                                                      gboolean            *encoded);
+static gchar*                  string_replace_str                    (const gchar         *original,
+                                                                      const gchar         *old_pattern,
+                                                                      const gchar         *replacement);
+static gint                    string_index_of                       (gchar               *haystack,
+                                                                      gchar               *needle,
+                                                                      gint                 start_index);
+static glong                   string_strnlen                        (gchar               *str,
+                                                                      glong                maxlen);
+static gchar*                  string_substring                      (gchar               *attribute,
+                                                                      glong                offset,
+                                                                      glong                len);
+
+
+/**
+ * gimp_attribute_new_string:
+ *
+ * @name:         a constant #gchar that describes the name of the attribute
+ * @value:        a #gchar value, representing a time
+ * @type:         a #GimpAttributeTagType
+ *
+ * Creates a new #GimpAttribute object with @name as name and a #gchar @value
+ * as value of type @type.
+ * @value is converted to the correct type.
+ *
+ * Return value:  a new @GimpAttribute
+ *
+ * Since: 2.10
+ */
+GimpAttribute*
+gimp_attribute_new_string (const gchar *name,
+                           gchar *value,
+                           GimpAttributeValueType type)
+{
+  GimpAttribute *attribute = NULL;
+  GimpAttributePrivate *private;
+
+  attribute = gimp_attribute_construct (GIMP_TYPE_ATTRIBUTE, name);
+  if (attribute)
+    {
+      private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+      private->tag_value = g_strdup (value);
+      private->value_type = type;
+    }
+
+  return attribute;
+}
+
+/**
+ * gimp_attribute_get_name:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value: full name of the #GimpAttribute object
+ * e.g. "Exif.Image.XResolution"
+ *
+ * Since: 2.10
+ */
+const gchar*
+gimp_attribute_get_name (GimpAttribute* attribute)
+{
+  GimpAttributePrivate *private;
+  g_return_val_if_fail (attribute != NULL, NULL);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  return (const gchar *) private->name;
+}
+
+/**
+ * gimp_attribute_get_attribute_type:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value: attribute type of the #GimpAttribute object
+ * e.g. "exif", "iptc", ...
+ *
+ * Since: 2.10
+ */
+const gchar*
+gimp_attribute_get_attribute_type (GimpAttribute* attribute)
+{
+  GimpAttributePrivate *private;
+  g_return_val_if_fail (attribute != NULL, NULL);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  return (const gchar *) private->attribute_type;
+}
+
+/**
+ * gimp_attribute_get_attribute_ifd:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value: ifd of the #GimpAttribute object
+ *
+ * Since: 2.10
+ */
+const gchar*
+gimp_attribute_get_attribute_ifd (GimpAttribute* attribute)
+{
+  GimpAttributePrivate *private;
+  g_return_val_if_fail (attribute != NULL, NULL);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  return (const gchar *) private->attribute_ifd;
+}
+
+/**
+ * gimp_attribute_get_attribute_tag:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value: tag of the #GimpAttribute object
+ *
+ * Since: 2.10
+ */
+const gchar*
+gimp_attribute_get_attribute_tag (GimpAttribute* attribute)
+{
+  GimpAttributePrivate *private;
+  g_return_val_if_fail (attribute != NULL, NULL);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  return (const gchar *) private->attribute_tag;
+}
+
+/**
+ * gimp_attribute_set_value_type:
+ *
+ * @attribute:    a @GimpAttribute
+ * @value_type:   a @GimpAttributeValueType
+ *
+ * sets value type of the #GimpAttribute object
+ *
+ * Since: 2.10
+ */
+void
+gimp_attribute_set_value_type (GimpAttribute* attribute,
+                               GimpAttributeValueType value_type)
+{
+  GimpAttributePrivate *private;
+  g_return_if_fail (attribute != NULL);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  private->value_type = value_type;
+}
+
+/**
+ * gimp_attribute_get_value_type:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value: value type of the #GimpAttribute object
+ *
+ * Since: 2.10
+ */
+GimpAttributeValueType
+gimp_attribute_get_value_type (GimpAttribute* attribute)
+{
+  GimpAttributePrivate *private;
+  g_return_val_if_fail (attribute != NULL, TYPE_INVALID);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  return private->value_type;
+}
+
+/**
+ * gimp_attribute_get_attribute_structure:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value: attribute_structure of the #GimpAttribute object
+ * This is the start value of a xmpBag sequence.
+ *
+ * Since: 2.10
+ */
+GSList *
+gimp_attribute_get_attribute_structure (GimpAttribute* attribute)
+{
+  GimpAttributePrivate *private;
+  g_return_val_if_fail (attribute != NULL, NULL);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  return private->attribute_structure;
+}
+/**
+ * gimp_attribute_is_new_namespace:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value: if namespace must be defined or not
+ *
+ * Since: 2.10
+ */
+const gboolean
+gimp_attribute_is_new_namespace (GimpAttribute* attribute)
+{
+  GimpAttributePrivate *private;
+  g_return_val_if_fail (attribute != NULL, FALSE);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  return (const gboolean) private->is_new_name_space;
+}
+
+/**
+ * gimp_attribute_get_value:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value:  #GValue of the #GimpAttribute object
+ * The type of value is represented by glib-types
+ *
+ * Since: 2.10
+ */
+GValue
+gimp_attribute_get_value (GimpAttribute *attribute)
+{
+  GimpAttributePrivate *private;
+  GValue val     = G_VALUE_INIT;
+  gchar                *value_string;
+
+  g_return_val_if_fail(GIMP_IS_ATTRIBUTE (attribute), val);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  value_string = private->tag_value;
+
+  switch (private->value_type)
+    {
+    case TYPE_LONG:
+      {
+        g_value_init (&val, G_TYPE_ULONG);
+        g_value_set_ulong (&val, (gulong) atol (value_string));
+      }
+      break;
+    case TYPE_SLONG:
+      {
+        g_value_init (&val, G_TYPE_LONG);
+        g_value_set_long (&val, (glong) atol (value_string));
+      }
+      break;
+    case TYPE_SHORT:
+      {
+        g_value_init (&val, G_TYPE_UINT);
+        g_value_set_uint (&val, (guint) atoi (value_string));
+      }
+      break;
+    case TYPE_SSHORT:
+      {
+        g_value_init (&val, G_TYPE_INT);
+        g_value_set_int (&val, (gint) atoi (value_string));
+      }
+      break;
+    case TYPE_DATE:
+      {
+        g_value_init (&val, G_TYPE_STRING);
+        g_value_set_string (&val, value_string);
+      }
+      break;
+    case TYPE_TIME:
+      {
+        g_value_init (&val, G_TYPE_STRING);
+        g_value_set_string (&val, value_string);
+      }
+      break;
+    case TYPE_ASCII:
+      {
+        g_value_init (&val, G_TYPE_STRING);
+        g_value_set_string (&val, value_string);
+      }
+      break;
+    case TYPE_UNICODE:
+      {
+        g_value_init (&val, G_TYPE_STRING);
+        g_value_set_string (&val, value_string);
+      }
+      break;
+    case TYPE_BYTE:
+      {
+        g_value_init (&val, G_TYPE_UCHAR);
+        g_value_set_uchar (&val, value_string[0]);
+      }
+      break;
+    case TYPE_MULTIPLE:
+      {
+        gchar **result;
+
+        g_value_init (&val, G_TYPE_STRV);
+        result = g_strsplit (value_string, "\n", 0);
+        g_value_set_boxed (&val, result);
+      }
+      break;
+    case TYPE_RATIONAL:
+      {
+        gchar **nom;
+        gchar **rats;
+        gint count;
+        gint i;
+        Rational *rval;
+        GArray *rational_array;
+
+        rats = g_strsplit (value_string, " ", -1);
+
+        count = 0;
+        while (rats[count])
+            count++;
+
+        rational_array = g_array_new (TRUE, TRUE, sizeof (RationalValue));
+
+        for (i = 0; i < count; i++)
+          {
+            RationalValue or;
+
+            nom = g_strsplit (rats[i], "/", 2);
+
+            if (nom[0] && nom[1])
+              {
+                or.nom = (guint) atoi (nom [0]);
+                or.denom = (guint) atoi (nom [1]);
+              }
+            else
+              count--;
+
+            rational_array = g_array_append_val (rational_array, or);
+
+            g_strfreev (nom);
+          }
+
+        rval = g_slice_new (Rational);
+
+        rval->rational_array = rational_array;
+        rval->length = count;
+
+        g_value_init (&val, GIMP_TYPE_RATIONAL);
+        g_value_set_boxed (&val, rval);
+
+        g_strfreev (rats);
+      }
+      break;
+    case TYPE_SRATIONAL:
+      {
+        gchar **nom;
+        gchar **srats;
+        gint count;
+        gint i;
+        SRational *srval;
+        GArray *srational_array;
+
+        srats = g_strsplit (value_string, " ", -1);
+
+        count = 0;
+        while (srats[count])
+            count++;
+
+        srational_array = g_array_new (TRUE, TRUE, sizeof (SRationalValue));
+
+        for (i = 0; i < count; i++)
+          {
+            SRationalValue or;
+
+            nom = g_strsplit (srats[i], "/", 2);
+
+            if (nom[0] && nom[1])
+              {
+                or.nom = (gint) atoi (nom [0]);
+                or.denom = (guint) atoi (nom [1]);
+              }
+            else
+              count--;
+
+            srational_array = g_array_append_val (srational_array, or);
+
+            g_strfreev (nom);
+          }
+
+        srval = g_slice_new (SRational);
+
+        srval->srational_array = srational_array;
+        srval->length = count;
+
+        g_value_init (&val, GIMP_TYPE_SRATIONAL);
+        g_value_set_boxed (&val, srval);
+
+        g_strfreev (srats);
+      }
+      break;
+    case TYPE_UNKNOWN:
+      default:
+      break;
+    }
+
+  return val;
+}
+
+/**
+ * gimp_attribute_get_string:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * Return value:  newly allocated #gchar string representation of the #GimpAttribute object.
+ * The return is always a valid value according to the #GimpAttributeValueType
+ *
+ * Since: 2.10
+ */
+gchar*
+gimp_attribute_get_string (GimpAttribute *attribute)
+{
+  GimpAttributePrivate *private;
+  gchar                *val = NULL;
+  TagDate               dt = {0};
+  TagTime               tm = {0};
+
+  g_return_val_if_fail(GIMP_IS_ATTRIBUTE (attribute), NULL);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  switch (private->value_type)
+    {
+    case TYPE_INVALID:
+      break;
+    case TYPE_LONG:
+      {
+        val = g_strdup_printf ("%lu", (gulong) atol (private->tag_value));
+      }
+      break;
+    case TYPE_SLONG:
+      {
+        val = g_strdup_printf ("%ld", (glong) atol (private->tag_value));
+      }
+      break;
+    case TYPE_FLOAT:
+      {
+        val = g_strdup_printf ("%.5f", (gfloat) atof (private->tag_value));
+      }
+      break;
+    case TYPE_DOUBLE:
+      {
+        val = g_strdup_printf ("%.6f", (gdouble) atof (private->tag_value));
+      }
+      break;
+    case TYPE_SHORT:
+      {
+        val = g_strdup_printf ("%u", (gushort) atoi (private->tag_value));
+      }
+      break;
+    case TYPE_SSHORT:
+      {
+        val = g_strdup_printf ("%d", (gshort) atoi (private->tag_value));
+      }
+      break;
+    case TYPE_DATE:
+      {
+        get_tag_date (private->tag_value, &dt);
+
+        val = g_strdup_printf ("%4d-%02d-%02d", dt.tag_year,
+                                            dt.tag_month,
+                                            dt.tag_day);
+      }
+      break;
+    case TYPE_TIME:
+      {
+        gchar *tz_h = NULL;
+        get_tag_time (private->tag_value, &tm);
+
+        tz_h = tm.tag_tz_hour < 0 ?
+            g_strdup_printf ("-%02d", tm.tag_tz_hour) :
+            g_strdup_printf ("+%02d", tm.tag_tz_hour);
+
+        val = g_strdup_printf ("%02d:%02d:%02d%s:%02d", tm.tag_time_hour,
+                                                  tm.tag_time_min,
+                                                  tm.tag_time_sec,
+                                                  tz_h,
+                                                  tm.tag_tz_min);
+        g_free (tz_h);
+      }
+      break;
+    case TYPE_ASCII:
+      {
+        val = g_strdup (private->tag_value);
+      }
+      break;
+    case TYPE_UNICODE:
+      {
+        val = g_strdup (private->tag_value);
+      }
+      break;
+    case TYPE_BYTE:
+      {
+        val = g_strdup_printf ("%c", private->tag_value[0]);
+      }
+      break;
+    case TYPE_MULTIPLE:
+      {
+        val = g_strdup (private->tag_value);
+      }
+      break;
+    case TYPE_RATIONAL:
+      {
+        gint i;
+        GString        *string;
+        Rational      *rational;
+
+        string_to_rational (private->tag_value, &rational);
+
+        string = g_string_new (NULL);
+
+        for (i = 0; i < rational->length; i++)
+          {
+            RationalValue or;
+
+            or = g_array_index (rational->rational_array, RationalValue, i);
+
+            g_string_append_printf (string, "%u/%u ",
+                                    or.nom,
+                                    or.denom);
+          }
+        g_string_truncate (string, string->len-1);
+        val = g_string_free (string, FALSE);
+      }
+      break;
+    case TYPE_SRATIONAL:
+      {
+        gint i;
+        GString        *string;
+        SRational      *srational;
+
+        string_to_srational (private->tag_value, &srational);
+
+        string = g_string_new (NULL);
+
+        for (i = 0; i < srational->length; i++)
+          {
+            SRationalValue or;
+
+            or = g_array_index (srational->srational_array, SRationalValue, i);
+
+            g_string_append_printf (string, "%u/%u ",
+                                    or.nom,
+                                    or.denom);
+          }
+
+        g_string_truncate (string, string->len-1);
+        val = g_string_free (string, FALSE);
+      }
+      break;
+    case TYPE_UNKNOWN:
+      default:
+      break;
+    }
+  return val;
+}
+
+/**
+ * gimp_attribute_get_interpreted_string:
+ *
+ * @attribute:    a #GimpAttribute
+ *
+ * returns the interpreted value or the pure string, if no
+ * interpreted value is found
+ *
+ * Since: 2.10
+ */
+const gchar *
+gimp_attribute_get_interpreted_string (GimpAttribute *attribute)
+{
+  GimpAttributePrivate *private;
+
+  g_return_val_if_fail(GIMP_IS_ATTRIBUTE (attribute), NULL);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  if (private->interpreted_value)
+    return (const gchar *) private->interpreted_value;
+  else
+    return (const gchar *) private->tag_value;
+}
+
+/**
+ * gimp_attribute_set_interpreted_string:
+ *
+ * @attribute:    a #GimpAttribute
+ * @value:        a constant #gchar
+ *
+ * sets the interpreted string of the #GimpAttribute object to
+ * a @value
+ *
+ * @value can be freed after
+ *
+ * Since: 2.10
+ */
+void
+gimp_attribute_set_interpreted_string (GimpAttribute* attribute, const gchar* value)
+{
+  GimpAttributePrivate *private;
+
+  g_return_if_fail(GIMP_IS_ATTRIBUTE (attribute));
+  g_return_if_fail (value != NULL);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  private->interpreted_value = g_strdup (value);
+}
+
+/**
+ * gimp_attribute_get_tag_type:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ *
+ * Return value:  #GimpAttributeTagType
+ * The tag type of the Attribute
+ *
+ * Since: 2.10
+ */
+GimpAttributeTagType
+gimp_attribute_get_tag_type (GimpAttribute *attribute)
+{
+  GimpAttributePrivate *private;
+
+  g_return_val_if_fail (attribute != NULL, TAG_INVALID);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  return private->tag_type;
+}
+
+void
+gimp_attribute_print (GimpAttribute *attribute)
+{
+  const gchar    *tag;
+  const gchar    *interpreted;
+  gchar          *value;
+
+  g_return_if_fail(GIMP_IS_ATTRIBUTE (attribute));
+
+  tag = gimp_attribute_get_name (attribute);
+  value = gimp_attribute_get_string (attribute);
+  interpreted = gimp_attribute_get_interpreted_string (attribute);
+
+  g_print ("---\n%p\nTag: %s\n\tValue:%s\n\tInterpreted value:%s\n", attribute, tag, value, interpreted);
+
+}
+
+/**
+ * gimp_attribute_get_xml:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * returns the xml representation of the #GimpAttribute
+ * in form:
+ *
+ * <tag name="name" type="GimpAttributeValueType">
+ * <value [encoding=base64]>value</value>
+ * [<interpreted [encoding=base64]>interpreted value</interpreted>]
+ * </tag>
+ *
+ * Return value:  #gchar xml representation of the #GimpAttribute object
+ *
+ * Since: 2.10
+ */
+gchar*
+gimp_attribute_get_xml (GimpAttribute *attribute)
+{
+  gchar                *v_escaped            = NULL;
+  gchar                *i_escaped            = NULL;
+  gchar                *interpreted_tag_elem = NULL;
+  gboolean              is_interpreted       = FALSE;
+  gboolean              encoded;
+  gchar                *start_tag_elem;
+  gchar                *end_tag_elem;
+  gchar                *value_tag_elem;
+  gchar                *struct_tag_elem      = NULL;
+  gboolean              utf                  = TRUE;
+  GimpAttributePrivate *private;
+  GString              *xml;
+
+  g_return_val_if_fail (GIMP_IS_ATTRIBUTE (attribute), NULL);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  xml = g_string_new (NULL);
+
+  if(private->interpreted_value && g_strcmp0 (private->tag_value, private->interpreted_value))
+    {
+      is_interpreted = TRUE;
+    }
+
+  v_escaped = gimp_attribute_escape_value (private->name, private->tag_value, &encoded);
+
+  start_tag_elem = g_strdup_printf ("  <tag name=\"%s\" type=\"%d\">\n", private->name, private->value_type);
+  end_tag_elem   = g_strdup_printf ("  </tag>");
+
+  g_string_append (xml, start_tag_elem);
+
+  if (encoded)
+    {
+      value_tag_elem = g_strdup_printf ("    <value encoding=\"base64\">%s</value>\n", v_escaped);
+    }
+  else
+    {
+      value_tag_elem = g_strdup_printf ("    <value>%s</value>\n", v_escaped);
+    }
+
+  g_string_append (xml, value_tag_elem);
+
+  if (private->has_structure)
+    {
+      struct_tag_elem = g_strdup_printf ("    <structure>%d</structure>\n", private->structure_type);
+      g_string_append (xml, struct_tag_elem);
+    }
+
+  if (is_interpreted && utf)
+    {
+      i_escaped = gimp_attribute_escape_value (private->name, private->interpreted_value, &encoded);
+
+      if (encoded)
+        {
+          interpreted_tag_elem = g_strdup_printf ("    <interpreted encoding=\"base64\">%s</interpreted>\n", 
i_escaped);
+        }
+      else
+        {
+          interpreted_tag_elem = g_strdup_printf ("    <interpreted>%s</interpreted>\n", i_escaped);
+        }
+
+      g_string_append (xml, interpreted_tag_elem);
+    }
+
+  g_string_append (xml, end_tag_elem);
+
+  g_free (v_escaped);
+  g_free (start_tag_elem);
+  g_free (end_tag_elem);
+  g_free (value_tag_elem);
+  if (i_escaped)
+    g_free (i_escaped);
+  if (interpreted_tag_elem)
+    g_free (interpreted_tag_elem);
+  if (struct_tag_elem)
+    g_free (interpreted_tag_elem);
+
+  return g_string_free (xml, FALSE);
+}
+
+/**
+ * gimp_attribute_get_value_type_from_string:
+ *
+ * @exiv_tag_type_string:    a @gchar
+ *
+ * converts a string representation tag type from gexiv2/exiv2
+ * to a #GimpAttributeValueType
+ *
+ * Return value: #GimpAttributeValueType
+ *
+ * Since: 2.10
+ */
+GimpAttributeValueType
+gimp_attribute_get_value_type_from_string (const gchar* string)
+{
+  GimpAttributeValueType type;
+  gchar *lowchar;
+
+  if (! string)
+    return TYPE_INVALID;
+
+  lowchar = g_ascii_strdown (string, -1);
+
+  if (!g_strcmp0 (lowchar, "invalid"))
+    type = TYPE_INVALID;
+  else if (!g_strcmp0 (lowchar, "byte"))
+    type = TYPE_BYTE;
+  else if (!g_strcmp0 (lowchar, "ascii"))
+    type = TYPE_ASCII;
+  else if (!g_strcmp0 (lowchar, "short"))
+    type = TYPE_SHORT;
+  else if (!g_strcmp0 (lowchar, "long"))
+    type = TYPE_LONG;
+  else if (!g_strcmp0 (lowchar, "rational"))
+    type = TYPE_RATIONAL;
+  else if (!g_strcmp0 (lowchar, "sbyte"))
+    type = TYPE_BYTE;
+  else if (!g_strcmp0 (lowchar, "undefined"))
+    type = TYPE_ASCII;
+  else if (!g_strcmp0 (lowchar, "sshort"))
+    type = TYPE_SSHORT;
+  else if (!g_strcmp0 (lowchar, "slong"))
+    type = TYPE_SLONG;
+  else if (!g_strcmp0 (lowchar, "srational"))
+    type = TYPE_SRATIONAL;
+  else if (!g_strcmp0 (lowchar, "float"))
+    type = TYPE_FLOAT;
+  else if (!g_strcmp0 (lowchar, "double"))
+    type = TYPE_DOUBLE;
+  else if (!g_strcmp0 (lowchar, "ifd"))
+    type = TYPE_ASCII;
+  else if (!g_strcmp0 (lowchar, "string"))
+    type = TYPE_UNICODE;
+  else if (!g_strcmp0 (lowchar, "date"))
+    type = TYPE_DATE;
+  else if (!g_strcmp0 (lowchar, "time"))
+    type = TYPE_TIME;
+  else if (!g_strcmp0 (lowchar, "comment"))
+    type = TYPE_UNICODE;
+  else if (!g_strcmp0 (lowchar, "directory"))
+    type = TYPE_UNICODE;
+  else if (!g_strcmp0 (lowchar, "xmptext"))
+    type = TYPE_ASCII;
+  else if (!g_strcmp0 (lowchar, "xmpalt"))
+    type = TYPE_MULTIPLE;
+  else if (!g_strcmp0 (lowchar, "xmpbag"))
+    type = TYPE_MULTIPLE;
+  else if (!g_strcmp0 (lowchar, "xmpseq"))
+    type = TYPE_MULTIPLE;
+  else if (!g_strcmp0 (lowchar, "langalt"))
+    type = TYPE_MULTIPLE;
+  else
+    type = TYPE_INVALID;
+
+  g_free (lowchar);
+
+  return type;
+}
+
+/**
+ * gimp_attribute_is_valid:
+ *
+ * @attribute:    a @GimpAttribute
+ *
+ * checks, if @attribute is valid.
+ * A @GimpAttribute is valid, if the @GimpAttributeValueType
+ * has a valid entry.
+ *
+ * Return value: @gboolean: TRUE if valid, FALSE otherwise
+ *
+ * Since: 2.10
+ */
+gboolean
+gimp_attribute_is_valid (GimpAttribute *attribute)
+{
+  GimpAttributePrivate *private;
+
+  g_return_val_if_fail (attribute != NULL, FALSE);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  if (private->value_type == TYPE_INVALID)
+    return FALSE;
+  else
+    return TRUE;
+}
+
+/*
+ * internal functions
+ */
+
+/**
+ * gimp_attribute_set_name:
+ *
+ * @attribute:    a #GimpAttribute
+ * @value:        a constant #gchar
+ *
+ * sets the name of the #GimpAttribute object to
+ * a @value
+ *
+ * @value can be freed after
+ *
+ * Since: 2.10
+ */
+static void
+gimp_attribute_set_name (GimpAttribute* attribute, const gchar* value)
+{
+  gchar                **split_name;
+  gchar                 *lowchar;
+  GimpAttributePrivate  *private;
+
+  g_return_if_fail (attribute != NULL);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  _g_free0 (private->name);
+
+  private->name = g_strdup (value);
+
+  private->name = string_replace_str (private->name, "Iptc4xmpExt", "iptcExt");
+  private->name = string_replace_str (private->name, "Iptc4xmpCore", "iptc");
+
+//  if (! g_strcmp0 (private->name, "Exif.Image.ResolutionUnit"))
+//    {
+//      g_print ("found: %s\n", private->name);
+//    }
+
+  split_name = g_strsplit (private->name, ".", 3);
+
+  if (split_name [0])
+    private->attribute_type = split_name [0];
+  if (split_name [1])
+    private->attribute_ifd = split_name [1];
+  if (split_name [2])
+    private->attribute_tag = split_name [2];
+
+  attribute->priv->is_new_name_space = FALSE;
+
+  lowchar = g_ascii_strdown (private->attribute_type, -1);
+
+  if (!g_strcmp0 (lowchar, "exif"))
+    {
+      private->tag_type = TAG_EXIF;
+    }
+  else if (!g_strcmp0 (lowchar, "xmp"))
+    {
+      gint     j;
+      gint     p1 = 0;
+      gint     p2 = 0;
+      gboolean is_known = FALSE;
+      private->tag_type = TAG_XMP;
+
+      while (p2 != -1)
+        {
+
+          p2 = string_index_of (private->name, "[", p1);
+
+          if (p2 > -1)
+            {
+              gchar *struct_string = NULL;
+
+              private->has_structure = TRUE;
+              private->structure_type = STRUCTURE_TYPE_BAG;
+
+              struct_string = string_substring (private->name, 0, p2);
+              private->attribute_structure = g_slist_prepend (private->attribute_structure, struct_string);
+
+              p1 = p2 + 1;
+            }
+        }
+
+      for (j = 0; j < G_N_ELEMENTS (xmp_namespaces); j++)
+        {
+          if (! g_strcmp0 (private->attribute_ifd, xmp_namespaces[j]))
+            {
+              is_known = TRUE;
+              break;
+            }
+        }
+      if (! is_known)
+        {
+          private->is_new_name_space = TRUE;
+        }
+    }
+  else if (!g_strcmp0 (lowchar, "iptc"))
+    {
+      private->tag_type = TAG_IPTC;
+    }
+  else if (!g_strcmp0 (lowchar, "gimp"))
+    {
+      private->tag_type = TAG_GIMP;
+    }
+  else
+    {
+      private->tag_type = TAG_MISC;
+    }
+
+  g_free (lowchar);
+}
+
+/**
+ * gimp_attribute_set_structure_type:
+ *
+ * @attribute:    a #GimpAttribute
+ * @value:        a GimpAttributeStructureType
+ *
+ * Sets the structure type, Bag, Seq, None, etc.
+ * The structure is not checked.
+ * The structure type is only relevant for
+ * GimpAttribute, that are part of a structure.
+ *
+ * Since : 2.10
+ */
+void
+gimp_attribute_set_structure_type (GimpAttribute              *attribute,
+                                   GimpAttributeStructureType  value)
+{
+  GimpAttributePrivate *private;
+
+  g_return_if_fail (attribute != NULL);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  private->structure_type = value;
+}
+
+/**
+ * gimp_attribute_get_structure_type:
+ *
+ * @attribute:    a #GimpAttribute
+ *
+ * The structure type, Bag, Seq, None, etc.
+ * Return value: a #GimpAttributeStructureType
+ *
+ * Since : 2.10
+ */
+GimpAttributeStructureType
+gimp_attribute_get_structure_type (GimpAttribute *attribute)
+{
+  GimpAttributePrivate *private;
+
+  g_return_val_if_fail (attribute != NULL, STRUCTURE_TYPE_NONE);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  return private->structure_type;
+
+}
+
+/**
+ * gimp_attribute_has_structure:
+ *
+ * @attribute:    a #GimpAttribute
+ *
+ * Return value:  TRUE, if @attribute is part
+ * of a structure.
+ *
+ * Since : 2.10
+ */
+gboolean
+gimp_attribute_has_structure (GimpAttribute *attribute)
+{
+  GimpAttributePrivate *private;
+
+  g_return_val_if_fail (attribute != NULL, FALSE);
+
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  return private->has_structure;
+}
+
+/**
+ * gimp_attribute_escape_value:
+ *
+ * @name: a gchar *
+ * @value: a gchar*
+ * @encoded: a pointer to a gboolean
+ *
+ * converts @value into an escaped string for GMarkup.
+ * If @value is not valid UTF-8, it is converted
+ * into a base64 coded string and @encoded is set to TRUE,
+ * otherwise FALSE
+ *
+ * Return value:  a new allocated @gchar *
+ *
+ * Since : 2.10
+ */
+static gchar *
+gimp_attribute_escape_value (gchar    *name,
+                             gchar    *value,
+                             gboolean *encoded)
+{
+
+  if (!g_utf8_validate (value, -1, NULL))
+    {
+      gchar *enc_val = NULL;
+
+      *encoded = TRUE;
+       enc_val = g_base64_encode ((const guchar *) value,
+                                   strlen (value) + 1);
+
+       return enc_val;
+    }
+  *encoded = FALSE;
+
+  return g_markup_escape_text (value, -1);
+}
+
+/**
+ * gimp_attribute_copy:
+ *
+ * @attribute:  a #GimpAttribute
+ *
+ * duplicates a  #GimpAttribute object
+ *
+ * Return value:  a new @GimpAttribute or %NULL
+ *
+ * Since : 2.10
+ */
+GimpAttribute*
+gimp_attribute_copy (GimpAttribute *attribute)
+{
+  GimpAttribute        *new_attribute     = NULL;
+  GimpAttributePrivate *private;
+  GimpAttributePrivate *new_private;
+
+  g_return_val_if_fail (GIMP_IS_ATTRIBUTE (attribute), NULL);
+
+  new_attribute = (GimpAttribute*) g_object_new (GIMP_TYPE_ATTRIBUTE, NULL);
+
+  if (new_attribute)
+    {
+      private = GIMP_ATTRIBUTE_GET_PRIVATE(attribute);
+      new_private = GIMP_ATTRIBUTE_GET_PRIVATE(new_attribute);
+      if (private->name)
+        new_private->name = g_strdup (private->name);
+
+      if (private->tag_value)
+        new_private->tag_value = g_strdup (private->tag_value);
+
+      if (private->interpreted_value)
+        new_private->interpreted_value = g_strdup (private->interpreted_value);
+
+      if (private->exif_type)
+        new_private->exif_type = g_strdup (private->exif_type);
+
+      if (private->attribute_type)
+        new_private->attribute_type = g_strdup (private->attribute_type);
+
+      if (private->attribute_ifd)
+        new_private->attribute_ifd = g_strdup (private->attribute_ifd);
+
+      if (private->attribute_tag)
+        new_private->attribute_tag = g_strdup (private->attribute_tag);
+
+      new_private->is_new_name_space = private->is_new_name_space;
+      new_private->value_type = private->value_type;
+      new_private->tag_type = private->tag_type;
+
+      return new_attribute;
+    }
+
+  return NULL;
+}
+
+/**
+ * gimp_attribute_construct:
+ *
+ * @object_type:  a #GType
+ * @name:         a constant #gchar that describes the name of the attribute
+ *
+ * constructs a new #GimpAttribute object
+ *
+ * Return value:  a new @GimpAttribute or %NULL if no @name is set
+ *
+ * Since : 2.10
+ */
+static GimpAttribute*
+gimp_attribute_construct (GType object_type,
+                          const gchar *name)
+{
+  GimpAttribute * attribute = NULL;
+
+  g_return_val_if_fail (name != NULL, NULL);
+
+  attribute = (GimpAttribute*) g_object_new (object_type, NULL);
+  if (attribute)
+    {
+      gimp_attribute_set_name (attribute, name);
+    }
+  return attribute;
+}
+
+/**
+ * gimp_attribute_class_init:
+ *
+ * class initializer
+ */
+static void
+gimp_attribute_class_init (GimpAttributeClass * klass)
+{
+  gimp_attribute_parent_class = g_type_class_peek_parent (klass);
+  g_type_class_add_private (klass, sizeof(GimpAttributePrivate));
+
+  G_OBJECT_CLASS (klass)->get_property = gimp_attribute_get_property;
+  G_OBJECT_CLASS (klass)->set_property = gimp_attribute_set_property;
+  G_OBJECT_CLASS (klass)->finalize = gimp_attribute_finalize;
+}
+
+/**
+ * gimp_attribute_instance_init:
+ *
+ * instance initializer
+ */
+static void
+gimp_attribute_instance_init (GimpAttribute * attribute)
+{
+  GimpAttributePrivate *private;
+  attribute->priv = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  private->name                    = NULL;
+  private->tag_value               = NULL;
+  private->interpreted_value       = NULL;
+  private->exif_type               = NULL;
+  private->value_type              = TYPE_INVALID;
+  private->attribute_type          = NULL;
+  private->attribute_ifd           = NULL;
+  private->attribute_tag           = NULL;
+  private->attribute_structure     = NULL;
+  private->is_new_name_space       = FALSE;
+  private->has_structure           = FALSE;
+  private->structure_type          = STRUCTURE_TYPE_NONE;
+}
+
+/**
+ * gimp_attribute_finalize:
+ *
+ * instance finalizer
+ */
+static void
+gimp_attribute_finalize (GObject* obj)
+{
+  GimpAttribute        *attribute;
+  GimpAttributePrivate *private;
+
+  g_return_if_fail (GIMP_IS_ATTRIBUTE (obj));
+
+  attribute = GIMP_ATTRIBUTE (obj);
+  private = GIMP_ATTRIBUTE_GET_PRIVATE (attribute);
+
+  counter++;
+
+  if(private->name)
+    _g_free0 (private->name);
+
+  if(private->tag_value)
+    _g_free0 (private->tag_value);
+
+  if(private->interpreted_value)
+    _g_free0 (private->interpreted_value);
+
+  if(private->exif_type)
+    _g_free0 (private->exif_type);
+
+  if(private->attribute_type)
+    _g_free0 (private->attribute_type);
+
+  if(private->attribute_ifd)
+    _g_free0 (private->attribute_ifd);
+
+  if(private->attribute_tag)
+    _g_free0 (private->attribute_tag);
+
+  if(private->attribute_structure)
+    g_slist_free_full (private->attribute_structure, g_free);
+
+  G_OBJECT_CLASS (gimp_attribute_parent_class)->finalize (obj);
+}
+
+/**
+ * gimp_attribute_get_property
+ *
+ * instance get property
+ */
+static void
+gimp_attribute_get_property (GObject * object,
+                             guint property_id,
+                             GValue * value,
+                             GParamSpec * pspec)
+{
+}
+
+/**
+ * gimp_attribute_set_property
+ *
+ * instance set property
+ */
+static void
+gimp_attribute_set_property (GObject * object,
+                             guint property_id,
+                             const GValue * value,
+                             GParamSpec * pspec)
+{
+}
+
+/**
+ * gimp_attribute_get_type
+ *
+ * Return value: #GimpAttribute type
+ */
+GType
+gimp_attribute_get_type (void)
+{
+  static volatile gsize gimp_attribute_type_id__volatile = 0;
+  if (g_once_init_enter(&gimp_attribute_type_id__volatile))
+    {
+      static const GTypeInfo g_define_type_info =
+            { sizeof(GimpAttributeClass),
+                (GBaseInitFunc) NULL,
+                (GBaseFinalizeFunc) NULL,
+                (GClassInitFunc) gimp_attribute_class_init,
+                (GClassFinalizeFunc) NULL,
+                NULL,
+                sizeof(GimpAttribute),
+                0,
+                (GInstanceInitFunc) gimp_attribute_instance_init,
+                NULL
+            };
+
+      GType gimp_attribute_type_id;
+      gimp_attribute_type_id = g_type_register_static (G_TYPE_OBJECT,
+                                                       "GimpAttribute",
+                                                       &g_define_type_info,
+                                                       0);
+
+      g_once_init_leave(&gimp_attribute_type_id__volatile,
+                        gimp_attribute_type_id);
+    }
+  return gimp_attribute_type_id__volatile;
+}
+
+
+/*
+ * Helper functions
+ */
+
+/**
+ * get_tag_time:
+ *
+ * @input:        a #gchar array
+ * @tm:           a pointer to a #TagTime struct
+ *
+ * converts a ISO 8601 IPTC Time to a TagTime structure
+ * Input is:
+ *  HHMMSS
+ *  HHMMSS:HHMM
+ *
+ * Return value:  #gboolean for success
+ *
+ * Since: 2.10
+ */
+static gboolean get_tag_time (gchar *input, TagTime *tm)
+{
+  long     val;
+  GString *string = NULL;
+  gchar   *tmpdate;
+  gboolean flong;
+
+  g_return_val_if_fail (input != NULL, FALSE);
+
+  input = g_strstrip (input);
+
+  if (*input == '\0' || !g_ascii_isdigit (*input))
+    return FALSE;
+
+  string = g_string_new (NULL);
+
+  val = strtoul (input, (char **)&input, 10);
+
+  if (val < 25)  /* HH:MM:SS+/-HH:MM */
+    {
+      flong = FALSE;
+      g_string_append_printf (string, "%02ld", val);
+    }
+  else
+    {
+      flong = TRUE;
+      g_string_append_printf (string, "%06ld", val);
+    }
+
+
+  if (! flong) /* exactly 2 times */
+    {
+      input++;
+      val = strtoul (input, (char **)&input, 10);
+      g_string_append_printf (string, "%02ld", val);
+      input++;
+      val = strtoul (input, (char **)&input, 10);
+      g_string_append_printf (string, "%02ld", val);
+    }
+
+  tmpdate = g_string_free (string, FALSE);
+
+  val = strtoul (tmpdate, (char **)&tmpdate, 10);
+
+  /* hhmmss */
+
+  tm->tag_time_sec = val % 100;
+  tm->tag_time_min = (val % 10000) / 100;
+  tm->tag_time_hour = val / 10000;
+
+  string = g_string_new (NULL);
+
+  if (flong) /* :HHSS for time zone */
+    {
+      val = 0L;
+
+      if (*input == ':')
+        {
+          input++;
+          val = strtoul (input, (char **)&input, 10);
+        }
+      g_string_append_printf (string, "%05ld", val);
+    }
+  else
+    {
+      val = 0L;
+
+      if (*input == '+' || *input == '-') /* +/- HH:MM for time zone */
+        {
+          val = strtoul (input, (char **)&input, 10);
+          g_string_append_printf (string, "%02ld", val);
+          input++;
+          val = strtoul (input, (char **)&input, 10);
+          g_string_append_printf (string, "%02ld", val);
+        }
+      else
+        {
+          g_string_append_printf (string, "%04ld", val);
+        }
+    }
+
+  tmpdate = g_string_free (string, FALSE);
+
+  val = strtoul (tmpdate, (char **)&tmpdate, 10);
+
+  tm->tag_tz_min = (val % 100) / 100;
+  tm->tag_tz_hour = val / 100;
+
+  return *input == '\0';
+}
+
+/**
+ * get_tag_date:
+ *
+ * @input:        a #gchar array
+ * @dt:           a pointer to a #TagDate struct
+ *
+ * converts a ISO 8601 IPTC Date to a TagDate structure
+ * Input is:
+ * CCYYMMDD
+ *
+ * Return value:  #gboolean for success
+ *
+ * Since: 2.10
+ */
+static gboolean get_tag_date (gchar *input, TagDate *dt)
+{
+  long     val;
+  GString *string = NULL;
+  gchar   *tmpdate;
+  gboolean eod;
+
+  g_return_val_if_fail (input != NULL, FALSE);
+
+  input = g_strstrip (input);
+
+  if (*input == '\0' || !g_ascii_isdigit (*input))
+    return FALSE;
+
+  string = g_string_new (NULL);
+  eod = FALSE;
+
+  while (! eod)
+    {
+      val = strtoul (input, (char **)&input, 10);
+
+      if (*input == '-' ||
+          *input == ':')
+        {
+          input++;
+        }
+      else
+        {
+          eod = TRUE;
+        }
+
+      if (val < 10)
+        g_string_append_printf (string, "%02ld", val);
+      else
+        g_string_append_printf (string, "%ld", val);
+    }
+  tmpdate = g_string_free (string, FALSE);
+
+  val = strtoul (tmpdate, (char **)&tmpdate, 10);
+
+  /* YYYYMMDD */
+  dt->tag_day = val % 100;
+  dt->tag_month = (val % 10000) / 100;
+  dt->tag_year = val / 10000;
+
+  return *input == '\0';
+}
+
+/**
+ * string_replace_str:
+ *
+ * @original:          the original string
+ * @old_pattern:       the pattern to replace
+ * @replacement:       the replacement
+ *
+ * replaces @old_pattern by @replacement in @original
+ * This routine is copied from VALA.
+ *
+ * Return value: the new string.
+ *
+ * Since: 2.10
+ */
+static gchar*
+string_replace_str (const gchar* original, const gchar* old_pattern, const gchar* replacement) {
+  gchar      *result        = NULL;
+  GError     *_inner_error_ = NULL;
+
+  g_return_val_if_fail (original != NULL, NULL);
+  g_return_val_if_fail (old_pattern != NULL, NULL);
+  g_return_val_if_fail (replacement != NULL, NULL);
+
+  {
+    GRegex           *regex  = NULL;
+    const gchar      *_tmp0_ = NULL;
+    gchar            *_tmp1_ = NULL;
+    gchar            *_tmp2_ = NULL;
+    GRegex           *_tmp3_ = NULL;
+    GRegex           *_tmp4_ = NULL;
+    gchar            *_tmp5_ = NULL;
+    GRegex           *_tmp6_ = NULL;
+    const gchar      *_tmp7_ = NULL;
+    gchar            *_tmp8_ = NULL;
+    gchar            *_tmp9_ = NULL;
+
+    _tmp0_ = old_pattern;
+    _tmp1_ = g_regex_escape_string (_tmp0_, -1);
+    _tmp2_ = _tmp1_;
+    _tmp3_ = g_regex_new (_tmp2_, 0, 0, &_inner_error_);
+    _tmp4_ = _tmp3_;
+    _g_free0 (_tmp2_);
+    regex = _tmp4_;
+
+    if (_inner_error_ != NULL)
+      {
+        if (_inner_error_->domain == G_REGEX_ERROR)
+          {
+            goto __catch0_g_regex_error;
+          }
+        g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, 
_inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+        g_clear_error (&_inner_error_);
+        return NULL;
+      }
+
+    _tmp6_ = regex;
+    _tmp7_ = replacement;
+    _tmp8_ = g_regex_replace_literal (_tmp6_, original, (gssize) (-1), 0, _tmp7_, 0, &_inner_error_);
+    _tmp5_ = _tmp8_;
+
+    if (_inner_error_ != NULL)
+      {
+        _g_regex_unref0 (regex);
+        if (_inner_error_->domain == G_REGEX_ERROR)
+          {
+            goto __catch0_g_regex_error;
+          }
+        _g_regex_unref0 (regex);
+        g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, 
_inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+        g_clear_error (&_inner_error_);
+        return NULL;
+      }
+
+    _tmp9_ = _tmp5_;
+    _tmp5_ = NULL;
+    result = _tmp9_;
+    _g_free0 (_tmp5_);
+    _g_regex_unref0 (regex);
+    return result;
+  }
+
+  goto __finally0;
+  __catch0_g_regex_error:
+  {
+    GError* e = NULL;
+    e = _inner_error_;
+    _inner_error_ = NULL;
+    g_assert_not_reached ();
+    _g_error_free0 (e);
+  }
+
+  __finally0:
+  if (_inner_error_ != NULL)
+    {
+      g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, 
_inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+      g_clear_error (&_inner_error_);
+      return NULL;
+    }
+}
+
+/**
+ * string_index_of:
+ *
+ * @haystack:          a #gchar
+ * @needle:            a #gchar
+ * @start_index:       a #gint
+ *
+ *
+ * Return value:  #gint that points to the position
+ * of @needle in @haystack, starting at @start_index,
+ * or -1, if @needle is not found
+ *
+ * Since: 2.10
+ */
+static gint
+string_index_of (gchar* haystack, gchar* needle, gint start_index)
+{
+  gint result = 0;
+  gchar* temp1_ = NULL;
+  g_return_val_if_fail (haystack != NULL, -1);
+  g_return_val_if_fail (needle != NULL, -1);
+  temp1_ = strstr (((gchar*) haystack) + start_index, needle);
+  if (temp1_ != NULL)
+    {
+      result = (gint) (temp1_ - ((gchar*) haystack));
+      return result;
+    }
+  else
+    {
+      result = -1;
+      return result;
+    }
+}
+
+/**
+ * string_strnlen:
+ *
+ * @str:          a #gchar
+ * @maxlen:       a #glong
+ *
+ * Returns the length of @str or @maxlen, if @str
+ * is longer that @maxlen
+ *
+ * Return value:  #glong
+ *
+ * Since: 2.10
+ */
+static glong
+string_strnlen (gchar* str, glong maxlen)
+{
+  glong result = 0L;
+  gchar* temp1_ = NULL;
+  temp1_ = memchr (str, 0, (gsize) maxlen);
+  if (temp1_ == NULL)
+    {
+      return maxlen;
+    }
+  else
+    {
+      result = (glong) (temp1_ - str);
+      return result;
+    }
+}
+
+/**
+ * string_substring:
+ *
+ * @string:          a #gchar
+ * @offset:          a #glong
+ * @len:             a #glong
+ *
+ * Returns a substring of @string, starting at @offset
+ * with a legth of @len
+ *
+ * Return value:  #gchar to be freed if no longer use
+ *
+ * Since: 2.10
+ */
+static gchar*
+string_substring (gchar* string, glong offset, glong len)
+{
+  gchar* result = NULL;
+  glong string_length = 0L;
+  gboolean _tmp0_ = FALSE;
+  g_return_val_if_fail(string != NULL, NULL);
+  if (offset >= ((glong) 0))
+    {
+      _tmp0_ = len >= ((glong) 0);
+    }
+  else
+    {
+      _tmp0_ = FALSE;
+    }
+
+  if (_tmp0_)
+    {
+      string_length = string_strnlen ((gchar*) string, offset + len);
+    }
+  else
+    {
+      string_length = (glong) strlen (string);
+    }
+
+  if (offset < ((glong) 0))
+    {
+      offset = string_length + offset;
+      g_return_val_if_fail (offset >= ((glong ) 0), NULL);
+    }
+  else
+    {
+      g_return_val_if_fail (offset <= string_length, NULL);
+    }
+  if (len < ((glong) 0))
+    {
+      len = string_length - offset;
+    }
+
+  g_return_val_if_fail ((offset + len) <= string_length, NULL);
+  result = g_strndup (((gchar*) string) + offset, (gsize) len);
+  return result;
+}
+
diff --git a/libgimpbase/gimpattribute.h b/libgimpbase/gimpattribute.h
new file mode 100644
index 0000000..875036d
--- /dev/null
+++ b/libgimpbase/gimpattribute.h
@@ -0,0 +1,95 @@
+/* gimpattribute.h generated by valac 0.24.0, the Vala compiler, do not modify */
+
+
+#ifndef __GIMPATTRIBUTE_H__
+#define __GIMPATTRIBUTE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GIMP_TYPE_ATTRIBUTE            (gimp_attribute_get_type ())
+#define GIMP_ATTRIBUTE(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ATTRIBUTE, 
GimpAttribute))
+#define GIMP_ATTRIBUTE_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_ATTRIBUTE, 
GimpAttributeClass))
+#define GIMP_IS_ATTRIBUTE(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_ATTRIBUTE))
+#define GIMP_IS_ATTRIBUTE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_ATTRIBUTE))
+#define GIMP_ATTRIBUTE_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ATTRIBUTE, 
GimpAttributeClass))
+#define GIMP_ATTRIBUTE_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIMP_TYPE_ATTRIBUTE, 
GimpAttributePrivate))
+
+#define GIMP_TYPE_ATTRIBUTE_TAG_TYPE (gimp_attribute_tag_type_get_type ())
+
+GType gimp_attribute_tag_type_get_type (void) G_GNUC_CONST;
+
+typedef enum  {
+  TYPE_INVALID,
+  TYPE_LONG,
+  TYPE_SLONG,
+  TYPE_FLOAT,
+  TYPE_DOUBLE,
+  TYPE_SHORT,
+  TYPE_SSHORT,
+  TYPE_DATE,
+  TYPE_TIME,
+  TYPE_ASCII,
+  TYPE_UNICODE,
+  TYPE_BYTE,
+  TYPE_MULTIPLE,
+  TYPE_RATIONAL,
+  TYPE_SRATIONAL,
+  TYPE_UNKNOWN,
+  NUM_VALUE_TYPES
+} GimpAttributeValueType;
+
+typedef enum  {
+  STRUCTURE_TYPE_BAG,
+  STRUCTURE_TYPE_SEQ,
+  STRUCTURE_TYPE_ALT,
+  STRUCTURE_TYPE_LANG,
+  STRUCTURE_TYPE_NONE,
+  STRUCTURE_TYPE_STRUCT,
+  NUM_STRUCTURE_TYPES
+} GimpAttributeStructureType;
+
+typedef enum {
+  TAG_INVALID,
+  TAG_EXIF,
+  TAG_XMP,
+  TAG_IPTC,
+  TAG_GIMP,
+  TAG_MISC,
+  NUM_TAG_TYPES
+} GimpAttributeTagType;
+
+GType                       gimp_attribute_get_type                       (void) G_GNUC_CONST;
+
+GimpAttribute*              gimp_attribute_new_string                     (const gchar                *name,
+                                                                           gchar                      *value,
+                                                                           GimpAttributeValueType      type);
+const gchar*                gimp_attribute_get_interpreted_string         (GimpAttribute              
*attribute);
+void                        gimp_attribute_set_interpreted_string         (GimpAttribute              
*attribute,
+                                                                           const gchar                
*value);
+GimpAttribute*              gimp_attribute_copy                           (GimpAttribute              
*attribute);
+gboolean                    gimp_attribute_is_valid                       (GimpAttribute              
*attribute);
+const gchar*                gimp_attribute_get_attribute_type             (GimpAttribute              
*attribute);
+const gchar*                gimp_attribute_get_attribute_ifd              (GimpAttribute              
*attribute);
+const gchar*                gimp_attribute_get_attribute_tag              (GimpAttribute              
*attribute);
+const gboolean              gimp_attribute_is_new_namespace               (GimpAttribute              
*attribute);
+const gchar*                gimp_attribute_get_name                       (GimpAttribute              
*attribute);
+GValue                      gimp_attribute_get_value                      (GimpAttribute              
*attribute);
+gchar*                      gimp_attribute_get_string                     (GimpAttribute              
*attribute);
+GimpAttributeTagType        gimp_attribute_get_tag_type                   (GimpAttribute              
*attribute);
+GimpAttributeValueType      gimp_attribute_get_value_type_from_string     (const gchar                
*string);
+GimpAttributeValueType      gimp_attribute_get_value_type                 (GimpAttribute              
*attribute);
+void                        gimp_attribute_set_value_type                 (GimpAttribute              
*attribute,
+                                                                           GimpAttributeValueType      
value_type);
+gboolean                    gimp_attribute_has_structure                  (GimpAttribute              
*attribute);
+GSList*                     gimp_attribute_get_attribute_structure        (GimpAttribute              
*attribute);
+void                        gimp_attribute_set_structure_type             (GimpAttribute              
*attribute,
+                                                                           GimpAttributeStructureType  
value);
+GimpAttributeStructureType  gimp_attribute_get_structure_type             (GimpAttribute              
*attribute);
+gchar*                      gimp_attribute_get_xml                        (GimpAttribute              
*attribute);
+void                        gimp_attribute_print                          (GimpAttribute              
*attribute);
+
+G_END_DECLS
+
+#endif
diff --git a/libgimpbase/gimpattributes-image.c b/libgimpbase/gimpattributes-image.c
new file mode 100644
index 0000000..b8918fa
--- /dev/null
+++ b/libgimpbase/gimpattributes-image.c
@@ -0,0 +1,282 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpattributes-image.c
+ * Copyright (C) 2014  Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib-object.h>
+#include <gexiv2/gexiv2.h>
+
+#ifdef G_OS_WIN32
+#endif
+
+#include "libgimpmath/gimpmath.h"
+
+#include "gimprational.h"
+#include "gimpbasetypes.h"
+#include "gimpattribute.h"
+#include "gimpattributes.h"
+#include "gimplimits.h"
+#include "gimpmetadata.h"
+#include "gimpunit.h"
+#include "gimpattributes-image.h"
+
+/**
+ * SECTION: gimpattributes-image
+ * @title: gimpattributes-image
+ * @short_description: handle image data.
+ * @see_also: GimpAttribute, GimpAttributes
+ *
+ * handle image data.
+ **/
+
+
+/**
+ * gimp_metadata_set_resolution:
+ * @metadata: A #GimpMetadata instance.
+ * @xres:     The image's X Resolution, in ppi
+ * @yres:     The image's Y Resolution, in ppi
+ * @unit:     The image's unit
+ *
+ * Sets Exif.Image.XResolution, Exif.Image.YResolution and
+ * Exif.Image.ResolutionUnit @metadata.
+ *
+ * Since: GIMP 2.10
+ */
+void
+gimp_attributes_set_resolution (GimpAttributes *attributes,
+                                gdouble         xres,
+                                gdouble         yres,
+                                GimpUnit        unit)
+{
+  gchar buffer[64];
+  gint  exif_unit;
+  gint  factor;
+
+  g_return_if_fail (GIMP_IS_ATTRIBUTES (attributes));
+
+  if (gimp_unit_is_metric (unit))
+    {
+      xres /= 2.54;
+      yres /= 2.54;
+
+      exif_unit = 3;
+    }
+  else
+    {
+      exif_unit = 2;
+    }
+
+  for (factor = 1; factor <= 100 /* arbitrary */; factor++)
+    {
+      if (fabs (xres * factor - ROUND (xres * factor)) < 0.01 &&
+          fabs (yres * factor - ROUND (yres * factor)) < 0.01)
+        break;
+    }
+
+  g_snprintf (buffer, sizeof (buffer), "%d/%d", ROUND (xres * factor), factor);
+  gimp_attributes_new_attribute (attributes, "Exif.Image.XResolution", buffer, TYPE_RATIONAL);
+
+  g_snprintf (buffer, sizeof (buffer), "%d/%d", ROUND (yres * factor), factor);
+  gimp_attributes_new_attribute (attributes, "Exif.Image.YResolution", buffer, TYPE_RATIONAL);
+
+  g_snprintf (buffer, sizeof (buffer), "%d", exif_unit);
+  gimp_attributes_new_attribute (attributes, "Exif.Image.ResolutionUnit", buffer, TYPE_SHORT);
+}
+
+/**
+ * gimp_attributes_get_resolution:
+ * @metadata: A #GimpMetadata instance.
+ * @xres:     Return location for the X Resolution, in ppi
+ * @yres:     Return location for the Y Resolution, in ppi
+ * @unit:     Return location for the unit unit
+ *
+ * Returns values based on Exif.Image.XResolution,
+ * Exif.Image.YResolution and Exif.Image.ResolutionUnit of @metadata.
+ *
+ * Return value: %TRUE on success, %FALSE otherwise.
+ *
+ * Since: GIMP 2.10
+ */
+gboolean
+gimp_attributes_get_resolution (GimpAttributes *attributes,
+                                gdouble        *xres,
+                                gdouble        *yres,
+                                GimpUnit       *unit)
+{
+  GimpAttribute *x_attribute;
+  GimpAttribute *y_attribute;
+  GimpAttribute *res_attribute;
+
+  gint   xnom, xdenom;
+  gint   ynom, ydenom;
+  gint   exif_unit = 2;
+
+  g_return_val_if_fail (GIMP_IS_ATTRIBUTES (attributes), FALSE);
+
+  x_attribute = gimp_attributes_get_attribute (attributes, "Exif.Image.XResolution");
+  y_attribute = gimp_attributes_get_attribute (attributes, "Exif.Image.YResolution");
+  res_attribute = gimp_attributes_get_attribute (attributes, "Exif.Image.ResolutionUnit");
+
+  if (x_attribute)
+    {
+      GValue    value;
+      Rational *rats;
+      gint     *_nom;
+      gint     *_denom;
+      gint      l;
+
+      value = gimp_attribute_get_value (x_attribute);
+
+      rats = g_value_get_boxed (&value);
+
+      rational_to_int (rats, &_nom, &_denom, &l);
+
+      if (l > 0)
+        {
+          xnom = _nom[0];
+          xdenom = _denom[0];
+        }
+      rational_free (rats);
+    }
+  else
+    return FALSE;
+
+  if (y_attribute)
+    {
+      GValue    value;
+      Rational *rats;
+      gint     *_nom;
+      gint     *_denom;
+      gint      l;
+
+      value = gimp_attribute_get_value (y_attribute);
+
+      rats = g_value_get_boxed (&value);
+
+      rational_to_int (rats, &_nom, &_denom, &l);
+
+      if (l > 0)
+        {
+          ynom = _nom[0];
+          ydenom = _denom[0];
+        }
+      rational_free (rats);
+    }
+  else
+    return FALSE;
+
+  if (res_attribute)
+    {
+      GValue value = gimp_attribute_get_value (res_attribute);
+
+      exif_unit = (gint) g_value_get_uint (&value);
+    }
+
+  if (xnom != 0 && xdenom != 0 &&
+      ynom != 0 && ydenom != 0)
+    {
+      gdouble xresolution = (gdouble) xnom / (gdouble) xdenom;
+      gdouble yresolution = (gdouble) ynom / (gdouble) ydenom;
+
+      if (exif_unit == 3)
+        {
+          xresolution *= 2.54;
+          yresolution *= 2.54;
+        }
+
+      if (xresolution >= GIMP_MIN_RESOLUTION &&
+          xresolution <= GIMP_MAX_RESOLUTION &&
+          yresolution >= GIMP_MIN_RESOLUTION &&
+          yresolution <= GIMP_MAX_RESOLUTION)
+        {
+          if (xres)
+            *xres = xresolution;
+
+          if (yres)
+            *yres = yresolution;
+
+          if (unit)
+            {
+              if (exif_unit == 3)
+                *unit = GIMP_UNIT_MM;
+              else
+                *unit = GIMP_UNIT_INCH;
+            }
+
+          return TRUE;
+        }
+    }
+  return FALSE;
+}
+
+/**
+ * gimp_attributes_set_bits_per_sample:
+ * @metadata: A #GimpMetadata instance.
+ * @bps:      Bytes per pixel, per component
+ *
+ * Sets Exif.Image.BitsPerSample on @metadata.
+ *
+ * Since: GIMP 2.10
+ */
+void
+gimp_attributes_set_bits_per_sample (GimpAttributes *attributes,
+                                     gint            bps)
+{
+  gchar buffer[32];
+
+  g_return_if_fail (GIMP_IS_ATTRIBUTES (attributes));
+
+  g_snprintf (buffer, sizeof (buffer), "%d", bps);
+  gimp_attributes_new_attribute (attributes, "Exif.Image.BitsPerSample", buffer, TYPE_SHORT);
+}
+
+/**
+ * gimp_attributes_set_pixel_size:
+ * @metadata: A #GimpMetadata instance.
+ * @width:    Width in pixels
+ * @height:   Height in pixels
+ *
+ * Sets Exif.Image.ImageWidth and Exif.Image.ImageLength on @metadata.
+ *
+ * Since: GIMP 2.10
+ */
+void
+gimp_attributes_set_pixel_size (GimpAttributes *attributes,
+                                gint            width,
+                                gint            height)
+{
+  gchar buffer[32];
+
+  g_return_if_fail (GIMP_IS_ATTRIBUTES (attributes));
+
+  g_snprintf (buffer, sizeof (buffer), "%d", width);
+  gimp_attributes_new_attribute (attributes, "Exif.Image.ImageWidth", buffer, TYPE_LONG);
+
+  g_snprintf (buffer, sizeof (buffer), "%d", height);
+  gimp_attributes_new_attribute (attributes, "Exif.Image.ImageLength", buffer, TYPE_LONG);
+}
diff --git a/libgimpbase/gimpattributes-image.h b/libgimpbase/gimpattributes-image.h
new file mode 100644
index 0000000..711a902
--- /dev/null
+++ b/libgimpbase/gimpattributes-image.h
@@ -0,0 +1,47 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpattributes-image.h
+ * Copyright (C) 2014  Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __GIMPATTRIBUTES_IMAGE_H__
+#define __GIMPATTRIBUTES_IMAGE_H__
+
+G_BEGIN_DECLS
+
+gboolean               gimp_attributes_get_resolution            (GimpAttributes *attributes,
+                                                                  gdouble        *xres,
+                                                                  gdouble        *yres,
+                                                                  GimpUnit       *unit);
+
+void                   gimp_attributes_set_resolution            (GimpAttributes *attributes,
+                                                                  gdouble         xres,
+                                                                  gdouble         yres,
+                                                                  GimpUnit        unit);
+
+void                   gimp_attributes_set_bits_per_sample       (GimpAttributes *attributes,
+                                                                  gint            bps);
+
+void                   gimp_attributes_set_pixel_size            (GimpAttributes *attributes,
+                                                                  gint            width,
+                                                                  gint            height);
+
+G_END_DECLS
+
+#endif
diff --git a/libgimpbase/gimpattributes.c b/libgimpbase/gimpattributes.c
new file mode 100644
index 0000000..7739702
--- /dev/null
+++ b/libgimpbase/gimpattributes.c
@@ -0,0 +1,1657 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpattributes.c
+ * Copyright (C) 2014  Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <stdio.h>
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib-object.h>
+#include <gexiv2/gexiv2.h>
+
+#ifdef G_OS_WIN32
+#endif
+
+#include "gimpbasetypes.h"
+#include "gimpattribute.h"
+#include "gimpattributes.h"
+#include "gimpmetadata.h"
+
+/**
+ * SECTION: gimpattributes
+ * @title: gimpattributes
+ * @short_description: Class to store #GimpAttribute objects.
+ * @see_also: GimpAttribute,
+ *
+ * Class to store #GimpAttribute objects.
+ **/
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+
+typedef struct _GimpAttributesClass GimpAttributesClass;
+typedef struct _GimpAttributesPrivate GimpAttributesPrivate;
+
+struct _GimpAttributes {
+  GObject               parent_instance;
+  GimpAttributesPrivate *priv;
+};
+
+struct _GimpAttributesClass {
+  GObjectClass parent_class;
+};
+
+struct _GimpAttributesPrivate {
+  GHashTable *attribute_table;
+  GList      *sorted_key_list;
+};
+
+typedef struct
+{
+  gchar                     name[1024];
+  gboolean                  base64;
+  GimpAttributeValueType    type;
+  GimpAttributes           *attributes;
+} GimpAttributesParseData;
+
+struct Namespaces{
+  const gchar         *namespace_name;
+  const gchar         *namespace_URI;
+};
+
+struct Namespaces namespaces_table[] = {
+  {"gimp",    "http://www.gimp.org/ns/2.10/";  },
+  {"dwc",     "http://rs.tdwg.org/dwc/terms/"; },
+  {"lr",      "http://ns.adobe.com/lr/1.0/";   }
+};
+
+
+static   gpointer                  gimp_attributes_parent_class = NULL;
+static   GimpAttribute            *current_attribute            = NULL;
+
+
+
+static GimpAttributes*         gimp_attributes_construct                   (GType                
object_type);
+static void                    gimp_attributes_finalize                    (GObject             *obj);
+static void                    gimp_attributes_get_property                (GObject             *object,
+                                                                            guint                property_id,
+                                                                            GValue              *value,
+                                                                            GParamSpec          *pspec);
+static void                    gimp_attributes_set_property                (GObject             *object,
+                                                                            guint                property_id,
+                                                                            const GValue        *value,
+                                                                            GParamSpec          *pspec);
+static void                    gimp_attributes_deserialize_error           (GMarkupParseContext *context,
+                                                                            GError              *error,
+                                                                            gpointer             user_data);
+static GQuark                  gimp_attributes_error_quark                 (void);
+static void                    gimp_attributes_deserialize_start_element   (GMarkupParseContext *context,
+                                                                            const gchar         
*element_name,
+                                                                            const gchar        
**attribute_names,
+                                                                            const gchar        
**attribute_values,
+                                                                            gpointer             user_data,
+                                                                            GError             **error);
+static void                    gimp_attributes_deserialize_text            (GMarkupParseContext  *context,
+                                                                            const gchar          *text,
+                                                                            gsize                 text_len,
+                                                                            gpointer              user_data,
+                                                                            GError              **error);
+static void                    gimp_attributes_deserialize_end_element     (GMarkupParseContext *context,
+                                                                            const gchar         
*element_name,
+                                                                            gpointer             user_data,
+                                                                            GError             **error);
+static const gchar*            gimp_attributes_name_to_value               (const gchar        
**attribute_names,
+                                                                            const gchar        
**attribute_values,
+                                                                            const gchar         *name);
+
+
+static gboolean                has_xmp_structure                           (GSList              *xmp_list,
+                                                                            const gchar         *entry);
+
+/**
+ * gimp_attributes_new:
+ *
+ * returns a new #GimpAttributes object
+ *
+ * Return value:  a new @GimpAttributes object
+ *
+ * Since : 2.10
+ */
+GimpAttributes *
+gimp_attributes_new (void)
+{
+  return gimp_attributes_construct (GIMP_TYPE_ATTRIBUTES);
+}
+
+/**
+ * gimp_attributes_construct:
+ *
+ * @object_type: a #GType
+ *
+ * constructs a new #GimpAttributes object
+ *
+ * Return value:  a new @GimpAttributes
+ *
+ * Since : 2.10
+ */
+static GimpAttributes*
+gimp_attributes_construct (GType object_type)
+{
+  GimpAttributes * attributes = NULL;
+
+  attributes = (GimpAttributes*) g_object_new (object_type, NULL);
+  return attributes;
+}
+
+/**
+ * gimp_attributes_class_init:
+ *
+ * class initializer
+ */
+static void
+gimp_attributes_class_init (GimpAttributesClass * klass)
+{
+  gimp_attributes_parent_class = g_type_class_peek_parent (klass);
+  g_type_class_add_private (klass, sizeof(GimpAttributesPrivate));
+
+  G_OBJECT_CLASS (klass)->get_property = gimp_attributes_get_property;
+  G_OBJECT_CLASS (klass)->set_property = gimp_attributes_set_property;
+  G_OBJECT_CLASS (klass)->finalize = gimp_attributes_finalize;
+}
+
+/**
+ * gimp_attributes_instance_init:
+ *
+ * instance initializer
+ */
+static void
+gimp_attributes_instance_init (GimpAttributes * attributes)
+{
+  attributes->priv = GIMP_ATTRIBUTES_GET_PRIVATE (attributes);
+  attributes->priv->attribute_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, 
g_object_unref);
+  attributes->priv->sorted_key_list = NULL;
+}
+
+/**
+ * gimp_attributes_finalize:
+ *
+ * instance finalizer
+ */
+static void
+gimp_attributes_finalize (GObject* obj)
+{
+  GimpAttributes * attributes;
+
+  attributes = G_TYPE_CHECK_INSTANCE_CAST (obj, GIMP_TYPE_ATTRIBUTES, GimpAttributes);
+
+  g_hash_table_unref (attributes->priv->attribute_table);
+  g_list_free_full (attributes->priv->sorted_key_list, (GDestroyNotify) g_free);
+
+  G_OBJECT_CLASS (gimp_attributes_parent_class)->finalize (obj);
+}
+
+/**
+ * gimp_attributes_get_property
+ *
+ * instance get property
+ */
+static void
+gimp_attributes_get_property (GObject * object,
+                             guint property_id,
+                             GValue * value,
+                             GParamSpec * pspec)
+{
+}
+
+/**
+ * gimp_attributes_set_property
+ *
+ * instance set property
+ */
+static void
+gimp_attributes_set_property (GObject * object,
+                             guint property_id,
+                             const GValue * value,
+                             GParamSpec * pspec)
+{
+}
+
+/**
+ * gimp_attributes_get_type
+ *
+ * Return value: #GimpAttributes type
+ */
+GType
+gimp_attributes_get_type (void)
+{
+  static volatile gsize gimp_attributes_type_id__volatile = 0;
+  if (g_once_init_enter(&gimp_attributes_type_id__volatile))
+    {
+      static const GTypeInfo g_define_type_info =
+            { sizeof(GimpAttributesClass),
+                (GBaseInitFunc) NULL,
+                (GBaseFinalizeFunc) NULL,
+                (GClassInitFunc) gimp_attributes_class_init,
+                (GClassFinalizeFunc) NULL,
+                NULL,
+                sizeof(GimpAttributes),
+                0,
+                (GInstanceInitFunc) gimp_attributes_instance_init,
+                NULL
+            };
+
+      GType gimp_attributes_type_id;
+      gimp_attributes_type_id = g_type_register_static (G_TYPE_OBJECT,
+                                                       "GimpAttributes",
+                                                       &g_define_type_info,
+                                                       0);
+
+      g_once_init_leave(&gimp_attributes_type_id__volatile,
+                        gimp_attributes_type_id);
+    }
+  return gimp_attributes_type_id__volatile;
+}
+
+/**
+ * gimp_attributes_size:
+ *
+ * @attributes: a #GimpAttributes
+ *
+ * Return value:  a #gint: amount of #GimpAttribute objects in
+ * the #GimpAttributes container
+ *
+ * Since : 2.10
+ */
+gint
+gimp_attributes_size (GimpAttributes *attributes)
+{
+  GimpAttributesPrivate *private = GIMP_ATTRIBUTES_GET_PRIVATE (attributes);
+
+  return g_hash_table_size (private->attribute_table);
+}
+
+/**
+ * gimp_attributes_duplicate:
+ *
+ * @attributes: a #GimpAttributes
+ *
+ * Duplicates the #GimpAttributes object with all the #GimpAttribute objects
+ * Return value:  a copy of the @attributes object
+ *
+ * Since : 2.10
+ */
+GimpAttributes *
+gimp_attributes_duplicate (GimpAttributes *attributes)
+{
+  GimpAttributes * new_attributes = NULL;
+
+  g_return_val_if_fail (GIMP_IS_ATTRIBUTES (attributes), NULL);
+
+  if (attributes)
+    {
+      gchar *xml;
+
+      xml = gimp_attributes_serialize (attributes);
+      new_attributes = gimp_attributes_deserialize (xml);
+    }
+
+  return new_attributes;
+}
+
+/**
+ * gimp_attributes_get_table:
+ *
+ * @attributes: a #GimpAttributes
+ *
+ * Return value:  the #GHashTable
+ *
+ * Since : 2.10
+ */
+GHashTable *
+gimp_attributes_get_table (GimpAttributes *attributes)
+{
+  return attributes->priv->attribute_table;
+}
+
+/**
+ * gimp_attributes_add_attribute:
+ *
+ * @attributes: a #GimpAttributes
+ * @attribute : a #GimpAttribute
+ *
+ * stores the @attribute in the @attributes container
+ *
+ * Since : 2.10
+ */
+void
+gimp_attributes_add_attribute (GimpAttributes      *attributes,
+                               GimpAttribute       *attribute)
+{
+  const gchar *name;
+  const gchar *lowchar;
+
+  g_return_if_fail (GIMP_IS_ATTRIBUTES (attributes));
+  g_return_if_fail (GIMP_IS_ATTRIBUTE (attribute));
+
+  name = gimp_attribute_get_name (attribute);
+
+  if (name)
+    {
+        lowchar = g_ascii_strdown (name, -1);
+
+      /* FIXME: really simply add? That means, that an older value is overwritten */
+
+      if (g_hash_table_insert (attributes->priv->attribute_table, (gpointer) g_strdup (lowchar), (gpointer) 
attribute))
+        attributes->priv->sorted_key_list = g_list_insert_sorted (attributes->priv->sorted_key_list,
+                                                                  (gpointer) g_strdup (lowchar),
+                                                                  (GCompareFunc) g_strcmp0);
+    }
+}
+
+/**
+ * gimp_attributes_get_attribute:
+ *
+ * @attributes: a #GimpAttributes
+ * @name : a #gchar array
+ *
+ * gets the #GimpAttribute object with @name
+ *
+ * Return value: the #GimpAttribute object if found, NULL otherwise.
+ *
+ * Since : 2.10
+ */
+GimpAttribute *
+gimp_attributes_get_attribute (GimpAttributes      *attributes,
+                               const gchar         *name)
+{
+  gchar          *lowchar;
+  GimpAttribute  *attribute_data = NULL;
+  gpointer       *data;
+
+  lowchar = g_ascii_strdown (name, -1);
+
+  data = g_hash_table_lookup (attributes->priv->attribute_table, (gpointer) lowchar);
+  if (data)
+    {
+      attribute_data = (GimpAttribute *) data;
+    }
+
+  g_free (lowchar);
+
+  return attribute_data;
+}
+
+/**
+ * gimp_attributes_remove_attribute:
+ *
+ * @attributes: a #GimpAttributes
+ * @name : a #gchar array
+ *
+ * removes the #GimpAttribute object with @name from the @attributes container
+ *
+ * Return value: TRUE, if removing was successful, FALSE otherwise.
+ *
+ * Since : 2.10
+ */
+gboolean
+gimp_attributes_remove_attribute (GimpAttributes      *attributes,
+                                  const gchar         *name)
+{
+  gchar *lowchar;
+  gboolean success;
+
+  lowchar = g_ascii_strdown (name, -1);
+
+  success = g_hash_table_remove (attributes->priv->attribute_table, (gpointer) lowchar);
+
+  attributes->priv->sorted_key_list = g_list_remove (attributes->priv->sorted_key_list,
+                                                     (gpointer) lowchar);
+  g_free (lowchar);
+
+  return success;
+
+}
+
+/**
+ * gimp_attributes_has_attribute:
+ *
+ * @attributes: a #GimpAttributes
+ * @name : a #gchar array
+ *
+ * tests, if a #GimpAttribute object with @name is in the @attributes container
+ *
+ * Return value: TRUE if yes, FALSE otherwise.
+ *
+ * Since : 2.10
+ */
+gboolean
+gimp_attributes_has_attribute (GimpAttributes      *attributes,
+                               const gchar         *name)
+{
+  gchar *lowchar;
+  gboolean success;
+
+  lowchar = g_ascii_strdown (name, -1);
+
+  success = g_hash_table_contains (attributes->priv->attribute_table, (gpointer) lowchar);
+
+  g_free (lowchar);
+
+  return success;
+}
+
+/**
+ * gimp_attributes_new_attribute:
+ *
+ * @attributes: a #GimpAttributes
+ * @name : a #gchar array
+ * @value: a #gchar array
+ * @type : a #GimpAttributeValueType
+ *
+ * adds a #GimpAttribute object to @attributes container.
+ * The #GimpAttribute object is created from the
+ * @name,
+ * @value and
+ * @type parameters.
+ *
+ * Return value: TRUE if successful, FALSE otherwise.
+ *
+ * Since : 2.10
+ */
+gboolean
+gimp_attributes_new_attribute (GimpAttributes *attributes,
+                               const gchar    *name,
+                               gchar          *value,
+                               GimpAttributeValueType type)
+{
+  GimpAttribute *attribute;
+
+  attribute = gimp_attribute_new_string (name, value, type);
+  if (attribute)
+    {
+      gimp_attributes_add_attribute (attributes, attribute);
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+/**
+ * gimp_attributes_serialize:
+ *
+ * @attributes: a #GimpAttributes
+ *
+ * creates a xml representation of all #GimpAttribute objects in the #GimpAttributes container.
+ * see #GimpAttribute:gimp_attribute_get_xml
+ *
+ * Return value: a new #gchar array, the xml representation of the #GimpAttributes object.
+ *
+ * Since : 2.10
+ */
+gchar *
+gimp_attributes_serialize (GimpAttributes *attributes)
+{
+  GString        *string;
+  GList          *key_list;
+
+  g_return_val_if_fail (GIMP_IS_ATTRIBUTES (attributes), NULL);
+
+  string = g_string_new (NULL);
+
+  g_string_append (string, "<?xml version='1.0' encoding='UTF-8'?>\n");
+  g_string_append (string, "<attributes>\n");
+
+  for (key_list = attributes->priv->sorted_key_list; key_list; key_list = key_list->next)
+    {
+      gchar          *xml       = NULL;
+      GimpAttribute  *attribute = NULL;
+      gchar          *p_key = (gchar *) key_list->data;
+
+      attribute      = gimp_attributes_get_attribute (attributes, p_key);
+
+      xml = gimp_attribute_get_xml (attribute);
+
+      g_string_append_printf (string, "%s\n", xml);
+
+      g_free (xml);
+    }
+
+  g_string_append (string, "</attributes>\n");
+
+  return g_string_free (string, FALSE);
+}
+
+/**
+ * gimp_attributes_deserialize:
+ *
+ * @xml: a #gchar array
+ *
+ * parses a xml representation of a #GimpAttributes container.
+ * see
+ * #GimpAttributes:gimp_attributes_deserialize_start_element
+ * #GimpAttributes:gimp_attributes_deserialize_end_element
+ * #GimpAttributes:gimp_attributes_deserialize_text
+ * #GimpAttributes:gimp_attributes_deserialize_error
+ *
+ * Return value: a new #GimpAttributes object.
+ *
+ * Since : 2.10
+ */
+GimpAttributes *
+gimp_attributes_deserialize (const gchar *xml)
+{
+  GMarkupParser            *markup_parser = g_slice_new (GMarkupParser);
+  GimpAttributesParseData  *parse_data = g_slice_new (GimpAttributesParseData);
+  GMarkupParseContext      *context;
+  GimpAttributes           *attributes;
+
+  g_return_val_if_fail (xml != NULL, NULL);
+
+  attributes = gimp_attributes_new ();
+
+  parse_data->attributes = attributes;
+
+  markup_parser->start_element = gimp_attributes_deserialize_start_element;
+  markup_parser->end_element   = gimp_attributes_deserialize_end_element;
+  markup_parser->text          = gimp_attributes_deserialize_text;
+  markup_parser->passthrough   = NULL;
+  markup_parser->error         = gimp_attributes_deserialize_error;
+
+  context = g_markup_parse_context_new (markup_parser, 0, parse_data, NULL);
+
+  g_markup_parse_context_parse (context,
+                                xml, strlen (xml),
+                                NULL);
+
+  g_markup_parse_context_unref (context);
+
+  g_slice_free (GMarkupParser, markup_parser);
+  g_slice_free (GimpAttributesParseData, parse_data);
+
+ return attributes;
+}
+
+
+/**
+ * gimp_attributes_from_metadata:
+ * @attributes:  The attributes the metadata will be added to, may be %NULL
+ * @metadata:  The metadata in gexiv2 format
+ *
+ * Converts the @metadata retrieved from a file into
+ * a #GimpAttributes object
+ *
+ * Return value: The #GimpAttributes object
+ *
+ * Since: GIMP 2.10
+ */
+GimpAttributes *
+gimp_attributes_from_metadata (GimpAttributes *attributes, GimpMetadata *metadata)
+{
+  const gchar               *tag_type;
+  GimpAttribute             *attribute;
+  GimpAttributeValueType     attrib_type;
+  gint                       i;
+  GimpAttributes            *new_attributes    = NULL;
+
+  g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), NULL);
+
+  if (!attributes)
+    {
+      new_attributes = gimp_attributes_new ();
+    }
+  else
+    {
+      new_attributes = gimp_attributes_duplicate (attributes);
+      g_object_unref (attributes);
+    }
+
+  if (new_attributes)
+    {
+      gchar    **exif_data;
+      gchar    **xmp_data;
+      gchar    **iptc_data;
+      gboolean   no_interpreted    = TRUE; /*FIXME: No interpreted String possible */
+
+      exif_data = gexiv2_metadata_get_exif_tags (metadata);
+
+      for (i = 0; exif_data[i] != NULL; i++)
+        {
+          gchar    *interpreted_value = NULL;
+          gchar    *value             = NULL;
+          gboolean  interpreted       = FALSE;
+
+          value = gexiv2_metadata_get_tag_string (metadata, exif_data[i]);
+          interpreted_value = gexiv2_metadata_get_tag_interpreted_string (metadata, exif_data[i]);
+          tag_type = gexiv2_metadata_get_tag_type (exif_data[i]);
+          attrib_type = gimp_attribute_get_value_type_from_string (tag_type);
+
+          interpreted = g_strcmp0 (value, interpreted_value);
+
+          attribute = gimp_attribute_new_string (exif_data[i], value, attrib_type);
+          if (gimp_attribute_is_valid (attribute))
+            {
+              if (no_interpreted)
+                {
+                  if (interpreted)
+                    gimp_attribute_set_interpreted_string (attribute, interpreted_value);
+                }
+
+              gimp_attributes_add_attribute (new_attributes, attribute);
+            }
+          else
+            {
+              g_object_unref (attribute);
+            }
+
+          g_free (interpreted_value);
+          g_free (value);
+        }
+
+      g_strfreev (exif_data);
+
+      xmp_data = gexiv2_metadata_get_xmp_tags (metadata);
+
+      for (i = 0; xmp_data[i] != NULL; i++)
+        {
+          gchar    *interpreted_value = NULL;
+          gchar    *value             = NULL;
+          gboolean  interpreted       = FALSE;
+
+          value = gexiv2_metadata_get_tag_string (metadata, xmp_data[i]);
+          interpreted_value = gexiv2_metadata_get_tag_interpreted_string (metadata, xmp_data[i]);
+          tag_type = gexiv2_metadata_get_tag_type (xmp_data[i]);
+          attrib_type = gimp_attribute_get_value_type_from_string (tag_type);
+
+          interpreted = g_strcmp0 (value, interpreted_value);
+
+          attribute = gimp_attribute_new_string (xmp_data[i], value, attrib_type);
+
+          if (gimp_attribute_is_valid (attribute))
+            {
+              if (no_interpreted)
+                {
+                  if (interpreted)
+                    gimp_attribute_set_interpreted_string (attribute, interpreted_value);
+                }
+              gimp_attributes_add_attribute (new_attributes, attribute);
+            }
+          else
+            {
+              g_object_unref (attribute);
+            }
+
+          g_free (value);
+        }
+
+      g_strfreev (xmp_data);
+
+      iptc_data = gexiv2_metadata_get_iptc_tags (metadata);
+
+      for (i = 0; iptc_data[i] != NULL; i++)
+        {
+          gchar    *interpreted_value = NULL;
+          gchar    *value             = NULL;
+          gboolean  interpreted       = FALSE;
+
+          value = gexiv2_metadata_get_tag_string (metadata, iptc_data[i]);
+          interpreted_value = gexiv2_metadata_get_tag_interpreted_string (metadata, iptc_data[i]);
+          tag_type = gexiv2_metadata_get_tag_type (iptc_data[i]);
+          attrib_type = gimp_attribute_get_value_type_from_string (tag_type);
+
+          interpreted = g_strcmp0 (value, interpreted_value);
+
+          attribute = gimp_attribute_new_string (iptc_data[i], value, attrib_type);
+          if (gimp_attribute_is_valid (attribute))
+            {
+              if (no_interpreted)
+                {
+                  if (interpreted)
+                    gimp_attribute_set_interpreted_string (attribute, interpreted_value);
+                }
+              gimp_attributes_add_attribute (new_attributes, attribute);
+            }
+          else
+            {
+              g_object_unref (attribute);
+            }
+
+          g_free (value);
+        }
+
+      g_strfreev (iptc_data);
+    }
+
+  return new_attributes;
+}
+
+/**
+ * gimp_attributes_print:
+ * @attributes:  The #GimpAttributes
+ *
+ * prints out information of attributes
+ *
+ * Since: GIMP 2.10
+ */
+void
+gimp_attributes_print (GimpAttributes *attributes)
+{
+  gint            i;
+  GList          *key_list = NULL;
+
+
+  g_return_if_fail (GIMP_IS_ATTRIBUTES (attributes));
+
+  i = 0;
+
+  for (key_list = attributes->priv->sorted_key_list; key_list; key_list = key_list->next)
+    {
+      const gchar    *tag;
+      const gchar    *interpreted;
+      gchar          *value;
+      GimpAttribute  *attribute;
+      gchar          *p_key = (gchar *) key_list->data;
+
+      attribute      = gimp_attributes_get_attribute (attributes, p_key);
+
+      if (! attribute)
+        continue;
+
+      i++;
+
+      tag = gimp_attribute_get_name (attribute);
+      value = gimp_attribute_get_string (attribute);
+      interpreted = gimp_attribute_get_interpreted_string (attribute);
+
+      g_print ("%p: %s\n%04d. Tag: %s\n\tValue:%s\n\tInterpreted value:%s\n", attribute, p_key, i, tag, 
value, interpreted);
+
+      if (value)
+        g_free (value);
+    }
+}
+
+/**
+ * gimp_attributes_to_metadata:
+ * @attributes:  The #GimpAttributes
+ * @metadata:  The #GimpMetadata
+ * @mime_type: the mime type of the image
+ *
+ * Converts @attributes to @metadata in gexiv2 format
+ *
+ * Since: GIMP 2.10
+ */
+void
+gimp_attributes_to_metadata (GimpAttributes *attributes,
+                             GimpMetadata *metadata,
+                             const gchar *mime_type)
+{
+  gchar          *o_packet            = NULL;
+  gboolean        write_tag           = FALSE;
+  gboolean        namespace           = FALSE;
+  gboolean        check_mime          = TRUE;
+  gboolean        support_exif;
+  gboolean        support_xmp;
+  gboolean        support_iptc;
+  GSList         *xmp_structure_list  = NULL;
+  GList          *key_list            = NULL;
+  gint            i;
+
+
+  g_return_if_fail (GIMP_IS_ATTRIBUTES (attributes));
+  g_return_if_fail (GEXIV2_IS_METADATA (metadata));
+
+  for (i = 0; i < G_N_ELEMENTS (namespaces_table); i++)
+    {
+      struct Namespaces n_space = namespaces_table[i];
+      gexiv2_metadata_register_xmp_namespace (n_space.namespace_URI, n_space.namespace_name);
+    }
+
+  support_exif = gexiv2_metadata_get_supports_exif (metadata);
+  support_xmp  = gexiv2_metadata_get_supports_xmp  (metadata);
+  support_iptc = gexiv2_metadata_get_supports_iptc (metadata);
+
+  for (key_list = attributes->priv->sorted_key_list; key_list; key_list = key_list->next)
+    {
+      const gchar              *tag;
+      const gchar              *ns_name;
+      gchar                    *p_key = (gchar *) key_list->data;
+      gchar                    *value         = NULL;
+      gchar                    *category      = NULL;
+      gboolean                  is_xmp        = FALSE;
+      gboolean                  has_structure = FALSE;
+      GimpAttribute            *attribute;
+      GimpAttributeValueType    tag_value_type;
+      GError                   *error = NULL;
+
+      write_tag      = FALSE;
+      namespace      = FALSE;
+
+      attribute      = gimp_attributes_get_attribute (attributes, p_key);
+
+      if (! attribute)
+        continue;
+
+      tag            = gimp_attribute_get_name (attribute);
+      has_structure  = gimp_attribute_has_structure (attribute);
+
+      if (mime_type)
+        check_mime = gimp_metadata_is_tag_supported (tag, mime_type);
+
+      if (check_mime)
+        {
+          gchar *t_packet       = NULL;
+
+          tag_value_type = gimp_attribute_get_value_type (attribute);
+          value = gimp_attribute_get_string (attribute);
+          category = g_ascii_strdown (gimp_attribute_get_attribute_type (attribute), -1);
+
+          if (tag && value && category)
+            {
+              if(! g_strcmp0 (category, "exif") && support_exif)
+                {
+                  write_tag = TRUE;
+                }
+              else if(! g_strcmp0 (category, "xmp") && support_xmp)
+                {
+                  write_tag = TRUE;
+                  is_xmp    = TRUE;
+
+                  namespace = gimp_attribute_is_new_namespace (attribute);
+
+                  if (namespace)
+                    {
+                      write_tag = FALSE;
+
+                      ns_name = gimp_attribute_get_attribute_ifd (attribute);
+
+                      for (i = 0; i < G_N_ELEMENTS (namespaces_table); i++)
+                        {
+                          struct Namespaces n_space = namespaces_table[i];
+                          if(! g_strcmp0 (ns_name, n_space.namespace_name))
+                            {
+                              write_tag = TRUE;
+                              break;
+                            }
+                        }
+                    }
+
+                  if (write_tag && has_structure)
+                    {
+                      gboolean                    success = TRUE;
+                      GSList                     *structure;
+                      GSList                     *list;
+                      GimpAttributeStructureType  structure_type;
+
+                      structure      = gimp_attribute_get_attribute_structure (attribute);
+                      structure_type = gimp_attribute_get_structure_type (attribute);
+
+                      for (list = structure; list; list = list->next)
+                        {
+                          const gchar   *structure_element = (const gchar*) list->data;
+                          gboolean       has_tag = gexiv2_metadata_has_tag (metadata, structure_element);
+
+                          if (!has_tag && ! has_xmp_structure (xmp_structure_list, structure_element))
+                            {
+                              switch (structure_type)
+                              {
+                                case STRUCTURE_TYPE_ALT:
+                                  success = gexiv2_metadata_set_xmp_tag_struct (metadata, structure_element, 
GEXIV2_STRUCTURE_XA_ALT); /*start block*/
+                                  break;
+                                case STRUCTURE_TYPE_BAG:
+                                  success = gexiv2_metadata_set_xmp_tag_struct (metadata, structure_element, 
GEXIV2_STRUCTURE_XA_BAG); /*start block*/
+                                  break;
+                                case STRUCTURE_TYPE_SEQ:
+                                  success = gexiv2_metadata_set_xmp_tag_struct (metadata, structure_element, 
GEXIV2_STRUCTURE_XA_SEQ); /*start block*/
+                                  break;
+                                default:
+                                  success = FALSE;
+                                  break;
+                              }
+
+                              if (success)
+                                xmp_structure_list = g_slist_prepend (xmp_structure_list, 
(gpointer)structure_element);
+                            }
+                        }
+                    }
+                }
+              else if(! g_strcmp0 (category, "iptc") && support_iptc)
+                {
+                  write_tag = TRUE;
+                }
+              else
+                {
+                  write_tag = FALSE;
+                }
+
+              if (write_tag)
+                {
+                  switch (tag_value_type)
+                  {
+                    case TYPE_INVALID:
+                      break;
+                    case TYPE_LONG:
+                    case TYPE_SLONG:
+                    case TYPE_FLOAT:
+                    case TYPE_DOUBLE:
+                    case TYPE_SHORT:
+                    case TYPE_SSHORT:
+                    case TYPE_DATE:
+                    case TYPE_TIME:
+                    case TYPE_ASCII:
+                    case TYPE_UNICODE:
+                    case TYPE_BYTE:
+                    case TYPE_RATIONAL:
+                    case TYPE_SRATIONAL:
+                      {
+                        gexiv2_metadata_set_tag_string (metadata, tag, value);
+                      }
+                      break;
+                    case TYPE_MULTIPLE:
+                      {
+                        GValue h;
+                        gchar **values;
+
+                        h = gimp_attribute_get_value (attribute);
+                        values = (gchar **) g_value_get_boxed (&h);
+                        gexiv2_metadata_set_tag_multiple (metadata, tag, (const gchar **) values);
+                        g_strfreev  (values);
+                      }
+                      break;
+                    case TYPE_UNKNOWN:
+                    default:
+                      break;
+
+                  }
+
+                  if (is_xmp)
+                    {
+                      t_packet = gexiv2_metadata_generate_xmp_packet (metadata, useCompactFormat  | 
omitAllFormatting, 0, &error);
+                      if (error)
+                        {
+                          g_print ("error: %s\n", error->message);
+                          g_clear_error (&error);
+                        }
+
+                      if (! g_strcmp0 (t_packet, o_packet))
+                        {
+                          gexiv2_metadata_clear_tag (metadata, tag);
+                          g_print ("cleared to metadata:\n%s, %s\n", tag, value);
+                        }
+                      else
+                        {
+                          o_packet = g_strdup (t_packet);
+                        }
+                    }
+                }
+            }
+
+          if (t_packet)
+            g_free (t_packet);
+          if (value)
+            g_free (value);
+          if (category)
+            g_free (category);
+       }
+    }
+
+  if (o_packet)
+    g_free (o_packet);
+  if (xmp_structure_list)
+    g_slist_free (xmp_structure_list);
+}
+
+
+#if 0
+/**
+ * gimp_attributes_to_xmp_packet:
+ * @attributes:  The #GimpAttributes
+ * @mime_type :  a mime_type
+ *
+ * placeholder, until gexiv2 can generate xmp packet.
+ * always returns NULL
+ *
+ * Since: GIMP 2.10
+ */
+const gchar *
+gimp_attributes_to_xmp_packet (GimpAttributes *attributes,
+                               const gchar *mime_type)
+
+{
+  return NULL;
+}
+#endif
+
+/**
+ * gimp_attributes_to_xmp_packet:
+ * @attributes:  The #GimpAttributes
+ * @mime_type :  a mime_type
+ *
+ * Converts @attributes to a xmp packet
+ * It looks like an ugly hack, but let
+ * gexiv2/exiv2 do all the hard work.
+ *
+ * Return value: a #gchar*, representing a xml packet.
+ *
+ * Since: GIMP 2.10
+ */
+const gchar *
+gimp_attributes_to_xmp_packet (GimpAttributes *attributes,
+                               const gchar *mime_type)
+
+{
+  gint            i;
+  const gchar    *packet_string;
+  gchar          *o_packet           = NULL;
+  gboolean        check_mime         = TRUE;
+  gboolean        write_tag          = FALSE;
+  gboolean        namespace          = FALSE;
+  gboolean        support_exif;
+  gboolean        support_xmp;
+  gboolean        support_iptc;
+  GimpMetadata   *metadata;
+  GSList         *xmp_structure_list = NULL;
+  GList          *key_list           = NULL;
+  GError         *error              = NULL;
+
+  g_return_val_if_fail (GIMP_IS_ATTRIBUTES (attributes), NULL);
+
+  metadata = gimp_metadata_new ();
+
+  for (i = 0; i < G_N_ELEMENTS (namespaces_table); i++)
+    {
+      struct Namespaces n_space = namespaces_table[i];
+      gexiv2_metadata_register_xmp_namespace (n_space.namespace_URI, n_space.namespace_name);
+    }
+
+  support_exif = gexiv2_metadata_get_supports_exif (metadata);
+  support_xmp  = gexiv2_metadata_get_supports_xmp  (metadata);
+  support_iptc = gexiv2_metadata_get_supports_iptc (metadata);
+
+  for (key_list = attributes->priv->sorted_key_list; key_list; key_list = key_list->next)
+    {
+      gchar          *p_key = (gchar *) key_list->data;
+
+      const gchar            *tag;
+      const gchar            *attribute_tag;
+      const gchar            *ns_name;
+      gchar                  *new_tag         = NULL;
+      gchar                  *value           = NULL;
+      gchar                  *category        = NULL;
+      gboolean                has_structure;
+      gboolean                temp_attribute  = FALSE;
+      GimpAttribute          *attribute;
+      GimpAttributeValueType  tag_value_type;
+
+      write_tag     = FALSE;
+      namespace = FALSE;
+
+      attribute = gimp_attributes_get_attribute (attributes, p_key);
+
+      if (! attribute)
+        continue;
+
+      tag            = gimp_attribute_get_name (attribute);
+      attribute_tag  = gimp_attribute_get_attribute_tag (attribute);
+      has_structure  = gimp_attribute_has_structure (attribute);
+
+      if (mime_type)
+        check_mime = gimp_metadata_is_tag_supported (tag, mime_type);
+
+      if (check_mime)
+        {
+          gchar *sec_tag        = NULL;
+          gchar *t_packet       = NULL;
+
+          tag_value_type = gimp_attribute_get_value_type (attribute);
+          value = gimp_attribute_get_string (attribute);
+          category = g_ascii_strdown (gimp_attribute_get_attribute_type (attribute), -1);
+
+          if (tag && value && category)
+            {
+              if(! g_strcmp0 (category, "exif") && support_exif)
+                {
+                  new_tag = g_strdup_printf ("Xmp.exif.%s", attribute_tag);
+
+                  write_tag = TRUE;
+
+//                  /* Now for some specialities */
+//                  if (! g_strcmp0 (new_tag, "Xmp.exif.ISOSpeedRatings"))
+//                    {
+//                      g_print ("ungültig\n");
+//                       attribute = gimp_attribute_new_string ("Xmp.exif.ISOSpeedRatings", value, 
TYPE_ASCII);
+//                      if (attribute)
+//                        {
+//                          temp_attribute = TRUE;
+//                          tag_value_type = TYPE_ASCII;
+//                        }
+//                      else
+//                        {
+//                          write_tag = FALSE;
+//                        }
+//                    }
+                }
+              else if(! g_strcmp0 (category, "xmp") && support_xmp)
+                {
+                  new_tag = g_strdup_printf ("%s", tag);
+
+                  write_tag = TRUE;
+
+                  namespace = gimp_attribute_is_new_namespace (attribute);
+
+                  if (namespace)
+                    {
+                      write_tag = FALSE;
+
+                      ns_name = gimp_attribute_get_attribute_ifd (attribute);
+
+                      for (i = 0; i < G_N_ELEMENTS (namespaces_table); i++)
+                        {
+                          struct Namespaces n_space = namespaces_table[i];
+                          if(! g_strcmp0 (ns_name, n_space.namespace_name))
+                            {
+                              write_tag = TRUE;
+                              break;
+                            }
+                        }
+                    }
+
+                  if (write_tag && has_structure)
+                    {
+                      gboolean                    success = TRUE;
+                      GSList                     *structure;
+                      GSList                     *list;
+                      GimpAttributeStructureType  structure_type;
+
+                      structure      = gimp_attribute_get_attribute_structure (attribute);
+                      structure_type = gimp_attribute_get_structure_type (attribute);
+
+                      for (list = structure; list; list = list->next)
+                        {
+                          const gchar   *structure_element = (const gchar*) list->data;
+                          gboolean       has_tag = gexiv2_metadata_has_tag (metadata, structure_element);
+
+                          if (!has_tag && ! has_xmp_structure (xmp_structure_list, structure_element))
+                            {
+                              switch (structure_type)
+                              {
+                                case STRUCTURE_TYPE_ALT:
+                                  success = gexiv2_metadata_set_xmp_tag_struct (metadata, structure_element, 
GEXIV2_STRUCTURE_XA_ALT); /*start block*/
+                                  break;
+                                case STRUCTURE_TYPE_BAG:
+                                  success = gexiv2_metadata_set_xmp_tag_struct (metadata, structure_element, 
GEXIV2_STRUCTURE_XA_BAG); /*start block*/
+                                  break;
+                                case STRUCTURE_TYPE_SEQ:
+                                  success = gexiv2_metadata_set_xmp_tag_struct (metadata, structure_element, 
GEXIV2_STRUCTURE_XA_SEQ); /*start block*/
+                                  break;
+                                default:
+                                  success = FALSE;
+                                  break;
+                              }
+
+                              if (success)
+                                xmp_structure_list = g_slist_prepend (xmp_structure_list, 
(gpointer)structure_element);
+                            }
+                        }
+                    }
+                }
+              else if(! g_strcmp0 (category, "iptc") && support_iptc)
+                {
+                  new_tag = g_strdup_printf ("Xmp.iptc.%s", attribute_tag);
+                  sec_tag = g_strdup_printf ("Xmp.iptcExt.%s", attribute_tag);
+                  write_tag = TRUE;
+                }
+              else
+                {
+                  write_tag = FALSE;
+                }
+
+              if (write_tag)
+                {
+                  switch (tag_value_type)
+                  {
+                    case TYPE_INVALID:
+                      break;
+                    case TYPE_LONG:
+                    case TYPE_SLONG:
+                    case TYPE_FLOAT:
+                    case TYPE_DOUBLE:
+                    case TYPE_SHORT:
+                    case TYPE_SSHORT:
+                    case TYPE_DATE:
+                    case TYPE_TIME:
+                    case TYPE_ASCII:
+                    case TYPE_UNICODE:
+                    case TYPE_BYTE:
+                    case TYPE_RATIONAL:
+                    case TYPE_SRATIONAL:
+                      {
+                        gexiv2_metadata_set_tag_string (metadata, new_tag, value);
+                        if (sec_tag)
+                          {
+                            gexiv2_metadata_set_tag_string (metadata, sec_tag, value);
+                            g_free (sec_tag);
+                          }
+
+                      }
+                      break;
+                    case TYPE_MULTIPLE:
+                      {
+                        GValue h;
+                        gchar **values;
+
+                        h = gimp_attribute_get_value (attribute);
+                        values = (gchar **) g_value_get_boxed (&h);
+                        gexiv2_metadata_set_tag_multiple (metadata, new_tag, (const gchar **) values);
+                        if (sec_tag)
+                          {
+                            gexiv2_metadata_set_tag_multiple (metadata, sec_tag, (const gchar **) values);
+                            g_free (sec_tag);
+                          }
+                        g_strfreev  (values);
+                      }
+                      break;
+                    case TYPE_UNKNOWN:
+                    default:
+                      break;
+
+                  }
+
+                  t_packet = gexiv2_metadata_generate_xmp_packet (metadata, useCompactFormat  | 
omitAllFormatting, 0, &error);
+
+                  if (! t_packet || ! g_strcmp0 (t_packet, o_packet))
+                    {
+                      gexiv2_metadata_clear_tag (metadata, new_tag);
+                    }
+                  else
+                    {
+                      o_packet = g_strdup (t_packet);
+                    }
+                }
+            }
+
+          if (t_packet)
+            g_free (t_packet);
+          if (value)
+            g_free (value);
+          if (category)
+            g_free (category);
+          if (new_tag)
+            g_free (new_tag);
+
+          if (temp_attribute)
+            g_object_unref (attribute);
+       }
+    }
+
+  if (o_packet)
+    g_free (o_packet);
+  if (xmp_structure_list)
+    g_slist_free (xmp_structure_list);
+
+  packet_string = gexiv2_metadata_generate_xmp_packet (metadata, useCompactFormat | writeAliasComments, 0, 
&error);
+  return packet_string;
+}
+
+/**
+ * gimp_attributes_has_tag_type:
+ * @attributes:  The attributes
+ * @tag_type:  The #GimpAttributeTagType to test
+ *
+ * tests, if @attributes contains at least one tag of @tag_type
+ *
+ * Return value: TRUE if found, FALSE otherwise
+ *
+ * Since: GIMP 2.10
+ */
+gboolean
+gimp_attributes_has_tag_type (GimpAttributes       *attributes,
+                              GimpAttributeTagType  tag_type)
+{
+  GHashTableIter  iter;
+  gpointer        p_key, p_value;
+
+  g_return_val_if_fail (GIMP_IS_ATTRIBUTES (attributes), FALSE);
+
+  g_hash_table_iter_init (&iter, attributes->priv->attribute_table);
+
+  while (g_hash_table_iter_next (&iter, &p_key, &p_value))
+    {
+      GimpAttribute         *attribute;
+
+      attribute = (GimpAttribute *) p_value;
+
+      if (gimp_attribute_get_tag_type (attribute) == tag_type)
+        return TRUE;
+
+    }
+  return FALSE;
+}
+
+/**
+ * gimp_attributes_error_quark:
+ *
+ * Return value: #GQuark
+ *
+ * Since: GIMP 2.10
+ */
+static GQuark
+gimp_attributes_error_quark (void)
+{
+  static GQuark quark = 0;
+
+  if (G_UNLIKELY (quark == 0))
+    quark = g_quark_from_static_string ("gimp-attributes-error-quark");
+
+  return quark;
+}
+
+/**
+ * gimp_attributes_deserialize_error:
+ *
+ * Error while parsing
+ *
+ * Since: GIMP 2.10
+ */
+static void
+gimp_attributes_deserialize_error (GMarkupParseContext *context,
+                                   GError              *error,
+                                   gpointer             user_data)
+{
+  g_printerr ("XML parse error: %s\n", error->message);
+}
+
+/**
+ * gimp_attributes_name_to_value:
+ *
+ * @attribute_names  : #gchar **
+ * @attribute_values : #gchar **
+ * @name             : #gchar *
+ *
+ * searches for values in @attribute_values by a given @name (parsing xml)
+ *
+ * Since: GIMP 2.10
+ */
+static const gchar*
+gimp_attributes_name_to_value (const gchar **attribute_names,
+                               const gchar **attribute_values,
+                               const gchar  *name)
+{
+  while (*attribute_names)
+    {
+      if (! strcmp (*attribute_names, name))
+        {
+          return *attribute_values;
+        }
+
+      attribute_names++;
+      attribute_values++;
+    }
+
+  return NULL;
+}
+
+/**
+ * gimp_attributes_deserialize_start_element:
+ *
+ * @context           : #GMarkupParseContext
+ * @element_name      : #gchar *
+ * @attribute_names   : #gchar **
+ * @attribute_values  : #gchar **
+ * @user_data         : #gpointer to #GimpAttributesParseData struct
+ * @error             : #GError **
+ *
+ * start of a tag (parsing xml)
+ *
+ * Since: GIMP 2.10
+ */
+static void
+gimp_attributes_deserialize_start_element (GMarkupParseContext *context,
+                                           const gchar         *element_name,
+                                           const gchar        **attribute_names,
+                                           const gchar        **attribute_values,
+                                           gpointer             user_data,
+                                           GError             **error)
+{
+  GimpAttributesParseData *parse_data = user_data;
+
+  if (! strcmp (element_name, "tag"))
+    {
+      const gchar *name = NULL;
+      const gchar *type = NULL;
+
+      name     = gimp_attributes_name_to_value (attribute_names,
+                                                attribute_values,
+                                                "name");
+      type     = gimp_attributes_name_to_value (attribute_names,
+                                                attribute_values,
+                                                "type");
+
+      if (! name)
+        {
+          g_set_error (error, gimp_attributes_error_quark (), 1001,
+                       "Element 'tag' does not contain required attribute 'name'.");
+          return;
+        }
+
+      if (! type)
+        {
+          g_set_error (error, gimp_attributes_error_quark (), 1001,
+                       "Element 'tag' does not contain required attribute 'type'.");
+          return;
+        }
+
+      strncpy (parse_data->name, name, sizeof (parse_data->name));
+      parse_data->name[sizeof (parse_data->name) - 1] = 0;
+
+      parse_data->type = (GimpAttributeValueType) atoi (type);
+    }
+  else if (! strcmp (element_name, "value"))
+    {
+      const gchar *encoding = NULL;
+
+      encoding = gimp_attributes_name_to_value (attribute_names,
+                                                attribute_values,
+                                                "encoding");
+
+      parse_data->base64 = (encoding && ! strcmp (encoding, "base64"));
+    }
+  else if (! strcmp (element_name, "interpreted"))
+    {
+      const gchar *encoding = NULL;
+
+      encoding = gimp_attributes_name_to_value (attribute_names,
+                                                attribute_values,
+                                                "encoding");
+
+      parse_data->base64 = (encoding && ! strcmp (encoding, "base64"));
+    }
+
+}
+
+/**
+ * gimp_attributes_deserialize_text:
+ *
+ * @context           : #GMarkupParseContext
+ * @text              : const #gchar *
+ * @text_len          : #gsize
+ * @user_data         : #gpointer to #GimpAttributesParseData struct
+ * @error             : #GError **
+ *
+ * text of a tag (parsing xml)
+ *
+ * Since: GIMP 2.10
+ */
+static void
+gimp_attributes_deserialize_text (GMarkupParseContext  *context,
+                                  const gchar          *text,
+                                  gsize                 text_len,
+                                  gpointer              user_data,
+                                  GError              **error)
+{
+  GimpAttributesParseData *parse_data = user_data;
+  GimpAttribute           *attribute;
+  const gchar             *current_element;
+
+  current_element = g_markup_parse_context_get_element (context);
+
+  if (! g_strcmp0 (current_element, "value"))
+    {
+      gchar *value = g_strndup (text, text_len);
+
+      if (parse_data->base64)
+        {
+          guchar *decoded;
+          gsize   len;
+
+          decoded = g_base64_decode (value, &len);
+
+          if (decoded[len - 1] == '\0')
+            attribute = gimp_attribute_new_string (parse_data->name,
+                                                   (gchar *)decoded,
+                                                   parse_data->type);
+
+          g_free (decoded);
+        }
+      else
+        {
+          attribute = gimp_attribute_new_string (parse_data->name,
+                                                 value,
+                                                 parse_data->type);
+        }
+
+      g_free (value);
+
+      if (gimp_attribute_is_valid (attribute))
+        {
+          gimp_attributes_add_attribute (parse_data->attributes, attribute);
+          current_attribute = attribute;
+        }
+      else
+        g_object_unref (attribute);
+
+    }
+  else if (! g_strcmp0 (current_element, "structure"))
+    {
+      GimpAttribute *attribute = NULL;
+      gchar         *value     = NULL;
+
+      attribute = current_attribute;
+
+      if (attribute)
+        {
+          gint                       v;
+          GimpAttributeStructureType struct_type = STRUCTURE_TYPE_BAG;
+
+          value = g_strndup (text, text_len);
+
+          v = atoi (value);
+
+          if (v > -1)
+            struct_type = (GimpAttributeStructureType) v;
+
+          gimp_attribute_set_structure_type (attribute, struct_type);
+
+          g_free (value);
+        }
+    }
+  else if (! g_strcmp0 (current_element, "interpreted"))
+    {
+      GimpAttribute *attribute = NULL;
+      gchar         *value     = NULL;
+
+      attribute = current_attribute;
+
+      if (attribute)
+        {
+          value = g_strndup (text, text_len);
+
+          if (parse_data->base64)
+            {
+              guchar *decoded = NULL;
+              gsize   len;
+
+              decoded = g_base64_decode (value, &len);
+
+              if (decoded[len - 1] == '\0')
+                gimp_attribute_set_interpreted_string (attribute, (const gchar *)decoded);
+
+              g_free (decoded);
+            }
+          else
+            {
+              gimp_attribute_set_interpreted_string (attribute, (const gchar *)value);
+            }
+          g_free (value);
+        }
+    }
+}
+
+/**
+ * gimp_attributes_deserialize_end_element:
+ *
+ * @context           : #GMarkupParseContext
+ * @element_name      : #gchar *
+ * @user_data         : #gpointer to #GimpAttributesParseData struct
+ * @error             : #GError **
+ *
+ * end of a tag (parsing xml)
+ *
+ * Since: GIMP 2.10
+ */
+static void
+gimp_attributes_deserialize_end_element (GMarkupParseContext *context,
+                                         const gchar         *element_name,
+                                         gpointer             user_data,
+                                         GError             **error)
+{
+  GimpAttributesParseData *parse_data = user_data;
+
+  if (! strcmp (element_name, "tag"))
+    {
+      current_attribute = NULL;
+    }
+  else if (! strcmp (element_name, "value"))
+    {
+      parse_data->base64 = FALSE;
+    }
+  else if (! strcmp (element_name, "interpreted"))
+    {
+      parse_data->base64 = FALSE;
+    }
+}
+
+static gboolean
+has_xmp_structure (GSList *xmp_list, const gchar *entry)
+{
+  GSList *list;
+
+  for (list = xmp_list; list; list = list->next)
+    {
+      const gchar *to_test = (const gchar*) list->data;
+
+       if (! g_strcmp0 (to_test, entry))
+        return TRUE;
+    }
+
+  return FALSE;
+}
diff --git a/libgimpbase/gimpattributes.h b/libgimpbase/gimpattributes.h
new file mode 100644
index 0000000..86bbe26
--- /dev/null
+++ b/libgimpbase/gimpattributes.h
@@ -0,0 +1,74 @@
+/* LIBGIMP - The GIMP Library
+ * Copyright (C) 1995-1997 Spencer Kimball and Peter Mattis
+ *
+ * gimpattributes.h
+ * Copyright (C) 2014  Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+
+#ifndef __GIMPATTRIBUTES_H__
+#define __GIMPATTRIBUTES_H__
+
+G_BEGIN_DECLS
+
+#define GIMP_TYPE_ATTRIBUTES            (gimp_attributes_get_type ())
+#define GIMP_ATTRIBUTES(obj)            (G_TYPE_CHECK_INSTANCE_CAST ((obj), GIMP_TYPE_ATTRIBUTES, 
GimpAttributes))
+#define GIMP_ATTRIBUTES_CLASS(klass)    (G_TYPE_CHECK_CLASS_CAST ((klass), GIMP_TYPE_ATTRIBUTES, 
GimpAttributesClass))
+#define GIMP_IS_ATTRIBUTES(obj)         (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GIMP_TYPE_ATTRIBUTES))
+#define GIMP_IS_ATTRIBUTES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GIMP_TYPE_ATTRIBUTES))
+#define GIMP_ATTRIBUTES_GET_CLASS(obj)  (G_TYPE_INSTANCE_GET_CLASS ((obj), GIMP_TYPE_ATTRIBUTES, 
GimpAttributesClass))
+#define GIMP_ATTRIBUTES_GET_PRIVATE(o)  (G_TYPE_INSTANCE_GET_PRIVATE ((o), GIMP_TYPE_ATTRIBUTES, 
GimpAttributesPrivate))
+
+
+GType                                     gimp_attributes_get_type                                   (void) 
G_GNUC_CONST;
+GimpAttributes *                          gimp_attributes_new                                        (void);
+gint                                      gimp_attributes_size                                       
(GimpAttributes      *attributes);
+GimpAttributes *                          gimp_attributes_duplicate                                  
(GimpAttributes      *attributes);
+GHashTable *                              gimp_attributes_get_table                                  
(GimpAttributes      *attributes);
+void                                      gimp_attributes_add_attribute                              
(GimpAttributes      *attributes,
+                                                                                                      
GimpAttribute       *attribute);
+GimpAttribute *                           gimp_attributes_get_attribute                              
(GimpAttributes      *attributes,
+                                                                                                      const 
gchar         *name);
+gboolean                                  gimp_attributes_remove_attribute                           
(GimpAttributes      *attributes,
+                                                                                                      const 
gchar         *name);
+gboolean                                  gimp_attributes_has_attribute                              
(GimpAttributes      *attributes,
+                                                                                                      const 
gchar         *name);
+gboolean                                  gimp_attributes_new_attribute                              
(GimpAttributes      *attributes,
+                                                                                                      const 
gchar         *name,
+                                                                                                      gchar  
             *value,
+                                                                                                      
GimpAttributeValueType
+                                                                                                             
              type);
+
+GimpAttributes *                          gimp_attributes_from_metadata                              
(GimpAttributes      *attributes,
+                                                                                                      
GimpMetadata        *metadata);
+void                                      gimp_attributes_to_metadata                                
(GimpAttributes      *attributes,
+                                                                                                      
GimpMetadata        *metadata,
+                                                                                                      const 
gchar         *mime_type);
+const gchar *                             gimp_attributes_to_xmp_packet                              
(GimpAttributes      *attributes,
+                                                                                                      const 
gchar         *mime_type);
+gchar *                                   gimp_attributes_serialize                                  
(GimpAttributes      *attributes);
+GimpAttributes *                          gimp_attributes_deserialize                                (const 
gchar         *xml);
+gboolean                                  gimp_attributes_has_tag_type                               
(GimpAttributes      *attributes,
+                                                                                                      
GimpAttributeTagType tag_type);
+void                                      gimp_attributes_print                                      
(GimpAttributes      *attributes);
+
+
+
+
+G_END_DECLS
+
+#endif
diff --git a/libgimpbase/gimpbase.def b/libgimpbase/gimpbase.def
index 4832eee..a4befd3 100644
--- a/libgimpbase/gimpbase.def
+++ b/libgimpbase/gimpbase.def
@@ -1,6 +1,47 @@
 EXPORTS
        gimp_add_mask_type_get_type
        gimp_any_to_utf8
+       gimp_attribute_copy
+       gimp_attribute_get_attribute_type
+       gimp_attribute_get_attribute_ifd
+       gimp_attribute_get_attribute_structure
+       gimp_attribute_get_attribute_tag
+       gimp_attribute_get_interpreted_string
+       gimp_attribute_get_name
+       gimp_attribute_get_string
+       gimp_attribute_get_structure_type
+       gimp_attribute_get_tag_type
+       gimp_attribute_get_value
+       gimp_attribute_get_value_type
+       gimp_attribute_get_value_type_from_string
+       gimp_attribute_get_xml
+       gimp_attribute_has_structure
+       gimp_attribute_is_valid
+       gimp_attribute_new_string
+       gimp_attribute_print
+       gimp_attribute_set_interpreted_string
+       gimp_attribute_set_structure_type
+       gimp_attribute_set_value_type
+       gimp_attributes_add_attribute
+       gimp_attributes_deserialize
+       gimp_attributes_duplicate
+       gimp_attributes_from_metadata
+       gimp_attributes_get_attribute
+       gimp_attributes_get_resolution
+       gimp_attributes_get_table
+       gimp_attributes_has_tag_type
+       gimp_attributes_new
+       gimp_attributes_new_attribute
+       gimp_attributes_print
+       gimp_attributes_remove_attribute
+       gimp_attributes_has_attribute
+       gimp_attributes_serialize
+       gimp_attributes_set_bits_per_sample
+       gimp_attributes_set_pixel_size
+       gimp_attributes_set_resolution
+       gimp_attributes_size
+       gimp_attributes_to_metadata
+       gimp_attributes_to_xmp_packet
        gimp_base_init
        gimp_blend_mode_get_type
        gimp_brush_generated_shape_get_type
@@ -66,19 +107,12 @@ EXPORTS
        gimp_memsize_to_string
        gimp_merge_type_get_type
        gimp_message_handler_type_get_type
-       gimp_metadata_deserialize
-       gimp_metadata_duplicate
-       gimp_metadata_get_resolution
        gimp_metadata_is_tag_supported
        gimp_metadata_load_from_file
        gimp_metadata_new
        gimp_metadata_save_to_file
-       gimp_metadata_serialize
-       gimp_metadata_set_bits_per_sample
        gimp_metadata_set_from_exif
        gimp_metadata_set_from_xmp
-       gimp_metadata_set_pixel_size
-       gimp_metadata_set_resolution
        gimp_micro_version
        gimp_minor_version
        gimp_offset_type_get_type
@@ -203,3 +237,5 @@ EXPORTS
        gp_tile_ack_write
        gp_tile_data_write
        gp_tile_req_write
+       rational_free
+       srational_free
diff --git a/libgimpbase/gimpbase.h b/libgimpbase/gimpbase.h
index a5682e7..35bace3 100644
--- a/libgimpbase/gimpbase.h
+++ b/libgimpbase/gimpbase.h
@@ -23,6 +23,9 @@
 
 #include <libgimpbase/gimpbasetypes.h>
 
+#include <libgimpbase/gimpattribute.h>
+#include <libgimpbase/gimpattributes.h>
+#include <libgimpbase/gimpattributes-image.h>
 #include <libgimpbase/gimpchecks.h>
 #include <libgimpbase/gimpcpuaccel.h>
 #include <libgimpbase/gimpdatafiles.h>
diff --git a/libgimpbase/gimpbasetypes.h b/libgimpbase/gimpbasetypes.h
index bef9904..85a699c 100644
--- a/libgimpbase/gimpbasetypes.h
+++ b/libgimpbase/gimpbasetypes.h
@@ -45,6 +45,8 @@ G_BEGIN_DECLS
 #endif
 
 
+typedef struct _GimpAttribute    GimpAttribute;
+typedef struct _GimpAttributes   GimpAttributes;
 typedef struct _GimpParasite     GimpParasite;
 typedef struct _GimpDatafileData GimpDatafileData;
 typedef struct _GimpEnumDesc     GimpEnumDesc;
diff --git a/libgimpbase/gimpmetadata.c b/libgimpbase/gimpmetadata.c
index 73ff2fc..fab2842 100644
--- a/libgimpbase/gimpmetadata.c
+++ b/libgimpbase/gimpmetadata.c
@@ -92,7 +92,6 @@ static const gchar *unsupported_tags[] =
   "Exif.Image.ClipPath",
   "Exif.Image.XClipPathUnits",
   "Exif.Image.YClipPathUnits",
-  "Xmp.xmpMM.History",
   "Exif.Image.XPTitle",
   "Exif.Image.XPComment",
   "Exif.Image.XPAuthor",
@@ -100,8 +99,7 @@ static const gchar *unsupported_tags[] =
   "Exif.Image.XPSubject",
   "Exif.Image.DNGVersion",
   "Exif.Image.DNGBackwardVersion",
-  "Exif.Iop"
-};
+  "Exif.Iop"};
 
 static const guint8 minimal_exif[] =
 {
@@ -173,35 +171,6 @@ gimp_metadata_new (void)
   return metadata;
 }
 
-/**
- * gimp_metadata_duplicate:
- * @metadata: The object to duplicate, or %NULL.
- *
- * Duplicates a #GimpMetadata instance.
- *
- * Return value: The new #GimpMetadata, or %NULL if @metadata is %NULL.
- *
- * Since: GIMP 2.10
- */
-GimpMetadata *
-gimp_metadata_duplicate (GimpMetadata *metadata)
-{
-  GimpMetadata *new_metadata = NULL;
-
-  g_return_val_if_fail (metadata == NULL || GEXIV2_IS_METADATA (metadata), NULL);
-
-  if (metadata)
-    {
-      gchar *xml;
-
-      xml = gimp_metadata_serialize (metadata);
-      new_metadata = gimp_metadata_deserialize (xml);
-      g_free (xml);
-    }
-
-  return new_metadata;
-}
-
 typedef struct
 {
   gchar         name[1024];
@@ -209,290 +178,6 @@ typedef struct
   GimpMetadata *metadata;
 } GimpMetadataParseData;
 
-static const gchar*
-gimp_metadata_attribute_name_to_value (const gchar **attribute_names,
-                                       const gchar **attribute_values,
-                                       const gchar  *name)
-{
-  while (*attribute_names)
-    {
-      if (! strcmp (*attribute_names, name))
-        {
-          return *attribute_values;
-        }
-
-      attribute_names++;
-      attribute_values++;
-    }
-
-  return NULL;
-}
-
-static void
-gimp_metadata_deserialize_start_element (GMarkupParseContext *context,
-                                         const gchar         *element_name,
-                                         const gchar        **attribute_names,
-                                         const gchar        **attribute_values,
-                                         gpointer             user_data,
-                                         GError             **error)
-{
-  GimpMetadataParseData *parse_data = user_data;
-
-  if (! strcmp (element_name, "tag"))
-    {
-      const gchar *name;
-      const gchar *encoding;
-
-      name = gimp_metadata_attribute_name_to_value (attribute_names,
-                                                    attribute_values,
-                                                    "name");
-      encoding = gimp_metadata_attribute_name_to_value (attribute_names,
-                                                        attribute_values,
-                                                        "encoding");
-
-      if (! name)
-        {
-          g_set_error (error, gimp_metadata_error_quark (), 1001,
-                       "Element 'tag' does not contain required attribute 'name'.");
-          return;
-        }
-
-      strncpy (parse_data->name, name, sizeof (parse_data->name));
-      parse_data->name[sizeof (parse_data->name) - 1] = 0;
-
-      parse_data->base64 = (encoding && ! strcmp (encoding, "base64"));
-    }
-}
-
-static void
-gimp_metadata_deserialize_end_element (GMarkupParseContext *context,
-                                       const gchar         *element_name,
-                                       gpointer             user_data,
-                                       GError             **error)
-{
-}
-
-static void
-gimp_metadata_deserialize_text (GMarkupParseContext  *context,
-                                const gchar          *text,
-                                gsize                 text_len,
-                                gpointer              user_data,
-                                GError              **error)
-{
-  GimpMetadataParseData *parse_data = user_data;
-  const gchar           *current_element;
-
-  current_element = g_markup_parse_context_get_element (context);
-
-  if (! g_strcmp0 (current_element, "tag"))
-    {
-      gchar *value = g_strndup (text, text_len);
-
-      if (parse_data->base64)
-        {
-          guchar *decoded;
-          gsize   len;
-
-          decoded = g_base64_decode (value, &len);
-
-          if (decoded[len - 1] == '\0')
-            gexiv2_metadata_set_tag_string (parse_data->metadata,
-                                            parse_data->name,
-                                            (const gchar *) decoded);
-
-          g_free (decoded);
-        }
-      else
-        {
-          gexiv2_metadata_set_tag_string (parse_data->metadata,
-                                          parse_data->name,
-                                          value);
-        }
-
-      g_free (value);
-    }
-}
-
-static  void
-gimp_metadata_deserialize_error (GMarkupParseContext *context,
-                                 GError              *error,
-                                 gpointer             user_data)
-{
-  g_printerr ("Metadata parse error: %s\n", error->message);
-}
-
-/**
- * gimp_metadata_deserialize:
- * @metadata_xml: A string of serialized metadata XML.
- *
- * Deserializes a string of XML that has been created by
- * gimp_metadata_serialize().
- *
- * Return value: The new #GimpMetadata.
- *
- * Since: GIMP 2.10
- */
-GimpMetadata *
-gimp_metadata_deserialize (const gchar *metadata_xml)
-{
-  GimpMetadata          *metadata;
-  GMarkupParser          markup_parser;
-  GimpMetadataParseData  parse_data;
-  GMarkupParseContext   *context;
-
-  g_return_val_if_fail (metadata_xml != NULL, NULL);
-
-  metadata = gimp_metadata_new ();
-
-  parse_data.metadata = metadata;
-
-  markup_parser.start_element = gimp_metadata_deserialize_start_element;
-  markup_parser.end_element   = gimp_metadata_deserialize_end_element;
-  markup_parser.text          = gimp_metadata_deserialize_text;
-  markup_parser.passthrough   = NULL;
-  markup_parser.error         = gimp_metadata_deserialize_error;
-
-  context = g_markup_parse_context_new (&markup_parser, 0, &parse_data, NULL);
-
-  g_markup_parse_context_parse (context,
-                                metadata_xml, strlen (metadata_xml),
-                                NULL);
-
-  g_markup_parse_context_unref (context);
-
-  return metadata;
-}
-
-static gchar *
-gimp_metadata_escape (const gchar *name,
-                      const gchar *value,
-                      gboolean    *base64)
-{
-  if (! g_utf8_validate (value, -1, NULL))
-    {
-      gchar *encoded;
-
-      encoded = g_base64_encode ((const guchar *) value, strlen (value) + 1);
-
-      g_printerr ("Invalid UTF-8 in metadata value %s, encoding as base64: %s\n",
-                  name, encoded);
-
-      *base64 = TRUE;
-
-      return encoded;
-    }
-
-  *base64 = FALSE;
-
-  return g_markup_escape_text (value, -1);
-}
-
-static void
-gimp_metadata_append_tag (GString     *string,
-                          const gchar *name,
-                          gchar       *value,
-                          gboolean     base64)
-{
-  if (value)
-    {
-      if (base64)
-        {
-          g_string_append_printf (string, "  <tag name=\"%s\" encoding=\"base64\">%s</tag>\n",
-                                  name, value);
-        }
-      else
-        {
-          g_string_append_printf (string, "  <tag name=\"%s\">%s</tag>\n",
-                                  name, value);
-        }
-
-      g_free (value);
-    }
-}
-
-/**
- * gimp_metadata_serialize:
- * @metadata: A #GimpMetadata instance.
- *
- * Serializes @metadata into an XML string that can later be deserialized
- * using gimp_metadata_deserialize().
- *
- * Return value: The serialized XML string.
- *
- * Since: GIMP 2.10
- */
-gchar *
-gimp_metadata_serialize (GimpMetadata *metadata)
-{
-  GString  *string;
-  gchar   **exif_data = NULL;
-  gchar   **iptc_data = NULL;
-  gchar   **xmp_data  = NULL;
-  gchar    *value;
-  gchar    *escaped;
-  gboolean  base64;
-  gint      i;
-
-  g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), NULL);
-
-  string = g_string_new (NULL);
-
-  g_string_append (string, "<?xml version='1.0' encoding='UTF-8'?>\n");
-  g_string_append (string, "<metadata>\n");
-
-  exif_data = gexiv2_metadata_get_exif_tags (metadata);
-
-  if (exif_data)
-    {
-      for (i = 0; exif_data[i] != NULL; i++)
-        {
-          value = gexiv2_metadata_get_tag_string (metadata, exif_data[i]);
-          escaped = gimp_metadata_escape (exif_data[i], value, &base64);
-          g_free (value);
-
-          gimp_metadata_append_tag (string, exif_data[i], escaped, base64);
-        }
-
-      g_strfreev (exif_data);
-    }
-
-  xmp_data = gexiv2_metadata_get_xmp_tags (metadata);
-
-  if (xmp_data)
-    {
-      for (i = 0; xmp_data[i] != NULL; i++)
-        {
-          value = gexiv2_metadata_get_tag_string (metadata, xmp_data[i]);
-          escaped = gimp_metadata_escape (xmp_data[i], value, &base64);
-          g_free (value);
-
-          gimp_metadata_append_tag (string, xmp_data[i], escaped, base64);
-        }
-
-      g_strfreev (xmp_data);
-    }
-
-  iptc_data = gexiv2_metadata_get_iptc_tags (metadata);
-
-  if (iptc_data)
-    {
-      for (i = 0; iptc_data[i] != NULL; i++)
-        {
-          value = gexiv2_metadata_get_tag_string (metadata, iptc_data[i]);
-          escaped = gimp_metadata_escape (iptc_data[i], value, &base64);
-          g_free (value);
-
-          gimp_metadata_append_tag (string, iptc_data[i], escaped, base64);
-        }
-
-      g_strfreev (iptc_data);
-    }
-
-  g_string_append (string, "</metadata>\n");
-
-  return g_string_free (string, FALSE);
-}
-
 /**
  * gimp_metadata_load_from_file:
  * @file:  The #GFile to load the metadata from
@@ -719,190 +404,6 @@ gimp_metadata_set_from_xmp (GimpMetadata  *metadata,
 }
 
 /**
- * gimp_metadata_set_pixel_size:
- * @metadata: A #GimpMetadata instance.
- * @width:    Width in pixels
- * @height:   Height in pixels
- *
- * Sets Exif.Image.ImageWidth and Exif.Image.ImageLength on @metadata.
- *
- * Since: GIMP 2.10
- */
-void
-gimp_metadata_set_pixel_size (GimpMetadata *metadata,
-                              gint          width,
-                              gint          height)
-{
-  gchar buffer[32];
-
-  g_return_if_fail (GEXIV2_IS_METADATA (metadata));
-
-  g_snprintf (buffer, sizeof (buffer), "%d", width);
-  gexiv2_metadata_set_tag_string (metadata, "Exif.Image.ImageWidth", buffer);
-
-  g_snprintf (buffer, sizeof (buffer), "%d", height);
-  gexiv2_metadata_set_tag_string (metadata, "Exif.Image.ImageLength", buffer);
-}
-
-/**
- * gimp_metadata_set_bits_per_sample:
- * @metadata: A #GimpMetadata instance.
- * @bps:      Bytes per pixel, per component
- *
- * Sets Exif.Image.BitsPerSample on @metadata.
- *
- * Since: GIMP 2.10
- */
-void
-gimp_metadata_set_bits_per_sample (GimpMetadata *metadata,
-                                   gint          bps)
-{
-  gchar buffer[32];
-
-  g_return_if_fail (GEXIV2_IS_METADATA (metadata));
-
-  g_snprintf (buffer, sizeof (buffer), "%d %d %d", bps, bps, bps);
-  gexiv2_metadata_set_tag_string (metadata, "Exif.Image.BitsPerSample", buffer);
-}
-
-/**
- * gimp_metadata_get_resolution:
- * @metadata: A #GimpMetadata instance.
- * @xres:     Return location for the X Resolution, in ppi
- * @yres:     Return location for the Y Resolution, in ppi
- * @unit:     Return location for the unit unit
- *
- * Returns values based on Exif.Image.XResolution,
- * Exif.Image.YResolution and Exif.Image.ResolutionUnit of @metadata.
- *
- * Return value: %TRUE on success, %FALSE otherwise.
- *
- * Since: GIMP 2.10
- */
-gboolean
-gimp_metadata_get_resolution (GimpMetadata *metadata,
-                              gdouble      *xres,
-                              gdouble      *yres,
-                              GimpUnit     *unit)
-{
-  gint xnom, xdenom;
-  gint ynom, ydenom;
-
-  g_return_val_if_fail (GEXIV2_IS_METADATA (metadata), FALSE);
-
-  if (gexiv2_metadata_get_exif_tag_rational (metadata,
-                                             "Exif.Image.XResolution",
-                                             &xnom, &xdenom) &&
-      gexiv2_metadata_get_exif_tag_rational (metadata,
-                                             "Exif.Image.YResolution",
-                                             &ynom, &ydenom))
-    {
-      gchar *un;
-      gint   exif_unit = 2;
-
-      un = gexiv2_metadata_get_tag_string (metadata,
-                                           "Exif.Image.ResolutionUnit");
-      if (un)
-        {
-          exif_unit = atoi (un);
-          g_free (un);
-        }
-
-      if (xnom != 0 && xdenom != 0 &&
-          ynom != 0 && ydenom != 0)
-        {
-          gdouble xresolution = (gdouble) xnom / (gdouble) xdenom;
-          gdouble yresolution = (gdouble) ynom / (gdouble) ydenom;
-
-          if (exif_unit == 3)
-            {
-              xresolution *= 2.54;
-              yresolution *= 2.54;
-            }
-
-         if (xresolution >= GIMP_MIN_RESOLUTION &&
-             xresolution <= GIMP_MAX_RESOLUTION &&
-             yresolution >= GIMP_MIN_RESOLUTION &&
-             yresolution <= GIMP_MAX_RESOLUTION)
-           {
-             if (xres)
-               *xres = xresolution;
-
-             if (yres)
-               *yres = yresolution;
-
-             if (unit)
-               {
-                 if (exif_unit == 3)
-                   *unit = GIMP_UNIT_MM;
-                 else
-                   *unit = GIMP_UNIT_INCH;
-               }
-
-             return TRUE;
-           }
-        }
-    }
-
-  return FALSE;
-}
-
-/**
- * gimp_metadata_set_resolution:
- * @metadata: A #GimpMetadata instance.
- * @xres:     The image's X Resolution, in ppi
- * @yres:     The image's Y Resolution, in ppi
- * @unit:     The image's unit
- *
- * Sets Exif.Image.XResolution, Exif.Image.YResolution and
- * Exif.Image.ResolutionUnit @metadata.
- *
- * Since: GIMP 2.10
- */
-void
-gimp_metadata_set_resolution (GimpMetadata *metadata,
-                              gdouble       xres,
-                              gdouble       yres,
-                              GimpUnit      unit)
-{
-  gchar buffer[32];
-  gint  exif_unit;
-  gint  factor;
-
-  g_return_if_fail (GEXIV2_IS_METADATA (metadata));
-
-  if (gimp_unit_is_metric (unit))
-    {
-      xres /= 2.54;
-      yres /= 2.54;
-
-      exif_unit = 3;
-    }
-  else
-    {
-      exif_unit = 2;
-    }
-
-  for (factor = 1; factor <= 100 /* arbitrary */; factor++)
-    {
-      if (fabs (xres * factor - ROUND (xres * factor)) < 0.01 &&
-          fabs (yres * factor - ROUND (yres * factor)) < 0.01)
-        break;
-    }
-
-  gexiv2_metadata_set_exif_tag_rational (metadata,
-                                         "Exif.Image.XResolution",
-                                         ROUND (xres * factor), factor);
-
-  gexiv2_metadata_set_exif_tag_rational (metadata,
-                                         "Exif.Image.YResolution",
-                                         ROUND (yres * factor), factor);
-
-  g_snprintf (buffer, sizeof (buffer), "%d", exif_unit);
-  gexiv2_metadata_set_tag_string (metadata, "Exif.Image.ResolutionUnit", buffer);
-}
-
-/**
  * gimp_metadata_is_tag_supported:
  * @tag:       A metadata tag name
  * @mime_type: A mime type
diff --git a/libgimpbase/gimpmetadata.h b/libgimpbase/gimpmetadata.h
index 03bca87..95ae641 100644
--- a/libgimpbase/gimpmetadata.h
+++ b/libgimpbase/gimpmetadata.h
@@ -45,11 +45,6 @@ typedef enum
 
 
 GimpMetadata * gimp_metadata_new                 (void);
-GimpMetadata * gimp_metadata_duplicate           (GimpMetadata  *metadata);
-
-GimpMetadata * gimp_metadata_deserialize         (const gchar   *metadata_xml);
-gchar        * gimp_metadata_serialize           (GimpMetadata  *metadata);
-
 GimpMetadata * gimp_metadata_load_from_file      (GFile         *file,
                                                   GError       **error);
 gboolean       gimp_metadata_save_to_file        (GimpMetadata  *metadata,
@@ -64,22 +59,6 @@ gboolean       gimp_metadata_set_from_xmp        (GimpMetadata  *metadata,
                                                   const guchar  *xmp_data,
                                                   gint           xmp_data_length,
                                                   GError       **error);
-
-void           gimp_metadata_set_pixel_size      (GimpMetadata  *metadata,
-                                                  gint           width,
-                                                  gint           height);
-void           gimp_metadata_set_bits_per_sample (GimpMetadata  *metadata,
-                                                  gint           bits_per_sample);
-
-gboolean       gimp_metadata_get_resolution      (GimpMetadata  *metadata,
-                                                  gdouble       *xres,
-                                                  gdouble       *yres,
-                                                  GimpUnit      *unit);
-void           gimp_metadata_set_resolution      (GimpMetadata  *metadata,
-                                                  gdouble        xres,
-                                                  gdouble        yres,
-                                                  GimpUnit       unit);
-
 gboolean       gimp_metadata_is_tag_supported    (const gchar   *tag,
                                                   const gchar   *mime_type);
 
diff --git a/libgimpbase/gimprational.c b/libgimpbase/gimprational.c
new file mode 100644
index 0000000..93d6754
--- /dev/null
+++ b/libgimpbase/gimprational.c
@@ -0,0 +1,301 @@
+/*
+ * gimprational.c
+ *
+ *  Created on: 19.09.2014
+ *      Author: kuhse
+ */
+
+#include <stdlib.h>
+
+#include "gimprational.h"
+
+
+static gpointer                rational_copy                         (gpointer             data);
+static gpointer                srational_copy                        (gpointer             data);
+
+
+G_DEFINE_BOXED_TYPE (Rational, rational,
+                     rational_copy,
+                     rational_free)
+G_DEFINE_BOXED_TYPE (SRational, srational,
+                     srational_copy,
+                     srational_free)
+
+
+/**
+ * string_to_rational:
+ *
+ * @string:     a #gchar array
+ * @rational:  a pointer to a #Rational struct
+ *
+ * converts a string, representing one/more rational values into
+ * a #Rational struct.
+ *
+ * Since: 2.10
+ */
+void
+string_to_rational (gchar *string, Rational **rational)
+{
+  gchar **nom;
+  gchar **rats;
+  gint count;
+  gint i;
+  Rational *rval;
+  GArray *rational_array;
+
+  rats = g_strsplit (string, " ", -1);
+
+  count = 0;
+  while (rats[count])
+    count++;
+
+  rational_array = g_array_new (TRUE, TRUE, sizeof (RationalValue));
+
+  for (i = 0; i < count; i++)
+    {
+      RationalValue or;
+
+      nom = g_strsplit (rats[i], "/", 2);
+
+      if (nom[0] && nom[1])
+        {
+          or.nom = (guint) atoi (nom [0]);
+          or.denom = (guint) atoi (nom [1]);
+        }
+      else
+        count--;
+
+      rational_array = g_array_append_val (rational_array, or);
+
+      g_strfreev (nom);
+    }
+
+  g_strfreev (rats);
+
+  rval = g_slice_new (Rational);
+
+  rval->rational_array = rational_array;
+  rval->length = count;
+
+  *rational = rval;
+}
+
+/**
+ * rational_to_string:
+ *
+ * @rational : a pointer to a @Rational struct
+ * @nom      : a pointer to a #gint array
+ * @denom    : a pointer to a #gint array
+ * @length   : a pointer to a #gint
+ *
+ * converts a @rational to nom/denum gchar arrays
+ *
+ * Since: 2.10
+ */
+void
+rational_to_int (Rational *rational, gint **nom, gint **denom, gint *length)
+{
+  gint i;
+  gint *_nom;
+  gint *_denom;
+
+  g_return_if_fail (rational != NULL);
+
+  _nom = g_new (gint, rational->length);
+  _denom = g_new (gint, rational->length);
+
+  for (i = 0; i < rational->length; i++)
+    {
+      RationalValue one;
+      one = g_array_index(rational->rational_array, RationalValue, i);
+      _nom[i] = one.nom;
+      _denom[i] = one.denom;
+    }
+
+  *nom = _nom;
+  *denom = _denom;
+  *length = rational->length;
+}
+
+/**
+ * rational_copy:
+ *
+ * @data:          a #gpointer to a #Rational structure
+ *
+ * copy part of the #Rational type
+ *
+ * Since: 2.10
+ */
+static gpointer
+rational_copy (gpointer data)
+{
+  struct _Rational *rational = (struct _Rational *) data;
+  struct _Rational *copy = g_slice_new (Rational);
+  gint i;
+  GArray *rlacp;
+
+  if (!data)
+    return NULL;
+
+  rlacp = g_array_new (TRUE, TRUE, sizeof (RationalValue));
+
+  for (i = 0; i < rational->length; i++)
+    {
+      RationalValue or;
+      RationalValue cor;
+
+      or = g_array_index (rational->rational_array, RationalValue, i);
+
+      cor.nom = or.nom;
+      cor.denom = or.denom;
+
+      rlacp = g_array_append_val (rlacp, cor);
+    }
+
+  copy->rational_array = rlacp;
+  copy->length = rational->length;
+
+  return (gpointer) copy;
+}
+
+/**
+ * rational_free:
+ *
+ * @data:          a #gpointer to a #Rational structure
+ *
+ * free part of the #Rational type
+ *
+ * Since: 2.10
+ */
+void
+rational_free (gpointer data)
+{
+  struct _Rational *rational = (struct _Rational *) data;
+
+  if (rational)
+    {
+      if (rational->rational_array)
+        g_array_free (rational->rational_array, TRUE);
+      rational->length = 0;
+    }
+}
+
+/**
+ * string_to_srational:
+ *
+ * @string:     a #gchar array
+ * @srational: a pointer to a #Rational struct
+ *
+ * converts a string, representing one/more srational values into
+ * a #SRational struct.
+ *
+ * Since: 2.10
+ */
+void
+string_to_srational (gchar *string, SRational **srational)
+{
+  gchar **nom;
+  gchar **srats;
+  gint count;
+  gint i;
+  SRational *srval;
+  GArray *srational_array;
+
+  srats = g_strsplit (string, " ", -1);
+
+  count = 0;
+  while (srats[count])
+    count++;
+
+  srational_array = g_array_new (TRUE, TRUE, sizeof (SRationalValue));
+
+  for (i = 0; i < count; i++)
+    {
+      SRationalValue or;
+
+      nom = g_strsplit (srats[i], "/", 2);
+
+      if (nom[0] && nom[1])
+        {
+          or.nom = (gint) atoi (nom [0]);
+          or.denom = (guint) atoi (nom [1]);
+        }
+      else
+        count--;
+
+      srational_array = g_array_append_val (srational_array, or);
+
+      g_strfreev (nom);
+    }
+
+  g_strfreev (srats);
+
+  srval = g_slice_new (SRational);
+
+  srval->srational_array = srational_array;
+  srval->length = count;
+
+  *srational = srval;
+}
+/**
+ * srational_copy:
+ *
+ * @data:          a #gpointer to a #SRational structure
+ *
+ * copy part of the #SRational type
+ *
+ * Since: 2.10
+ */
+static gpointer
+srational_copy (gpointer data)
+{
+  struct _SRational *srational = (struct _SRational *) data;
+  struct _SRational *copy = g_slice_new (SRational);
+  gint i;
+  GArray *rlacp;
+
+  if (!data)
+    return NULL;
+
+  rlacp = g_array_new (TRUE, TRUE, sizeof (SRationalValue));
+
+  for (i = 0; i < srational->length; i++)
+    {
+      SRationalValue or;
+      SRationalValue cor;
+
+      or = g_array_index (srational->srational_array, SRationalValue, i);
+
+      cor.nom = or.nom;
+      cor.denom = or.denom;
+
+      rlacp = g_array_append_val (rlacp, cor);
+    }
+
+  copy->srational_array = rlacp;
+  copy->length = srational->length;
+
+  return (gpointer) copy;
+}
+
+/**
+ * srational_free:
+ *
+ * @data:          a #gpointer to a #SRational structure
+ *
+ * free part of the #SRational type
+ *
+ * Since: 2.10
+ */
+void
+srational_free (gpointer data)
+{
+  struct _SRational *srational = (struct _SRational *) data;
+
+  if (srational)
+    {
+      if (srational->srational_array)
+        g_array_free (srational->srational_array, TRUE);
+      srational->length = 0;
+    }
+}
diff --git a/libgimpbase/gimprational.h b/libgimpbase/gimprational.h
new file mode 100644
index 0000000..ab020c8
--- /dev/null
+++ b/libgimpbase/gimprational.h
@@ -0,0 +1,68 @@
+/*
+ * gimprational.h
+ *
+ *  Created on: 19.09.2014
+ *      Author: kuhse
+ */
+
+#ifndef __GIMPRATIONAL_H__
+#define __GIMPRATIONAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define GIMP_TYPE_RATIONAL             (rational_get_type  ())
+#define GIMP_TYPE_SRATIONAL            (srational_get_type ())
+
+typedef struct _RationalValue RationalValue;
+
+struct _RationalValue
+{
+  guint nom;
+  guint denom;
+};
+
+typedef struct _SRationalValue SRationalValue;
+
+struct _SRationalValue
+{
+  gint  nom;
+  guint denom;
+};
+
+typedef struct _Rational Rational;
+
+struct _Rational
+{
+  GArray *rational_array;
+  gint length;
+};
+
+typedef struct _SRational SRational;
+
+struct _SRational
+{
+  GArray *srational_array;
+  gint length;
+};
+
+GType                          rational_get_type                     (void) G_GNUC_CONST;
+GType                          srational_get_type                    (void) G_GNUC_CONST;
+
+void                           rational_free                         (gpointer             data);
+void                           srational_free                        (gpointer             data);
+
+void                           string_to_rational                    (gchar               *string,
+                                                                      Rational           **rational);
+void                           rational_to_int                       (Rational            *rational,
+                                                                      gint               **nom,
+                                                                      gint               **denom,
+                                                                      gint                *length);
+void                           string_to_srational                   (gchar               *string,
+                                                                      SRational          **srational);
+
+
+G_END_DECLS
+
+#endif /* __GIMPRATIONAL_H__ */
diff --git a/plug-ins/Makefile.am b/plug-ins/Makefile.am
index bcc3e26..d0a101a 100644
--- a/plug-ins/Makefile.am
+++ b/plug-ins/Makefile.am
@@ -53,6 +53,7 @@ SUBDIRS = \
        lighting                \
        map-object              \
        maze                    \
+       metainfo                \
        pagecurl                \
        $(print)                \
        selection-to-path       \
diff --git a/plug-ins/common/Makefile.am b/plug-ins/common/Makefile.am
index 6ff1821..606b2b5 100644
--- a/plug-ins/common/Makefile.am
+++ b/plug-ins/common/Makefile.am
@@ -47,6 +47,7 @@ libexec_PROGRAMS = \
        align-layers \
        animation-optimize \
        animation-play \
+       attributes \
        blinds \
        blur \
        blur-gauss-selective \
@@ -122,13 +123,13 @@ libexec_PROGRAMS = \
        guillotine \
        hot \
        illusion \
+       iptc \
        iwarp \
        jigsaw \
        lcms \
        lens-flare \
        $(MAIL) \
        max-rgb \
-       metadata \
        newsprint \
        nl-filter \
        noise-solid \
@@ -239,6 +240,24 @@ animation_play_LDADD = \
        $(INTLLIBS)             \
        $(animation_play_RC)
 
+attributes_SOURCES = \
+       attributes.c
+
+attributes_LDADD = \
+       $(libgimpui)            \
+       $(libgimpwidgets)       \
+       $(libgimpmodule)        \
+       $(libgimp)              \
+       $(libgimpmath)          \
+       $(libgimpconfig)        \
+       $(libgimpcolor)         \
+       $(libgimpbase)          \
+       $(GTK_LIBS)             \
+       $(GEGL_LIBS)            \
+       $(RT_LIBS)              \
+       $(INTLLIBS)             \
+       $(attributes_RC)
+
 blinds_SOURCES = \
        blinds.c
 
@@ -1566,6 +1585,26 @@ illusion_LDADD = \
        $(INTLLIBS)             \
        $(illusion_RC)
 
+iptc_CFLAGS = $(GEXIV2_CFLAGS)
+
+iptc_SOURCES = \
+       iptc.c
+
+iptc_LDADD = \
+       $(libgimpui)            \
+       $(libgimpwidgets)       \
+       $(libgimpmodule)        \
+       $(libgimp)              \
+       $(libgimpmath)          \
+       $(libgimpconfig)        \
+       $(libgimpcolor)         \
+       $(libgimpbase)          \
+       $(GTK_LIBS)             \
+       $(GEXIV2_LIBS)          \
+       $(RT_LIBS)              \
+       $(INTLLIBS)             \
+       $(iptc_RC)
+
 iwarp_SOURCES = \
        iwarp.c
 
@@ -1672,26 +1711,6 @@ max_rgb_LDADD = \
        $(INTLLIBS)             \
        $(max_rgb_RC)
 
-metadata_CFLAGS = $(GEXIV2_CFLAGS)
-
-metadata_SOURCES = \
-       metadata.c
-
-metadata_LDADD = \
-       $(libgimpui)            \
-       $(libgimpwidgets)       \
-       $(libgimpmodule)        \
-       $(libgimp)              \
-       $(libgimpmath)          \
-       $(libgimpconfig)        \
-       $(libgimpcolor)         \
-       $(libgimpbase)          \
-       $(GTK_LIBS)             \
-       $(GEXIV2_LIBS)          \
-       $(RT_LIBS)              \
-       $(INTLLIBS)             \
-       $(metadata_RC)
-
 newsprint_SOURCES = \
        newsprint.c
 
diff --git a/plug-ins/common/attributes.c b/plug-ins/common/attributes.c
new file mode 100644
index 0000000..09b9126
--- /dev/null
+++ b/plug-ins/common/attributes.c
@@ -0,0 +1,876 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * attributes.c
+ * Copyright (C) 2014 Hartmut Kuhse <hatti gimp org>
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ * additions: share/gimp/2.0/ui/plug-ins/plug-in-attributes.ui
+ * This plug-in reads in a (libgimpbase/gimpattributes.c) object and
+ * presents it:
+ * as GtkTreeView lists
+ * in a GtkNotebook.
+ * The GtkNotebook pages represents the type of attributes, as "exif",
+ * "xmp", "iptc" or more.
+ * The expanders of the GtkTreeView represents the IFD (Exif) or Key (XMP, IPTC).
+ * of the attribute.
+ * The list entry of the GtkTreeView represents the tag of the attribute.
+ */
+
+#include "config.h"
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib/gstdio.h>
+
+#ifdef G_OS_WIN32
+#include <io.h>
+#endif
+
+#include <gtk/gtk.h>
+#include <gexiv2/gexiv2.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+
+#define PLUG_IN_IMAGE_PROC     "plug-in-image-attributes-viewer"
+#define PLUG_IN_LAYER_PROC     "plug-in-layer-attributes-viewer"
+#define PLUG_IN_CHANNEL_PROC   "plug-in-channel-attributes-viewer"
+#define PLUG_IN_HELP           "plug-in-attributes-viewer"
+#define PLUG_IN_BINARY         "attributes"
+
+#define THUMB_SIZE       48
+#define RESPONSE_EXPORT   1
+
+typedef enum
+{
+  ATT_IMAGE,
+  ATT_LAYER,
+  ATT_CHANNEL
+} AttributesSource;
+
+enum
+{
+  C_IFD = 0,
+  C_TAG,
+  C_VALUE,
+  NUM_COL
+};
+
+/*  local function prototypes  */
+
+static void            query                              (void);
+static void            run                                (const gchar      *name,
+                                                           gint              nparams,
+                                                           const GimpParam  *param,
+                                                           gint             *nreturn_vals,
+                                                           GimpParam       **return_vals);
+static void            attributes_dialog_response         (GtkWidget        *widget,
+                                                           gint              response_id,
+                                                           gpointer          data);
+static gboolean        attributes_dialog                  (gint32            image_id,
+                                                           AttributesSource  source,
+                                                           GimpAttributes   *attributes);
+static void            attributes_dialog_set_attributes   (GimpAttributes   *attributes,
+                                                           GtkBuilder       *builder);
+static GtkTreeIter    *attributes_get_parent              (const gchar      *type,
+                                                           const gchar      *name);
+static void            attributes_add_parent              (const gchar      *type,
+                                                           const gchar      *name,
+                                                           GtkTreeIter      *iter);
+static GtkTreeStore   *attributes_notebook_page_get       (GtkWidget        *notebook,
+                                                           const gchar      *name);
+static GtkWidget      *attributes_treeview_new            (void);
+static void            attributes_file_export_dialog      (GtkWidget        *parent,
+                                                           GimpAttributes   *attributes);
+static void            attributes_export_dialog_response  (GtkWidget        *dlg,
+                                                           gint              response_id,
+                                                           gpointer          data);
+
+static void            attributes_message_dialog          (GtkMessageType    type,
+                                                           GtkWindow        *parent,
+                                                           const gchar      *title,
+                                                           const gchar      *message);
+
+/* local variables */
+
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+  NULL,  /* init_proc  */
+  NULL,  /* quit_proc  */
+  query, /* query_proc */
+  run,   /* run_proc   */
+};
+
+static GHashTable *ifd_table = NULL;
+static GHashTable *tab_table = NULL;
+
+/*  functions  */
+
+MAIN ()
+
+static void
+query (void)
+{
+  static const GimpParamDef image_attribs_args[] =
+  {
+    { GIMP_PDB_INT32, "run-mode", "Run mode { RUN-INTERACTIVE (0) }" },
+    { GIMP_PDB_IMAGE, "image",    "Input image"                      }
+  };
+
+  static const GimpParamDef layer_attribs_args[] =
+  {
+    { GIMP_PDB_INT32, "run-mode", "Run mode { RUN-INTERACTIVE (0) }" },
+    { GIMP_PDB_IMAGE, "image",    "Input image"                      },
+    { GIMP_PDB_LAYER, "layer",    "Input layer"                      }
+  };
+
+  static const GimpParamDef channel_attribs_args[] =
+  {
+    { GIMP_PDB_INT32,   "run-mode",   "Run mode { RUN-INTERACTIVE (0) }" },
+    { GIMP_PDB_IMAGE,   "image",      "Input image"                      },
+    { GIMP_PDB_CHANNEL, "channel",    "Input channel"                    }
+  };
+
+  gimp_install_procedure (PLUG_IN_IMAGE_PROC,
+                          N_("View attributes (Exif, IPTC, XMP, ...)"),
+                          "View attributes information attached to the "
+                          "current image.  This can include Exif, IPTC, "
+                          "XMP and/or other information. Some or all of these "
+                          "attributes will be saved in the file, depending on "
+                          "the output file format.",
+                          "Hartmut Kuhse",
+                          "Hartmut Kuhse",
+                          "2014",
+                          N_("Image Attributes"),
+                          "*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (image_attribs_args), 0,
+                          image_attribs_args, NULL);
+
+  gimp_plugin_menu_register (PLUG_IN_IMAGE_PROC, "<Image>/Image");
+
+  gimp_install_procedure (PLUG_IN_LAYER_PROC,
+                          N_("View attributes (Exif, IPTC, XMP, ...)"),
+                          "View attributes information attached to the "
+                          "current layer.  This can include Exif, IPTC, "
+                          "XMP and/or other information.",
+                          "Hartmut Kuhse",
+                          "Hartmut Kuhse",
+                          "2014",
+                          N_("Layer Attributes"),
+                          "*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (layer_attribs_args), 0,
+                          layer_attribs_args, NULL);
+
+  gimp_plugin_menu_register (PLUG_IN_LAYER_PROC, "<Layers>");
+
+  gimp_install_procedure (PLUG_IN_CHANNEL_PROC,
+                          N_("View attributes (Exif, IPTC, XMP, ...)"),
+                          "View attributes information attached to the "
+                          "current channel.  This can include Exif, IPTC, "
+                          "XMP and/or other information.",
+                          "Hartmut Kuhse",
+                          "Hartmut Kuhse",
+                          "2014",
+                          N_("Channel Attributes"),
+                          "*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (channel_attribs_args), 0,
+                          channel_attribs_args, NULL);
+
+  gimp_plugin_menu_register (PLUG_IN_CHANNEL_PROC, "<Channels>");
+}
+
+static void
+run (const gchar      *name,
+     gint              nparams,
+     const GimpParam  *param,
+     gint             *nreturn_vals,
+     GimpParam       **return_vals)
+{
+  GimpAttributes   *attributes;
+  AttributesSource   source;
+  gint32             item_ID;
+  static GimpParam   values[1];
+  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
+
+  *nreturn_vals = 1;
+  *return_vals  = values;
+
+  values[0].type          = GIMP_PDB_STATUS;
+  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
+
+  INIT_I18N();
+  gimp_ui_init (PLUG_IN_BINARY, TRUE);
+
+  if (! strcmp (name, PLUG_IN_IMAGE_PROC))
+    {
+      item_ID = param[1].data.d_image;
+
+      attributes = gimp_image_get_attributes (item_ID);
+      source = ATT_IMAGE;
+
+      status = GIMP_PDB_SUCCESS;
+    }
+  else if (! strcmp (name, PLUG_IN_LAYER_PROC))
+    {
+      item_ID = param[2].data.d_layer;
+
+      attributes = gimp_item_get_attributes (item_ID);
+      source = ATT_LAYER;
+
+      status = GIMP_PDB_SUCCESS;
+    }
+  else if (! strcmp (name, PLUG_IN_CHANNEL_PROC))
+    {
+      item_ID = param[2].data.d_channel;
+
+      attributes = gimp_item_get_attributes (item_ID);
+      source = ATT_CHANNEL;
+
+      status = GIMP_PDB_SUCCESS;
+    }
+  else
+    {
+      status = GIMP_PDB_CALLING_ERROR;
+    }
+
+  if (attributes)
+    {
+      ifd_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+      tab_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
+      attributes_dialog (item_ID, source, attributes);
+    }
+  else
+    {
+      g_message (_("This image has no attributes attached to it."));
+    }
+
+  if (attributes)
+    g_object_unref (attributes);
+
+  if (ifd_table)
+    g_hash_table_unref (ifd_table);
+
+  values[0].data.d_status = status;
+}
+
+static void
+attributes_dialog_response (GtkWidget *widget,
+                            gint       response_id,
+                            gpointer   data)
+{
+
+  GimpAttributes *attributes = (GimpAttributes *) data;
+  switch (response_id)
+    {
+    case RESPONSE_EXPORT:
+      attributes_file_export_dialog (widget, attributes);
+      break;
+
+    default:
+      gtk_widget_destroy (widget);
+      break;
+    }
+}
+
+static gboolean
+attributes_dialog (gint32           item_id,
+                   AttributesSource source,
+                   GimpAttributes  *attributes)
+{
+  GtkBuilder *builder;
+  GtkWidget  *dialog;
+  GtkWidget  *attributes_vbox;
+  GtkWidget  *content_area;
+  GdkPixbuf  *pixbuf;
+  GtkWidget  *label_header;
+  GtkWidget  *label_info;
+  GtkWidget  *thumb_box;
+
+  gchar      *header;
+  gchar      *ui_file;
+  gchar      *title;
+  gchar      *fname;
+  gchar      *role;
+  GError     *error = NULL;
+
+  gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+  switch (source)
+  {
+    case ATT_IMAGE:
+      fname = g_filename_display_basename (gimp_image_get_uri (item_id));
+      header  = g_strdup_printf ("Image");
+      role  = g_strdup_printf ("gimp-image-attributes-dialog");
+      pixbuf = gimp_image_get_thumbnail (item_id, THUMB_SIZE, THUMB_SIZE,
+                                         GIMP_PIXBUF_SMALL_CHECKS);
+
+      break;
+    case ATT_LAYER:
+      fname = gimp_item_get_name (item_id);
+      header  = g_strdup_printf ("Layer");
+      role  = g_strdup_printf ("gimp-layer-attributes-dialog");
+      pixbuf = gimp_drawable_get_thumbnail (item_id, THUMB_SIZE, THUMB_SIZE,
+                                            GIMP_PIXBUF_SMALL_CHECKS);
+      break;
+    case ATT_CHANNEL:
+      fname = gimp_item_get_name (item_id);
+      header  = g_strdup_printf ("Channel");
+      role  = g_strdup_printf ("gimp-channel-attributes-dialog");
+      pixbuf = gimp_drawable_get_thumbnail (item_id, THUMB_SIZE, THUMB_SIZE,
+                                            GIMP_PIXBUF_SMALL_CHECKS);
+      break;
+    default:
+      fname = g_strdup_printf ("unknown");
+      header  = g_strdup_printf ("Unknown");
+      role  = g_strdup_printf ("gimp-attributes-dialog");
+      pixbuf = NULL;
+      break;
+  }
+
+  title = g_strdup_printf ("Attributes: %s", fname);
+
+  builder = gtk_builder_new ();
+
+  ui_file = g_build_filename (gimp_data_directory (),
+                              "ui", "plug-ins", "plug-in-attributes.ui", NULL);
+
+  if (! gtk_builder_add_from_file (builder, ui_file, &error))
+    {
+      g_printerr ("Error occured while loading UI file!\n");
+      g_printerr ("Message: %s\n", error->message);
+      g_clear_error (&error);
+      g_free (ui_file);
+      g_object_unref (builder);
+      return FALSE;
+    }
+
+  g_free (ui_file);
+
+  dialog = gimp_dialog_new (title,
+                            role,
+                            NULL, 0,
+                            gimp_standard_help_func, PLUG_IN_HELP,
+                            _("_Export XMP..."), RESPONSE_EXPORT,
+                            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+                            NULL);
+
+  g_signal_connect (dialog, "response",
+                    G_CALLBACK (attributes_dialog_response),
+                    attributes);
+
+  g_signal_connect (dialog, "destroy",
+                    G_CALLBACK (gtk_main_quit),
+                    NULL);
+
+  g_free (title);
+  g_free (role);
+
+  gtk_window_set_default_size (GTK_WINDOW (dialog),
+                               650,
+                               550);
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                           RESPONSE_EXPORT,
+                                           GTK_RESPONSE_CLOSE,
+                                           -1);
+
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+  attributes_vbox = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                      "attributes-vbox"));
+  gtk_container_set_border_width (GTK_CONTAINER (attributes_vbox), 2);
+  gtk_box_pack_start (GTK_BOX (content_area), attributes_vbox, TRUE, TRUE, 0);
+
+  label_header = GTK_WIDGET (gtk_builder_get_object (builder, "label-header"));
+  gimp_label_set_attributes (GTK_LABEL (label_header),
+                             PANGO_ATTR_SCALE,  PANGO_SCALE_LARGE,
+                             PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
+                             -1);
+  gtk_label_set_text (GTK_LABEL (label_header), header);
+
+  label_info = GTK_WIDGET (gtk_builder_get_object (builder, "label-info"));
+  gimp_label_set_attributes (GTK_LABEL (label_info),
+                             PANGO_ATTR_SCALE,  PANGO_SCALE_SMALL,
+                             -1);
+  gtk_label_set_text (GTK_LABEL (label_info), fname);
+
+  g_free (header);
+  g_free (fname);
+
+  if (pixbuf)
+    {
+      GtkWidget *image;
+
+      thumb_box = GTK_WIDGET (gtk_builder_get_object (builder, "thumb-box"));
+
+      if (thumb_box)
+        {
+          image = gtk_image_new_from_pixbuf (pixbuf);
+          gtk_box_pack_end (GTK_BOX (thumb_box), image, FALSE, FALSE, 0);
+          gtk_widget_show (image);
+        }
+    }
+
+  attributes_dialog_set_attributes (attributes, builder);
+
+  gtk_widget_show (GTK_WIDGET (dialog));
+
+  gtk_main ();
+
+  return TRUE;
+}
+
+
+/*  private functions  */
+
+static void
+attributes_dialog_set_attributes (GimpAttributes *attributes,
+                                  GtkBuilder     *builder)
+{
+  GtkTreeStore   *exif_store;
+  GtkTreeStore   *xmp_store;
+  GtkTreeStore   *iptc_store;
+  GtkTreeView    *exif_treeview;
+  GtkTreeView    *xmp_treeview;
+  GtkTreeView    *iptc_treeview;
+  GtkWidget      *attributes_notebook;
+  GHashTableIter  hash_iter;
+  GHashTable     *table;
+  gpointer        p_key, p_value;
+
+  exif_store = GTK_TREE_STORE (gtk_builder_get_object (builder,
+                                                       "exif-treestore"));
+  xmp_store  = GTK_TREE_STORE (gtk_builder_get_object (builder,
+                                                       "xmp-treestore"));
+  iptc_store  = GTK_TREE_STORE (gtk_builder_get_object (builder,
+                                                       "iptc-treestore"));
+
+  exif_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+                                                       "exif-treeview"));
+  xmp_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+                                                       "xmp-treeview"));
+  iptc_treeview = GTK_TREE_VIEW (gtk_builder_get_object (builder,
+                                                       "iptc-treeview"));
+
+  attributes_notebook = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                       "attributes-notebook"));
+
+  table = gimp_attributes_get_table (attributes);
+
+  g_hash_table_iter_init (&hash_iter, table);
+
+  while (g_hash_table_iter_next (&hash_iter, &p_key, &p_value))
+    {
+      const gchar    *name;
+      const gchar    *type;
+      const gchar    *ifd;
+      const gchar    *tag;
+      const gchar    *value;
+      gchar          *value_utf;
+      GimpAttribute  *attribute;
+      GtkTreeIter    *parent = NULL;
+      GtkTreeIter    *iter = g_slice_new (GtkTreeIter);
+
+      attribute = (GimpAttribute *) p_value;
+
+      name      = gimp_attribute_get_name (attribute);
+      type      = gimp_attribute_get_attribute_type (attribute);
+      ifd       = gimp_attribute_get_attribute_ifd (attribute);
+      tag       = gimp_attribute_get_attribute_tag (attribute);
+      value     = gimp_attribute_get_interpreted_string (attribute);
+
+      value_utf = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
+
+      parent = attributes_get_parent (type, ifd);
+
+      switch (gimp_attribute_get_tag_type (attribute))
+      {
+        case TAG_EXIF:
+          {
+            gtk_tree_store_append (exif_store, iter, parent);
+
+            if (!parent)
+              {
+                GtkTreeIter child;
+                gtk_tree_store_set (exif_store, iter,
+                                    C_IFD, ifd,
+                                    C_TAG, "",
+                                    C_VALUE, "",
+                                    -1);
+                parent = iter;
+                gtk_tree_store_append (exif_store, &child, parent);
+                gtk_tree_store_set (exif_store, &child,
+                                    C_IFD, "",
+                                    C_TAG, tag,
+                                    C_VALUE, value_utf,
+                                    -1);
+                attributes_add_parent (type, ifd, parent);
+              }
+            else
+              {
+
+                gtk_tree_store_set (exif_store, iter,
+                                    C_IFD, "",
+                                    C_TAG, tag,
+                                    C_VALUE, value_utf,
+                                    -1);
+              }
+          }
+          break;
+        case TAG_XMP:
+          {
+            gtk_tree_store_append (xmp_store, iter, parent);
+            if (!parent)
+              {
+                GtkTreeIter child;
+                gtk_tree_store_set (xmp_store, iter,
+                                    C_IFD, ifd,
+                                    C_TAG, "",
+                                    C_VALUE, "",
+                                    -1);
+                parent = iter;
+                gtk_tree_store_append (xmp_store, &child, parent);
+                gtk_tree_store_set (xmp_store, &child,
+                                    C_IFD, "",
+                                    C_TAG, tag,
+                                    C_VALUE, value_utf,
+                                    -1);
+                attributes_add_parent (type, ifd, parent);
+              }
+            else
+              {
+
+                gtk_tree_store_set (xmp_store, iter,
+                                    C_IFD, "",
+                                    C_TAG, tag,
+                                    C_VALUE, value_utf,
+                                    -1);
+              }
+          }
+          break;
+        case TAG_IPTC:
+          {
+            gtk_tree_store_append (iptc_store, iter, parent);
+            if (!parent)
+              {
+                GtkTreeIter child;
+                gtk_tree_store_set (iptc_store, iter,
+                                    C_IFD, ifd,
+                                    C_TAG, "",
+                                    C_VALUE, "",
+                                    -1);
+                parent = iter;
+                gtk_tree_store_append (iptc_store, &child, parent);
+                gtk_tree_store_set (iptc_store, &child,
+                                    C_IFD, "",
+                                    C_TAG, tag,
+                                    C_VALUE, value_utf,
+                                    -1);
+                attributes_add_parent (type, ifd, parent);
+              }
+            else
+              {
+
+                gtk_tree_store_set (iptc_store, iter,
+                                    C_IFD, "",
+                                    C_TAG, tag,
+                                    C_VALUE, value_utf,
+                                    -1);
+              }
+          }
+          break;
+        default:
+          {
+            GtkTreeStore   *treestore;
+            GtkTreeIter     iter;
+
+            treestore = attributes_notebook_page_get (attributes_notebook, type);
+
+            gtk_tree_store_append (treestore, &iter, NULL);
+            gtk_tree_store_set (treestore, &iter,
+                                C_IFD, "",
+                                C_TAG, name,
+                                C_VALUE, value_utf,
+                                -1);
+          }
+          break;
+      }
+    }
+  gtk_tree_view_expand_all (exif_treeview);
+  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(exif_store),
+                                       C_TAG, GTK_SORT_ASCENDING);
+
+  gtk_tree_view_expand_all (xmp_treeview);
+  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(xmp_store),
+                                       C_TAG, GTK_SORT_ASCENDING);
+  gtk_tree_view_expand_all (iptc_treeview);
+  gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(iptc_store),
+                                       C_TAG, GTK_SORT_ASCENDING);
+}
+
+static GtkTreeIter *
+attributes_get_parent (const gchar *type, const gchar *name)
+{
+  gchar          *key;
+  gchar          *lowchar;
+  GtkTreeIter    *iter;
+  gpointer       *data;
+
+  key = g_strdup_printf ("%s.%s", type, name);
+  lowchar = g_ascii_strdown (key, -1);
+  g_free (key);
+
+  data = g_hash_table_lookup (ifd_table, (gpointer) lowchar);
+  g_free (lowchar);
+
+  if (data)
+    {
+      iter = (GtkTreeIter *) data;
+      return iter;
+    }
+  else
+    {
+      return NULL;
+    }
+}
+
+static void
+attributes_add_parent (const gchar *type, const gchar *name, GtkTreeIter *iter)
+{
+  gchar          *key;
+  gchar          *lowchar;
+
+  key = g_strdup_printf ("%s.%s", type, name);
+  lowchar = g_ascii_strdown (key, -1);
+  g_free (key);
+
+  g_hash_table_insert (ifd_table, (gpointer) lowchar, (gpointer) iter);
+
+}
+
+static GtkTreeStore *
+attributes_notebook_page_get (GtkWidget *notebook,
+                              const gchar *name)
+{
+  GtkWidget        *scrolledwindow;
+  GtkWidget        *treeview;
+  gchar            *lowchar;
+  gpointer         *data;
+  GtkTreeStore     *treestore;
+
+  lowchar = g_ascii_strdown (name, -1);
+
+  data = g_hash_table_lookup (tab_table, (gpointer) lowchar);
+
+  if (data)
+    {
+      treestore = (GtkTreeStore *) data;
+      g_free (lowchar);
+    }
+  else
+    {
+      treeview = attributes_treeview_new ();
+
+      scrolledwindow = gtk_scrolled_window_new (NULL, NULL);
+      gtk_widget_show (scrolledwindow);
+      gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (scrolledwindow), GTK_SHADOW_IN);
+
+      gtk_widget_show (treeview);
+      gtk_container_add (GTK_CONTAINER (scrolledwindow), treeview);
+      gtk_tree_view_set_enable_search (GTK_TREE_VIEW (treeview), FALSE);
+
+      gtk_notebook_append_page (GTK_NOTEBOOK (notebook),
+                                scrolledwindow,
+                                gtk_label_new (name));
+
+      treestore = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)));
+
+      g_hash_table_insert (tab_table, (gpointer) lowchar, (gpointer) treestore);
+    }
+  return treestore;
+}
+
+static GtkWidget *
+attributes_treeview_new (void)
+{
+  GtkWidget        *treeview;
+  GtkTreeStore     *treestore;
+  GtkCellRenderer  *ifd_renderer;
+  GtkCellRenderer  *tag_renderer;
+  GtkCellRenderer  *val_renderer;
+  GtkTreeViewColumn *ifd_column;
+  GtkTreeViewColumn *tag_column;
+  GtkTreeViewColumn *val_column;
+
+  ifd_renderer = gtk_cell_renderer_text_new ();
+  tag_renderer = gtk_cell_renderer_text_new ();
+  val_renderer = gtk_cell_renderer_text_new ();
+  treestore = gtk_tree_store_new (NUM_COL, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_STRING);
+  treeview = gtk_tree_view_new ();
+  gtk_tree_view_set_model(GTK_TREE_VIEW (treeview), GTK_TREE_MODEL(treestore));
+
+  ifd_column = gtk_tree_view_column_new_with_attributes ("", ifd_renderer, "text", C_IFD, NULL);
+  tag_column = gtk_tree_view_column_new_with_attributes ("Tag", tag_renderer, "text", C_TAG, NULL);
+  val_column = gtk_tree_view_column_new_with_attributes ("Value", val_renderer, "text", C_VALUE, NULL);
+
+  gtk_tree_view_column_set_resizable (ifd_column, TRUE);
+  gtk_tree_view_column_set_resizable (tag_column, TRUE);
+  gtk_tree_view_column_set_resizable (val_column, TRUE);
+
+  gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), ifd_column, -1);
+  gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), tag_column, -1);
+  gtk_tree_view_insert_column (GTK_TREE_VIEW (treeview), val_column, -1);
+
+  return treeview;
+}
+
+/* select file to export */
+static void
+attributes_file_export_dialog (GtkWidget      *parent,
+                               GimpAttributes *attributes)
+{
+  static GtkWidget *dlg = NULL;
+//                                          GTK_WINDOW (parent),
+
+  if (! dlg)
+    {
+      dlg = gtk_file_chooser_dialog_new (_("Export XMP to File"),
+                                         GTK_WINDOW (parent),
+                                         GTK_FILE_CHOOSER_ACTION_SAVE,
+
+                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+                                         GTK_STOCK_SAVE,   GTK_RESPONSE_OK,
+
+                                         NULL);
+
+      gtk_dialog_set_alternative_button_order (GTK_DIALOG (dlg),
+                                               GTK_RESPONSE_OK,
+                                               GTK_RESPONSE_CANCEL,
+                                               -1);
+      gtk_dialog_set_default_response (GTK_DIALOG (dlg), GTK_RESPONSE_OK);
+
+      gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dlg),
+                                                      TRUE);
+
+      g_signal_connect (dlg, "destroy",
+                        G_CALLBACK (gtk_widget_destroyed),
+                        &dlg);
+      g_signal_connect (dlg, "response",
+                        G_CALLBACK (attributes_export_dialog_response),
+                        attributes);
+    }
+  gtk_window_present (GTK_WINDOW (dlg));
+//  gtk_dialog_run (GTK_DIALOG (dlg));
+}
+
+/* save XMP metadata to a file (only XMP, nothing else) */
+static void
+attributes_export_dialog_response (GtkWidget *dlg,
+                                   gint       response_id,
+                                   gpointer   data)
+{
+  GimpAttributes *attributes = (GimpAttributes *) data;
+
+  g_return_if_fail (attributes != NULL);
+
+  if (response_id == GTK_RESPONSE_OK)
+    {
+      GString       *buffer;
+      const gchar   *xmp_data = NULL;
+      gchar         *filename = NULL;
+      int            fd;
+
+      xmp_data = gimp_attributes_to_xmp_packet (attributes, "file/xmp");
+
+      if (!xmp_data)
+        {
+          attributes_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
+                                   _("XMP creation failed"),
+                                   _("Cannot create xmp packet"));
+          return;
+        }
+
+      buffer = g_string_new (xmp_data);
+
+      filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dlg));
+      fd = g_open (filename, O_CREAT | O_TRUNC | O_WRONLY | _O_BINARY, 0666);
+      if (fd < 0)
+        {
+          attributes_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
+                                   _("Open failed"),
+                                   _("Cannot create file"));
+          g_string_free (buffer, TRUE);
+          g_free (filename);
+          return;
+        }
+
+      if (write (fd, buffer->str, buffer->len) < 0)
+        {
+          attributes_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
+                                   _("Save failed"),
+                                   _("Some error occurred while saving"));
+          g_string_free (buffer, TRUE);
+          g_free (filename);
+          return;
+        }
+
+      if (close (fd) < 0)
+        {
+          attributes_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (dlg),
+                                   _("Save failed"),
+                                   _("Could not close the file"));
+          g_string_free (buffer, TRUE);
+          g_free (filename);
+          return;
+        }
+
+      g_string_free (buffer, TRUE);
+      g_free (filename);
+    }
+
+  gtk_widget_destroy (dlg); /* FIXME: destroy or unmap? */
+}
+
+/* show a transient message dialog */
+static void
+attributes_message_dialog (GtkMessageType  type,
+                           GtkWindow      *parent,
+                           const gchar    *title,
+                           const gchar    *message)
+{
+  GtkWidget *dlg;
+
+  dlg = gtk_message_dialog_new (parent, 0, type, GTK_BUTTONS_OK, "%s", message);
+
+  if (title)
+    gtk_window_set_title (GTK_WINDOW (dlg), title);
+
+  gtk_window_set_role (GTK_WINDOW (dlg), "metadata-message");
+  gtk_dialog_run (GTK_DIALOG (dlg));
+  gtk_widget_destroy (dlg);
+}
diff --git a/plug-ins/common/file-jp2-load.c b/plug-ins/common/file-jp2-load.c
index 261142b..e68e5b9 100644
--- a/plug-ins/common/file-jp2-load.c
+++ b/plug-ins/common/file-jp2-load.c
@@ -57,6 +57,7 @@ static void     run               (const gchar      *name,
                                    gint             *nreturn_vals,
                                    GimpParam       **return_vals);
 static gint32   load_image        (const gchar      *filename,
+                                   gint32           *layer_ID,
                                    GError          **error);
 static void     load_icc_profile  (jas_image_t      *jas_image,
                                    gint              image_ID);
@@ -125,6 +126,7 @@ run (const gchar      *name,
   GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
   gint               image_ID;
   GError            *error = NULL;
+  gint32             layer_ID;
 
   run_mode = param[0].data.d_int32;
 
@@ -153,7 +155,7 @@ run (const gchar      *name,
           break;
         }
 
-      image_ID = load_image (param[1].data.d_string, &error);
+      image_ID = load_image (param[1].data.d_string, &layer_ID, &error);
 
       if (image_ID != -1)
         {
@@ -167,7 +169,7 @@ run (const gchar      *name,
             {
               GimpMetadataLoadFlags flags = GIMP_METADATA_LOAD_ALL;
 
-              gimp_image_metadata_load_finish (image_ID, "image/jp2",
+              gimp_image_metadata_load_finish (image_ID, layer_ID, "image/jp2",
                                                metadata, flags,
                                                interactive);
 
@@ -202,13 +204,13 @@ run (const gchar      *name,
 
 static gint32
 load_image (const gchar  *filename,
+            gint32       *layer_ID,
             GError      **error)
 {
   gint               fd;
   jas_stream_t      *stream;
   gint32             image_ID = -1;
   jas_image_t       *image;
-  gint32             layer_ID;
   GimpImageType      image_type;
   GimpImageBaseType  base_type;
   gint               width;
diff --git a/plug-ins/common/file-png.c b/plug-ins/common/file-png.c
index 44d7aac..c9ec00f 100644
--- a/plug-ins/common/file-png.c
+++ b/plug-ins/common/file-png.c
@@ -140,6 +140,7 @@ static void      run                       (const gchar      *name,
                                             GimpParam       **return_vals);
 
 static gint32    load_image                (const gchar      *filename,
+                                            gint32           *layer_ID,
                                             gboolean          interactive,
                                             gboolean         *resolution_loaded,
                                             GError          **error);
@@ -147,6 +148,7 @@ static gboolean  save_image                (const gchar      *filename,
                                             gint32            image_ID,
                                             gint32            drawable_ID,
                                             gint32            orig_image_ID,
+                                            gint             *bits_depth,
                                             GError          **error);
 
 static int       respin_cmap               (png_structp       pp,
@@ -416,6 +418,7 @@ run (const gchar      *name,
   GimpRunMode       run_mode;
   GimpPDBStatusType status = GIMP_PDB_SUCCESS;
   gint32            image_ID;
+  gint32            layer_ID;
   gint32            drawable_ID;
   GError           *error  = NULL;
 
@@ -448,6 +451,7 @@ run (const gchar      *name,
         }
 
       image_ID = load_image (param[1].data.d_string,
+                             &layer_ID,
                              interactive,
                              &resolution_loaded,
                              &error);
@@ -467,7 +471,7 @@ run (const gchar      *name,
               if (resolution_loaded)
                 flags &= ~GIMP_METADATA_LOAD_RESOLUTION;
 
-              gimp_image_metadata_load_finish (image_ID, "image/png",
+              gimp_image_metadata_load_finish (image_ID, layer_ID, "image/png",
                                                metadata, flags,
                                                interactive);
 
@@ -489,9 +493,10 @@ run (const gchar      *name,
            strcmp (name, SAVE2_PROC) == 0 ||
            strcmp (name, SAVE_DEFAULTS_PROC) == 0)
     {
-      GimpMetadata          *metadata;
+      GimpAttributes        *attributes;
       GimpMetadataSaveFlags  metadata_flags;
       gint32                 orig_image_ID;
+      gint                   bits_depth;
       GimpExportReturn       export = GIMP_EXPORT_CANCEL;
       gboolean               alpha;
 
@@ -524,9 +529,9 @@ run (const gchar      *name,
           break;
         }
 
-      metadata = gimp_image_metadata_save_prepare (orig_image_ID,
-                                                   "image/png",
-                                                   &metadata_flags);
+      attributes = gimp_image_metadata_save_prepare (orig_image_ID,
+                                                     "image/png",
+                                                     &metadata_flags);
 
       pngvals.save_exif      = (metadata_flags & GIMP_METADATA_SAVE_EXIF) != 0;
       pngvals.save_xmp       = (metadata_flags & GIMP_METADATA_SAVE_XMP) != 0;
@@ -608,13 +613,19 @@ run (const gchar      *name,
       if (status == GIMP_PDB_SUCCESS)
         {
           if (save_image (param[3].data.d_string,
-                          image_ID, drawable_ID, orig_image_ID, &error))
+                          image_ID, drawable_ID, orig_image_ID, &bits_depth, &error))
             {
-              if (metadata)
+              if (attributes)
                 {
                   GFile *file;
+                  gchar *val = g_strdup_printf ("%u", (gushort) bits_depth);
+
+                  gimp_attributes_add_attribute (attributes,
+                                                 gimp_attribute_new_string ("Exif.Image.BitsPerSample",
+                                                                             val, TYPE_SHORT)
+                                                );
 
-                  gimp_metadata_set_bits_per_sample (metadata, 8);
+                  g_free (val);
 
                   if (pngvals.save_exif)
                     metadata_flags |= GIMP_METADATA_SAVE_EXIF;
@@ -639,8 +650,9 @@ run (const gchar      *name,
                   file = g_file_new_for_path (param[3].data.d_string);
                   gimp_image_metadata_save_finish (orig_image_ID,
                                                    "image/png",
-                                                   metadata, metadata_flags,
+                                                   attributes, metadata_flags,
                                                    file, NULL);
+                  g_object_unref (attributes);
                   g_object_unref (file);
                 }
 
@@ -655,8 +667,6 @@ run (const gchar      *name,
       if (export == GIMP_EXPORT_EXPORT)
         gimp_image_delete (image_ID);
 
-      if (metadata)
-        g_object_unref (metadata);
     }
   else if (strcmp (name, GET_DEFAULTS_PROC) == 0)
     {
@@ -788,6 +798,7 @@ get_bit_depth_for_palette (int num_palette)
  */
 static gint32
 load_image (const gchar  *filename,
+            gint32       *layer_ID,
             gboolean      interactive,
             gboolean     *resolution_loaded,
             GError      **error)
@@ -1013,6 +1024,8 @@ load_image (const gchar  *filename,
                           layer_type, 100, GIMP_NORMAL_MODE);
   gimp_image_insert_layer (image, layer, -1, 0);
 
+  *layer_ID = layer;
+
   if (layer_type == GIMP_INDEXED_IMAGE)
     file_format = gimp_drawable_get_format (layer);
 
@@ -1410,6 +1423,7 @@ save_image (const gchar  *filename,
             gint32        image_ID,
             gint32        drawable_ID,
             gint32        orig_image_ID,
+            gint         *bits_depth,
             GError      **error)
 {
   gint i, k,                    /* Looping vars */
@@ -1449,6 +1463,8 @@ save_image (const gchar  *filename,
   else
     bit_depth = 16;
 
+  *bits_depth = bit_depth;
+
   pp = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
   if (!pp)
     {
diff --git a/plug-ins/common/file-tiff-load.c b/plug-ins/common/file-tiff-load.c
index 647d608..d9f7d23 100644
--- a/plug-ins/common/file-tiff-load.c
+++ b/plug-ins/common/file-tiff-load.c
@@ -97,6 +97,7 @@ static gboolean  load_dialog      (TIFF               *tif,
                                    TiffSelectedPages  *pages);
 
 static gint32    load_image       (const gchar        *filename,
+                                   gint32             *layer_ID,
                                    TIFF               *tif,
                                    TiffSelectedPages  *pages,
                                    gboolean           *resolution_loaded,
@@ -262,11 +263,12 @@ run (const gchar      *name,
               if (run_it)
                 {
                   gint32   image;
+                  gint32   layer_ID;
                   gboolean resolution_loaded = FALSE;
 
                   gimp_set_data (LOAD_PROC, &target, sizeof (target));
 
-                  image = load_image (param[1].data.d_string, tif, &pages,
+                  image = load_image (param[1].data.d_string, &layer_ID, tif, &pages,
                                       &resolution_loaded,
                                       &error);
 
@@ -290,7 +292,7 @@ run (const gchar      *name,
                           if (resolution_loaded)
                             flags &= ~GIMP_METADATA_LOAD_RESOLUTION;
 
-                          gimp_image_metadata_load_finish (image, "image/tiff",
+                          gimp_image_metadata_load_finish (image, layer_ID, "image/tiff",
                                                            metadata, flags,
                                                            run_mode == GIMP_RUN_INTERACTIVE);
 
@@ -518,6 +520,7 @@ load_dialog (TIFF              *tif,
 
 static gint32
 load_image (const gchar        *filename,
+            gint32             *layer_ID,
             TIFF               *tif,
             TiffSelectedPages  *pages,
             gboolean           *resolution_loaded,
@@ -1113,6 +1116,7 @@ load_image (const gchar        *filename,
           g_free (name);
         }
 
+      *layer_ID         = layer;
       channel[0].ID     = layer;
       channel[0].buffer = gimp_drawable_get_buffer (layer);
       channel[0].format = base_format;
diff --git a/plug-ins/common/file-tiff-save.c b/plug-ins/common/file-tiff-save.c
index 45fdbef..57fd017 100644
--- a/plug-ins/common/file-tiff-save.c
+++ b/plug-ins/common/file-tiff-save.c
@@ -234,7 +234,7 @@ run (const gchar      *name,
     {
       /* Plug-in is either file_tiff_save or file_tiff_save2 */
 
-      GimpMetadata          *metadata;
+      GimpAttributes        *attributes;
       GimpMetadataSaveFlags  metadata_flags;
       GimpParasite          *parasite;
       gint32                 image      = param[1].data.d_int32;
@@ -264,9 +264,9 @@ run (const gchar      *name,
           break;
         }
 
-      metadata = gimp_image_metadata_save_prepare (orig_image,
-                                                   "image/tiff",
-                                                   &metadata_flags);
+      attributes = gimp_image_metadata_save_prepare (orig_image,
+                                                     "image/tiff",
+                                                     &metadata_flags);
 
       tsvals.save_exif      = (metadata_flags & GIMP_METADATA_SAVE_EXIF) != 0;
       tsvals.save_xmp       = (metadata_flags & GIMP_METADATA_SAVE_XMP) != 0;
@@ -357,11 +357,17 @@ run (const gchar      *name,
           if (save_image (param[3].data.d_string, image, drawable, orig_image,
                           &saved_bpp, &error))
             {
-              if (metadata)
+              if (attributes)
                 {
                   GFile *file;
+                  gchar *val = g_strdup_printf ("%u", (gushort) saved_bpp);
+
+                  gimp_attributes_add_attribute (attributes,
+                                                 gimp_attribute_new_string ("Exif.Image.BitsPerSample",
+                                                                             val, TYPE_SHORT)
+                                                );
 
-                  gimp_metadata_set_bits_per_sample (metadata, saved_bpp);
+                  g_free (val);
 
                   if (tsvals.save_exif)
                     metadata_flags |= GIMP_METADATA_SAVE_EXIF;
@@ -386,8 +392,9 @@ run (const gchar      *name,
                   file = g_file_new_for_path (param[3].data.d_string);
                   gimp_image_metadata_save_finish (image,
                                                    "image/tiff",
-                                                   metadata, metadata_flags,
+                                                   attributes, metadata_flags,
                                                    file, NULL);
+                  g_object_unref (attributes);
                   g_object_unref (file);
                 }
 
@@ -402,9 +409,6 @@ run (const gchar      *name,
 
       if (export == GIMP_EXPORT_EXPORT)
         gimp_image_delete (image);
-
-      if (metadata)
-        g_object_unref (metadata);
     }
   else
     {
diff --git a/plug-ins/common/gimprc.common b/plug-ins/common/gimprc.common
index 421fb1e..2195d64 100644
--- a/plug-ins/common/gimprc.common
+++ b/plug-ins/common/gimprc.common
@@ -1,6 +1,7 @@
 align_layers_RC = align-layers.rc.o
 animation_optimize_RC = animation-optimize.rc.o
 animation_play_RC = animation-play.rc.o
+attributes_RC = attributes.rc.o
 blinds_RC = blinds.rc.o
 blur_RC = blur.rc.o
 blur_gauss_selective_RC = blur-gauss-selective.rc.o
@@ -76,13 +77,13 @@ grid_RC = grid.rc.o
 guillotine_RC = guillotine.rc.o
 hot_RC = hot.rc.o
 illusion_RC = illusion.rc.o
+iptc_RC = iptc.rc.o
 iwarp_RC = iwarp.rc.o
 jigsaw_RC = jigsaw.rc.o
 lcms_RC = lcms.rc.o
 lens_flare_RC = lens-flare.rc.o
 mail_RC = mail.rc.o
 max_rgb_RC = max-rgb.rc.o
-metadata_RC = metadata.rc.o
 newsprint_RC = newsprint.rc.o
 nl_filter_RC = nl-filter.rc.o
 noise_solid_RC = noise-solid.rc.o
diff --git a/plug-ins/common/iptc.c b/plug-ins/common/iptc.c
new file mode 100644
index 0000000..943c892
--- /dev/null
+++ b/plug-ins/common/iptc.c
@@ -0,0 +1,513 @@
+/* GIMP - The GNU Image Manipulation Program
+ * Copyright (C) 1995 Spencer Kimball and Peter Mattis
+ *
+ * iptc.c
+ * Copyright (C) 2013 Hartmut Kuhse
+ *
+ * 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 <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <gegl.h>
+#include <gtk/gtk.h>
+#include <gexiv2/gexiv2.h>
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+
+#define PLUG_IN_IMAGE_PROC     "plug-in-image-iptc-editor"
+#define PLUG_IN_LAYER_PROC     "plug-in-layer-iptc-editor"
+#define PLUG_IN_CHANNEL_PROC   "plug-in-channel-iptc-editor"
+#define PLUG_IN_HELP           "plug-in-iptc-editor"
+#define PLUG_IN_BINARY         "iptc"
+
+#define THUMB_SIZE 48
+
+#define IPTC_PREFIX "Iptc."
+
+typedef struct
+{
+  gchar *tag;
+  gchar *mode;
+} iptc_tag;
+
+typedef enum
+{
+  ATT_IMAGE,
+  ATT_LAYER,
+  ATT_CHANNEL
+} AttributesSource;
+
+/*  local function prototypes  */
+
+static void              query                      (void);
+static void              run                        (const gchar           *name,
+                                                     gint                   nparams,
+                                                     const GimpParam       *param,
+                                                     gint                  *nreturn_vals,
+                                                     GimpParam            **return_vals);
+
+static gboolean        iptc_dialog                  (gint32                 image_id,
+                                                     GimpAttributes        *attributes,
+                                                     AttributesSource       source,
+                                                     GtkBuilder            *builder);
+
+static void            iptc_dialog_set_iptc         (GimpAttributes        *attributes,
+                                                     GtkBuilder            *builder);
+
+static void            iptc_change_iptc             (GimpAttributes        *attributes,
+                                                     GtkBuilder            *builder);
+
+
+/* local variables */
+
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+  NULL,  /* init_proc  */
+  NULL,  /* quit_proc  */
+  query, /* query_proc */
+  run,   /* run_proc   */
+};
+
+static const iptc_tag const iptc_tags[] =
+{
+  { "Iptc.Application2.Byline",                  "single" },
+  { "Iptc.Application2.BylineTitle",             "single" },
+  { "Iptc.Application2.Caption",                 "multi"  },
+  { "Iptc.Application2.Category",                "single" },
+  { "Iptc.Application2.City",                    "single" },
+  { "Iptc.Application2.Copyright",               "single" },
+  { "Iptc.Application2.CountryName",             "single" },
+  { "Iptc.Application2.Credit",                  "single" },
+  { "Iptc.Application2.Headline",                "multi"  },
+  { "Iptc.Application2.Keywords",                "multi"  },
+  { "Iptc.Application2.ObjectName",              "single" },
+  { "Iptc.Application2.ProvinceState",           "single" },
+  { "Iptc.Application2.Source",                  "single" },
+  { "Iptc.Application2.SpecialInstructions",     "multi"  },
+  { "Iptc.Application2.SubLocation",             "single" },
+  { "Iptc.Application2.SuppCategory",            "multi"  },
+  { "Iptc.Application2.TransmissionReference",   "single" },
+  { "Iptc.Application2.Urgency",                 "single" },
+  { "Iptc.Application2.Writer",                  "single" }
+};
+
+/*  functions  */
+
+MAIN ()
+
+static void
+query (void)
+{
+  static const GimpParamDef image_attribs_args[] =
+  {
+    { GIMP_PDB_INT32, "run-mode", "Run mode { RUN-INTERACTIVE (0) }" },
+    { GIMP_PDB_IMAGE, "image",    "Input image"                      }
+  };
+
+  static const GimpParamDef layer_attribs_args[] =
+  {
+    { GIMP_PDB_INT32, "run-mode", "Run mode { RUN-INTERACTIVE (0) }" },
+    { GIMP_PDB_IMAGE, "image",    "Input image"                      },
+    { GIMP_PDB_LAYER, "layer",    "Input layer"                      }
+  };
+
+  static const GimpParamDef channel_attribs_args[] =
+  {
+    { GIMP_PDB_INT32,   "run-mode",   "Run mode { RUN-INTERACTIVE (0) }" },
+    { GIMP_PDB_IMAGE,   "image",      "Input image"                      },
+    { GIMP_PDB_CHANNEL, "channel",    "Input channel"                    }
+  };
+
+  gimp_install_procedure (PLUG_IN_IMAGE_PROC,
+                          N_("View and edit IPTC data"),
+                          "View and edit IPTC information attached to the "
+                          "current image. This iptc will be saved in the "
+                          "file, depending on the output file format.",
+                          "Hartmut Kuhse",
+                          "Hartmut Kuhse",
+                          "2014",
+                          N_("Edit IPTC Metadata"),
+                          "*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (image_attribs_args), 0,
+                          image_attribs_args, NULL);
+
+  gimp_plugin_menu_register (PLUG_IN_IMAGE_PROC, "<Image>/Image");
+
+  gimp_install_procedure (PLUG_IN_LAYER_PROC,
+                          N_("View and edit IPTC data"),
+                          "View and edit IPTC information attached to the "
+                          "current layer. This iptc will be saved in the "
+                          "xcf file.",
+                          "Hartmut Kuhse",
+                          "Hartmut Kuhse",
+                          "2014",
+                          N_("Edit layers IPTC Metadata"),
+                          "*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (layer_attribs_args), 0,
+                          layer_attribs_args, NULL);
+
+  gimp_plugin_menu_register (PLUG_IN_LAYER_PROC, "<Layers>");
+
+  gimp_install_procedure (PLUG_IN_CHANNEL_PROC,
+                          N_("View and edit IPTC data"),
+                          "View and edit IPTC information attached to the "
+                          "current channel. This iptc will be saved in the "
+                          "xcf file.",
+                          "Hartmut Kuhse",
+                          "Hartmut Kuhse",
+                          "2014",
+                          N_("Edit channels IPTC Metadata"),
+                          "*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (channel_attribs_args), 0,
+                          channel_attribs_args, NULL);
+
+  gimp_plugin_menu_register (PLUG_IN_CHANNEL_PROC, "<Channels>");
+
+}
+
+static void
+run (const gchar      *name,
+     gint              nparams,
+     const GimpParam  *param,
+     gint             *nreturn_vals,
+     GimpParam       **return_vals)
+{
+  GimpAttributes    *attributes;
+  GtkBuilder        *builder;
+  AttributesSource   source;
+  gint32             item_ID;
+  static GimpParam   values[1];
+  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
+
+  *nreturn_vals = 1;
+  *return_vals  = values;
+
+  values[0].type          = GIMP_PDB_STATUS;
+  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
+
+  INIT_I18N();
+  gimp_ui_init (PLUG_IN_BINARY, TRUE);
+
+  if (! strcmp (name, PLUG_IN_IMAGE_PROC))
+    {
+      item_ID = param[1].data.d_image;
+
+      attributes = gimp_image_get_attributes (item_ID);
+      source = ATT_IMAGE;
+
+      status = GIMP_PDB_SUCCESS;
+    }
+  else if (! strcmp (name, PLUG_IN_LAYER_PROC))
+    {
+      item_ID = param[2].data.d_layer;
+
+      attributes = gimp_item_get_attributes (item_ID);
+      source = ATT_LAYER;
+
+      status = GIMP_PDB_SUCCESS;
+    }
+  else if (! strcmp (name, PLUG_IN_CHANNEL_PROC))
+    {
+      item_ID = param[2].data.d_channel;
+
+      attributes = gimp_item_get_attributes (item_ID);
+      source = ATT_CHANNEL;
+
+      status = GIMP_PDB_SUCCESS;
+    }
+  else
+    {
+      status = GIMP_PDB_CALLING_ERROR;
+    }
+
+  if (! attributes)
+    {
+      attributes = gimp_attributes_new();
+    }
+
+  builder = gtk_builder_new ();
+
+  if (status == GIMP_PDB_SUCCESS && iptc_dialog (item_ID, attributes, source, builder))
+    {
+
+      iptc_change_iptc (attributes, builder);
+
+      if (! strcmp (name, PLUG_IN_IMAGE_PROC))
+        {
+          gimp_image_set_attributes (item_ID, attributes);
+        }
+      else if (! strcmp (name, PLUG_IN_LAYER_PROC))
+        {
+          gimp_item_set_attributes (item_ID, attributes);
+        }
+      else if (! strcmp (name, PLUG_IN_CHANNEL_PROC))
+        {
+          gimp_item_set_attributes (item_ID, attributes);
+        }
+      status = GIMP_PDB_SUCCESS;
+    }
+  else
+    {
+      status = GIMP_PDB_CALLING_ERROR;
+    }
+
+  g_object_unref (attributes);
+
+  values[0].data.d_status = status;
+}
+
+static gboolean
+iptc_dialog (gint32            item_id,
+             GimpAttributes   *attributes,
+             AttributesSource  source,
+             GtkBuilder       *builder)
+{
+  GtkWidget  *dialog;
+  GtkWidget  *iptc_vbox;
+  GtkWidget  *content_area;
+  GdkPixbuf  *pixbuf;
+  GtkWidget  *label_header;
+  GtkWidget  *label_info;
+  GtkWidget  *thumb_box;
+  gchar      *ui_file;
+  gchar      *title;
+  gchar      *fname;
+  gchar      *header;
+  gchar      *role;
+  GError     *error = NULL;
+  gboolean    run;
+
+
+  switch (source)
+  {
+    case ATT_IMAGE:
+      fname = g_filename_display_basename (gimp_image_get_uri (item_id));
+      header  = g_strdup_printf ("Image");
+      title = g_strdup_printf ("Image: %s", fname);
+      role  = g_strdup_printf ("gimp-image-iptc-dialog");
+      pixbuf = gimp_image_get_thumbnail (item_id, THUMB_SIZE, THUMB_SIZE,
+                                         GIMP_PIXBUF_SMALL_CHECKS);
+
+      break;
+    case ATT_LAYER:
+      fname = gimp_item_get_name (item_id);
+      header  = g_strdup_printf ("Layer");
+      title = g_strdup_printf ("Layer: %s", fname);
+      role  = g_strdup_printf ("gimp-layer-iptc-dialog");
+      pixbuf = gimp_drawable_get_thumbnail (item_id, THUMB_SIZE, THUMB_SIZE,
+                                            GIMP_PIXBUF_SMALL_CHECKS);
+      break;
+    case ATT_CHANNEL:
+      fname = gimp_item_get_name (item_id);
+      header  = g_strdup_printf ("Channel");
+      title = g_strdup_printf ("Channel: %s", fname);
+      role  = g_strdup_printf ("gimp-channel-iptc-dialog");
+      pixbuf = gimp_drawable_get_thumbnail (item_id, THUMB_SIZE, THUMB_SIZE,
+                                            GIMP_PIXBUF_SMALL_CHECKS);
+      break;
+    default:
+      fname = g_strdup_printf ("unknown");
+      header  = g_strdup_printf ("Unknown");
+      title = g_strdup_printf ("Attributes: %s", fname);
+      role  = g_strdup_printf ("gimp-iptc-dialog");
+      pixbuf = NULL;
+      break;
+  }
+
+  ui_file = g_build_filename (gimp_data_directory (),
+                              "ui", "plug-ins", "plug-in-iptc.ui", NULL);
+
+  if (! gtk_builder_add_from_file (builder, ui_file, &error))
+    {
+      g_printerr ("Error occured while loading UI file!\n");
+      g_printerr ("Message: %s\n", error->message);
+      g_clear_error (&error);
+      g_free (ui_file);
+      g_object_unref (builder);
+      return FALSE;
+    }
+
+  g_free (ui_file);
+
+  dialog = gimp_dialog_new (title,
+                            role,
+                            NULL, 0,
+                            gimp_standard_help_func, PLUG_IN_HELP,
+                            
+                            GTK_STOCK_CLOSE, GTK_RESPONSE_CLOSE,
+                            GTK_STOCK_OK,    GTK_RESPONSE_OK,
+
+                            NULL);
+
+  g_free (title);
+  g_free (role);
+
+  gtk_window_set_default_size (GTK_WINDOW (dialog),
+                               600,
+                               -1);
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                           GTK_RESPONSE_OK,
+                                           GTK_RESPONSE_CLOSE,
+                                           -1);
+
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+  iptc_vbox = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                  "iptc-vbox"));
+  gtk_container_set_border_width (GTK_CONTAINER (iptc_vbox), 2);
+  gtk_box_pack_start (GTK_BOX (content_area), iptc_vbox, TRUE, TRUE, 0);
+
+  label_header = GTK_WIDGET (gtk_builder_get_object (builder, "label-header"));
+  gimp_label_set_attributes (GTK_LABEL (label_header),
+                             PANGO_ATTR_SCALE,  PANGO_SCALE_LARGE,
+                             PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
+                             -1);
+  gtk_label_set_text (GTK_LABEL (label_header), header);
+
+  label_info = GTK_WIDGET (gtk_builder_get_object (builder, "label-info"));
+  gimp_label_set_attributes (GTK_LABEL (label_info),
+                             PANGO_ATTR_SCALE,  PANGO_SCALE_SMALL,
+                             -1);
+  gtk_label_set_text (GTK_LABEL (label_info), fname);
+
+  g_free (header);
+  g_free (fname);
+
+  if (pixbuf)
+    {
+      GtkWidget *image;
+
+      thumb_box = GTK_WIDGET (gtk_builder_get_object (builder, "thumb-box"));
+
+      if (thumb_box)
+        {
+          image = gtk_image_new_from_pixbuf (pixbuf);
+          gtk_box_pack_end (GTK_BOX (thumb_box), image, FALSE, FALSE, 0);
+          gtk_widget_show (image);
+        }
+    }
+
+  iptc_dialog_set_iptc (attributes, builder);
+
+  run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+  return run;
+}
+
+
+/*  private functions  */
+
+static void
+iptc_dialog_set_iptc (GimpAttributes *attributes,
+                      GtkBuilder     *builder)
+{
+  gchar         *value;
+  gint           i;
+
+  for (i = 0; i < G_N_ELEMENTS (iptc_tags); i++)
+    {
+      GimpAttribute *attribute = NULL;
+      GtkWidget     *widget    = NULL;
+
+      attribute = gimp_attributes_get_attribute (attributes, iptc_tags[i].tag);
+      widget = GTK_WIDGET (gtk_builder_get_object (builder, iptc_tags[i].tag));
+
+      if (attribute && widget)
+        {
+          value = gimp_attribute_get_string (attribute);
+
+          if (GTK_IS_ENTRY (widget))
+            {
+              GtkEntry *entry_widget = GTK_ENTRY (widget);
+
+              gtk_entry_set_text (entry_widget, value);
+            }
+          else if (GTK_IS_TEXT_VIEW (widget))
+            {
+              GtkTextView   *text_view = GTK_TEXT_VIEW (widget);
+              GtkTextBuffer *buffer;
+
+              buffer = gtk_text_view_get_buffer (text_view);
+              gtk_text_buffer_set_text (buffer, value, -1);
+            }
+          g_free (value);
+        }
+    }
+}
+
+static void
+iptc_change_iptc (GimpAttributes *attributes,
+                  GtkBuilder     *builder)
+{
+  gint            i;
+
+  for (i = 0; i < G_N_ELEMENTS (iptc_tags); i++)
+    {
+      GimpAttribute *attribute;
+
+      GObject *object = gtk_builder_get_object (builder,
+                                                iptc_tags[i].tag);
+
+      if (! strcmp ("single", iptc_tags[i].mode))
+        {
+          GtkEntry     *entry = GTK_ENTRY (object);
+          const gchar  *text  = gtk_entry_get_text (entry);
+
+          if (strcmp ("", text))
+            {
+              attribute = gimp_attribute_new_string (iptc_tags[i].tag, (gchar *) text, TYPE_UNICODE);
+              gimp_attributes_add_attribute (attributes, attribute);
+            }
+          else
+            {
+              gimp_attributes_remove_attribute (attributes, iptc_tags[i].tag);
+            }
+        }
+      else  if (!strcmp ("multi", iptc_tags[i].mode))
+        {
+          GtkTextView   *text_view = GTK_TEXT_VIEW (object);
+          GtkTextBuffer *buffer;
+          GtkTextIter    start;
+          GtkTextIter    end;
+          gchar         *text;
+
+          buffer = gtk_text_view_get_buffer (text_view);
+          gtk_text_buffer_get_start_iter (buffer, &start);
+          gtk_text_buffer_get_end_iter (buffer, &end);
+
+          text = gtk_text_buffer_get_text (buffer, &start, &end, TRUE);
+          
+          if (strcmp ("", text))
+            {
+              attribute = gimp_attribute_new_string (iptc_tags[i].tag, (gchar *) text, TYPE_MULTIPLE);
+              gimp_attributes_add_attribute (attributes, attribute);
+            }
+          else
+            {
+              gimp_attributes_remove_attribute (attributes, iptc_tags[i].tag);
+            }
+
+          g_free (text);
+        }
+    }
+}
diff --git a/plug-ins/file-jpeg/jpeg-load.c b/plug-ins/file-jpeg/jpeg-load.c
index 40aa0e6..b52e2e6 100644
--- a/plug-ins/file-jpeg/jpeg-load.c
+++ b/plug-ins/file-jpeg/jpeg-load.c
@@ -58,12 +58,13 @@ gint32           preview_layer_ID;
 gint32
 load_image (const gchar  *filename,
             GimpRunMode   runmode,
+            gint32       *layer_ID,
             gboolean      preview,
             gboolean     *resolution_loaded,
             GError      **error)
 {
   gint32 volatile  image_ID;
-  gint32           layer_ID;
+  gint32           _layer_ID;
   struct jpeg_decompress_struct cinfo;
   struct my_error_mgr           jerr;
   jpeg_saved_marker_ptr         marker;
@@ -229,11 +230,11 @@ load_image (const gchar  *filename,
                                          cinfo.output_width,
                                          cinfo.output_height,
                                          layer_type, 100, GIMP_NORMAL_MODE);
-      layer_ID = preview_layer_ID;
+      _layer_ID = preview_layer_ID;
     }
   else
     {
-      layer_ID = gimp_layer_new (image_ID, _("Background"),
+      _layer_ID = gimp_layer_new (image_ID, _("Background"),
                                  cinfo.output_width,
                                  cinfo.output_height,
                                  layer_type, 100, GIMP_NORMAL_MODE);
@@ -338,7 +339,7 @@ load_image (const gchar  *filename,
    * loop counter, so that we don't have to keep track ourselves.
    */
 
-  buffer = gimp_drawable_get_buffer (layer_ID);
+  buffer = gimp_drawable_get_buffer (_layer_ID);
   format = babl_format (image_type == GIMP_RGB ? "R'G'B' u8" : "Y' u8");
 
   while (cinfo.output_scanline < cinfo.output_height)
@@ -407,7 +408,9 @@ load_image (const gchar  *filename,
       gimp_progress_update (1.0);
     }
 
-  gimp_image_insert_layer (image_ID, layer_ID, -1, 0);
+  gimp_image_insert_layer (image_ID, _layer_ID, -1, 0);
+
+  *layer_ID = _layer_ID;
 
   return image_ID;
 }
diff --git a/plug-ins/file-jpeg/jpeg-load.h b/plug-ins/file-jpeg/jpeg-load.h
index d4e61b0..281e03d 100644
--- a/plug-ins/file-jpeg/jpeg-load.h
+++ b/plug-ins/file-jpeg/jpeg-load.h
@@ -20,6 +20,7 @@
 
 gint32 load_image           (const gchar  *filename,
                              GimpRunMode   runmode,
+                             gint32       *layer_ID,
                              gboolean      preview,
                              gboolean     *resolution_loaded,
                              GError      **error);
diff --git a/plug-ins/file-jpeg/jpeg-save.c b/plug-ins/file-jpeg/jpeg-save.c
index eb45b15..269f311 100644
--- a/plug-ins/file-jpeg/jpeg-save.c
+++ b/plug-ins/file-jpeg/jpeg-save.c
@@ -186,6 +186,7 @@ background_jpeg_save (PreviewPersistent *pp)
           GFile     *file = g_file_new_for_path (pp->file_name);
           GFileInfo *info;
           gchar     *text;
+          gint32     layer_ID;
           GError    *error = NULL;
 
           info = g_file_query_info (file,
@@ -216,7 +217,7 @@ background_jpeg_save (PreviewPersistent *pp)
           g_object_unref (file);
 
           /* and load the preview */
-          load_image (pp->file_name, GIMP_RUN_NONINTERACTIVE, TRUE, NULL, NULL);
+          load_image (pp->file_name, GIMP_RUN_NONINTERACTIVE, &layer_ID, TRUE, NULL, NULL);
         }
 
       /* we cleanup here (load_image doesn't run in the background) */
diff --git a/plug-ins/file-jpeg/jpeg.c b/plug-ins/file-jpeg/jpeg.c
index ef2c15c..3606fc1 100644
--- a/plug-ins/file-jpeg/jpeg.c
+++ b/plug-ins/file-jpeg/jpeg.c
@@ -173,6 +173,7 @@ run (const gchar      *name,
   GimpRunMode        run_mode;
   GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
   gint32             image_ID;
+  gint32             layer_ID;
   gint32             drawable_ID;
   GimpParasite      *parasite;
   GError            *error  = NULL;
@@ -210,7 +211,7 @@ run (const gchar      *name,
           break;
         }
 
-      image_ID = load_image (param[1].data.d_string, run_mode, FALSE,
+      image_ID = load_image (param[1].data.d_string, run_mode, &layer_ID, FALSE,
                              &resolution_loaded, &error);
 
       if (image_ID != -1)
@@ -223,12 +224,12 @@ run (const gchar      *name,
 
           if (metadata)
             {
-              GimpMetadataLoadFlags flags = GIMP_METADATA_LOAD_ALL;
+              GimpMetadataLoadFlags  flags = GIMP_METADATA_LOAD_ALL;
 
               if (resolution_loaded)
                 flags &= ~GIMP_METADATA_LOAD_RESOLUTION;
 
-              gimp_image_metadata_load_finish (image_ID, "image/jpeg",
+              gimp_image_metadata_load_finish (image_ID, layer_ID, "image/jpeg",
                                                metadata, flags,
                                                load_interactive);
 
@@ -286,7 +287,7 @@ run (const gchar      *name,
     }
   else if (strcmp (name, SAVE_PROC) == 0)
     {
-      GimpMetadata          *metadata;
+      GimpAttributes        *attributes;
       GimpMetadataSaveFlags  metadata_flags;
       gint32                 orig_image_ID;
       GimpExportReturn       export = GIMP_EXPORT_CANCEL;
@@ -336,7 +337,7 @@ run (const gchar      *name,
           break;
         }
 
-      metadata = gimp_image_metadata_save_prepare (orig_image_ID,
+      attributes = gimp_image_metadata_save_prepare (orig_image_ID,
                                                    "image/jpeg",
                                                    &metadata_flags);
 
@@ -534,11 +535,12 @@ run (const gchar      *name,
 
           /* write metadata */
 
-          if (metadata)
+          if (attributes)
             {
               GFile *file;
+              GimpAttribute  *attribute;
 
-              gimp_metadata_set_bits_per_sample (metadata, 8);
+              gimp_attributes_new_attribute (attributes, "Exif.Image.BitsPerSample", "8", TYPE_SHORT);
 
               if (jsvals.save_exif)
                 metadata_flags |= GIMP_METADATA_SAVE_EXIF;
@@ -563,14 +565,12 @@ run (const gchar      *name,
               file = g_file_new_for_path (param[3].data.d_string);
               gimp_image_metadata_save_finish (orig_image_ID,
                                                "image/jpeg",
-                                               metadata, metadata_flags,
+                                               attributes, metadata_flags,
                                                file, NULL);
               g_object_unref (file);
+              g_object_unref (attributes);
             }
         }
-
-      if (metadata)
-        g_object_unref (metadata);
     }
   else
     {
diff --git a/plug-ins/file-psd/psd-save.c b/plug-ins/file-psd/psd-save.c
index 376c9a2..dde2abc 100644
--- a/plug-ins/file-psd/psd-save.c
+++ b/plug-ins/file-psd/psd-save.c
@@ -271,7 +271,7 @@ run (const gchar      *name,
     {
       gint32                 image_id;
       gint32                 drawable_id;
-      GimpMetadata          *metadata;
+      GimpAttributes        *attributes;
       GimpMetadataSaveFlags  metadata_flags;
       GimpExportReturn       export = GIMP_EXPORT_IGNORE;
 
@@ -306,26 +306,26 @@ run (const gchar      *name,
           break;
         }
 
-      metadata = gimp_image_metadata_save_prepare (image_id,
+      attributes = gimp_image_metadata_save_prepare (image_id,
                                                    "image/x-psd",
                                                    &metadata_flags);
 
       if (save_image (param[3].data.d_string, image_id, &error))
         {
-          if (metadata)
+          if (attributes)
             {
               GFile *file;
 
-              gimp_metadata_set_bits_per_sample (metadata, 8);
+              gimp_attributes_new_attribute (attributes, "Exif.Image.BitsPerSample", "8", TYPE_SHORT);
 
               file = g_file_new_for_path (param[3].data.d_string);
               gimp_image_metadata_save_finish (image_id,
                                                "image/x-psd",
-                                               metadata, metadata_flags,
+                                               attributes, metadata_flags,
                                                file, NULL);
               g_object_unref (file);
 
-              g_object_unref (metadata);
+              g_object_unref (attributes);
             }
 
           values[0].data.d_status = GIMP_PDB_SUCCESS;
@@ -344,9 +344,6 @@ run (const gchar      *name,
 
       if (export == GIMP_EXPORT_EXPORT)
         gimp_image_delete (image_id);
-
-      if (metadata)
-        g_object_unref (metadata);
     }
 }
 
diff --git a/plug-ins/file-psd/psd.c b/plug-ins/file-psd/psd.c
index a7911e6..1310dc0 100644
--- a/plug-ins/file-psd/psd.c
+++ b/plug-ins/file-psd/psd.c
@@ -226,7 +226,7 @@ run (const gchar      *name,
               if (resolution_loaded)
                 flags &= ~GIMP_METADATA_LOAD_RESOLUTION;
 
-              gimp_image_metadata_load_finish (image_ID, "image/x-psd",
+              gimp_image_metadata_load_finish (image_ID, -1, "image/x-psd",
                                                metadata, flags,
                                                interactive);
 
diff --git a/plug-ins/metainfo/Makefile.am b/plug-ins/metainfo/Makefile.am
new file mode 100644
index 0000000..ffb8138
--- /dev/null
+++ b/plug-ins/metainfo/Makefile.am
@@ -0,0 +1,61 @@
+## Process this file with automake to produce Makefile.in
+
+libgimpui = $(top_builddir)/libgimp/libgimpui-$(GIMP_API_VERSION).la
+libgimpwidgets = $(top_builddir)/libgimpwidgets/libgimpwidgets-$(GIMP_API_VERSION).la
+libgimp = $(top_builddir)/libgimp/libgimp-$(GIMP_API_VERSION).la
+libgimpconfig = $(top_builddir)/libgimpconfig/libgimpconfig-$(GIMP_API_VERSION).la
+libgimpcolor = $(top_builddir)/libgimpcolor/libgimpcolor-$(GIMP_API_VERSION).la
+libgimpbase = $(top_builddir)/libgimpbase/libgimpbase-$(GIMP_API_VERSION).la
+libgimpmath = $(top_builddir)/libgimpmath/libgimpmath-$(GIMP_API_VERSION).la
+
+if OS_WIN32
+mwindows = -mwindows
+endif
+
+if HAVE_WINDRES
+include $(top_srcdir)/build/windows/gimprc-plug-ins.rule
+metainfo_RC = metainfo.rc.o
+endif
+
+AM_LDFLAGS = $(mwindows)
+
+libexecdir = $(gimpplugindir)/plug-ins
+
+libexec_PROGRAMS = metainfo
+
+metainfo_SOURCES = \
+       metainfo.c              \
+       metainfo.h              \
+       interface.h             \
+       interface.c             \
+       metainfo-helper.c               \
+       metainfo-helper.h               \
+       page-description.c              \
+       page-description.h      \
+       page-artwork.c          \
+       page-artwork.h          \
+       page-administration.c           \
+       page-administration.h           \
+       page-rights.c           \
+       page-rights.h
+
+AM_CPPFLAGS = \
+       -I$(top_srcdir) \
+       $(GTK_CFLAGS)   \
+       $(GEGL_CFLAGS) \
+       $(GEXIV2_CFLAGS)        \
+       -I$(includedir)
+
+LDADD = \
+       $(libgimpui)            \
+       $(libgimpwidgets)       \
+       $(libgimp)              \
+       $(libgimpmath)          \
+       $(libgimpconfig)        \
+       $(libgimpcolor)         \
+       $(libgimpbase)          \
+       $(GEXIV2_LIBS)          \
+       $(GTK_LIBS)             \
+       $(RT_LIBS)              \
+       $(INTLLIBS)             \
+       $(metainfo_RC)
diff --git a/plug-ins/metainfo/interface.c b/plug-ins/metainfo/interface.c
new file mode 100644
index 0000000..7235d42
--- /dev/null
+++ b/plug-ins/metainfo/interface.c
@@ -0,0 +1,236 @@
+/* interface.c - user interface for the metadata editor
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#ifdef HAVE_UNISTD_H
+#include <unistd.h>
+#endif
+
+#include <glib/gstdio.h>
+
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+#include <io.h>
+#endif
+
+#ifndef _O_BINARY
+#define _O_BINARY 0
+#endif
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "interface.h"
+#include "metainfo.h"
+
+#include "libgimp/stdplugins-intl.h"
+
+static gboolean    save_attributes_to_image;
+static GtkWidget  *save_button;
+
+/* show a transient message dialog */
+void
+metainfo_message_dialog (GtkMessageType  type,
+                         GtkWindow      *parent,
+                         const gchar    *title,
+                         const gchar    *message)
+{
+  GtkWidget *dlg;
+
+  dlg = gtk_message_dialog_new (parent, 0, type, GTK_BUTTONS_OK, "%s", message);
+
+  if (title)
+    gtk_window_set_title (GTK_WINDOW (dlg), title);
+
+  gtk_window_set_role (GTK_WINDOW (dlg), "metainfo-message");
+  gtk_dialog_run (GTK_DIALOG (dlg));
+  gtk_widget_destroy (dlg);
+}
+
+static void
+metainfo_dialog_response (GtkWidget *widget,
+                          gint       response_id,
+                          gpointer   data)
+{
+  GimpAttributes *attributes = (GimpAttributes *) data;
+
+  switch (response_id)
+    {
+    case METAINFO_RESPONSE_SAVE:
+      page_description_save_to_attributes (attributes);
+      page_artwork_save_to_attributes (attributes);
+      page_administration_save_to_attributes (attributes);
+      page_rights_save_to_attributes (attributes);
+      save_attributes_to_image = TRUE;
+      break;
+    case GTK_RESPONSE_OK:
+    default:
+      save_attributes_to_image = FALSE;
+      break;
+    }
+  gtk_widget_destroy (widget);
+}
+
+gboolean
+metainfo_get_save_attributes (void)
+{
+  return save_attributes_to_image;
+}
+
+gboolean
+metainfo_dialog (gint32          image_id,
+                 GimpAttributes *attributes)
+{
+  GtkBuilder *builder;
+  GtkWidget  *dialog;
+  GtkWidget  *attributes_vbox;
+  GtkWidget  *content_area;
+  GdkPixbuf  *pixbuf;
+  GtkWidget  *label_header;
+  GtkWidget  *label_info;
+  GtkWidget  *thumb_box;
+
+  gchar      *header;
+  gchar      *ui_file;
+  gchar      *title;
+  gchar      *fname;
+  gchar      *role;
+  GError     *error = NULL;
+
+  gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+  fname = g_filename_display_basename (gimp_image_get_uri (image_id));
+  header  = g_strdup_printf ("Image");
+  role  = g_strdup_printf ("gimp-image-metainfo-dialog");
+  pixbuf = gimp_image_get_thumbnail (image_id, THUMB_SIZE, THUMB_SIZE,
+                                     GIMP_PIXBUF_SMALL_CHECKS);
+  title = g_strdup_printf ("Digital Rights: %s", fname);
+
+  builder = gtk_builder_new ();
+
+  ui_file = g_build_filename (gimp_data_directory (),
+                              "ui", "plug-ins", "plug-in-metainfo.ui", NULL);
+
+  if (! gtk_builder_add_from_file (builder, ui_file, &error))
+    {
+      g_printerr ("Error occured while loading UI file!\n");
+      g_printerr ("Message: %s\n", error->message);
+      g_clear_error (&error);
+      g_free (ui_file);
+      g_object_unref (builder);
+      return FALSE;
+    }
+
+  g_free (ui_file);
+
+  dialog = gimp_dialog_new (title,
+                            role,
+                            NULL, 0,
+                            gimp_standard_help_func, PLUG_IN_HELP,
+
+                            GTK_STOCK_OK, GTK_RESPONSE_OK,
+                            NULL);
+
+  save_button = gtk_dialog_add_button (GTK_DIALOG (dialog), GTK_STOCK_SAVE, METAINFO_RESPONSE_SAVE);
+  gtk_widget_set_sensitive (GTK_WIDGET (save_button), FALSE);
+  set_save_attributes_button (save_button);
+
+  g_signal_connect (dialog, "response",
+                    G_CALLBACK (metainfo_dialog_response),
+                    attributes);
+
+  g_signal_connect (dialog, "destroy",
+                    G_CALLBACK (gtk_main_quit),
+                    NULL);
+
+  g_free (title);
+  g_free (role);
+
+  gtk_window_set_default_size (GTK_WINDOW (dialog),
+                               250,
+                               500);
+
+  gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+                                           METAINFO_RESPONSE_SAVE,
+                                           GTK_RESPONSE_OK,
+                                           -1);
+
+  content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
+
+  attributes_vbox = GTK_WIDGET (gtk_builder_get_object (builder,
+                                                      "metainfo-vbox"));
+
+  gtk_container_set_border_width (GTK_CONTAINER (attributes_vbox), 2);
+  gtk_box_pack_start (GTK_BOX (content_area), attributes_vbox, TRUE, TRUE, 0);
+
+  label_header = GTK_WIDGET (gtk_builder_get_object (builder, "label-header"));
+  gimp_label_set_attributes (GTK_LABEL (label_header),
+                             PANGO_ATTR_SCALE,  PANGO_SCALE_LARGE,
+                             PANGO_ATTR_WEIGHT, PANGO_WEIGHT_BOLD,
+                             -1);
+  gtk_label_set_text (GTK_LABEL (label_header), header);
+
+  label_info = GTK_WIDGET (gtk_builder_get_object (builder, "label-info"));
+  gimp_label_set_attributes (GTK_LABEL (label_info),
+                             PANGO_ATTR_SCALE,  PANGO_SCALE_SMALL,
+                             -1);
+  gtk_label_set_text (GTK_LABEL (label_info), fname);
+
+  g_free (header);
+  g_free (fname);
+
+  if (pixbuf)
+    {
+      GtkWidget *image;
+
+      thumb_box = GTK_WIDGET (gtk_builder_get_object (builder, "thumb-box"));
+
+      if (thumb_box)
+        {
+          image = gtk_image_new_from_pixbuf (pixbuf);
+          gtk_box_pack_end (GTK_BOX (thumb_box), image, FALSE, FALSE, 0);
+          gtk_widget_show (image);
+        }
+    }
+
+  page_description_read_from_attributes    (attributes,
+                                            builder);
+  page_artwork_read_from_attributes        (attributes,
+                                            builder);
+  page_administration_read_from_attributes (attributes,
+                                            builder);
+  page_rights_read_from_attributes         (attributes,
+                                            builder);
+
+  gtk_widget_show (GTK_WIDGET (dialog));
+
+  gtk_main ();
+  
+  return TRUE;
+}
diff --git a/plug-ins/metainfo/interface.h b/plug-ins/metainfo/interface.h
new file mode 100644
index 0000000..a1589ff
--- /dev/null
+++ b/plug-ins/metainfo/interface.h
@@ -0,0 +1,49 @@
+/* interface.h - user interface for the metadata editor
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef INTERFACE_H
+#define INTERFACE_H
+
+#include <glib-object.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+#include "page-description.h"
+#include "page-artwork.h"
+#include "page-administration.h"
+#include "page-rights.h"
+
+G_BEGIN_DECLS
+
+#define THUMB_SIZE              48
+
+#define METAINFO_RESPONSE_SAVE 201
+
+void             metainfo_message_dialog      (GtkMessageType  type,
+                                               GtkWindow      *parent,
+                                               const gchar    *title,
+                                               const gchar    *message);
+gboolean         metainfo_get_save_attributes (void);
+                                          
+gboolean         metainfo_dialog              (gint32          image_ID,
+                                               GimpAttributes *attributes);
+
+G_END_DECLS
+
+#endif /* INTERFACE_H */
diff --git a/plug-ins/metainfo/metainfo-helper.c b/plug-ins/metainfo/metainfo-helper.c
new file mode 100644
index 0000000..4005193
--- /dev/null
+++ b/plug-ins/metainfo/metainfo-helper.c
@@ -0,0 +1,272 @@
+/* metainfo-helper.c
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+#include "metainfo-helper.h"
+
+static GtkWidget *save_attributes_button = NULL;
+/**
+ * string_replace_str:
+ *
+ * @original:          the original string
+ * @old_pattern:       the pattern to replace
+ * @replacement:       the replacement
+ *
+ * replaces @old_pattern by @replacement in @original
+ * This routine is copied from VALA.
+ *
+ * Return value: the new string.
+ *
+ * Since: 2.10
+ */
+gchar*
+string_replace_str (const gchar* original, const gchar* old_pattern, const gchar* replacement) {
+  gchar      *result        = NULL;
+  GError     *_inner_error_ = NULL;
+
+  g_return_val_if_fail (original != NULL, NULL);
+  g_return_val_if_fail (old_pattern != NULL, NULL);
+  g_return_val_if_fail (replacement != NULL, NULL);
+
+  {
+    GRegex           *regex  = NULL;
+    const gchar      *_tmp0_ = NULL;
+    gchar            *_tmp1_ = NULL;
+    gchar            *_tmp2_ = NULL;
+    GRegex           *_tmp3_ = NULL;
+    GRegex           *_tmp4_ = NULL;
+    gchar            *_tmp5_ = NULL;
+    GRegex           *_tmp6_ = NULL;
+    const gchar      *_tmp7_ = NULL;
+    gchar            *_tmp8_ = NULL;
+    gchar            *_tmp9_ = NULL;
+
+    _tmp0_ = old_pattern;
+    _tmp1_ = g_regex_escape_string (_tmp0_, -1);
+    _tmp2_ = _tmp1_;
+    _tmp3_ = g_regex_new (_tmp2_, 0, 0, &_inner_error_);
+    _tmp4_ = _tmp3_;
+    _g_free0 (_tmp2_);
+    regex = _tmp4_;
+
+    if (_inner_error_ != NULL)
+      {
+        if (_inner_error_->domain == G_REGEX_ERROR)
+          {
+            goto __catch0_g_regex_error;
+          }
+        g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, 
_inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+        g_clear_error (&_inner_error_);
+        return NULL;
+      }
+
+    _tmp6_ = regex;
+    _tmp7_ = replacement;
+    _tmp8_ = g_regex_replace_literal (_tmp6_, original, (gssize) (-1), 0, _tmp7_, 0, &_inner_error_);
+    _tmp5_ = _tmp8_;
+
+    if (_inner_error_ != NULL)
+      {
+        _g_regex_unref0 (regex);
+        if (_inner_error_->domain == G_REGEX_ERROR)
+          {
+            goto __catch0_g_regex_error;
+          }
+        _g_regex_unref0 (regex);
+        g_critical ("file %s: line %d: unexpected error: %s (%s, %d)", __FILE__, __LINE__, 
_inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+        g_clear_error (&_inner_error_);
+        return NULL;
+      }
+
+    _tmp9_ = _tmp5_;
+    _tmp5_ = NULL;
+    result = _tmp9_;
+    _g_free0 (_tmp5_);
+    _g_regex_unref0 (regex);
+    return result;
+  }
+
+  goto __finally0;
+  __catch0_g_regex_error:
+  {
+    GError* e = NULL;
+    e = _inner_error_;
+    _inner_error_ = NULL;
+    g_assert_not_reached ();
+    _g_error_free0 (e);
+  }
+
+  __finally0:
+  if (_inner_error_ != NULL)
+    {
+      g_critical ("file %s: line %d: uncaught error: %s (%s, %d)", __FILE__, __LINE__, 
_inner_error_->message, g_quark_to_string (_inner_error_->domain), _inner_error_->code);
+      g_clear_error (&_inner_error_);
+      return NULL;
+    }
+}
+
+/**
+ * string_index_of:
+ *
+ * @haystack:          a #gchar
+ * @needle:            a #gchar
+ * @start_index:       a #gint
+ *
+ *
+ * Return value:  #gint that points to the position
+ * of @needle in @haystack, starting at @start_index,
+ * or -1, if @needle is not found
+ *
+ * Since: 2.10
+ */
+gint
+string_index_of (const gchar* haystack, const gchar* needle, gint start_index)
+{
+  gint result = 0;
+  gchar* temp1_ = NULL;
+  g_return_val_if_fail (haystack != NULL, -1);
+  g_return_val_if_fail (needle != NULL, -1);
+  temp1_ = strstr (((gchar*) haystack) + start_index, needle);
+  if (temp1_ != NULL)
+    {
+      result = (gint) (temp1_ - ((gchar*) haystack));
+      return result;
+    }
+  else
+    {
+      result = -1;
+      return result;
+    }
+}
+
+/**
+ * string_strnlen:
+ *
+ * @str:          a #gchar
+ * @maxlen:       a #glong
+ *
+ * Returns the length of @str or @maxlen, if @str
+ * is longer that @maxlen
+ *
+ * Return value:  #glong
+ *
+ * Since: 2.10
+ */
+glong
+string_strnlen (gchar* str, glong maxlen)
+{
+  glong result = 0L;
+  gchar* temp1_ = NULL;
+  temp1_ = memchr (str, 0, (gsize) maxlen);
+  if (temp1_ == NULL)
+    {
+      return maxlen;
+    }
+  else
+    {
+      result = (glong) (temp1_ - str);
+      return result;
+    }
+}
+
+/**
+ * string_substring:
+ *
+ * @string:          a #gchar
+ * @offset:          a #glong
+ * @len:             a #glong
+ *
+ * Returns a substring of @string, starting at @offset
+ * with a legth of @len
+ *
+ * Return value:  #gchar to be freed if no longer use
+ *
+ * Since: 2.10
+ */
+gchar*
+string_substring (const gchar* string, glong offset, glong len)
+{
+  gchar* result = NULL;
+  glong string_length = 0L;
+  gboolean _tmp0_ = FALSE;
+  g_return_val_if_fail(string != NULL, NULL);
+  if (offset >= ((glong) 0))
+    {
+      _tmp0_ = len >= ((glong) 0);
+    }
+  else
+    {
+      _tmp0_ = FALSE;
+    }
+
+  if (_tmp0_)
+    {
+      string_length = string_strnlen ((gchar*) string, offset + len);
+    }
+  else
+    {
+      string_length = (glong) strlen (string);
+    }
+
+  if (offset < ((glong) 0))
+    {
+      offset = string_length + offset;
+      g_return_val_if_fail (offset >= ((glong ) 0), NULL);
+    }
+  else
+    {
+      g_return_val_if_fail (offset <= string_length, NULL);
+    }
+  if (len < ((glong) 0))
+    {
+      len = string_length - offset;
+    }
+
+  g_return_val_if_fail ((offset + len) <= string_length, NULL);
+  result = g_strndup (((gchar*) string) + offset, (gsize) len);
+  return result;
+}
+
+GObject *
+get_widget_from_label (GtkBuilder *builder, const gchar *label)
+{
+  GObject *obj;
+
+  obj = gtk_builder_get_object (builder, label);
+
+  return obj;
+}
+
+void
+set_save_attributes_button (GtkButton *button)
+{
+  save_attributes_button = GTK_WIDGET (button);
+}
+
+void
+set_save_attributes_button_sensitive (gboolean sensitive)
+{
+  gtk_widget_set_sensitive (save_attributes_button, sensitive);
+}
diff --git a/plug-ins/metainfo/metainfo-helper.h b/plug-ins/metainfo/metainfo-helper.h
new file mode 100644
index 0000000..07fabf4
--- /dev/null
+++ b/plug-ins/metainfo/metainfo-helper.h
@@ -0,0 +1,102 @@
+/* metainfo-helper.h
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __METAINFO_HELPER_H__
+#define __METAINFO_HELPER_H__
+
+#include <glib-object.h>
+
+#define _g_free0(var) (var = (g_free (var), NULL))
+#define _g_regex_unref0(var) ((var == NULL) ? NULL : (var = (g_regex_unref (var), NULL)))
+#define _g_error_free0(var) ((var == NULL) ? NULL : (var = (g_error_free (var), NULL)))
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  WIDGET_TYPE_ENTRY,
+  WIDGET_TYPE_COMBOBOX
+} WidgetType;
+
+typedef enum
+{
+  LIST_TYPE_NONE,
+  LIST_TYPE_SEQ,
+  LIST_TYPE_BAG,
+  LIST_TYPE_LANGALT
+} ListType;
+
+typedef struct _ComboBoxData      ComboBoxData;
+
+struct _ComboBoxData
+{
+  const gchar  *val_in_combo;                          /* translateable - value shown in the combobox */
+  const gchar  *val_in_tag;                            /* value saved as tag value */
+};
+
+
+typedef struct _MetadataEntry     MetadataEntry;
+
+struct _MetadataEntry
+{
+        gchar      *label;                             /* translateable - label of the widget */
+  const gchar      *ui_label;                          /* name of the label widget in GtkBuilder ui file */
+  const gchar      *ui_entry;                          /* name of the entry widget in GtkBuilder ui file */
+  const gchar      *xmp_tag;                           /* xmp tag, saved in GimpAttribute.name */
+  WidgetType        widget_type;                       /* type of entry widget in GtkBuilder ui : GtkEntry 
or GtkComboBox */
+        gint        number_of_comboarray;              /*number of entry in ComboBoxData - array. Only valid 
for combobox entries */
+};
+
+typedef struct _StructureElement StructureElement;
+
+struct _StructureElement
+{
+  gint                        number_of_element;       /* simply the number, corresponding to 
STRUCTURES_ON_PAGE */
+  const gchar                *identifier;              /* translateble - identifier for combobox entries */
+  const gchar                *struct_tag;              /* structure tag without array number */
+  GimpAttributeStructureType  struct_type;               /* type of structure, gexiv2 cannot get the right 
list type from tag*/
+  const gchar                *struct_combo_widget;     /* name of the combobox widget for this structure */
+  const gchar                *struct_liststore_widget; /* name of the liststore of the combobox for this 
structure */
+  const gchar                *add_widget;              /* name of the add structure button for this 
structure */
+  const gchar                *remove_widget;           /* name of the remove structure button for this 
structure */
+};
+
+
+gchar*                  string_replace_str                        (const gchar         *original,
+                                                                   const gchar         *old_pattern,
+                                                                   const gchar         *replacement);
+gint                    string_index_of                           (const gchar         *haystack,
+                                                                   const gchar         *needle,
+                                                                   gint                 start_index);
+glong                   string_strnlen                            (gchar               *str,
+                                                                   glong                maxlen);
+gchar*                  string_substring                          (const gchar         *attribute,
+                                                                   glong                offset,
+                                                                   glong                len);
+GObject*                get_widget_from_label                     (GtkBuilder          *builder,
+                                                                   const gchar         *label);
+void                    set_save_attributes_button                (GtkButton           *button);
+void                    set_save_attributes_button_sensitive      (gboolean             sensitive);
+
+
+
+
+G_END_DECLS
+
+#endif /* __METAINFO_HELPER_H__ */
diff --git a/plug-ins/metainfo/metainfo.c b/plug-ins/metainfo/metainfo.c
new file mode 100644
index 0000000..55224f4
--- /dev/null
+++ b/plug-ins/metainfo/metainfo.c
@@ -0,0 +1,156 @@
+/* metainfo.c - main() for the metainfo editor
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include <libgimp/gimp.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+#include "metainfo.h"
+#include "interface.h"
+
+
+/* prototypes of local functions */
+static void  query (void);
+static void  run   (const gchar      *name,
+                    gint              nparams,
+                    const GimpParam  *param,
+                    gint             *nreturn_vals,
+                    GimpParam       **return_vals);
+
+
+/* local variables */
+const GimpPlugInInfo PLUG_IN_INFO =
+{
+  NULL,  /* init_proc  */
+  NULL,  /* quit_proc  */
+  query, /* query_proc */
+  run,   /* run_proc   */
+};
+
+/* local functions */
+MAIN ()
+
+static void
+query (void)
+{
+  static const GimpParamDef editor_args[] =
+  {
+    { GIMP_PDB_INT32,       "run-mode",  "Run mode { RUN-INTERACTIVE (0), RUN-NONINTERACTIVE (1) }" },
+    { GIMP_PDB_IMAGE,       "image",     "Input image"                  },
+    { GIMP_PDB_DRAWABLE,    "drawable",  "Input drawable (unused)"      }
+  };
+
+
+  gimp_install_procedure (EDITOR_PROC,
+                          N_("View and edit metainformation"),
+                          "View and edit meta information reagarding digital "
+                          "rights, attached to the current image. "
+                          "This metainformation will be saved in the file, "
+                          "depending on the output file format.",
+                          "Hartmut Kuhse <hatti gimp org>",
+                          "Hartmut Kuhse <hatti gimp org>",
+                          "2014",
+                          N_("Digital Rights"),
+                          "RGB*, INDEXED*, GRAY*",
+                          GIMP_PLUGIN,
+                          G_N_ELEMENTS (editor_args), 0,
+                          editor_args, NULL);
+
+  gimp_plugin_menu_register (EDITOR_PROC, "<Image>/Image");
+  // XXX gimp_plugin_icon_register (EDITOR_PROC, GIMP_ICON_TYPE_STOCK_ID,
+}
+
+static void
+run (const gchar      *name,
+     gint              nparams,
+     const GimpParam  *param,
+     gint             *nreturn_vals,
+     GimpParam       **return_vals)
+{
+  static GimpParam   values[4];
+  gint32             image_ID;
+  GimpPDBStatusType  status = GIMP_PDB_SUCCESS;
+  GimpAttributes    *attributes;
+
+  *nreturn_vals = 1;
+  *return_vals  = values;
+
+  values[0].type          = GIMP_PDB_STATUS;
+  values[0].data.d_status = GIMP_PDB_EXECUTION_ERROR;
+
+  INIT_I18N();
+
+  if (! strcmp (name, EDITOR_PROC))
+    image_ID = param[1].data.d_image;
+  else
+    image_ID = param[0].data.d_image;
+
+
+
+  /* Now check what we are supposed to do */
+if (! strcmp (name, EDITOR_PROC))
+    {
+      GimpRunMode run_mode;
+
+      run_mode = param[0].data.d_int32;
+      if (run_mode == GIMP_RUN_INTERACTIVE)
+        {
+          attributes = gimp_image_get_attributes (image_ID);
+
+          if (! attributes)
+            {
+              attributes = gimp_attributes_new ();
+            }
+
+          if (attributes)
+            {
+              if (! metainfo_dialog (image_ID, attributes))
+                status = GIMP_PDB_CANCEL;
+              else
+                {
+                  if (metainfo_get_save_attributes())
+                    gimp_image_set_attributes (image_ID, attributes);
+                  status = GIMP_PDB_SUCCESS;
+                }
+            }
+          else
+            {
+              g_message (_("General attributes failure."));
+            }
+        }
+      else
+        status = GIMP_PDB_CALLING_ERROR;
+    }
+  else
+    {
+      status = GIMP_PDB_CALLING_ERROR;
+    }
+
+  if (status == GIMP_PDB_SUCCESS)
+    {
+    }
+
+  values[0].data.d_status = status;
+}
diff --git a/plug-ins/metainfo/metainfo.h b/plug-ins/metainfo/metainfo.h
new file mode 100644
index 0000000..e50a6bb
--- /dev/null
+++ b/plug-ins/metainfo/metainfo.h
@@ -0,0 +1,29 @@
+/* metadata.h - defines for the metadata editor
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __METAINFO_H__
+#define __METAINFO_H__
+
+
+#define EDITOR_PROC         "plug-in-metainfo-editor"
+#define PLUG_IN_BINARY      "metainfo"
+#define PLUG_IN_ROLE        "plug-in-metainfo"
+#define PLUG_IN_HELP        "plug-in-metainfo"
+
+#endif /* __METAINFO_H__ */
diff --git a/plug-ins/metainfo/page-administration.c b/plug-ins/metainfo/page-administration.c
new file mode 100644
index 0000000..64793b8
--- /dev/null
+++ b/plug-ins/metainfo/page-administration.c
@@ -0,0 +1,1039 @@
+/* page-administration.c
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+#include "metainfo-helper.h"
+#include "page-administration.h"
+
+
+static void                page_administration_init_ui                       (GtkBuilder        *builder);
+static void                page_administration_set_entry_sensitive           (GtkBuilder        *builder,
+                                                                              const gchar       *struct_name,
+                                                                              gboolean           sensitive);
+static void                page_administration_init_combobox                 (GtkBuilder        *builder);
+static void                page_administration_set_to_ui                     (GtkBuilder        *builder,
+                                                                              gint               repaint);
+static void                page_administration_entry_activate_cb             (GtkWidget         *widget,
+                                                                              gpointer           userdata);
+static gboolean            page_administration_entry_focus_out_cb            (GtkWidget         *widget,
+                                                                              GdkEvent          *event,
+                                                                              gpointer           userdata);
+static gboolean            page_administration_store_in_hash_table           (const gchar       *entry_name,
+                                                                              const gchar       *value,
+                                                                              gint               nr);
+static void                page_administration_structure_add                 (GtkButton         *button,
+                                                                              gpointer           userdata);
+static void                page_administration_structure_remove              (GtkButton         *button,
+                                                                              gpointer           userdata);
+static void                page_administration_entry_combo_changed_callback  (GtkWidget         *combo,
+                                                                              gpointer           userdata);
+static void                page_administration_combobox_changed_callback     (GtkWidget         *combo,
+                                                                              gpointer           userdata);
+static void                page_administration_structure_save                (GtkBuilder        *builder,
+                                                                              gint               
struct_number);
+
+
+#define STRUCTURES_ON_PAGE 2
+#define COMBOBOX_WITH_DATA 1
+
+
+static GHashTable           *elements_table;
+static gint                  curr_shown_structure[STRUCTURES_ON_PAGE];
+static gint                  highest_structure[STRUCTURES_ON_PAGE];
+
+static StructureElement struct_element [] =
+    {
+        {0,
+            N_("Image supplier"),
+            "Xmp.plus.ImageSupplier",
+            STRUCTURE_TYPE_SEQ,
+            "imagesupplier-combo",
+            "imagesupplier-liststore",
+            "imagesupplier-button-plus",
+            "imagesupplier-button-minus"},
+
+        {1,
+            N_("Registry ID"),
+            "Xmp.iptcExt.RegistryId",
+            STRUCTURE_TYPE_BAG,
+            "registryid-combo",
+            "registryid-liststore",
+            "registryid-button-plus",
+            "registryid-button-minus"}
+    };
+
+
+static ComboBoxData combobox_data[][256] =
+{
+    {
+        {N_(" "),                                                ""},
+        {N_("Original digital capture of a real life scene"),    
"http://cv.iptc.org/newscodes/digitalsourcetype/digitalCapture"},
+        {N_("Digitised from a negative on film"),                
"http://cv.iptc.org/newscodes/digitalsourcetype/negativeFilm"},
+        {N_("Digitised from a positive on film"),                
"http://cv.iptc.org/newscodes/digitalsourcetype/positiveFilm"},
+        {N_("Digitised from a print on non-transparent medium"), 
"http://cv.iptc.org/newscodes/digitalsourcetype/print"},
+        {N_("Created by software"),                              
"http://cv.iptc.org/newscodes/digitalsourcetype/softwareImage"}
+    },
+};
+
+static MetadataEntry administration_entries[] =
+    {
+        {N_("Image supplier name"),
+            "imagesupplier-name-label",
+            "imagesupplier-name-entry",
+            "Xmp.plus.ImageSupplier[x]/plus:ImageSupplierName",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Image supplier ID"),
+            "imagesupplier-id-label",
+            "imagesupplier-id-entry",
+            "Xmp.plus.ImageSupplier[x]/plus:ImageSupplierID",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Image supplier image ID"),
+            "imagesupplier-imageid-label",
+            "imagesupplier-imageid-entry",
+            "Xmp.plus.ImageSupplierImageID",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Registry organistaion ID"),
+            "regorgid-label",
+            "regorgid-entry",
+            "Xmp.iptcExt.RegistryId[x]/iptcExt:RegOrgId",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Registry item ID"),
+            "regitemid-label",
+            "regitemid-entry",
+            "Xmp.iptcExt.RegistryId[x]/iptcExt:RegItemId",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Max available height"),
+            "maxavailheight-label",
+            "maxavailheight-entry",
+            "Xmp.iptcExt.MaxAvailHeight",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Max available width"),
+            "maxavailwidth-label",
+            "maxavailwidth-entry",
+            "Xmp.iptcExt.MaxAvailWidth",
+             WIDGET_TYPE_ENTRY,
+             -1},
+
+        {N_("Digital source type"),
+            "digitalsourcetype-label",
+            "digitalsourcetype-combobox",
+            "Xmp.iptcExt.DigitalSourceType",
+            WIDGET_TYPE_COMBOBOX,
+            0}
+    };
+
+
+static void
+page_administration_init_ui (GtkBuilder *builder)
+{
+  GObject *obj;
+  gint     i;
+
+  elements_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  for (i = 0; i < G_N_ELEMENTS(administration_entries); i++)
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, administration_entries[i].ui_label));
+
+      gtk_label_set_text (GTK_LABEL (obj), administration_entries[i].label);
+
+      obj = G_OBJECT (get_widget_from_label (builder, administration_entries[i].ui_entry));
+      gtk_widget_set_name (GTK_WIDGET (obj), administration_entries[i].ui_entry);
+
+      if (administration_entries[i].widget_type == WIDGET_TYPE_ENTRY)
+        {
+          g_signal_connect (GTK_WIDGET (obj), "focus-out-event",
+                            G_CALLBACK (page_administration_entry_focus_out_cb),
+                            (gpointer) administration_entries[i].ui_entry);
+          g_signal_connect (GTK_ENTRY (obj), "activate",
+                            G_CALLBACK (page_administration_entry_activate_cb),
+                            (gpointer) administration_entries[i].ui_entry);
+        }
+      else if (administration_entries[i].widget_type == WIDGET_TYPE_COMBOBOX)
+        {
+          gint array_nr = administration_entries[i].number_of_comboarray;
+
+          if (array_nr >= 0)
+            {
+              gint i;
+              GtkTreeIter   iter;
+              GtkListStore *liststore;
+              gint array_length;
+
+              liststore = GTK_LIST_STORE(gtk_combo_box_get_model (GTK_COMBO_BOX (obj)));
+
+              array_length = G_N_ELEMENTS(combobox_data[array_nr]);
+
+              for (i = 0; i < array_length; i++) /*get info about structure */
+                {
+                  const gchar  *val_in_combo = combobox_data[array_nr][i].val_in_combo;
+
+                  if (! val_in_combo)
+                    break;
+
+                  gtk_list_store_append(liststore, &iter);
+
+                  gtk_list_store_set (liststore, &iter,
+                                      0, val_in_combo,
+                                      -1);
+                }
+
+              g_signal_connect (obj, "changed",
+                                G_CALLBACK (page_administration_entry_combo_changed_callback),
+                                GINT_TO_POINTER (array_nr));
+            }
+        }
+    }
+
+  for (i = 0; i < G_N_ELEMENTS(struct_element); i++) /*get info about structure */
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].add_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].add_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_administration_structure_add),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].remove_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].remove_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_administration_structure_remove),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].struct_combo_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].struct_combo_widget);
+      g_signal_connect (obj, "changed",
+                        G_CALLBACK (page_administration_combobox_changed_callback),
+                        builder);
+    }
+}
+
+static void
+page_administration_set_entry_sensitive (GtkBuilder  *builder,
+                                      const gchar *struct_name,
+                                      gboolean     sensitive)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS(administration_entries); i++)
+    {
+      const gchar   *tag;
+      GObject       *obj;
+
+      tag = administration_entries[i].xmp_tag;
+      if (g_str_has_prefix (tag, struct_name))
+        {
+          obj = G_OBJECT (get_widget_from_label (builder, administration_entries[i].ui_entry));
+          gtk_widget_set_sensitive (GTK_WIDGET (obj), sensitive);
+        }
+    }
+
+}
+
+void
+page_administration_read_from_attributes (GimpAttributes *attributes,
+                                       GtkBuilder     *builder)
+{
+  gint i;
+  gint sct;
+
+  g_return_if_fail (attributes != NULL);
+
+  page_administration_init_ui (builder);
+
+  for (i = 0; i < G_N_ELEMENTS(administration_entries); i++)
+    {
+      GimpAttribute *attribute = NULL;
+      const gchar   *o_tag      = NULL;
+      gchar         *tag       = NULL;
+      gint           p;
+      gint           counter;
+
+      o_tag = administration_entries[i].xmp_tag;
+
+      tag =g_strdup (o_tag);
+
+//      if (g_str_has_prefix (tag, "Xmp.iptcExt.Add"))
+//          g_print ("found\n");
+
+      p = string_index_of (tag, "[x]", 0);  /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gint    j;
+          gchar  *struct_string = NULL;
+
+          /* check last number */
+
+          struct_string = string_substring (tag, 0, p); /* get structure tag */
+
+          for (j = 0; j < G_N_ELEMENTS(struct_element); j++) /*get info about structure */
+            {
+              if (! g_strcmp0 (struct_string, struct_element[j].struct_tag))  /* is a structure */
+                {
+                  GimpAttribute *struct_attribute = NULL;
+                  gint num = highest_structure[struct_element[j].number_of_element];
+
+                  counter = 0;  /*start the loop */
+
+                  while (struct_attribute ||
+                         counter == 0     ||  /* at least once, because counter IS 0 */
+                         counter < num)       /* at least until the highest structure */
+                    {
+                      gchar           *nr_string = NULL;
+                      gchar           *new_tag = NULL;
+                      gchar           *value;
+
+                      counter ++;
+                      nr_string = g_strdup_printf ("[%d]", counter);
+                      new_tag = string_replace_str (tag, "[x]", nr_string);
+
+                      struct_attribute = gimp_attributes_get_attribute (attributes, new_tag);
+
+                      if (struct_attribute)
+                        {
+                          gint sct;
+                          value = gimp_attribute_get_string (struct_attribute);
+
+                          for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                            {
+                              if (g_str_has_prefix (new_tag, struct_element[sct].struct_tag))
+                                {
+                                  highest_structure[struct_element[sct].number_of_element] = counter;
+                                  break;
+                                }
+                            }
+                          g_hash_table_insert (elements_table,
+                                               (gpointer) g_strdup (new_tag),
+                                               (gpointer) g_strdup (value));
+
+                          gimp_attributes_remove_attribute (attributes, new_tag);
+                          g_free (value);
+                        }
+                      g_free (nr_string);
+                      g_free (new_tag);
+                    }
+                  break;
+                }
+            }
+        }
+      else
+        {
+          attribute = gimp_attributes_get_attribute (attributes, tag);
+          if (attribute)
+            {
+              gchar *value = gimp_attribute_get_string (attribute);
+              g_hash_table_insert (elements_table,
+                                   (gpointer) g_strdup (administration_entries[i].xmp_tag),
+                                   (gpointer) g_strdup (value));
+
+              gimp_attributes_remove_attribute (attributes, administration_entries[i].xmp_tag);
+              g_free (value);
+            }
+        }
+      g_free (tag);
+    }
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (highest_structure[sct] > 0)
+        curr_shown_structure[sct] = 1;
+      else
+        curr_shown_structure[sct] = 0;
+    }
+
+  page_administration_init_combobox (builder);
+
+  page_administration_set_to_ui (builder,
+                              -1); /* all */
+}
+
+void
+page_administration_save_to_attributes (GimpAttributes *attributes)
+{
+  GHashTableIter     iter;
+  gpointer           key, value;
+
+
+  g_hash_table_iter_init (&iter, elements_table);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      GimpAttribute                   *attribute     = NULL;
+      gchar                           *tag = (gchar *) key;
+      gchar                           *value         = NULL;
+      gint                             p;
+      gint                             sct;
+      gint i;
+
+      value = (gchar *) g_hash_table_lookup (elements_table, (gpointer) tag);
+      attribute = gimp_attribute_new_string (tag, value, TYPE_ASCII);
+
+      if (attribute)
+        {
+          p = string_index_of (tag, "[", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes! */
+            {
+
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (tag, struct_element[sct].struct_tag))
+                    {
+                      gimp_attribute_set_structure_type (attribute, struct_element[sct].struct_type);
+                      break;
+                    }
+                }
+            }
+
+          for (i = 0; i < G_N_ELEMENTS(administration_entries); i++)
+            {
+              gchar *t_tag;
+              gint   p1;
+              gint   p2;
+
+              p1 = string_index_of (tag, "[", 0);                           /* is it a structure tag? */
+              if (p > -1) /* yes! */
+                {
+                  gchar *t1;
+                  gchar *t2;
+                  gint   l;
+
+                  p2 = string_index_of (tag, "]", p1);
+
+                  l = strlen (tag);
+
+                  t1 = string_substring (tag, 0, p);
+                  t2 = string_substring (tag, p2 + 1, l - (p2 + 1));
+
+                  t_tag = g_strdup_printf ("%s[x]%s", t1, t2);
+                }
+              else
+                {
+                  t_tag = g_strdup (tag);
+                }
+
+
+              if (! g_strcmp0 (t_tag, administration_entries[i].xmp_tag))
+                {
+                  if (administration_entries[i].number_of_comboarray > -1)
+                    {
+                      gint combobox_data_counter;
+                      gint array_length;
+                      gint number_in_comboarray = administration_entries[i].number_of_comboarray;
+
+                      array_length = G_N_ELEMENTS(combobox_data[number_in_comboarray]);
+
+                      for (combobox_data_counter = 0; combobox_data_counter < array_length; 
combobox_data_counter++)
+                        {
+                          const gchar  *val_in_tag = 
combobox_data[number_in_comboarray][combobox_data_counter].val_in_tag;
+                          const gchar  *interpreted_val;
+
+                          if (! val_in_tag)
+                            break;
+
+                          if (! g_strcmp0 (value, val_in_tag))
+                            {
+                              interpreted_val =  
combobox_data[number_in_comboarray][combobox_data_counter].val_in_combo;
+                              gimp_attribute_set_interpreted_string (attribute, interpreted_val);
+                              break;
+                            }
+                        }
+                    }
+                  break;
+                }
+            }
+          gimp_attributes_add_attribute (attributes, attribute);
+        }
+    }
+}
+
+static void
+page_administration_entry_activate_cb (GtkWidget *widget, gpointer userdata)
+{
+  const gchar *entry_name = (const gchar *) userdata;
+  const gchar *value      = gtk_entry_get_text (GTK_ENTRY (widget));
+
+  page_administration_store_in_hash_table (entry_name, value, 0);
+}
+
+static gboolean
+page_administration_entry_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer userdata)
+{
+  const gchar *entry_name = (const gchar *) userdata;
+  const gchar *value      = gtk_entry_get_text (GTK_ENTRY (widget));
+
+  page_administration_store_in_hash_table (entry_name, value, 0);
+
+  return FALSE;
+}
+
+static void
+page_administration_entry_combo_changed_callback (GtkWidget *combo, gpointer userdata)
+{
+  const gchar *widget_name;
+  const gchar *value;
+  gint         array_nr   = GPOINTER_TO_INT (userdata);
+  gint         index      = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+
+  value = combobox_data[array_nr][index].val_in_tag;
+  widget_name = gtk_widget_get_name (GTK_WIDGET (combo));
+
+  page_administration_store_in_hash_table (widget_name, value, 0);
+}
+
+static gboolean
+page_administration_store_in_hash_table (const gchar *entry_name, const gchar *value, gint nr)
+{
+  gint           i;
+  const gchar   *o_tag;
+  gint           p;
+  gint           number = 0;
+  gboolean       success;
+
+  g_return_val_if_fail (entry_name != NULL, FALSE);
+
+  if (nr > 0)
+    number = nr;
+
+  success = FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS(administration_entries); i++)
+    {
+      if (! g_strcmp0 (entry_name, administration_entries[i].ui_entry))
+        {
+          gchar   *new_tag;
+          gchar   *nr_string;
+
+          o_tag = administration_entries[i].xmp_tag;
+
+          new_tag =g_strdup (o_tag);
+
+          p = string_index_of (new_tag, "[x]", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes */
+            {
+              gint sct;
+
+              if (number <= 0)
+                {
+                  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                    {
+                      if (g_strcmp0 (o_tag, struct_element[sct].struct_tag))
+                        {
+                          number = curr_shown_structure[struct_element[sct].number_of_element];
+                          break;
+                        }
+                    }
+                }
+
+              nr_string = g_strdup_printf ("[%d]", number);
+              new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              g_free (nr_string);
+              if (number <=0 )
+                {
+                  g_free (new_tag);
+                  return FALSE;
+                }
+            }
+
+          if (value && g_strcmp0 (value, ""))
+            {
+              if (g_hash_table_insert (elements_table, (gpointer) g_strdup (new_tag), (gpointer) g_strdup 
(value)))
+                success = TRUE;
+            }
+          else
+            {
+              if (g_hash_table_remove (elements_table, (gpointer) new_tag))
+                success = TRUE;
+            }
+
+          set_save_attributes_button_sensitive (TRUE);
+
+          g_free (new_tag);
+          break;
+        }
+    }
+  return success;
+}
+
+static void
+page_administration_structure_add (GtkButton *button, gpointer userdata)
+{
+  gint             number_to_add;
+  GtkComboBox     *combo;
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  const gchar     *widget_name;
+  gchar           *line;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].add_widget))
+        {
+          page_administration_structure_save (builder, struct_element[sct].number_of_element);
+          number_to_add = ++highest_structure[struct_element[sct].number_of_element];
+
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          line = g_strdup_printf ("%s [%d]", struct_element[sct].identifier, number_to_add);
+          curr_shown_structure [struct_element[sct].number_of_element] = number_to_add;
+
+          repaint = struct_element[sct].number_of_element;
+
+          g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_administration_combobox_changed_callback), builder);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+
+          gtk_combo_box_set_active (combo, number_to_add-1);
+
+          if (number_to_add == 1)
+            page_administration_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+
+          g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_administration_combobox_changed_callback), builder);
+
+          g_free (line);
+          break;
+       }
+    }
+
+  page_administration_set_to_ui (builder, repaint);
+}
+
+static void
+page_administration_structure_remove (GtkButton *button, gpointer userdata)
+{
+  GtkBuilder      *builder           = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GHashTableIter   iter_remove;
+  gboolean         found;
+  gchar           *nr_string;
+  gchar           *nr_string_new;
+  gpointer         key, value;
+  GSList          *delete_key_list   = NULL;
+  GSList          *list;
+  gchar           *tag_prefix;
+  gchar           *new_key;
+  gint             number_to_delete;
+  GtkComboBox     *combo;
+  GtkTreeIter      combo_iter;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+  gint             combo_to_del;
+
+  GHashTable           *reorder_table;
+
+  reorder_table = g_hash_table_new_full  (g_str_hash, g_str_equal, g_free, g_free);
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].remove_widget))
+        {
+          number_to_delete = curr_shown_structure[sct];
+          tag_prefix = g_strdup (struct_element[sct].struct_tag);
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          combo_to_del = highest_structure[sct] - 1;
+
+          if (number_to_delete == highest_structure[struct_element[sct].number_of_element])
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete - 1;
+          else
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete;
+
+          highest_structure[sct]--;
+          repaint = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr_string = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete);
+
+  /* remove entries */
+  {
+
+    g_hash_table_iter_init (&iter_remove, elements_table);
+    while (g_hash_table_iter_next (&iter_remove, &key, &value))
+      {
+        gchar *tag = (gchar *) key;
+        if (g_str_has_prefix (tag, nr_string))
+          {
+            delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+          }
+      }
+
+    for (list = delete_key_list; list; list = list->next)
+      {
+        gchar *key = (gchar *) list->data;
+        g_hash_table_remove (elements_table, key);
+      }
+
+    g_slist_free_full (delete_key_list, g_free);
+
+  }
+  /* reorder entries */
+
+  found = TRUE;
+
+  {
+    while (found) /* first: element table */
+      {
+        GHashTableIter   iter_reorder;
+
+        delete_key_list = NULL;
+        found           = FALSE;
+
+        nr_string_new = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete + 1);
+
+        g_hash_table_iter_init (&iter_reorder, elements_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            if (g_str_has_prefix (tag, nr_string_new))
+              {
+                found = TRUE;
+                new_key = string_replace_str (tag, nr_string_new, nr_string);
+                g_hash_table_insert (reorder_table, g_strdup (new_key), g_strdup (tag_value));
+                delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+              }
+          }
+
+        for (list = delete_key_list; list; list = list->next)
+          {
+            gchar *key = (gchar *) list->data;
+            g_hash_table_remove (elements_table, key);
+          }
+        g_slist_free_full (delete_key_list, g_free);
+
+        g_hash_table_iter_init (&iter_reorder, reorder_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            g_hash_table_insert (elements_table, g_strdup (tag), g_strdup (tag_value));
+          }
+
+        g_hash_table_remove_all (reorder_table);
+
+        nr_string = g_strdup (nr_string_new);
+        number_to_delete ++;
+      }
+
+  }
+
+  g_free (tag_prefix);
+  g_free (nr_string);
+  g_free (nr_string_new);
+  g_free (new_key);
+
+  g_hash_table_unref (reorder_table);
+
+  g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_administration_combobox_changed_callback), builder);
+
+  gtk_combo_box_set_active (combo, combo_to_del);
+  if (gtk_combo_box_get_active_iter (combo, &combo_iter))
+    gtk_list_store_remove (liststore, &combo_iter);
+
+  if (curr_shown_structure[repaint] == 0)
+    page_administration_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+  else
+    gtk_combo_box_set_active (combo, curr_shown_structure[repaint] - 1);
+
+  g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_administration_combobox_changed_callback), builder);
+
+  page_administration_set_to_ui (builder, repaint);
+}
+
+static void
+page_administration_combobox_changed_callback (GtkWidget *combo, gpointer userdata)
+{
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkComboBox     *combobox;
+  gint             nr;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (combo));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].struct_combo_widget))
+        {
+          page_administration_structure_save (builder, struct_element[sct].number_of_element);
+          combobox = GTK_COMBO_BOX (get_widget_from_label (builder, 
struct_element[sct].struct_combo_widget));
+          repaint  = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr = gtk_combo_box_get_active (combobox);
+  nr++;
+  curr_shown_structure[repaint] = nr;
+
+  page_administration_set_to_ui (builder, repaint);
+}
+
+static void
+page_administration_structure_save (GtkBuilder *builder, gint struct_number)
+{
+  gint         i;
+  const gchar *prefix = struct_element[struct_number].struct_tag;
+
+  for (i = 0; i < G_N_ELEMENTS(administration_entries); i++)
+    {
+      GObject       *obj;
+      gchar         *tag      = NULL;
+      const gchar   *o_tag;
+
+      if (curr_shown_structure[struct_number] > 0)
+        {
+          o_tag = administration_entries[i].xmp_tag;
+          if (g_str_has_prefix (o_tag, prefix))
+            {
+              gchar *nr_string;
+
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[struct_number]);
+              tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              obj   = get_widget_from_label (builder, administration_entries[i].ui_entry);
+
+              switch (administration_entries[i].widget_type)
+              {
+                case WIDGET_TYPE_ENTRY:
+                  {
+                    gchar *value;
+                    value = g_strdup (gtk_entry_get_text (GTK_ENTRY (obj)));
+                    if (value && g_strcmp0 (value, ""))
+                      g_hash_table_insert (elements_table, (gpointer) g_strdup (tag), (gpointer) g_strdup 
(value));
+                    else
+                      g_hash_table_remove (elements_table, (gpointer) tag);
+                  }
+                  break;
+                case WIDGET_TYPE_COMBOBOX:
+                  break;
+                default:
+                  break;
+              }
+
+              g_free (nr_string);
+              g_free (tag);
+            }
+        }
+    }
+}
+
+static void
+page_administration_set_to_ui (GtkBuilder *builder, gint repaint)
+{
+  gint         i;
+  gint         sct;
+  const gchar *prefix;
+
+  if (repaint != -1)
+    prefix = struct_element[repaint].struct_tag;
+  else
+    prefix = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS(administration_entries); i++)
+    {
+      GObject       *obj;
+      const gchar   *o_tag;
+      gchar         *value = NULL;
+      gchar         *new_tag;
+      gint           p;
+
+      o_tag = administration_entries[i].xmp_tag;
+
+      obj = get_widget_from_label (builder, administration_entries[i].ui_entry);
+
+      if (prefix)
+        {
+          if (! g_str_has_prefix (o_tag, prefix))
+            continue;
+        }
+
+      p = string_index_of (o_tag, "[x]", 0);     /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gchar         *nr_string;
+
+          if (repaint != -1)
+            {
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[repaint]);
+            }
+          else
+            {
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (o_tag, struct_element[sct].struct_tag))
+                    {
+                      nr_string = g_strdup_printf ("[%d]", curr_shown_structure[sct]);
+                      break;
+                    }
+                }
+            }
+
+          new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+          g_free (nr_string);
+        }
+      else
+        {
+          new_tag = g_strdup (o_tag);
+        }
+
+      value = (gchar *) g_hash_table_lookup (elements_table, new_tag);
+
+      switch (administration_entries[i].widget_type)
+      {
+        case WIDGET_TYPE_ENTRY:
+          {
+           gtk_entry_set_text (GTK_ENTRY (obj), "");
+          }
+          break;
+        default:
+          break;
+      }
+
+      if (value)
+        {
+          switch (administration_entries[i].widget_type)
+          {
+            case WIDGET_TYPE_ENTRY:
+              {
+               gtk_entry_set_text (GTK_ENTRY (obj), value);
+              }
+              break;
+            case WIDGET_TYPE_COMBOBOX:
+              {
+                gint combobox_data_counter;
+                gint array_length;
+                gint number_in_comboarray = administration_entries[i].number_of_comboarray;
+
+                array_length = G_N_ELEMENTS(combobox_data[number_in_comboarray]);
+
+                for (combobox_data_counter = 0; combobox_data_counter < array_length; 
combobox_data_counter++)
+                  {
+                    const gchar  *val_in_tag = 
combobox_data[number_in_comboarray][combobox_data_counter].val_in_tag;
+
+                    if (! val_in_tag)
+                      break;
+
+                    if (! g_strcmp0 (value, val_in_tag))
+                      {
+                        g_signal_handlers_block_by_func (obj,
+                                                         G_CALLBACK 
(page_administration_entry_combo_changed_callback),
+                                                         GINT_TO_POINTER (number_in_comboarray));
+
+                        gtk_combo_box_set_active (GTK_COMBO_BOX (obj), combobox_data_counter);
+
+                        g_signal_handlers_unblock_by_func (obj,
+                                                           G_CALLBACK 
(page_administration_entry_combo_changed_callback),
+                                                           GINT_TO_POINTER (number_in_comboarray));
+                        break;
+                      }
+                  }
+              }
+              break;
+            default:
+              break;
+          }
+        }
+      g_free (new_tag);
+    }
+}
+
+static void
+page_administration_init_combobox (GtkBuilder *builder)
+{
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  GtkComboBox     *combo;
+  gint             sct;
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      gchar *line;
+      gint   i;
+      gint   high;
+      gint   active;
+
+      liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+      combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+
+      high = highest_structure[struct_element[sct].number_of_element];
+      active = curr_shown_structure[struct_element[sct].number_of_element];
+
+      g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_administration_combobox_changed_callback), builder);
+
+      for (i = 0; i < high; i++)
+        {
+          line = g_strdup_printf ("%s [%d]",struct_element[sct].identifier, i + 1);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+          g_free (line);
+        }
+
+      gtk_combo_box_set_active (combo, active-1);
+
+      if (active >= 1)
+        page_administration_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+      else
+        page_administration_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+
+      g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_administration_combobox_changed_callback), builder);
+
+    }
+}
diff --git a/plug-ins/metainfo/page-administration.h b/plug-ins/metainfo/page-administration.h
new file mode 100644
index 0000000..801d0d5
--- /dev/null
+++ b/plug-ins/metainfo/page-administration.h
@@ -0,0 +1,33 @@
+/* page-administration.h
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PAGE_ADMINISTRATION_H__
+#define __PAGE_ADMINISTRATION_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void                          page_administration_read_from_attributes       (GimpAttributes        
*attributes,
+                                                                              GtkBuilder            
*builder);
+void                          page_administration_save_to_attributes         (GimpAttributes        
*attributes);
+
+G_END_DECLS
+
+#endif /* __PAGE_ADMINISTRATION_H__ */
diff --git a/plug-ins/metainfo/page-artwork.c b/plug-ins/metainfo/page-artwork.c
new file mode 100644
index 0000000..1c3f9a6
--- /dev/null
+++ b/plug-ins/metainfo/page-artwork.c
@@ -0,0 +1,1067 @@
+/* page-artwork.c
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+#include "metainfo-helper.h"
+#include "page-artwork.h"
+
+
+static void                page_artwork_init_ui                       (GtkBuilder        *builder);
+static void                page_artwork_set_entry_sensitive           (GtkBuilder        *builder,
+                                                                       const gchar       *struct_name,
+                                                                       gboolean           sensitive);
+static void                page_artwork_init_combobox                 (GtkBuilder        *builder);
+static void                page_artwork_set_to_ui                     (GtkBuilder        *builder,
+                                                                       gint               repaint);
+static void                page_artwork_entry_activate_cb             (GtkWidget         *widget,
+                                                                       gpointer           userdata);
+static gboolean            page_artwork_entry_focus_out_cb            (GtkWidget         *widget,
+                                                                       GdkEvent          *event,
+                                                                       gpointer           userdata);
+static gboolean            page_artwork_store_in_hash_table           (const gchar       *entry_name,
+                                                                       const gchar       *value,
+                                                                       gint               nr);
+static void                page_artwork_structure_add                 (GtkButton         *button,
+                                                                       gpointer           userdata);
+static void                page_artwork_structure_remove              (GtkButton         *button,
+                                                                       gpointer           userdata);
+static void                page_artwork_entry_combo_changed_callback  (GtkWidget         *combo,
+                                                                       gpointer           userdata);
+static void                page_artwork_combobox_changed_callback     (GtkWidget         *combo,
+                                                                       gpointer           userdata);
+static void                page_artwork_structure_save                (GtkBuilder        *builder,
+                                                                       gint               struct_number);
+
+
+#define STRUCTURES_ON_PAGE 1
+#define COMBOBOX_WITH_DATA 2
+
+
+static GHashTable           *elements_table;
+static gint                  curr_shown_structure[STRUCTURES_ON_PAGE];
+static gint                  highest_structure[STRUCTURES_ON_PAGE];
+
+static StructureElement struct_element [] =
+    {
+        {0,
+            N_("Artwork or Object"),
+            "Xmp.iptcExt.ArtworkOrObject",
+            STRUCTURE_TYPE_BAG,
+            "artworkorobject-combo",
+            "artworkorobject-liststore",
+            "artworkorobject-button-plus",
+            "artworkorobject-button-minus"}
+    };
+
+
+static ComboBoxData combobox_data[][256] =
+{
+    {
+        {N_(" "),                                    ""},
+        {N_("unknown"),                              "http://ns.useplus.org/ldf/vocab/AG-UNK"},
+        {N_("Age 25 or over"),                       "http://ns.useplus.org/ldf/vocab/AG-A25"},
+        {N_("Age 24"),                               "http://ns.useplus.org/ldf/vocab/AG-A24"},
+        {N_("Age 23"),                               "http://ns.useplus.org/ldf/vocab/AG-A23"},
+        {N_("Age 22"),                               "http://ns.useplus.org/ldf/vocab/AG-A22"},
+        {N_("Age 21"),                               "http://ns.useplus.org/ldf/vocab/AG-A21"},
+        {N_("Age 20"),                               "http://ns.useplus.org/ldf/vocab/AG-A20"},
+        {N_("Age 19"),                               "http://ns.useplus.org/ldf/vocab/AG-A19"},
+        {N_("Age 18"),                               "http://ns.useplus.org/ldf/vocab/AG-A18"},
+        {N_("Age 17"),                               "http://ns.useplus.org/ldf/vocab/AG-A17"},
+        {N_("Age 16"),                               "http://ns.useplus.org/ldf/vocab/AG-A16"},
+        {N_("Age 15"),                               "http://ns.useplus.org/ldf/vocab/AG-A15"},
+        {N_("Age 14 or under"),                      "http://ns.useplus.org/ldf/vocab/AG-U14"}
+    },
+    {
+        {N_(" "),                                    ""},
+        {N_("None"),                                 "http://ns.useplus.org/ldf/vocab/MR-NON"},
+        {N_("Not Applicable"),                       "http://ns.useplus.org/ldf/vocab/MR-NAP"},
+        {N_("Unlimited Model Releases"),             "http://ns.useplus.org/ldf/vocab/MR-UMR"},
+        {N_("Limited or Incomplete Model Releases"), "http://ns.useplus.org/ldf/vocab/MR-LMR"}
+    },
+};
+
+static MetadataEntry artwork_entries[] =
+    {
+        {N_("Title"),
+            "artworkorobject-title-label",
+            "artworkorobject-title-entry",
+            "Xmp.iptcExt.ArtworkOrObject[x]/iptcExt:AOTitle",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Date created"),
+            "artworkorobject-datecreated-label",
+            "artworkorobject-datecreated-entry",
+            "Xmp.iptcExt.ArtworkOrObject[x]/iptcExt:AODateCreated",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Creator"),
+            "artworkorobject-creator-label",
+            "artworkorobject-creator-entry",
+            "Xmp.iptcExt.ArtworkOrObject[x]/iptcExt:AOCreator",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Source"),
+            "artworkorobject-source-label",
+            "artworkorobject-source-entry",
+            "Xmp.iptcExt.ArtworkOrObject[x]/iptcExt:AOSource",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Source inventory number"),
+            "artworkorobject-sourceinvno-label",
+            "artworkorobject-sourceinvno-entry",
+            "Xmp.iptcExt.ArtworkOrObject[x]/iptcExt:AOSourceInvNo",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Copyright notice"),
+            "artworkorobject-copyrightnotice-label",
+            "artworkorobject-copyrightnotice-entry",
+            "Xmp.iptcExt.ArtworkOrObject[x]/iptcExt:AOCopyrightNotice",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+
+        {N_("Additional model information"),
+            "addlmodelinfo-label",
+            "addlmodelinfo-entry",
+            "Xmp.iptcExt.AddlModelInfo",
+             WIDGET_TYPE_ENTRY,
+             -1},
+
+        {N_("Model age"),
+            "modelage-label",
+            "modelage-entry",
+            "Xmp.iptcExt.ModelAge",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Model release ID"),
+            "modelreleaseid-label",
+            "modelreleaseid-entry",
+            "Xmp.plus.ModelReleaseID",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Minor model age"),
+            "minormodelagedisclosure-label",
+            "minormodelagedisclosure-combobox",
+            "Xmp.plus.MinorModelAgeDisclosure",
+            WIDGET_TYPE_COMBOBOX,
+            0},
+
+        {N_("Model release status"),
+            "modelreleasestatus-label",
+            "modelreleasestatus-combobox",
+            "Xmp.plus.ModelReleaseStatus",
+            WIDGET_TYPE_COMBOBOX,
+            1}
+    };
+
+
+static void
+page_artwork_init_ui (GtkBuilder *builder)
+{
+  GObject *obj;
+  gint     i;
+
+  elements_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  for (i = 0; i < G_N_ELEMENTS(artwork_entries); i++)
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, artwork_entries[i].ui_label));
+
+      gtk_label_set_text (GTK_LABEL (obj), artwork_entries[i].label);
+
+      obj = G_OBJECT (get_widget_from_label (builder, artwork_entries[i].ui_entry));
+      gtk_widget_set_name (GTK_WIDGET (obj), artwork_entries[i].ui_entry);
+
+      if (artwork_entries[i].widget_type == WIDGET_TYPE_ENTRY)
+        {
+          g_signal_connect (GTK_WIDGET (obj), "focus-out-event",
+                            G_CALLBACK (page_artwork_entry_focus_out_cb),
+                            (gpointer) artwork_entries[i].ui_entry);
+          g_signal_connect (GTK_ENTRY (obj), "activate",
+                            G_CALLBACK (page_artwork_entry_activate_cb),
+                            (gpointer) artwork_entries[i].ui_entry);
+        }
+      else if (artwork_entries[i].widget_type == WIDGET_TYPE_COMBOBOX)
+        {
+          gint array_nr = artwork_entries[i].number_of_comboarray;
+
+          if (array_nr >= 0)
+            {
+              gint i;
+              GtkTreeIter   iter;
+              GtkListStore *liststore;
+              gint array_length;
+
+              liststore = GTK_LIST_STORE(gtk_combo_box_get_model (GTK_COMBO_BOX (obj)));
+
+              array_length = G_N_ELEMENTS(combobox_data[array_nr]);
+
+              for (i = 0; i < array_length; i++) /*get info about structure */
+                {
+                  const gchar  *val_in_combo = combobox_data[array_nr][i].val_in_combo;
+
+                  if (! val_in_combo)
+                    break;
+
+                  gtk_list_store_append(liststore, &iter);
+
+                  gtk_list_store_set (liststore, &iter,
+                                      0, val_in_combo,
+                                      -1);
+                }
+
+              g_signal_connect (obj, "changed",
+                                G_CALLBACK (page_artwork_entry_combo_changed_callback),
+                                GINT_TO_POINTER (array_nr));
+            }
+        }
+    }
+
+  for (i = 0; i < G_N_ELEMENTS(struct_element); i++) /*get info about structure */
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].add_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].add_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_artwork_structure_add),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].remove_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].remove_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_artwork_structure_remove),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].struct_combo_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].struct_combo_widget);
+      g_signal_connect (obj, "changed",
+                        G_CALLBACK (page_artwork_combobox_changed_callback),
+                        builder);
+    }
+}
+
+static void
+page_artwork_set_entry_sensitive (GtkBuilder  *builder,
+                                      const gchar *struct_name,
+                                      gboolean     sensitive)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS(artwork_entries); i++)
+    {
+      const gchar   *tag;
+      GObject       *obj;
+
+      tag = artwork_entries[i].xmp_tag;
+      if (g_str_has_prefix (tag, struct_name))
+        {
+          obj = G_OBJECT (get_widget_from_label (builder, artwork_entries[i].ui_entry));
+          gtk_widget_set_sensitive (GTK_WIDGET (obj), sensitive);
+        }
+    }
+
+}
+
+void
+page_artwork_read_from_attributes (GimpAttributes *attributes,
+                                       GtkBuilder     *builder)
+{
+  gint i;
+  gint sct;
+
+  g_return_if_fail (attributes != NULL);
+
+  page_artwork_init_ui (builder);
+
+  for (i = 0; i < G_N_ELEMENTS(artwork_entries); i++)
+    {
+      GimpAttribute *attribute = NULL;
+      const gchar   *o_tag      = NULL;
+      gchar         *tag       = NULL;
+      gint           p;
+      gint           counter;
+
+      o_tag = artwork_entries[i].xmp_tag;
+
+      tag =g_strdup (o_tag);
+
+//      if (g_str_has_prefix (tag, "Xmp.iptcExt.Add"))
+//          g_print ("found\n");
+
+      p = string_index_of (tag, "[x]", 0);  /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gint    j;
+          gchar  *struct_string = NULL;
+
+          /* check last number */
+
+          struct_string = string_substring (tag, 0, p); /* get structure tag */
+
+          for (j = 0; j < G_N_ELEMENTS(struct_element); j++) /*get info about structure */
+            {
+              if (! g_strcmp0 (struct_string, struct_element[j].struct_tag))  /* is a structure */
+                {
+                  GimpAttribute *struct_attribute = NULL;
+                  gint num = highest_structure[struct_element[j].number_of_element];
+
+                  counter = 0;  /*start the loop */
+
+                  while (struct_attribute ||
+                         counter == 0     ||  /* at least once, because counter IS 0 */
+                         counter < num)       /* at least until the highest structure */
+                    {
+                      gchar           *nr_string = NULL;
+                      gchar           *new_tag = NULL;
+                      gchar           *value;
+
+                      counter ++;
+                      nr_string = g_strdup_printf ("[%d]", counter);
+                      new_tag = string_replace_str (tag, "[x]", nr_string);
+
+                      struct_attribute = gimp_attributes_get_attribute (attributes, new_tag);
+
+                      if (struct_attribute)
+                        {
+                          gint sct;
+                          value = gimp_attribute_get_string (struct_attribute);
+
+                          for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                            {
+                              if (g_str_has_prefix (new_tag, struct_element[sct].struct_tag))
+                                {
+                                  highest_structure[struct_element[sct].number_of_element] = counter;
+                                  break;
+                                }
+                            }
+                          g_hash_table_insert (elements_table,
+                                               (gpointer) g_strdup (new_tag),
+                                               (gpointer) g_strdup (value));
+
+                          gimp_attributes_remove_attribute (attributes, new_tag);
+                          g_free (value);
+                        }
+                      g_free (nr_string);
+                      g_free (new_tag);
+                    }
+                  break;
+                }
+            }
+        }
+      else
+        {
+          attribute = gimp_attributes_get_attribute (attributes, tag);
+          if (attribute)
+            {
+              gchar *value = gimp_attribute_get_string (attribute);
+              g_hash_table_insert (elements_table,
+                                   (gpointer) g_strdup (artwork_entries[i].xmp_tag),
+                                   (gpointer) g_strdup (value));
+
+              gimp_attributes_remove_attribute (attributes, artwork_entries[i].xmp_tag);
+              g_free (value);
+            }
+        }
+      g_free (tag);
+    }
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (highest_structure[sct] > 0)
+        curr_shown_structure[sct] = 1;
+      else
+        curr_shown_structure[sct] = 0;
+    }
+
+  page_artwork_init_combobox (builder);
+
+  page_artwork_set_to_ui (builder,
+                              -1); /* all */
+}
+
+void
+page_artwork_save_to_attributes (GimpAttributes *attributes)
+{
+  GHashTableIter     iter;
+  gpointer           key, value;
+
+
+  g_hash_table_iter_init (&iter, elements_table);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      GimpAttribute                   *attribute     = NULL;
+      gchar                           *tag = (gchar *) key;
+      gchar                           *value         = NULL;
+      gint                             p;
+      gint                             sct;
+      gint i;
+
+      value = (gchar *) g_hash_table_lookup (elements_table, (gpointer) tag);
+      attribute = gimp_attribute_new_string (tag, value, TYPE_ASCII);
+
+      if (attribute)
+        {
+          p = string_index_of (tag, "[", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes! */
+            {
+
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (tag, struct_element[sct].struct_tag))
+                    {
+                      gimp_attribute_set_structure_type (attribute, struct_element[sct].struct_type);
+                      break;
+                    }
+                }
+            }
+
+          for (i = 0; i < G_N_ELEMENTS(artwork_entries); i++)
+            {
+              gchar *t_tag;
+              gint   p1;
+              gint   p2;
+
+              p1 = string_index_of (tag, "[", 0);                           /* is it a structure tag? */
+              if (p > -1) /* yes! */
+                {
+                  gchar *t1;
+                  gchar *t2;
+                  gint   l;
+
+                  p2 = string_index_of (tag, "]", p1);
+
+                  l = strlen (tag);
+
+                  t1 = string_substring (tag, 0, p);
+                  t2 = string_substring (tag, p2 + 1, l - (p2 + 1));
+
+                  t_tag = g_strdup_printf ("%s[x]%s", t1, t2);
+                }
+              else
+                {
+                  t_tag = g_strdup (tag);
+                }
+
+
+              if (! g_strcmp0 (t_tag, artwork_entries[i].xmp_tag))
+                {
+                  if (artwork_entries[i].number_of_comboarray > -1)
+                    {
+                      gint combobox_data_counter;
+                      gint array_length;
+                      gint number_in_comboarray = artwork_entries[i].number_of_comboarray;
+
+                      array_length = G_N_ELEMENTS(combobox_data[number_in_comboarray]);
+
+                      for (combobox_data_counter = 0; combobox_data_counter < array_length; 
combobox_data_counter++)
+                        {
+                          const gchar  *val_in_tag = 
combobox_data[number_in_comboarray][combobox_data_counter].val_in_tag;
+                          const gchar  *interpreted_val;
+
+                          if (! val_in_tag)
+                            break;
+
+                          if (! g_strcmp0 (value, val_in_tag))
+                            {
+                              interpreted_val =  
combobox_data[number_in_comboarray][combobox_data_counter].val_in_combo;
+                              gimp_attribute_set_interpreted_string (attribute, interpreted_val);
+                              break;
+                            }
+                        }
+                    }
+                  break;
+                }
+            }
+          gimp_attributes_add_attribute (attributes, attribute);
+        }
+    }
+}
+
+static void
+page_artwork_entry_activate_cb (GtkWidget *widget, gpointer userdata)
+{
+  const gchar *entry_name = (const gchar *) userdata;
+  const gchar *value      = gtk_entry_get_text (GTK_ENTRY (widget));
+
+  page_artwork_store_in_hash_table (entry_name, value, 0);
+}
+
+static gboolean
+page_artwork_entry_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer userdata)
+{
+  const gchar *entry_name = (const gchar *) userdata;
+  const gchar *value      = gtk_entry_get_text (GTK_ENTRY (widget));
+
+  page_artwork_store_in_hash_table (entry_name, value, 0);
+
+  return FALSE;
+}
+
+static void
+page_artwork_entry_combo_changed_callback (GtkWidget *combo, gpointer userdata)
+{
+  const gchar *widget_name;
+  const gchar *value;
+  gint         array_nr   = GPOINTER_TO_INT (userdata);
+  gint         index      = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+
+  value = combobox_data[array_nr][index].val_in_tag;
+  widget_name = gtk_widget_get_name (GTK_WIDGET (combo));
+
+  page_artwork_store_in_hash_table (widget_name, value, 0);
+}
+
+static gboolean
+page_artwork_store_in_hash_table (const gchar *entry_name, const gchar *value, gint nr)
+{
+  gint           i;
+  const gchar   *o_tag;
+  gint           p;
+  gint           number = 0;
+  gboolean       success;
+
+  g_return_val_if_fail (entry_name != NULL, FALSE);
+
+  if (nr > 0)
+    number = nr;
+
+  success = FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS(artwork_entries); i++)
+    {
+      if (! g_strcmp0 (entry_name, artwork_entries[i].ui_entry))
+        {
+          gchar   *new_tag;
+          gchar   *nr_string;
+
+          o_tag = artwork_entries[i].xmp_tag;
+
+          new_tag =g_strdup (o_tag);
+
+          p = string_index_of (new_tag, "[x]", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes */
+            {
+              gint sct;
+
+              if (number <= 0)
+                {
+                  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                    {
+                      if (g_strcmp0 (o_tag, struct_element[sct].struct_tag))
+                        {
+                          number = curr_shown_structure[struct_element[sct].number_of_element];
+                          break;
+                        }
+                    }
+                }
+
+              nr_string = g_strdup_printf ("[%d]", number);
+              new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              g_free (nr_string);
+              if (number <=0 )
+                {
+                  g_free (new_tag);
+                  return FALSE;
+                }
+            }
+
+          if (value && g_strcmp0 (value, ""))
+            {
+              if (g_hash_table_insert (elements_table, (gpointer) g_strdup (new_tag), (gpointer) g_strdup 
(value)))
+                success = TRUE;
+            }
+          else
+            {
+              if (g_hash_table_remove (elements_table, (gpointer) new_tag))
+                success = TRUE;
+            }
+
+          set_save_attributes_button_sensitive (TRUE);
+
+          g_free (new_tag);
+          break;
+        }
+    }
+  return success;
+}
+
+static void
+page_artwork_structure_add (GtkButton *button, gpointer userdata)
+{
+  gint             number_to_add;
+  GtkComboBox     *combo;
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  const gchar     *widget_name;
+  gchar           *line;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].add_widget))
+        {
+          page_artwork_structure_save (builder, struct_element[sct].number_of_element);
+          number_to_add = ++highest_structure[struct_element[sct].number_of_element];
+
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          line = g_strdup_printf ("%s [%d]", struct_element[sct].identifier, number_to_add);
+          curr_shown_structure [struct_element[sct].number_of_element] = number_to_add;
+
+          repaint = struct_element[sct].number_of_element;
+
+          g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_artwork_combobox_changed_callback), builder);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+
+          gtk_combo_box_set_active (combo, number_to_add-1);
+
+          if (number_to_add == 1)
+            page_artwork_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+
+          g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_artwork_combobox_changed_callback), builder);
+
+          g_free (line);
+          break;
+       }
+    }
+
+  page_artwork_set_to_ui (builder, repaint);
+}
+
+static void
+page_artwork_structure_remove (GtkButton *button, gpointer userdata)
+{
+  GtkBuilder      *builder           = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GHashTableIter   iter_remove;
+  gboolean         found;
+  gchar           *nr_string;
+  gchar           *nr_string_new;
+  gpointer         key, value;
+  GSList          *delete_key_list   = NULL;
+  GSList          *list;
+  gchar           *tag_prefix;
+  gchar           *new_key;
+  gint             number_to_delete;
+  GtkComboBox     *combo;
+  GtkTreeIter      combo_iter;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+  gint             combo_to_del;
+
+  GHashTable           *reorder_table;
+
+  reorder_table = g_hash_table_new_full  (g_str_hash, g_str_equal, g_free, g_free);
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].remove_widget))
+        {
+          number_to_delete = curr_shown_structure[sct];
+          tag_prefix = g_strdup (struct_element[sct].struct_tag);
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          combo_to_del = highest_structure[sct] - 1;
+
+          if (number_to_delete == highest_structure[struct_element[sct].number_of_element])
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete - 1;
+          else
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete;
+
+          highest_structure[sct]--;
+          repaint = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr_string = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete);
+
+  /* remove entries */
+  {
+
+    g_hash_table_iter_init (&iter_remove, elements_table);
+    while (g_hash_table_iter_next (&iter_remove, &key, &value))
+      {
+        gchar *tag = (gchar *) key;
+        if (g_str_has_prefix (tag, nr_string))
+          {
+            delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+          }
+      }
+
+    for (list = delete_key_list; list; list = list->next)
+      {
+        gchar *key = (gchar *) list->data;
+        g_hash_table_remove (elements_table, key);
+      }
+
+    g_slist_free_full (delete_key_list, g_free);
+
+  }
+  /* reorder entries */
+
+  found = TRUE;
+
+  {
+    while (found) /* first: element table */
+      {
+        GHashTableIter   iter_reorder;
+
+        delete_key_list = NULL;
+        found           = FALSE;
+
+        nr_string_new = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete + 1);
+
+        g_hash_table_iter_init (&iter_reorder, elements_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            if (g_str_has_prefix (tag, nr_string_new))
+              {
+                found = TRUE;
+                new_key = string_replace_str (tag, nr_string_new, nr_string);
+                g_hash_table_insert (reorder_table, g_strdup (new_key), g_strdup (tag_value));
+                delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+              }
+          }
+
+        for (list = delete_key_list; list; list = list->next)
+          {
+            gchar *key = (gchar *) list->data;
+            g_hash_table_remove (elements_table, key);
+          }
+        g_slist_free_full (delete_key_list, g_free);
+
+        g_hash_table_iter_init (&iter_reorder, reorder_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            g_hash_table_insert (elements_table, g_strdup (tag), g_strdup (tag_value));
+          }
+
+        g_hash_table_remove_all (reorder_table);
+
+        nr_string = g_strdup (nr_string_new);
+        number_to_delete ++;
+      }
+
+  }
+
+  g_free (tag_prefix);
+  g_free (nr_string);
+  g_free (nr_string_new);
+  g_free (new_key);
+
+  g_hash_table_unref (reorder_table);
+
+  g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK (page_artwork_combobox_changed_callback), 
builder);
+
+  gtk_combo_box_set_active (combo, combo_to_del);
+  if (gtk_combo_box_get_active_iter (combo, &combo_iter))
+    gtk_list_store_remove (liststore, &combo_iter);
+
+  if (curr_shown_structure[repaint] == 0)
+    page_artwork_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+  else
+    gtk_combo_box_set_active (combo, curr_shown_structure[repaint] - 1);
+
+  g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK (page_artwork_combobox_changed_callback), 
builder);
+
+  page_artwork_set_to_ui (builder, repaint);
+}
+
+static void
+page_artwork_combobox_changed_callback (GtkWidget *combo, gpointer userdata)
+{
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkComboBox     *combobox;
+  gint             nr;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (combo));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].struct_combo_widget))
+        {
+          page_artwork_structure_save (builder, struct_element[sct].number_of_element);
+          combobox = GTK_COMBO_BOX (get_widget_from_label (builder, 
struct_element[sct].struct_combo_widget));
+          repaint  = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr = gtk_combo_box_get_active (combobox);
+  nr++;
+  curr_shown_structure[repaint] = nr;
+
+  page_artwork_set_to_ui (builder, repaint);
+}
+
+static void
+page_artwork_structure_save (GtkBuilder *builder, gint struct_number)
+{
+  gint         i;
+  const gchar *prefix = struct_element[struct_number].struct_tag;
+
+  for (i = 0; i < G_N_ELEMENTS(artwork_entries); i++)
+    {
+      GObject       *obj;
+      gchar         *tag      = NULL;
+      const gchar   *o_tag;
+
+      if (curr_shown_structure[struct_number] > 0)
+        {
+          o_tag = artwork_entries[i].xmp_tag;
+          if (g_str_has_prefix (o_tag, prefix))
+            {
+              gchar *nr_string;
+
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[struct_number]);
+              tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              obj   = get_widget_from_label (builder, artwork_entries[i].ui_entry);
+
+              switch (artwork_entries[i].widget_type)
+              {
+                case WIDGET_TYPE_ENTRY:
+                  {
+                    gchar *value;
+                    value = g_strdup (gtk_entry_get_text (GTK_ENTRY (obj)));
+                    if (value && g_strcmp0 (value, ""))
+                      g_hash_table_insert (elements_table, (gpointer) g_strdup (tag), (gpointer) g_strdup 
(value));
+                    else
+                      g_hash_table_remove (elements_table, (gpointer) tag);
+                  }
+                  break;
+                case WIDGET_TYPE_COMBOBOX:
+                  break;
+                default:
+                  break;
+              }
+
+              g_free (nr_string);
+              g_free (tag);
+            }
+        }
+    }
+}
+
+static void
+page_artwork_set_to_ui (GtkBuilder *builder, gint repaint)
+{
+  gint         i;
+  gint         sct;
+  const gchar *prefix;
+
+  if (repaint != -1)
+    prefix = struct_element[repaint].struct_tag;
+  else
+    prefix = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS(artwork_entries); i++)
+    {
+      GObject       *obj;
+      const gchar   *o_tag;
+      gchar         *value = NULL;
+      gchar         *new_tag;
+      gint           p;
+
+      o_tag = artwork_entries[i].xmp_tag;
+
+      obj = get_widget_from_label (builder, artwork_entries[i].ui_entry);
+
+      if (prefix)
+        {
+          if (! g_str_has_prefix (o_tag, prefix))
+            continue;
+        }
+
+      p = string_index_of (o_tag, "[x]", 0);     /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gchar         *nr_string;
+
+          if (repaint != -1)
+            {
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[repaint]);
+            }
+          else
+            {
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (o_tag, struct_element[sct].struct_tag))
+                    {
+                      nr_string = g_strdup_printf ("[%d]", curr_shown_structure[sct]);
+                      break;
+                    }
+                }
+            }
+
+          new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+          g_free (nr_string);
+        }
+      else
+        {
+          new_tag = g_strdup (o_tag);
+        }
+
+      value = (gchar *) g_hash_table_lookup (elements_table, new_tag);
+
+      switch (artwork_entries[i].widget_type)
+      {
+        case WIDGET_TYPE_ENTRY:
+          {
+           gtk_entry_set_text (GTK_ENTRY (obj), "");
+          }
+          break;
+        default:
+          break;
+      }
+
+      if (value)
+        {
+          switch (artwork_entries[i].widget_type)
+          {
+            case WIDGET_TYPE_ENTRY:
+              {
+               gtk_entry_set_text (GTK_ENTRY (obj), value);
+              }
+              break;
+            case WIDGET_TYPE_COMBOBOX:
+              {
+                gint combobox_data_counter;
+                gint array_length;
+                gint number_in_comboarray = artwork_entries[i].number_of_comboarray;
+
+                array_length = G_N_ELEMENTS(combobox_data[number_in_comboarray]);
+
+                for (combobox_data_counter = 0; combobox_data_counter < array_length; 
combobox_data_counter++)
+                  {
+                    const gchar  *val_in_tag = 
combobox_data[number_in_comboarray][combobox_data_counter].val_in_tag;
+
+                    if (! val_in_tag)
+                      break;
+
+                    if (! g_strcmp0 (value, val_in_tag))
+                      {
+                        g_signal_handlers_block_by_func (obj,
+                                                         G_CALLBACK 
(page_artwork_entry_combo_changed_callback),
+                                                         GINT_TO_POINTER (number_in_comboarray));
+
+                        gtk_combo_box_set_active (GTK_COMBO_BOX (obj), combobox_data_counter);
+
+                        g_signal_handlers_unblock_by_func (obj,
+                                                           G_CALLBACK 
(page_artwork_entry_combo_changed_callback),
+                                                           GINT_TO_POINTER (number_in_comboarray));
+                        break;
+                      }
+                  }
+              }
+              break;
+            default:
+              break;
+          }
+        }
+      g_free (new_tag);
+    }
+}
+
+static void
+page_artwork_init_combobox (GtkBuilder *builder)
+{
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  GtkComboBox     *combo;
+  gint             sct;
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      gchar *line;
+      gint   i;
+      gint   high;
+      gint   active;
+
+      liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+      combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+
+      high = highest_structure[struct_element[sct].number_of_element];
+      active = curr_shown_structure[struct_element[sct].number_of_element];
+
+      g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_artwork_combobox_changed_callback), builder);
+
+      for (i = 0; i < high; i++)
+        {
+          line = g_strdup_printf ("%s [%d]",struct_element[sct].identifier, i + 1);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+          g_free (line);
+        }
+
+      gtk_combo_box_set_active (combo, active-1);
+
+      if (active >= 1)
+        page_artwork_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+      else
+        page_artwork_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+
+      g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_artwork_combobox_changed_callback), builder);
+
+    }
+}
diff --git a/plug-ins/metainfo/page-artwork.h b/plug-ins/metainfo/page-artwork.h
new file mode 100644
index 0000000..7b3ce1a
--- /dev/null
+++ b/plug-ins/metainfo/page-artwork.h
@@ -0,0 +1,33 @@
+/* page-artwork.h
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PAGE_ARTWORK_H__
+#define __PAGE_ARTWORK_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void                          page_artwork_read_from_attributes       (GimpAttributes        *attributes,
+                                                                       GtkBuilder            *builder);
+void                          page_artwork_save_to_attributes         (GimpAttributes        *attributes);
+
+G_END_DECLS
+
+#endif /* __PAGE_ARTWORK_H__ */
diff --git a/plug-ins/metainfo/page-description.c b/plug-ins/metainfo/page-description.c
new file mode 100644
index 0000000..e24fc82
--- /dev/null
+++ b/plug-ins/metainfo/page-description.c
@@ -0,0 +1,927 @@
+/* page-description.c
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+#include "metainfo-helper.h"
+#include "page-description.h"
+
+
+static void                page_description_init_ui                    (GtkBuilder        *builder);
+static void                page_description_set_entry_sensitive        (GtkBuilder        *builder,
+                                                                        const gchar       *struct_name,
+                                                                        gboolean           sensitive);
+static void                page_description_init_combobox              (GtkBuilder        *builder);
+static void                page_description_set_to_ui                  (GtkBuilder        *builder,
+                                                                        gint               repaint);
+static void                page_description_entry_activate_cb          (GtkWidget         *widget,
+                                                                        gpointer           userdata);
+static gboolean            page_description_entry_focus_out_cb         (GtkWidget         *widget,
+                                                                        GdkEvent          *event,
+                                                                        gpointer           userdata);
+static gboolean            page_description_store_in_hash_table        (gchar             *entry_name,
+                                                                        gchar             *value,
+                                                                        gint               nr);
+static void                page_description_structure_add              (GtkButton         *button,
+                                                                        gpointer           userdata);
+static void                page_description_structure_remove           (GtkButton         *button,
+                                                                        gpointer           userdata);
+static void                page_description_combobox_changed_callback  (GtkWidget         *button,
+                                                                        gpointer           userdata);
+static void                page_description_structure_save             (GtkBuilder        *builder,
+                                                                        gint               struct_number);
+
+
+#define STRUCTURES_ON_PAGE 2
+
+
+static GHashTable           *elements_table;
+static gint                  curr_shown_structure[STRUCTURES_ON_PAGE];
+static gint                  highest_structure[STRUCTURES_ON_PAGE];
+
+static StructureElement struct_element [] =
+    {
+        {0,
+            N_("Location created"),
+            "Xmp.iptcExt.LocationCreated",
+            STRUCTURE_TYPE_BAG,
+            "location-created-combo",
+            "location-created-liststore",
+            "location-created-button-plus",
+            "location-created-button-minus"},
+
+        {1,
+            N_("Location shown"),
+            "Xmp.iptcExt.LocationShown",
+            STRUCTURE_TYPE_SEQ,
+            "location-shown-combo",
+            "location-shown-liststore",
+            "location-shown-button-plus",
+            "location-shown-button-minus"}
+    };
+
+static MetadataEntry description_entries[] =
+    {
+        {N_("Person in image"),
+            "personinimage-label",
+            "personinimage-entry",
+            "Xmp.iptcExt.PersonInImage",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Event"),
+            "event-label",
+            "event-entry",
+            "Xmp.iptcExt.Event",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Sublocation"),
+            "location-created-sublocation-label",
+            "location-created-sublocation-entry",
+            "Xmp.iptcExt.LocationCreated[x]/iptcExt:Sublocation",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("City"),
+            "location-created-city-label",
+            "location-created-city-entry",
+            "Xmp.iptcExt.LocationCreated[x]/iptcExt:City",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Province/State"),
+            "location-created-provincestate-label",
+            "location-created-provincestate-entry",
+            "Xmp.iptcExt.LocationCreated[x]/iptcExt:ProvinceState",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Countryname"),
+            "location-created-countryname-label",
+            "location-created-countryname-entry",
+            "Xmp.iptcExt.LocationCreated[x]/iptcExt:CountryName",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Countrycode"),
+            "location-created-countrycode-label",
+            "location-created-countrycode-entry",
+            "Xmp.iptcExt.LocationCreated[x]/iptcExt:CountryCode",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Worldregion"),
+            "location-created-worldregion-label",
+            "location-created-worldregion-entry",
+            "Xmp.iptcExt.LocationCreated[x]/iptcExt:WorldRegion",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+
+        {N_("Sublocation"),
+            "location-shown-sublocation-label",
+            "location-shown-sublocation-entry",
+            "Xmp.iptcExt.LocationShown[x]/iptcExt:Sublocation",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("City"),
+            "location-shown-city-label",
+            "location-shown-city-entry",
+            "Xmp.iptcExt.LocationShown[x]/iptcExt:City",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Province/State"),
+            "location-shown-provincestate-label",
+            "location-shown-provincestate-entry",
+            "Xmp.iptcExt.LocationShown[x]/iptcExt:ProvinceState",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Countryname"),
+            "location-shown-countryname-label",
+            "location-shown-countryname-entry",
+            "Xmp.iptcExt.LocationShown[x]/iptcExt:CountryName",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Countrycode"),
+            "location-shown-countrycode-label",
+            "location-shown-countrycode-entry",
+            "Xmp.iptcExt.LocationShown[x]/iptcExt:CountryCode",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Worldregion"),
+            "location-shown-worldregion-label",
+            "location-shown-worldregion-entry",
+            "Xmp.iptcExt.LocationShown[x]/iptcExt:WorldRegion",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Name"),
+            "orginimage-name-label",
+            "orginimage-name-entry",
+            "Xmp.iptcExt.OrganisationInImageName",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Code"),
+            "orginimage-code-label",
+            "orginimage-code-entry",
+            "Xmp.iptcExt.OrganisationInImageCode",
+            WIDGET_TYPE_ENTRY,
+            -1}
+    };
+
+
+static void
+page_description_init_ui (GtkBuilder *builder)
+{
+  GObject *obj;
+  gint     i;
+
+  elements_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  for (i = 0; i < G_N_ELEMENTS(description_entries); i++)
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, description_entries[i].ui_label));
+
+      gtk_label_set_text (GTK_LABEL (obj), description_entries[i].label);
+
+      obj = G_OBJECT (get_widget_from_label (builder, description_entries[i].ui_entry));
+      gtk_widget_set_name (GTK_WIDGET (obj), description_entries[i].ui_entry);
+      g_signal_connect (GTK_WIDGET (obj), "focus-out-event",
+                        G_CALLBACK (page_description_entry_focus_out_cb),
+                        (gpointer) description_entries[i].ui_entry);
+      g_signal_connect (GTK_ENTRY (obj), "activate",
+                        G_CALLBACK (page_description_entry_activate_cb),
+                        (gpointer) description_entries[i].ui_entry);
+    }
+
+  for (i = 0; i < G_N_ELEMENTS(struct_element); i++) /*get info about structure */
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].add_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].add_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_description_structure_add),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].remove_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].remove_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_description_structure_remove),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].struct_combo_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].struct_combo_widget);
+      g_signal_connect (obj, "changed", G_CALLBACK (page_description_combobox_changed_callback), builder);
+    }
+}
+
+static void
+page_description_set_entry_sensitive (GtkBuilder  *builder,
+                                      const gchar *struct_name,
+                                      gboolean     sensitive)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS(description_entries); i++)
+    {
+      const gchar   *tag;
+      GObject       *obj;
+
+      tag = description_entries[i].xmp_tag;
+      if (g_str_has_prefix (tag, struct_name))
+        {
+          obj = G_OBJECT (get_widget_from_label (builder, description_entries[i].ui_entry));
+          gtk_widget_set_sensitive (GTK_WIDGET (obj), sensitive);
+        }
+    }
+
+}
+
+void
+page_description_read_from_attributes (GimpAttributes *attributes,
+                                       GtkBuilder     *builder)
+{
+  gint i;
+  gint sct;
+
+  g_return_if_fail (attributes != NULL);
+
+  page_description_init_ui (builder);
+
+  for (i = 0; i < G_N_ELEMENTS(description_entries); i++)
+    {
+      GimpAttribute *attribute = NULL;
+      const gchar   *o_tag      = NULL;
+      gchar         *tag       = NULL;
+      gint           p;
+      gint           counter;
+
+      o_tag = description_entries[i].xmp_tag;
+
+      tag =g_strdup (o_tag);
+
+      p = string_index_of (tag, "[x]", 0);                           /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gint    j;
+          gchar  *struct_string = NULL;
+
+          /* check last number */
+
+          struct_string = string_substring (tag, 0, p); /* get structure tag */
+
+          for (j = 0; j < G_N_ELEMENTS(struct_element); j++) /*get info about structure */
+            {
+              if (! g_strcmp0 (struct_string, struct_element[j].struct_tag))  /* is a structure */
+                {
+                  GimpAttribute *struct_attribute = NULL;
+                   gint num = highest_structure[struct_element[j].number_of_element];
+
+                  counter = 0;  /*start the loop */
+
+                  while (struct_attribute ||
+                         counter == 0     ||  /* at least once, because counter IS 0 */
+                         counter < num)       /* at least until the highest structure */
+                    {
+                      gchar           *nr_string = NULL;
+                      gchar           *new_tag = NULL;
+                      gchar           *value;
+
+                      counter ++;
+                      nr_string = g_strdup_printf ("[%d]", counter);
+                      new_tag = string_replace_str (tag, "[x]", nr_string);
+
+                      struct_attribute = gimp_attributes_get_attribute (attributes, new_tag);
+
+                      if (struct_attribute)
+                        {
+                          gint sct;
+                          value = gimp_attribute_get_string (struct_attribute);
+
+                          for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                            {
+                              if (g_str_has_prefix (new_tag, struct_element[sct].struct_tag))
+                                {
+                                  highest_structure[struct_element[sct].number_of_element] = counter;
+                                  break;
+                                }
+                            }
+                          g_hash_table_insert (elements_table,
+                                               (gpointer) g_strdup (new_tag),
+                                               (gpointer) g_strdup (value));
+
+                          gimp_attributes_remove_attribute (attributes, new_tag);
+                          g_free (value);
+                        }
+                      g_free (nr_string);
+                      g_free (new_tag);
+                    }
+                  break;
+                }
+            }
+        }
+      else
+        {
+          attribute = gimp_attributes_get_attribute (attributes, tag);
+          if (attribute)
+            {
+              gchar *value = gimp_attribute_get_string (attribute);
+              g_hash_table_insert (elements_table,
+                                   (gpointer) g_strdup (description_entries[i].xmp_tag),
+                                   (gpointer) g_strdup (value));
+
+              gimp_attributes_remove_attribute (attributes, description_entries[i].xmp_tag);
+              g_free (value);
+            }
+        }
+      g_free (tag);
+    }
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (highest_structure[sct] > 0)
+        curr_shown_structure[sct] = 1;
+      else
+        curr_shown_structure[sct] = 0;
+    }
+
+  page_description_init_combobox (builder);
+
+  page_description_set_to_ui (builder,
+                              -1); /* all */
+}
+
+void
+page_description_save_to_attributes (GimpAttributes *attributes)
+{
+  GHashTableIter     iter;
+  gpointer           key, value;
+
+
+  g_hash_table_iter_init (&iter, elements_table);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      GimpAttribute                   *attribute     = NULL;
+      gchar                           *tag = (gchar *) key;
+      gchar                           *value         = NULL;
+      gint                             p;
+      gint                             sct;
+
+      value = (gchar *) g_hash_table_lookup (elements_table, (gpointer) tag);
+      attribute = gimp_attribute_new_string (tag, value, TYPE_ASCII);
+
+      if (attribute)
+        {
+          p = string_index_of (tag, "[", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes! */
+            {
+
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (tag, struct_element[sct].struct_tag))
+                    {
+                      gimp_attribute_set_structure_type (attribute, struct_element[sct].struct_type);
+                      break;
+                    }
+                }
+            }
+
+          gimp_attributes_add_attribute (attributes, attribute);
+        }
+    }
+}
+
+static void
+page_description_entry_activate_cb (GtkWidget *widget, gpointer userdata)
+{
+  gchar *entry_name = (gchar *) userdata;
+  gchar *value      = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
+
+  page_description_store_in_hash_table (entry_name, value, 0);
+}
+
+static gboolean
+page_description_entry_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer userdata)
+{
+  gchar *entry_name = (gchar *) userdata;
+  gchar *value      = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget)));
+
+  page_description_store_in_hash_table (entry_name, value, 0);
+
+  return FALSE;
+}
+
+static gboolean
+page_description_store_in_hash_table (gchar *entry_name, gchar *value, gint nr)
+{
+  gint     i;
+  const gchar   *o_tag;
+  gint     p;
+  gint     number = 0;
+  gboolean success;
+
+  g_return_val_if_fail (entry_name != NULL, FALSE);
+
+  if (nr > 0)
+    number = nr;
+
+  success = FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS(description_entries); i++)
+    {
+      if (! g_strcmp0 (entry_name, description_entries[i].ui_entry))
+        {
+          gchar   *new_tag;
+          gchar   *nr_string;
+
+          o_tag = description_entries[i].xmp_tag;
+
+          new_tag =g_strdup (o_tag);
+
+          p = string_index_of (new_tag, "[x]", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes */
+            {
+              gint sct;
+
+              if (number <= 0)
+                {
+                  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                    {
+                      if (g_strcmp0 (o_tag, struct_element[sct].struct_tag))
+                        {
+                          number = curr_shown_structure[struct_element[sct].number_of_element];
+                          break;
+                        }
+                    }
+                }
+
+              nr_string = g_strdup_printf ("[%d]", number);
+              new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              g_free (nr_string);
+
+              if (number <= 0)
+                {
+                  g_free (new_tag);
+                  return FALSE;
+                }
+            }
+
+          if (value && g_strcmp0 (value, ""))
+            {
+              if (g_hash_table_insert (elements_table, (gpointer) g_strdup (new_tag), (gpointer) g_strdup 
(value)))
+                success = TRUE;
+            }
+          else
+            {
+              if (g_hash_table_remove (elements_table, (gpointer) new_tag))
+                success = TRUE;
+            }
+
+          set_save_attributes_button_sensitive (TRUE);
+
+          g_free (new_tag);
+          break;
+        }
+    }
+  return success;
+}
+
+static void
+page_description_structure_add (GtkButton *button, gpointer userdata)
+{
+  gint             number_to_add;
+  GtkComboBox     *combo;
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  const gchar     *widget_name;
+  gchar           *line;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].add_widget))
+        {
+          page_description_structure_save (builder, struct_element[sct].number_of_element);
+          number_to_add = ++highest_structure[struct_element[sct].number_of_element];
+
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          line = g_strdup_printf ("%s [%d]", struct_element[sct].identifier, number_to_add);
+          curr_shown_structure [struct_element[sct].number_of_element] = number_to_add;
+
+          repaint = struct_element[sct].number_of_element;
+
+          g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_description_combobox_changed_callback), builder);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+
+          gtk_combo_box_set_active (combo, number_to_add-1);
+
+          if (number_to_add == 1)
+            page_description_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+
+          g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_description_combobox_changed_callback), builder);
+
+          g_free (line);
+          break;
+       }
+    }
+
+  page_description_set_to_ui (builder, repaint);
+}
+
+static void
+page_description_structure_remove (GtkButton *button, gpointer userdata)
+{
+  GtkBuilder      *builder           = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GHashTableIter   iter_remove;
+  gboolean         found;
+  gchar           *nr_string;
+  gchar           *nr_string_new;
+  gpointer         key, value;
+  GSList          *delete_key_list   = NULL;
+  GSList          *list;
+  gchar           *tag_prefix;
+  gchar           *new_key;
+  gint             number_to_delete;
+  GtkComboBox     *combo;
+  GtkTreeIter      combo_iter;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+  gint             combo_to_del;
+
+  GHashTable           *reorder_table;
+
+  reorder_table = g_hash_table_new_full  (g_str_hash, g_str_equal, g_free, g_free);
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].remove_widget))
+        {
+          number_to_delete = curr_shown_structure[sct];
+          tag_prefix = g_strdup (struct_element[sct].struct_tag);
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          combo_to_del = highest_structure[sct] - 1;
+
+          if (number_to_delete == highest_structure[struct_element[sct].number_of_element])
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete - 1;
+          else
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete;
+
+          highest_structure[sct]--;
+          repaint = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr_string = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete);
+
+  /* remove entries */
+  {
+
+    g_hash_table_iter_init (&iter_remove, elements_table);
+    while (g_hash_table_iter_next (&iter_remove, &key, &value))
+      {
+        gchar *tag = (gchar *) key;
+        if (g_str_has_prefix (tag, nr_string))
+          {
+            delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+          }
+      }
+
+    for (list = delete_key_list; list; list = list->next)
+      {
+        gchar *key = (gchar *) list->data;
+        g_hash_table_remove (elements_table, key);
+      }
+
+    g_slist_free_full (delete_key_list, g_free);
+
+  }
+  /* reorder entries */
+
+  found = TRUE;
+
+  {
+    while (found) /* first: element table */
+      {
+        GHashTableIter   iter_reorder;
+
+        delete_key_list = NULL;
+        found           = FALSE;
+
+        nr_string_new = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete + 1);
+
+        g_hash_table_iter_init (&iter_reorder, elements_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            if (g_str_has_prefix (tag, nr_string_new))
+              {
+                found = TRUE;
+                new_key = string_replace_str (tag, nr_string_new, nr_string);
+                g_hash_table_insert (reorder_table, g_strdup (new_key), g_strdup (tag_value));
+                delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+              }
+          }
+
+        for (list = delete_key_list; list; list = list->next)
+          {
+            gchar *key = (gchar *) list->data;
+            g_hash_table_remove (elements_table, key);
+          }
+        g_slist_free_full (delete_key_list, g_free);
+
+        g_hash_table_iter_init (&iter_reorder, reorder_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            g_hash_table_insert (elements_table, g_strdup (tag), g_strdup (tag_value));
+          }
+
+        g_hash_table_remove_all (reorder_table);
+
+        nr_string = g_strdup (nr_string_new);
+        number_to_delete ++;
+      }
+
+  }
+
+  g_free (tag_prefix);
+  g_free (nr_string);
+  g_free (nr_string_new);
+  g_free (new_key);
+
+  g_hash_table_unref (reorder_table);
+
+  g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_description_combobox_changed_callback), builder);
+
+  gtk_combo_box_set_active (combo, combo_to_del);
+  if (gtk_combo_box_get_active_iter (combo, &combo_iter))
+    gtk_list_store_remove (liststore, &combo_iter);
+
+  if (curr_shown_structure[repaint] == 0)
+    page_description_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+  else
+    gtk_combo_box_set_active (combo, curr_shown_structure[repaint] - 1);
+
+  g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_description_combobox_changed_callback), builder);
+
+  page_description_set_to_ui (builder, repaint);
+}
+
+static void
+page_description_combobox_changed_callback (GtkWidget *combo, gpointer userdata)
+{
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkComboBox     *combobox;
+  gint             nr;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (combo));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].struct_combo_widget))
+        {
+          page_description_structure_save (builder, struct_element[sct].number_of_element);
+          combobox = GTK_COMBO_BOX (get_widget_from_label (builder, 
struct_element[sct].struct_combo_widget));
+          repaint  = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr = gtk_combo_box_get_active (combobox);
+  nr++;
+  curr_shown_structure[repaint] = nr;
+
+  page_description_set_to_ui (builder, repaint);
+}
+
+static void
+page_description_structure_save (GtkBuilder *builder, gint struct_number)
+{
+  gint         i;
+  const gchar *prefix = struct_element[struct_number].struct_tag;
+
+  for (i = 0; i < G_N_ELEMENTS(description_entries); i++)
+    {
+      GObject       *obj;
+      gchar         *tag      = NULL;
+      const gchar   *o_tag;
+
+      if (curr_shown_structure[struct_number] > 0)
+        {
+          o_tag = description_entries[i].xmp_tag;
+          if (g_str_has_prefix (o_tag, prefix))
+            {
+              gchar *nr_string;
+
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[struct_number]);
+              tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              obj   = get_widget_from_label (builder, description_entries[i].ui_entry);
+
+              switch (description_entries[i].widget_type)
+              {
+                case WIDGET_TYPE_ENTRY:
+                  {
+                    gchar *value;
+                    value = g_strdup (gtk_entry_get_text (GTK_ENTRY (obj)));
+                    if (value && g_strcmp0 (value, ""))
+                      g_hash_table_insert (elements_table, (gpointer) g_strdup (tag), (gpointer) g_strdup 
(value));
+                    else
+                      g_hash_table_remove (elements_table, (gpointer) tag);
+                  }
+                  break;
+                case WIDGET_TYPE_COMBOBOX: /*no combobox in "description" */
+                  break;
+                default:
+                  break;
+              }
+
+              g_free (nr_string);
+              g_free (tag);
+            }
+        }
+    }
+}
+
+static void
+page_description_set_to_ui (GtkBuilder *builder, gint repaint)
+{
+  gint         i;
+  gint         sct;
+  const gchar *prefix;
+
+  if (repaint != -1)
+    prefix = struct_element[repaint].struct_tag;
+  else
+    prefix = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS(description_entries); i++)
+    {
+      GObject       *obj;
+      const gchar   *o_tag;
+      gchar         *value = NULL;
+      gchar         *new_tag;
+      gint           p;
+
+      o_tag = description_entries[i].xmp_tag;
+
+      obj = get_widget_from_label (builder, description_entries[i].ui_entry);
+
+      if (prefix)
+        {
+          if (! g_str_has_prefix (o_tag, prefix))
+            continue;
+        }
+
+      p = string_index_of (o_tag, "[x]", 0);                           /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gchar         *nr_string;
+
+          if (repaint != -1)
+            {
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[repaint]);
+            }
+          else
+            {
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (o_tag, struct_element[sct].struct_tag))
+                    {
+                      nr_string = g_strdup_printf ("[%d]", curr_shown_structure[sct]);
+                      break;
+                    }
+                }
+            }
+
+          new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+          g_free (nr_string);
+        }
+      else
+        {
+          new_tag = g_strdup (o_tag);
+        }
+
+      value = (gchar *) g_hash_table_lookup (elements_table, new_tag);
+      gtk_entry_set_text (GTK_ENTRY (obj), "");
+
+      if (value)
+        {
+          switch (description_entries[i].widget_type)
+          {
+            case WIDGET_TYPE_ENTRY:
+              {
+                gtk_entry_set_text (GTK_ENTRY (obj), value);
+              }
+              break;
+            case WIDGET_TYPE_COMBOBOX: /*no combobox in "description" */
+              break;
+            default:
+              break;
+          }
+        }
+      g_free (new_tag);
+    }
+}
+
+static void
+page_description_init_combobox (GtkBuilder *builder)
+{
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  GtkComboBox     *combo;
+  gint             sct;
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      gchar *line;
+      gint   i;
+      gint   high;
+      gint   active;
+
+      liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+      combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+
+      high = highest_structure[struct_element[sct].number_of_element];
+      active = curr_shown_structure[struct_element[sct].number_of_element];
+
+      g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_description_combobox_changed_callback), builder);
+
+      for (i = 0; i < high; i++)
+        {
+          line = g_strdup_printf ("%s [%d]",struct_element[sct].identifier, i + 1);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+          g_free (line);
+        }
+
+      gtk_combo_box_set_active (combo, active-1);
+
+      if (active >= 1)
+        page_description_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+      else
+        page_description_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+
+      g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_description_combobox_changed_callback), builder);
+
+    }
+}
diff --git a/plug-ins/metainfo/page-description.h b/plug-ins/metainfo/page-description.h
new file mode 100644
index 0000000..fecb0ca
--- /dev/null
+++ b/plug-ins/metainfo/page-description.h
@@ -0,0 +1,33 @@
+/* page-description.h
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PAGE_DESCRIPTION_H__
+#define __PAGE_DESCRIPTION_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void                          page_description_read_from_attributes       (GimpAttributes        *attributes,
+                                                                           GtkBuilder            *builder);
+void                          page_description_save_to_attributes         (GimpAttributes        
*attributes);
+
+G_END_DECLS
+
+#endif /* __PAGE_DESCRIPTION_H__ */
diff --git a/plug-ins/metainfo/page-rights.c b/plug-ins/metainfo/page-rights.c
new file mode 100644
index 0000000..2c292f9
--- /dev/null
+++ b/plug-ins/metainfo/page-rights.c
@@ -0,0 +1,1117 @@
+/* page-administration.c
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+#include "config.h"
+
+#include <libgimp/gimp.h>
+#include <libgimp/gimpui.h>
+
+#include "libgimp/stdplugins-intl.h"
+
+#include "metainfo-helper.h"
+#include "page-rights.h"
+
+
+static void                page_rights_init_ui                       (GtkBuilder        *builder);
+static void                page_rights_set_entry_sensitive           (GtkBuilder        *builder,
+                                                                      const gchar       *struct_name,
+                                                                      gboolean           sensitive);
+static void                page_rights_init_combobox                 (GtkBuilder        *builder);
+static void                page_rights_set_to_ui                     (GtkBuilder        *builder,
+                                                                      gint               repaint);
+static void                page_rights_entry_activate_cb             (GtkWidget         *widget,
+                                                                      gpointer           userdata);
+static gboolean            page_rights_entry_focus_out_cb            (GtkWidget         *widget,
+                                                                      GdkEvent          *event,
+                                                                      gpointer           userdata);
+static gboolean            page_rights_store_in_hash_table           (const gchar       *entry_name,
+                                                                      const gchar       *value,
+                                                                      gint               nr);
+static void                page_rights_structure_add                 (GtkButton         *button,
+                                                                      gpointer           userdata);
+static void                page_rights_structure_remove              (GtkButton         *button,
+                                                                      gpointer           userdata);
+static void                page_rights_entry_combo_changed_callback  (GtkWidget         *combo,
+                                                                      gpointer           userdata);
+static void                page_rights_combobox_changed_callback     (GtkWidget         *combo,
+                                                                      gpointer           userdata);
+static void                page_rights_structure_save                (GtkBuilder        *builder,
+                                                                      gint               struct_number);
+
+
+#define STRUCTURES_ON_PAGE 3
+#define COMBOBOX_WITH_DATA 1
+
+
+static GHashTable           *elements_table;
+static gint                  curr_shown_structure[STRUCTURES_ON_PAGE];
+static gint                  highest_structure[STRUCTURES_ON_PAGE];
+
+static StructureElement struct_element [] =
+    {
+        {0,
+            N_("Image creator"),
+            "Xmp.plus.ImageCreator",
+            STRUCTURE_TYPE_SEQ,
+            "imagecreator-combo",
+            "imagecreator-liststore",
+            "imagecreator-button-plus",
+            "imagecreator-button-minus"},
+
+        {1,
+            N_("Copyright Owner"),
+            "Xmp.plus.CopyrightOwner",
+            STRUCTURE_TYPE_SEQ,
+            "copyrightowner-combo",
+            "copyrightowner-liststore",
+            "copyrightowner-button-plus",
+            "copyrightowner-button-minus"},
+
+        {2,
+            N_("Licensor"),
+            "Xmp.plus.Licensor",
+            STRUCTURE_TYPE_BAG,
+            "licensor-combo",
+            "licensor-liststore",
+            "licensor-button-plus",
+            "licensor-button-minus"}
+    };
+
+
+static ComboBoxData combobox_data[][256] =
+{
+    {
+        {N_(" "),                                         ""},
+        {N_("None"),                                      "http://ns.useplus.org/ldf/vocab/PR-NON"},
+        {N_("Not applicable"),                            "http://ns.useplus.org/ldf/vocab/PR-NAP"},
+        {N_("Unlimited property release"),                "http://ns.useplus.org/ldf/vocab/PR-UPR"},
+        {N_("Limited or Incomplete Property Releases"),   "http://ns.useplus.org/ldf/vocab/PR-LPR"}
+    },
+};
+
+static MetadataEntry rights_entries[] =
+    {
+        {N_("Image creator name"),
+            "imagecreator-name-label",
+            "imagecreator-name-entry",
+            "Xmp.plus.ImageCreator[x]/plus:ImageCreatorName",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Image creator ID"),
+            "imagecreator-id-label",
+            "imagecreator-id-entry",
+            "Xmp.plus.ImageCreator[x]/plus:ImageCreatorID",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Copyright owner name"),
+            "copyrightowner-name-label",
+            "copyrightowner-name-entry",
+            "Xmp.plus.CopyrightOwner[x]/plus:CopyrightOwnerName",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Copyright owner ID"),
+            "copyrightowner-id-label",
+            "copyrightowner-id-entry",
+            "Xmp.plus.CopyrightOwner[x]/plus:CopyrightOwnerID",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Name"),
+            "licensor-name-label",
+            "licensor-name-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorName",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("ID"),
+            "licensor-id-label",
+            "licensor-id-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorID",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Address"),
+            "licensor-streetaddress-label",
+            "licensor-streetaddress-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorStreetAddress",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Extended Address"),
+            "licensor-extendedaddress-label",
+            "licensor-extendedaddress-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorExtendedAddress",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("City"),
+            "licensor-city-label",
+            "licensor-city-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorCity",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Region"),
+            "licensor-region-label",
+            "licensor-region-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorRegion",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Postal code"),
+            "licensor-postalcode-label",
+            "licensor-postalcode-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorPostalCode",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Country"),
+            "licensor-country-label",
+            "licensor-country-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorCountry",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Telephone 1"),
+            "licensor-telephone1-label",
+            "licensor-telephone1-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorTelephone1",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Telephone 2"),
+            "licensor-telephone2-label",
+            "licensor-telephone2-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorTelephone2",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("E-Mail"),
+            "licensor-email-label",
+            "licensor-email-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorEmail",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("URL"),
+            "licensor-url-label",
+            "licensor-url-entry",
+            "Xmp.plus.Licensor[x]/plus:LicensorURL",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Release ID"),
+            "release-id-label",
+            "release-id-entry",
+            "Xmp.plus.PropertyReleaseID",
+            WIDGET_TYPE_ENTRY,
+            -1},
+
+        {N_("Release status"),
+            "release-status-label",
+            "release-status-combobox",
+            "Xmp.plus.PropertyReleaseStatus",
+            WIDGET_TYPE_COMBOBOX,
+            0}
+    };
+
+
+static void
+page_rights_init_ui (GtkBuilder *builder)
+{
+  GObject *obj;
+  gint     i;
+
+  elements_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+  for (i = 0; i < G_N_ELEMENTS(rights_entries); i++)
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, rights_entries[i].ui_label));
+
+      gtk_label_set_text (GTK_LABEL (obj), rights_entries[i].label);
+
+      obj = G_OBJECT (get_widget_from_label (builder, rights_entries[i].ui_entry));
+      gtk_widget_set_name (GTK_WIDGET (obj), rights_entries[i].ui_entry);
+
+      if (rights_entries[i].widget_type == WIDGET_TYPE_ENTRY)
+        {
+          g_signal_connect (GTK_WIDGET (obj), "focus-out-event",
+                            G_CALLBACK (page_rights_entry_focus_out_cb),
+                            (gpointer) rights_entries[i].ui_entry);
+          g_signal_connect (GTK_ENTRY (obj), "activate",
+                            G_CALLBACK (page_rights_entry_activate_cb),
+                            (gpointer) rights_entries[i].ui_entry);
+        }
+      else if (rights_entries[i].widget_type == WIDGET_TYPE_COMBOBOX)
+        {
+          gint array_nr = rights_entries[i].number_of_comboarray;
+
+          if (array_nr >= 0)
+            {
+              gint i;
+              GtkTreeIter   iter;
+              GtkListStore *liststore;
+              gint array_length;
+
+              liststore = GTK_LIST_STORE(gtk_combo_box_get_model (GTK_COMBO_BOX (obj)));
+
+              array_length = G_N_ELEMENTS(combobox_data[array_nr]);
+
+              for (i = 0; i < array_length; i++) /*get info about structure */
+                {
+                  const gchar  *val_in_combo = combobox_data[array_nr][i].val_in_combo;
+
+                  if (! val_in_combo)
+                    break;
+
+                  gtk_list_store_append(liststore, &iter);
+
+                  gtk_list_store_set (liststore, &iter,
+                                      0, val_in_combo,
+                                      -1);
+                }
+
+              g_signal_connect (obj, "changed",
+                                G_CALLBACK (page_rights_entry_combo_changed_callback),
+                                GINT_TO_POINTER (array_nr));
+            }
+        }
+    }
+
+  for (i = 0; i < G_N_ELEMENTS(struct_element); i++) /*get info about structure */
+    {
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].add_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].add_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_rights_structure_add),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].remove_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].remove_widget);
+      g_signal_connect (obj, "clicked",
+                        G_CALLBACK (page_rights_structure_remove),
+                        builder);
+
+      obj = G_OBJECT (get_widget_from_label (builder, struct_element[i].struct_combo_widget));
+      gtk_widget_set_name (GTK_WIDGET (obj), struct_element[i].struct_combo_widget);
+      g_signal_connect (obj, "changed",
+                        G_CALLBACK (page_rights_combobox_changed_callback),
+                        builder);
+    }
+}
+
+static void
+page_rights_set_entry_sensitive (GtkBuilder  *builder,
+                                      const gchar *struct_name,
+                                      gboolean     sensitive)
+{
+  gint i;
+
+  for (i = 0; i < G_N_ELEMENTS(rights_entries); i++)
+    {
+      const gchar   *tag;
+      GObject       *obj;
+
+      tag = rights_entries[i].xmp_tag;
+      if (g_str_has_prefix (tag, struct_name))
+        {
+          obj = G_OBJECT (get_widget_from_label (builder, rights_entries[i].ui_entry));
+          gtk_widget_set_sensitive (GTK_WIDGET (obj), sensitive);
+        }
+    }
+
+}
+
+void
+page_rights_read_from_attributes (GimpAttributes *attributes,
+                                       GtkBuilder     *builder)
+{
+  gint i;
+  gint sct;
+
+  g_return_if_fail (attributes != NULL);
+
+  page_rights_init_ui (builder);
+
+  for (i = 0; i < G_N_ELEMENTS(rights_entries); i++)
+    {
+      GimpAttribute *attribute = NULL;
+      const gchar   *o_tag      = NULL;
+      gchar         *tag       = NULL;
+      gint           p;
+      gint           counter;
+
+      o_tag = rights_entries[i].xmp_tag;
+
+      tag =g_strdup (o_tag);
+
+//      if (g_str_has_prefix (tag, "Xmp.plus.ImageCreator"))
+//          g_print ("found\n");
+//
+      p = string_index_of (tag, "[x]", 0);  /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gint    j;
+          gchar  *struct_string = NULL;
+
+          /* check last number */
+
+          struct_string = string_substring (tag, 0, p); /* get structure tag */
+
+          for (j = 0; j < G_N_ELEMENTS(struct_element); j++) /*get info about structure */
+            {
+              if (! g_strcmp0 (struct_string, struct_element[j].struct_tag))  /* is a structure */
+                {
+                  GimpAttribute *struct_attribute = NULL;
+                  gint num = highest_structure[struct_element[j].number_of_element];
+
+                  counter = 0;  /*start the loop */
+
+                  while (struct_attribute ||
+                         counter == 0     ||  /* at least once, because counter IS 0 */
+                         counter < num)       /* at least until the highest structure */
+                    {
+                      gchar           *nr_string = NULL;
+                      gchar           *new_tag = NULL;
+                      gchar           *value;
+
+                      counter ++;
+                      nr_string = g_strdup_printf ("[%d]", counter);
+                      new_tag = string_replace_str (tag, "[x]", nr_string);
+
+                      struct_attribute = gimp_attributes_get_attribute (attributes, new_tag);
+
+                      if (struct_attribute)
+                        {
+                          gint sct;
+                          value = gimp_attribute_get_string (struct_attribute);
+
+                          for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                            {
+                              if (g_str_has_prefix (new_tag, struct_element[sct].struct_tag))
+                                {
+                                  highest_structure[struct_element[sct].number_of_element] = counter;
+                                  break;
+                                }
+                            }
+                          g_hash_table_insert (elements_table,
+                                               (gpointer) g_strdup (new_tag),
+                                               (gpointer) g_strdup (value));
+
+                          gimp_attributes_remove_attribute (attributes, new_tag);
+                          g_free (value);
+                        }
+                      g_free (nr_string);
+                      g_free (new_tag);
+                    }
+                  break;
+                }
+            }
+        }
+      else
+        {
+          attribute = gimp_attributes_get_attribute (attributes, tag);
+          if (attribute)
+            {
+              gchar *value = gimp_attribute_get_string (attribute);
+              g_hash_table_insert (elements_table,
+                                   (gpointer) g_strdup (rights_entries[i].xmp_tag),
+                                   (gpointer) g_strdup (value));
+
+              gimp_attributes_remove_attribute (attributes, rights_entries[i].xmp_tag);
+              g_free (value);
+            }
+        }
+      g_free (tag);
+    }
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (highest_structure[sct] > 0)
+        curr_shown_structure[sct] = 1;
+      else
+        curr_shown_structure[sct] = 0;
+    }
+
+  page_rights_init_combobox (builder);
+
+  page_rights_set_to_ui (builder,
+                              -1); /* all */
+}
+
+void
+page_rights_save_to_attributes (GimpAttributes *attributes)
+{
+  GHashTableIter     iter;
+  gpointer           key, value;
+
+
+  g_hash_table_iter_init (&iter, elements_table);
+  while (g_hash_table_iter_next (&iter, &key, &value))
+    {
+      GimpAttribute                   *attribute     = NULL;
+      gchar                           *tag = (gchar *) key;
+      gchar                           *value         = NULL;
+      gint                             p;
+      gint                             sct;
+      gint i;
+
+      value = (gchar *) g_hash_table_lookup (elements_table, (gpointer) tag);
+      attribute = gimp_attribute_new_string (tag, value, TYPE_ASCII);
+
+      if (attribute)
+        {
+          p = string_index_of (tag, "[", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes! */
+            {
+
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (tag, struct_element[sct].struct_tag))
+                    {
+                      gimp_attribute_set_structure_type (attribute, struct_element[sct].struct_type);
+                      break;
+                    }
+                }
+            }
+
+          for (i = 0; i < G_N_ELEMENTS(rights_entries); i++)
+            {
+              gchar *t_tag;
+              gint   p1;
+              gint   p2;
+
+              p1 = string_index_of (tag, "[", 0);                           /* is it a structure tag? */
+              if (p > -1) /* yes! */
+                {
+                  gchar *t1;
+                  gchar *t2;
+                  gint   l;
+
+                  p2 = string_index_of (tag, "]", p1);
+
+                  l = strlen (tag);
+
+                  t1 = string_substring (tag, 0, p);
+                  t2 = string_substring (tag, p2 + 1, l - (p2 + 1));
+
+                  t_tag = g_strdup_printf ("%s[x]%s", t1, t2);
+                }
+              else
+                {
+                  t_tag = g_strdup (tag);
+                }
+
+
+              if (! g_strcmp0 (t_tag, rights_entries[i].xmp_tag))
+                {
+                  if (rights_entries[i].number_of_comboarray > -1)
+                    {
+                      gint combobox_data_counter;
+                      gint array_length;
+                      gint number_in_comboarray = rights_entries[i].number_of_comboarray;
+
+                      array_length = G_N_ELEMENTS(combobox_data[number_in_comboarray]);
+
+                      for (combobox_data_counter = 0; combobox_data_counter < array_length; 
combobox_data_counter++)
+                        {
+                          const gchar  *val_in_tag = 
combobox_data[number_in_comboarray][combobox_data_counter].val_in_tag;
+                          const gchar  *interpreted_val;
+
+                          if (! val_in_tag)
+                            break;
+
+                          if (! g_strcmp0 (value, val_in_tag))
+                            {
+                              interpreted_val =  
combobox_data[number_in_comboarray][combobox_data_counter].val_in_combo;
+                              gimp_attribute_set_interpreted_string (attribute, interpreted_val);
+                              break;
+                            }
+                        }
+                    }
+                  break;
+                }
+            }
+          gimp_attributes_add_attribute (attributes, attribute);
+        }
+    }
+}
+
+static void
+page_rights_entry_activate_cb (GtkWidget *widget, gpointer userdata)
+{
+  const gchar *entry_name = (const gchar *) userdata;
+  const gchar *value      = gtk_entry_get_text (GTK_ENTRY (widget));
+
+  page_rights_store_in_hash_table (entry_name, value, 0);
+}
+
+static gboolean
+page_rights_entry_focus_out_cb (GtkWidget *widget, GdkEvent *event, gpointer userdata)
+{
+  const gchar *entry_name = (const gchar *) userdata;
+  const gchar *value      = gtk_entry_get_text (GTK_ENTRY (widget));
+
+  page_rights_store_in_hash_table (entry_name, value, 0);
+
+  return FALSE;
+}
+
+static void
+page_rights_entry_combo_changed_callback (GtkWidget *combo, gpointer userdata)
+{
+  const gchar *widget_name;
+  const gchar *value;
+  gint         array_nr   = GPOINTER_TO_INT (userdata);
+  gint         index      = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
+
+  value = combobox_data[array_nr][index].val_in_tag;
+  widget_name = gtk_widget_get_name (GTK_WIDGET (combo));
+
+  page_rights_store_in_hash_table (widget_name, value, 0);
+}
+
+static gboolean
+page_rights_store_in_hash_table (const gchar *entry_name, const gchar *value, gint nr)
+{
+  gint           i;
+  const gchar   *o_tag;
+  gint           p;
+  gint           number = 0;
+  gboolean       success;
+
+  g_return_val_if_fail (entry_name != NULL, FALSE);
+
+  if (nr > 0)
+    number = nr;
+
+  success = FALSE;
+
+  for (i = 0; i < G_N_ELEMENTS(rights_entries); i++)
+    {
+      if (! g_strcmp0 (entry_name, rights_entries[i].ui_entry))
+        {
+          gchar   *new_tag;
+          gchar   *nr_string;
+
+          o_tag = rights_entries[i].xmp_tag;
+
+          new_tag =g_strdup (o_tag);
+
+          p = string_index_of (new_tag, "[x]", 0);                           /* is it a structure tag? */
+
+          if (p > -1) /* yes */
+            {
+              gint sct;
+
+              if (number <= 0)
+                {
+                  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                    {
+                      if (g_strcmp0 (o_tag, struct_element[sct].struct_tag))
+                        {
+                          number = curr_shown_structure[struct_element[sct].number_of_element];
+                          break;
+                        }
+                    }
+                }
+
+              nr_string = g_strdup_printf ("[%d]", number);
+              new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              g_free (nr_string);
+              if (number <=0 )
+                {
+                  g_free (new_tag);
+                  return FALSE;
+                }
+            }
+
+          if (value && g_strcmp0 (value, ""))
+            {
+              if (g_hash_table_insert (elements_table, (gpointer) g_strdup (new_tag), (gpointer) g_strdup 
(value)))
+                success = TRUE;
+            }
+          else
+            {
+              if (g_hash_table_remove (elements_table, (gpointer) new_tag))
+                success = TRUE;
+            }
+
+          set_save_attributes_button_sensitive (TRUE);
+
+          g_free (new_tag);
+          break;
+        }
+    }
+  return success;
+}
+
+static void
+page_rights_structure_add (GtkButton *button, gpointer userdata)
+{
+  gint             number_to_add;
+  GtkComboBox     *combo;
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  const gchar     *widget_name;
+  gchar           *line;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].add_widget))
+        {
+          page_rights_structure_save (builder, struct_element[sct].number_of_element);
+          number_to_add = ++highest_structure[struct_element[sct].number_of_element];
+
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          line = g_strdup_printf ("%s [%d]", struct_element[sct].identifier, number_to_add);
+          curr_shown_structure [struct_element[sct].number_of_element] = number_to_add;
+
+          repaint = struct_element[sct].number_of_element;
+
+          g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK 
(page_rights_combobox_changed_callback), builder);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+
+          gtk_combo_box_set_active (combo, number_to_add-1);
+
+          if (number_to_add == 1)
+            page_rights_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+
+          g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_rights_combobox_changed_callback), builder);
+
+          g_free (line);
+          break;
+       }
+    }
+
+  page_rights_set_to_ui (builder, repaint);
+}
+
+static void
+page_rights_structure_remove (GtkButton *button, gpointer userdata)
+{
+  GtkBuilder      *builder           = (GtkBuilder *) userdata;
+  GtkListStore    *liststore;
+  GHashTableIter   iter_remove;
+  gboolean         found;
+  gchar           *nr_string;
+  gchar           *nr_string_new;
+  gpointer         key, value;
+  GSList          *delete_key_list   = NULL;
+  GSList          *list;
+  gchar           *tag_prefix;
+  gchar           *new_key;
+  gint             number_to_delete;
+  GtkComboBox     *combo;
+  GtkTreeIter      combo_iter;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+  gint             combo_to_del;
+
+  GHashTable           *reorder_table;
+
+  reorder_table = g_hash_table_new_full  (g_str_hash, g_str_equal, g_free, g_free);
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (button));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].remove_widget))
+        {
+          number_to_delete = curr_shown_structure[sct];
+          tag_prefix = g_strdup (struct_element[sct].struct_tag);
+          liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+          combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+          combo_to_del = highest_structure[sct] - 1;
+
+          if (number_to_delete == highest_structure[struct_element[sct].number_of_element])
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete - 1;
+          else
+            curr_shown_structure[struct_element[sct].number_of_element] = number_to_delete;
+
+          highest_structure[sct]--;
+          repaint = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr_string = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete);
+
+  /* remove entries */
+  {
+
+    g_hash_table_iter_init (&iter_remove, elements_table);
+    while (g_hash_table_iter_next (&iter_remove, &key, &value))
+      {
+        gchar *tag = (gchar *) key;
+        if (g_str_has_prefix (tag, nr_string))
+          {
+            delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+          }
+      }
+
+    for (list = delete_key_list; list; list = list->next)
+      {
+        gchar *key = (gchar *) list->data;
+        g_hash_table_remove (elements_table, key);
+      }
+
+    g_slist_free_full (delete_key_list, g_free);
+
+  }
+  /* reorder entries */
+
+  found = TRUE;
+
+  {
+    while (found) /* first: element table */
+      {
+        GHashTableIter   iter_reorder;
+
+        delete_key_list = NULL;
+        found           = FALSE;
+
+        nr_string_new = g_strdup_printf ("%s[%d]", tag_prefix, number_to_delete + 1);
+
+        g_hash_table_iter_init (&iter_reorder, elements_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            if (g_str_has_prefix (tag, nr_string_new))
+              {
+                found = TRUE;
+                new_key = string_replace_str (tag, nr_string_new, nr_string);
+                g_hash_table_insert (reorder_table, g_strdup (new_key), g_strdup (tag_value));
+                delete_key_list = g_slist_prepend (delete_key_list, g_strdup (tag));
+              }
+          }
+
+        for (list = delete_key_list; list; list = list->next)
+          {
+            gchar *key = (gchar *) list->data;
+            g_hash_table_remove (elements_table, key);
+          }
+        g_slist_free_full (delete_key_list, g_free);
+
+        g_hash_table_iter_init (&iter_reorder, reorder_table);
+        while (g_hash_table_iter_next (&iter_reorder, &key, &value))
+          {
+            gchar *tag       = (gchar *) key;
+            gchar *tag_value = (gchar *) value;
+
+            g_hash_table_insert (elements_table, g_strdup (tag), g_strdup (tag_value));
+          }
+
+        g_hash_table_remove_all (reorder_table);
+
+        nr_string = g_strdup (nr_string_new);
+        number_to_delete ++;
+      }
+
+  }
+
+  g_free (tag_prefix);
+  g_free (nr_string);
+  g_free (nr_string_new);
+  g_free (new_key);
+
+  g_hash_table_unref (reorder_table);
+
+  g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK (page_rights_combobox_changed_callback), 
builder);
+
+  gtk_combo_box_set_active (combo, combo_to_del);
+  if (gtk_combo_box_get_active_iter (combo, &combo_iter))
+    gtk_list_store_remove (liststore, &combo_iter);
+
+  if (curr_shown_structure[repaint] == 0)
+    page_rights_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+  else
+    gtk_combo_box_set_active (combo, curr_shown_structure[repaint] - 1);
+
+  g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK (page_rights_combobox_changed_callback), 
builder);
+
+  page_rights_set_to_ui (builder, repaint);
+}
+
+static void
+page_rights_combobox_changed_callback (GtkWidget *combo, gpointer userdata)
+{
+  GtkBuilder      *builder = (GtkBuilder *) userdata;
+  GtkComboBox     *combobox;
+  gint             nr;
+  const gchar     *widget_name;
+  gint             sct;
+  gint             repaint;
+
+  widget_name = gtk_widget_get_name (GTK_WIDGET (combo));
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      if (! g_strcmp0 (widget_name, struct_element[sct].struct_combo_widget))
+        {
+          page_rights_structure_save (builder, struct_element[sct].number_of_element);
+          combobox = GTK_COMBO_BOX (get_widget_from_label (builder, 
struct_element[sct].struct_combo_widget));
+          repaint  = struct_element[sct].number_of_element;
+          break;
+       }
+    }
+
+  nr = gtk_combo_box_get_active (combobox);
+  nr++;
+  curr_shown_structure[repaint] = nr;
+
+  page_rights_set_to_ui (builder, repaint);
+}
+
+static void
+page_rights_structure_save (GtkBuilder *builder, gint struct_number)
+{
+  gint         i;
+  const gchar *prefix = struct_element[struct_number].struct_tag;
+
+  for (i = 0; i < G_N_ELEMENTS(rights_entries); i++)
+    {
+      GObject       *obj;
+      gchar         *tag      = NULL;
+      const gchar   *o_tag;
+
+      if (curr_shown_structure[struct_number] > 0)
+        {
+          o_tag = rights_entries[i].xmp_tag;
+          if (g_str_has_prefix (o_tag, prefix))
+            {
+              gchar *nr_string;
+
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[struct_number]);
+              tag = string_replace_str (o_tag, "[x]", nr_string);
+
+              obj   = get_widget_from_label (builder, rights_entries[i].ui_entry);
+
+              switch (rights_entries[i].widget_type)
+              {
+                case WIDGET_TYPE_ENTRY:
+                  {
+                    gchar *value;
+                    value = g_strdup (gtk_entry_get_text (GTK_ENTRY (obj)));
+                    if (value && g_strcmp0 (value, ""))
+                      g_hash_table_insert (elements_table, (gpointer) g_strdup (tag), (gpointer) g_strdup 
(value));
+                    else
+                      g_hash_table_remove (elements_table, (gpointer) tag);
+                  }
+                  break;
+                case WIDGET_TYPE_COMBOBOX:
+                  break;
+                default:
+                  break;
+              }
+
+              g_free (nr_string);
+              g_free (tag);
+            }
+        }
+    }
+}
+
+static void
+page_rights_set_to_ui (GtkBuilder *builder, gint repaint)
+{
+  gint         i;
+  gint         sct;
+  const gchar *prefix;
+
+  if (repaint != -1)
+    prefix = struct_element[repaint].struct_tag;
+  else
+    prefix = NULL;
+
+  for (i = 0; i < G_N_ELEMENTS(rights_entries); i++)
+    {
+      GObject       *obj;
+      const gchar   *o_tag;
+      gchar         *value = NULL;
+      gchar         *new_tag;
+      gint           p;
+
+      o_tag = rights_entries[i].xmp_tag;
+
+      obj = get_widget_from_label (builder, rights_entries[i].ui_entry);
+
+      if (prefix)
+        {
+          if (! g_str_has_prefix (o_tag, prefix))
+            continue;
+        }
+
+      p = string_index_of (o_tag, "[x]", 0);     /* is it a structure tag? */
+
+      if (p > -1) /* yes! */
+        {
+          gchar         *nr_string;
+
+          if (repaint != -1)
+            {
+              nr_string = g_strdup_printf ("[%d]", curr_shown_structure[repaint]);
+            }
+          else
+            {
+              for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+                {
+                  if (g_str_has_prefix (o_tag, struct_element[sct].struct_tag))
+                    {
+                      nr_string = g_strdup_printf ("[%d]", curr_shown_structure[sct]);
+                      break;
+                    }
+                }
+            }
+
+          new_tag = string_replace_str (o_tag, "[x]", nr_string);
+
+          g_free (nr_string);
+        }
+      else
+        {
+          new_tag = g_strdup (o_tag);
+        }
+
+      value = (gchar *) g_hash_table_lookup (elements_table, new_tag);
+
+      switch (rights_entries[i].widget_type)
+      {
+        case WIDGET_TYPE_ENTRY:
+          {
+           gtk_entry_set_text (GTK_ENTRY (obj), "");
+          }
+          break;
+        default:
+          break;
+      }
+
+      if (value)
+        {
+          switch (rights_entries[i].widget_type)
+          {
+            case WIDGET_TYPE_ENTRY:
+              {
+               gtk_entry_set_text (GTK_ENTRY (obj), value);
+              }
+              break;
+            case WIDGET_TYPE_COMBOBOX:
+              {
+                gint combobox_data_counter;
+                gint array_length;
+                gint number_in_comboarray = rights_entries[i].number_of_comboarray;
+
+                array_length = G_N_ELEMENTS(combobox_data[number_in_comboarray]);
+
+                for (combobox_data_counter = 0; combobox_data_counter < array_length; 
combobox_data_counter++)
+                  {
+                    const gchar  *val_in_tag = 
combobox_data[number_in_comboarray][combobox_data_counter].val_in_tag;
+
+                    if (! val_in_tag)
+                      break;
+
+                    if (! g_strcmp0 (value, val_in_tag))
+                      {
+                        g_signal_handlers_block_by_func (obj,
+                                                         G_CALLBACK 
(page_rights_entry_combo_changed_callback),
+                                                         GINT_TO_POINTER (number_in_comboarray));
+
+                        gtk_combo_box_set_active (GTK_COMBO_BOX (obj), combobox_data_counter);
+
+                        g_signal_handlers_unblock_by_func (obj,
+                                                           G_CALLBACK 
(page_rights_entry_combo_changed_callback),
+                                                           GINT_TO_POINTER (number_in_comboarray));
+                        break;
+                      }
+                  }
+              }
+              break;
+            default:
+              break;
+          }
+        }
+      g_free (new_tag);
+    }
+}
+
+static void
+page_rights_init_combobox (GtkBuilder *builder)
+{
+  GtkListStore    *liststore;
+  GtkTreeIter      iter;
+  GtkComboBox     *combo;
+  gint             sct;
+
+  for (sct = 0; sct < STRUCTURES_ON_PAGE; sct ++)
+    {
+      gchar *line;
+      gint   i;
+      gint   high;
+      gint   active;
+
+      liststore = GTK_LIST_STORE (get_widget_from_label (builder, 
struct_element[sct].struct_liststore_widget));
+      combo = GTK_COMBO_BOX (get_widget_from_label (builder, struct_element[sct].struct_combo_widget));
+
+      high = highest_structure[struct_element[sct].number_of_element];
+      active = curr_shown_structure[struct_element[sct].number_of_element];
+
+      g_signal_handlers_block_by_func (G_OBJECT (combo), G_CALLBACK (page_rights_combobox_changed_callback), 
builder);
+
+      for (i = 0; i < high; i++)
+        {
+          line = g_strdup_printf ("%s [%d]",struct_element[sct].identifier, i + 1);
+
+          gtk_list_store_append(liststore, &iter);
+
+          gtk_list_store_set (liststore, &iter,
+                              0, line,
+                              -1);
+          g_free (line);
+        }
+
+      gtk_combo_box_set_active (combo, active-1);
+
+      if (active >= 1)
+        page_rights_set_entry_sensitive (builder, struct_element[sct].struct_tag, TRUE);
+      else
+        page_rights_set_entry_sensitive (builder, struct_element[sct].struct_tag, FALSE);
+
+      g_signal_handlers_unblock_by_func(G_OBJECT (combo), G_CALLBACK 
(page_rights_combobox_changed_callback), builder);
+
+    }
+}
diff --git a/plug-ins/metainfo/page-rights.h b/plug-ins/metainfo/page-rights.h
new file mode 100644
index 0000000..fac3922
--- /dev/null
+++ b/plug-ins/metainfo/page-rights.h
@@ -0,0 +1,33 @@
+/* page-rights.h
+ *
+ * Copyright (C) 2014, Hartmut Kuhse <hatti gimp org>
+ *
+ * This library is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library.  If not, see
+ * <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __PAGE_RIGHTS_H__
+#define __PAGE_RIGHTS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+void                          page_rights_read_from_attributes       (GimpAttributes        *attributes,
+                                                                      GtkBuilder            *builder);
+void                          page_rights_save_to_attributes         (GimpAttributes        *attributes);
+
+G_END_DECLS
+
+#endif /* __PAGE_RIGHTS_H__ */
diff --git a/plug-ins/ui/Makefile.am b/plug-ins/ui/Makefile.am
index aec82b9..b8d32ad 100644
--- a/plug-ins/ui/Makefile.am
+++ b/plug-ins/ui/Makefile.am
@@ -4,6 +4,9 @@ uidata_DATA = \
        plug-in-file-gif.ui     \
        plug-in-file-png.ui     \
        plug-in-file-tiff.ui    \
-       plug-in-metadata.ui
+       plug-in-attributes.ui   \
+       plug-in-iptc.ui \
+       plug-in-metainfo.ui
+
 
 EXTRA_DIST = $(uidata_DATA)
diff --git a/plug-ins/ui/plug-in-attributes.ui b/plug-ins/ui/plug-in-attributes.ui
new file mode 100644
index 0000000..951bf4a
--- /dev/null
+++ b/plug-ins/ui/plug-in-attributes.ui
@@ -0,0 +1,346 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <!-- interface-requires gtk+ 3.0 -->
+  <!-- interface-naming-policy toplevel-contextual -->
+  <object class="GtkTreeStore" id="exif-treestore">
+    <columns>
+      <!-- column-name c-exif-ifd -->
+      <column type="gchararray"/>
+      <!-- column-name c-exif-tag -->
+      <column type="gchararray"/>
+      <!-- column-name c-exif-value -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkVBox" id="attributes-vbox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <property name="spacing">2</property>
+    <child>
+      <object class="GtkFrame" id="frame1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label_xalign">0</property>
+        <property name="shadow_type">out</property>
+        <child>
+          <object class="GtkHBox" id="header-hbox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">3</property>
+            <child>
+              <object class="GtkVBox" id="vbox1">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkLabel" id="label-header">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">label</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label-info">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">label</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="thumb-box">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+        <child type="label_item">
+          <placeholder/>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkNotebook" id="attributes-notebook">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <property name="scrollable">True</property>
+        <child>
+          <object class="GtkScrolledWindow" id="exif-scroll">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">6</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkTreeView" id="exif-treeview">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="model">exif-treestore</property>
+                <property name="headers_clickable">False</property>
+                <property name="expander_column">exif_ifd_column</property>
+                <property name="rules_hint">True</property>
+                <property name="search_column">1</property>
+                <property name="enable_tree_lines">True</property>
+                <child>
+                  <object class="GtkTreeViewColumn" id="exif_ifd_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">Exif IFD</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="exif_ifd_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="exif_tag_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">Exif Tag</property>
+                    <property name="expand">True</property>
+                    <property name="sort_column_id">1</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="exif_tag_renderer_text"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="exif_value_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">Value</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="exif_value_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">2</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="exif">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xpad">4</property>
+            <property name="ypad">4</property>
+            <property name="label" translatable="yes">Exif</property>
+          </object>
+          <packing>
+            <property name="tab_expand">True</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="xmp-scroll">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">6</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkTreeView" id="xmp-treeview">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="model">xmp-treestore</property>
+                <property name="headers_clickable">False</property>
+                <property name="rules_hint">True</property>
+                <property name="search_column">1</property>
+                <property name="enable_tree_lines">True</property>
+                <child>
+                  <object class="GtkTreeViewColumn" id="xmp_schema_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">XMP schema</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="xmp_schema_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="xmp_tag_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">XMP Property</property>
+                    <property name="expand">True</property>
+                    <property name="sort_column_id">1</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="xmp_tag_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="xmp_value_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">Value</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="xmp_value_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">2</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="xmp">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xpad">4</property>
+            <property name="ypad">4</property>
+            <property name="label" translatable="yes">XMP</property>
+          </object>
+          <packing>
+            <property name="position">1</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkScrolledWindow" id="iptc-scroll">
+            <property name="visible">True</property>
+            <property name="can_focus">True</property>
+            <property name="border_width">6</property>
+            <property name="shadow_type">in</property>
+            <child>
+              <object class="GtkTreeView" id="iptc-treeview">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="model">iptc-treestore</property>
+                <property name="headers_clickable">False</property>
+                <property name="rules_hint">True</property>
+                <property name="search_column">1</property>
+                <property name="enable_tree_lines">True</property>
+                <child>
+                  <object class="GtkTreeViewColumn" id="iptc_key_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">IPTC key</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="iptc_key_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">0</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="iptc_tag_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">IPTC Tag</property>
+                    <property name="expand">True</property>
+                    <property name="sort_column_id">1</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="iptc_tag_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">1</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+                <child>
+                  <object class="GtkTreeViewColumn" id="iptc_value_column">
+                    <property name="resizable">True</property>
+                    <property name="title" translatable="yes">Value</property>
+                    <child>
+                      <object class="GtkCellRendererText" id="iptc_value_cell_renderer"/>
+                      <attributes>
+                        <attribute name="text">2</attribute>
+                      </attributes>
+                    </child>
+                  </object>
+                </child>
+              </object>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="iptc">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xpad">4</property>
+            <property name="ypad">4</property>
+            <property name="label" translatable="yes">IPTC</property>
+          </object>
+          <packing>
+            <property name="position">2</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">True</property>
+        <property name="fill">True</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkTreeStore" id="iptc-treestore">
+    <columns>
+      <!-- column-name c-iptc-ifd -->
+      <column type="gchararray"/>
+      <!-- column-name c-iptc-tag -->
+      <column type="gchararray"/>
+      <!-- column-name c-iptc-value -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkTreeStore" id="xmp-treestore">
+    <columns>
+      <!-- column-name c-xmp-ifd -->
+      <column type="gchararray"/>
+      <!-- column-name c-xmp-tag -->
+      <column type="gchararray"/>
+      <!-- column-name c-xmp-value -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+</interface>
diff --git a/plug-ins/ui/plug-in-iptc.ui b/plug-ins/ui/plug-in-iptc.ui
new file mode 100644
index 0000000..1b95e5a
--- /dev/null
+++ b/plug-ins/ui/plug-in-iptc.ui
@@ -0,0 +1,779 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.24"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkVBox" id="iptc-vbox">
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkNotebook" id="iptc-notebook">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <child>
+          <object class="GtkVBox" id="box2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkTable" id="desctable">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">6</property>
+                <property name="n_rows">8</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">3</property>
+                <property name="row_spacing">3</property>
+                <child>
+                  <object class="GtkLabel" id="l_title">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Title</property>
+                    <property name="single_line_mode">True</property>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_author">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Author</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_authortitle">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Authortitle</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_copyright">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Copyright</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_caption">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Caption</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_captionwriter">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Captionwriter</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_headline">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Headline</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_specialinstruct">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Special
+Instructions</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.ObjectName">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.Byline">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.BylineTitle">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.Copyright">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.Writer">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="caption_scroll">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTextView" id="Iptc.Application2.Caption">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="headline_scroll">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTextView" id="Iptc.Application2.Headline">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="instruct_scroll">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTextView" id="Iptc.Application2.SpecialInstructions">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="iptcdesc">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xpad">2</property>
+            <property name="ypad">2</property>
+            <property name="label" translatable="yes">Description</property>
+          </object>
+          <packing>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="box3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkTable" id="table3">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">6</property>
+                <property name="n_rows">4</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">3</property>
+                <property name="row_spacing">3</property>
+                <child>
+                  <object class="GtkLabel" id="l_keywords1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Keywords</property>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_category1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Category</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_suppcat1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="yalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Supplemental
+Category</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_urgency1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Urgency</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow10">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTextView" id="Iptc.Application2.Keywords">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkScrolledWindow" id="scrolledwindow12">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="shadow_type">in</property>
+                    <child>
+                      <object class="GtkTextView" id="Iptc.Application2.SuppCategory">
+                        <property name="visible">True</property>
+                        <property name="can_focus">True</property>
+                      </object>
+                    </child>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.Urgency">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.Category">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="iptckeys">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xpad">2</property>
+            <property name="ypad">2</property>
+            <property name="label" translatable="yes">Keywords/Categories</property>
+          </object>
+          <packing>
+            <property name="position">1</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="box4">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkTable" id="table4">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <property name="border_width">6</property>
+                <property name="n_rows">9</property>
+                <property name="n_columns">2</property>
+                <property name="column_spacing">3</property>
+                <property name="row_spacing">3</property>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">2</property>
+                    <property name="bottom_attach">3</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_credit">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Credit</property>
+                  </object>
+                  <packing>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_source">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Source</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.Credit">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.Source">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">1</property>
+                    <property name="bottom_attach">2</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_transmission">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Transmission
+reference</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">8</property>
+                    <property name="bottom_attach">9</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.TransmissionReference">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">8</property>
+                    <property name="bottom_attach">9</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_city">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">City</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.City">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">3</property>
+                    <property name="bottom_attach">4</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_sublocation">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Sublocation</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.SubLocation">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">4</property>
+                    <property name="bottom_attach">5</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_province">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="xpad">3</property>
+                    <property name="ypad">3</property>
+                    <property name="label" translatable="yes">Province/State</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.ProvinceState">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">5</property>
+                    <property name="bottom_attach">6</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="l_country">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">Country</property>
+                  </object>
+                  <packing>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                    <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkEntry" id="Iptc.Application2.CountryName">
+                    <property name="visible">True</property>
+                    <property name="can_focus">True</property>
+                    <property name="invisible_char">●</property>
+                    <property name="invisible_char_set">True</property>
+                    <property name="primary_icon_activatable">False</property>
+                    <property name="secondary_icon_activatable">False</property>
+                    <property name="primary_icon_sensitive">True</property>
+                    <property name="secondary_icon_sensitive">True</property>
+                  </object>
+                  <packing>
+                    <property name="left_attach">1</property>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">6</property>
+                    <property name="bottom_attach">7</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkHSeparator" id="hseparator2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                  </object>
+                  <packing>
+                    <property name="right_attach">2</property>
+                    <property name="top_attach">7</property>
+                    <property name="bottom_attach">8</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="iptccredits">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="xpad">2</property>
+            <property name="ypad">2</property>
+            <property name="label" translatable="yes">Credits/Origin</property>
+          </object>
+          <packing>
+            <property name="position">2</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">True</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+  </object>
+</interface>
diff --git a/plug-ins/ui/plug-in-metainfo.ui b/plug-ins/ui/plug-in-metainfo.ui
new file mode 100644
index 0000000..1d449cc
--- /dev/null
+++ b/plug-ins/ui/plug-in-metainfo.ui
@@ -0,0 +1,3556 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <requires lib="gtk+" version="2.24"/>
+  <!-- interface-naming-policy project-wide -->
+  <object class="GtkListStore" id="artworkorobject-liststore">
+    <columns>
+      <!-- column-name Artwork -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="copyrightowner-liststore">
+    <columns>
+      <!-- column-name Owner -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="digitalsourcetype-liststore">
+    <columns>
+      <!-- column-name Digital -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="imagecreator-liststore">
+    <columns>
+      <!-- column-name Creator -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="imagesupplier-liststore">
+    <columns>
+      <!-- column-name Supplier -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="licensor-liststore">
+    <columns>
+      <!-- column-name Licensor -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="location-created-liststore">
+    <columns>
+      <!-- column-name Location -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="location-shown-liststore">
+    <columns>
+      <!-- column-name Location -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="minormodelagedisclosure-liststore">
+    <columns>
+      <!-- column-name Model -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="modelreleasestatus-liststore">
+    <columns>
+      <!-- column-name Model -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkListStore" id="release-status-liststore">
+    <columns>
+      <!-- column-name Status -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+  <object class="GtkVBox" id="metainfo-vbox">
+    <property name="width_request">600</property>
+    <property name="height_request">300</property>
+    <property name="visible">True</property>
+    <property name="can_focus">False</property>
+    <child>
+      <object class="GtkFrame" id="frame1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <property name="label_xalign">0</property>
+        <property name="shadow_type">out</property>
+        <child>
+          <object class="GtkHBox" id="header-hbox">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="border_width">3</property>
+            <child>
+              <object class="GtkVBox" id="vbox6">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <object class="GtkLabel" id="label-header">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">label</property>
+                    <attributes>
+                      <attribute name="weight" value="bold"/>
+                    </attributes>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">0</property>
+                  </packing>
+                </child>
+                <child>
+                  <object class="GtkLabel" id="label-info">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="xalign">0</property>
+                    <property name="label" translatable="yes">label</property>
+                  </object>
+                  <packing>
+                    <property name="expand">True</property>
+                    <property name="fill">True</property>
+                    <property name="position">1</property>
+                  </packing>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+            <child>
+              <object class="GtkHBox" id="thumb-box">
+                <property name="visible">True</property>
+                <property name="can_focus">False</property>
+                <child>
+                  <placeholder/>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">False</property>
+                <property name="fill">True</property>
+                <property name="position">1</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+        <child type="label_item">
+          <placeholder/>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">0</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkNotebook" id="notebook1">
+        <property name="visible">True</property>
+        <property name="can_focus">True</property>
+        <child>
+          <object class="GtkVBox" id="vbox2">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow1">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <child>
+                  <object class="GtkViewport" id="viewport1">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="shadow_type">etched-in</property>
+                    <child>
+                      <object class="GtkTable" id="table1">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="n_rows">11</property>
+                        <property name="n_columns">2</property>
+                        <property name="column_spacing">4</property>
+                        <property name="row_spacing">8</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="location-shown-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment6">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table3">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">8</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-shown-sublocation-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Sublocation</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-shown-city-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">City</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-shown-provincestate-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Province / State</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-shown-countryname-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Countryname</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-shown-countrycode-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Countrycode</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-shown-worldregion-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Worldregion</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox5">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkButton" id="location-shown-button-plus">
+                                            <property name="label" translatable="yes">+</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="location-shown-button-minus">
+                                            <property name="label" translatable="yes">-</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">7</property>
+                                        <property name="bottom_attach">8</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment17">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkComboBox" id="location-shown-combo">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="model">location-shown-liststore</property>
+                                            <child>
+                                              <object class="GtkCellRendererText" id="cellrenderertext2"/>
+                                              <attributes>
+                                                <attribute name="text">0</attribute>
+                                              </attributes>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-shown-sublocation-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-shown-city-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-shown-provincestate-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-shown-countryname-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-shown-countrycode-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-shown-worldregion-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="location-shown-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Location shown</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">5</property>
+                            <property name="bottom_attach">6</property>
+                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="organisationinimage-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment18">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table4">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">2</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="orginimage-name-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Org. in image</property>
+                                      </object>
+                                      <packing>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="orginimage-code-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Org. in image 
code</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="orginimage-name-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="orginimage-code-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="organisationinimage-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Organisation in image</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">7</property>
+                            <property name="bottom_attach">8</property>
+                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="location-created-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment5">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table2">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">8</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="location-created-city-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">City</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-created-provincestate-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Province / State</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-created-countryname-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Countryname</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-created-countrycode-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Countrycode</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-created-worldregion-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Worldregion</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox3">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkButton" id="location-created-button-plus">
+                                            <property name="label" translatable="yes">+</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                            <property name="focus_on_click">False</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="location-created-button-minus">
+                                            <property name="label" translatable="yes">-</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                            <property name="focus_on_click">False</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">7</property>
+                                        <property name="bottom_attach">8</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment16">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkComboBox" id="location-created-combo">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="model">location-created-liststore</property>
+                                            <child>
+                                              <object class="GtkCellRendererText" id="cellrenderertext1"/>
+                                              <attributes>
+                                                <attribute name="text">0</attribute>
+                                              </attributes>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed2">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed3">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">7</property>
+                                        <property name="bottom_attach">8</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="location-created-sublocation-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Sublocation</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-created-sublocation-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-created-city-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-created-provincestate-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-created-countryname-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-created-countrycode-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="location-created-worldregion-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="location-created-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Location created</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">3</property>
+                            <property name="bottom_attach">4</property>
+                            <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator1">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">4</property>
+                            <property name="bottom_attach">5</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator2">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">6</property>
+                            <property name="bottom_attach">7</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFixed" id="fixed1">
+                            <property name="height_request">150</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">9</property>
+                            <property name="bottom_attach">10</property>
+                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                            <property name="y_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator3">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">8</property>
+                            <property name="bottom_attach">9</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator10">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">3</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFrame" id="frame4">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label_xalign">0</property>
+                            <property name="shadow_type">none</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment20">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="left_padding">8</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table17">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">2</property>
+                                    <property name="n_columns">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="personinimage-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">4</property>
+                                        <property name="ypad">8</property>
+                                        <property name="label" translatable="yes">Person in Image</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="personinimage-entry">
+                                        <property name="width_request">0</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="event-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">4</property>
+                                        <property name="label" translatable="yes">Event</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="event-entry">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="common-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="label" translatable="yes">Common</property>
+                                <property name="use_markup">True</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="desc-label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Description</property>
+          </object>
+          <packing>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox4">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow2">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <child>
+                  <object class="GtkViewport" id="viewport2">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="shadow_type">etched-in</property>
+                    <child>
+                      <object class="GtkTable" id="table5">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="n_rows">6</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="artworkorobject-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment7">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table7">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">8</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="artworkorobject-title-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Title</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="artworkorobject-datecreated-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Date created</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="artworkorobject-creator-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Creator</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="artworkorobject-source-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Source</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="artworkorobject-sourceinvno-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Source inventory 
number</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="artworkorobject-copyrightnotice-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Copyright notice</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="artworkorobject-title-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="artworkorobject-datecreated-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="artworkorobject-creator-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="artworkorobject-source-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="artworkorobject-sourceinvno-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="artworkorobject-copyrightnotice-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox2">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkButton" id="artworkorobject-button-plus">
+                                            <property name="label" translatable="yes">+</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="artworkorobject-button-minus">
+                                            <property name="label" translatable="yes">-</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">7</property>
+                                        <property name="bottom_attach">8</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment30">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkComboBox" id="artworkorobject-combo">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="model">artworkorobject-liststore</property>
+                                            <child>
+                                              <object class="GtkCellRendererText" id="cellrenderertext3"/>
+                                              <attributes>
+                                                <attribute name="text">0</attribute>
+                                              </attributes>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed4">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed5">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">7</property>
+                                        <property name="bottom_attach">8</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="artworkorobject-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Artwork or object</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="y_padding">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFrame" id="frame2">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label_xalign">0</property>
+                            <property name="shadow_type">none</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment8">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="left_padding">12</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table8">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">5</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">16</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="addlmodelinfo-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Additional model 
information</property>
+                                      </object>
+                                      <packing>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="modelage-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Model age</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="minormodelagedisclosure-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Minor model age</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="modelreleasestatus-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Model release 
status</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="modelreleaseid-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Model release ID</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="modelage-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="minormodelagedisclosure-combobox">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="model">minormodelagedisclosure-liststore</property>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="cellrenderertext4"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="modelreleasestatus-combobox">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="model">modelreleasestatus-liststore</property>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="cellrenderertext5"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="modelreleaseid-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment9">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkEntry" id="addlmodelinfo-entry">
+                                            <property name="width_request">350</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="invisible_char">●</property>
+                                            <property name="primary_icon_activatable">False</property>
+                                            <property name="secondary_icon_activatable">False</property>
+                                            <property name="primary_icon_sensitive">True</property>
+                                            <property name="secondary_icon_sensitive">True</property>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="modelframe-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Model</property>
+                                <property name="use_markup">True</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator4">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFixed" id="fixed6">
+                            <property name="height_request">230</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">3</property>
+                            <property name="bottom_attach">4</property>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">1</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="art-label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Artwork / Model</property>
+          </object>
+          <packing>
+            <property name="position">1</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox5">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow3">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <child>
+                  <object class="GtkViewport" id="viewport3">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <property name="shadow_type">etched-in</property>
+                    <child>
+                      <object class="GtkTable" id="table6">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="n_rows">7</property>
+                        <property name="n_columns">2</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="registryid-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment10">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table10">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">4</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="regorgid-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Registry Organistaion 
ID</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="regitemid-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Registry item ID</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="regorgid-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="regitemid-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox4">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkButton" id="registryid-button-plus">
+                                            <property name="label" translatable="yes">+</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="registryid-button-minus">
+                                            <property name="label" translatable="yes">-</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment32">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkComboBox" id="registryid-combo">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="model">registryid-liststore</property>
+                                            <child>
+                                              <object class="GtkCellRendererText" id="cellrenderertext7"/>
+                                              <attributes>
+                                                <attribute name="text">0</attribute>
+                                              </attributes>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed11">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed12">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="registryid-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Registry ID</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">3</property>
+                            <property name="bottom_attach">4</property>
+                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                            <property name="y_padding">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator5">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator6">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">4</property>
+                            <property name="bottom_attach">5</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFixed" id="fixed7">
+                            <property name="height_request">175</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">6</property>
+                            <property name="bottom_attach">7</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkAlignment" id="alignment19">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="left_padding">4</property>
+                            <property name="right_padding">4</property>
+                            <child>
+                              <object class="GtkTable" id="table11">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="n_rows">3</property>
+                                <property name="n_columns">2</property>
+                                <property name="column_spacing">4</property>
+                                <property name="row_spacing">2</property>
+                                <child>
+                                  <object class="GtkLabel" id="maxavailheight-label">
+                                    <property name="width_request">150</property>
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="xpad">4</property>
+                                    <property name="label" translatable="yes">Max available height</property>
+                                  </object>
+                                  <packing>
+                                    <property name="x_options">GTK_FILL</property>
+                                    <property name="y_options">GTK_EXPAND</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="maxavailwidth-label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="xpad">4</property>
+                                    <property name="label" translatable="yes">Max available width</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                    <property name="y_options">GTK_EXPAND</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkLabel" id="digitalsourcetype-label">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="xalign">0</property>
+                                    <property name="xpad">4</property>
+                                    <property name="label" translatable="yes">Digital Source Type</property>
+                                  </object>
+                                  <packing>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                    <property name="x_options">GTK_FILL</property>
+                                    <property name="y_options">GTK_EXPAND</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment35">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <child>
+                                      <object class="GtkComboBox" id="digitalsourcetype-combobox">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="model">digitalsourcetype-liststore</property>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="cellrenderertext8"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">2</property>
+                                    <property name="bottom_attach">3</property>
+                                    <property name="y_options">GTK_EXPAND</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="maxavailheight-entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="y_options">GTK_EXPAND</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkEntry" id="maxavailwidth-entry">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">True</property>
+                                    <property name="invisible_char">●</property>
+                                    <property name="invisible_char_set">True</property>
+                                    <property name="primary_icon_activatable">False</property>
+                                    <property name="secondary_icon_activatable">False</property>
+                                    <property name="primary_icon_sensitive">True</property>
+                                    <property name="secondary_icon_sensitive">True</property>
+                                  </object>
+                                  <packing>
+                                    <property name="left_attach">1</property>
+                                    <property name="right_attach">2</property>
+                                    <property name="top_attach">1</property>
+                                    <property name="bottom_attach">2</property>
+                                    <property name="y_options">GTK_EXPAND</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">5</property>
+                            <property name="bottom_attach">6</property>
+                            <property name="y_padding">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="imagesupplier-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkVBox" id="vbox1">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment3">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="bottom_padding">6</property>
+                                    <property name="right_padding">4</property>
+                                    <child>
+                                      <object class="GtkTable" id="table9">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="n_columns">2</property>
+                                        <property name="column_spacing">8</property>
+                                        <property name="row_spacing">2</property>
+                                        <child>
+                                          <object class="GtkLabel" id="imagesupplier-imageid-label">
+                                            <property name="width_request">160</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="xalign">0</property>
+                                            <property name="xpad">3</property>
+                                            <property name="label" translatable="yes">Image supplier image 
ID</property>
+                                          </object>
+                                          <packing>
+                                            <property name="x_options">GTK_FILL</property>
+                                            <property name="y_options"/>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkAlignment" id="alignment4">
+                                            <property name="width_request">350</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <child>
+                                              <object class="GtkEntry" id="imagesupplier-imageid-entry">
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="invisible_char">●</property>
+                                                <property name="invisible_char_set">True</property>
+                                                <property name="primary_icon_activatable">False</property>
+                                                <property name="secondary_icon_activatable">False</property>
+                                                <property name="primary_icon_sensitive">True</property>
+                                                <property name="secondary_icon_sensitive">True</property>
+                                              </object>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="left_attach">1</property>
+                                            <property name="right_attach">2</property>
+                                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | 
GTK_FILL</property>
+                                            <property name="y_options">GTK_EXPAND</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">0</property>
+                                  </packing>
+                                </child>
+                                <child>
+                                  <object class="GtkAlignment" id="alignment1">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="right_padding">4</property>
+                                    <child>
+                                      <object class="GtkTable" id="table18">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="n_rows">4</property>
+                                        <property name="n_columns">2</property>
+                                        <property name="column_spacing">8</property>
+                                        <property name="row_spacing">2</property>
+                                        <child>
+                                          <object class="GtkHBox" id="hbox9">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="homogeneous">True</property>
+                                            <child>
+                                              <object class="GtkButton" id="imagesupplier-button-plus">
+                                                <property name="label" translatable="yes">+</property>
+                                                <property name="width_request">20</property>
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="receives_default">True</property>
+                                              </object>
+                                              <packing>
+                                                <property name="expand">False</property>
+                                                <property name="fill">False</property>
+                                                <property name="position">0</property>
+                                              </packing>
+                                            </child>
+                                            <child>
+                                              <object class="GtkButton" id="imagesupplier-button-minus">
+                                                <property name="label" translatable="yes">-</property>
+                                                <property name="width_request">20</property>
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">True</property>
+                                                <property name="receives_default">True</property>
+                                              </object>
+                                              <packing>
+                                                <property name="expand">False</property>
+                                                <property name="fill">False</property>
+                                                <property name="position">1</property>
+                                              </packing>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="top_attach">3</property>
+                                            <property name="bottom_attach">4</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <placeholder/>
+                                        </child>
+                                        <child>
+                                          <object class="GtkAlignment" id="alignment2">
+                                            <property name="width_request">350</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <child>
+                                              <object class="GtkComboBox" id="imagesupplier-combo">
+                                                <property name="visible">True</property>
+                                                <property name="can_focus">False</property>
+                                                <property name="model">imagesupplier-liststore</property>
+                                                <child>
+                                                  <object class="GtkCellRendererText" 
id="cellrenderertext6"/>
+                                                  <attributes>
+                                                    <attribute name="text">0</attribute>
+                                                  </attributes>
+                                                </child>
+                                              </object>
+                                            </child>
+                                          </object>
+                                          <packing>
+                                            <property name="left_attach">1</property>
+                                            <property name="right_attach">2</property>
+                                            <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                            <property name="y_options">GTK_EXPAND</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <placeholder/>
+                                        </child>
+                                        <child>
+                                          <placeholder/>
+                                        </child>
+                                        <child>
+                                          <placeholder/>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="imagesupplier-name-label">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="xalign">0</property>
+                                            <property name="xpad">3</property>
+                                            <property name="label" translatable="yes">Image supplier 
name</property>
+                                          </object>
+                                          <packing>
+                                            <property name="top_attach">1</property>
+                                            <property name="bottom_attach">2</property>
+                                            <property name="x_options">GTK_FILL</property>
+                                            <property name="y_options"/>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkLabel" id="imagesupplier-id-label">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="xalign">0</property>
+                                            <property name="xpad">3</property>
+                                            <property name="label" translatable="yes">Image supplier 
ID</property>
+                                          </object>
+                                          <packing>
+                                            <property name="top_attach">2</property>
+                                            <property name="bottom_attach">3</property>
+                                            <property name="x_options">GTK_FILL</property>
+                                            <property name="y_options"/>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkEntry" id="imagesupplier-name-entry">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="invisible_char">●</property>
+                                            <property name="invisible_char_set">True</property>
+                                            <property name="primary_icon_activatable">False</property>
+                                            <property name="secondary_icon_activatable">False</property>
+                                            <property name="primary_icon_sensitive">True</property>
+                                            <property name="secondary_icon_sensitive">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="left_attach">1</property>
+                                            <property name="right_attach">2</property>
+                                            <property name="top_attach">1</property>
+                                            <property name="bottom_attach">2</property>
+                                            <property name="y_options">GTK_EXPAND</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkEntry" id="imagesupplier-id-entry">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="invisible_char">●</property>
+                                            <property name="invisible_char_set">True</property>
+                                            <property name="primary_icon_activatable">False</property>
+                                            <property name="secondary_icon_activatable">False</property>
+                                            <property name="primary_icon_sensitive">True</property>
+                                            <property name="secondary_icon_sensitive">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="left_attach">1</property>
+                                            <property name="right_attach">2</property>
+                                            <property name="top_attach">2</property>
+                                            <property name="bottom_attach">3</property>
+                                            <property name="y_options">GTK_EXPAND</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <placeholder/>
+                                        </child>
+                                      </object>
+                                    </child>
+                                  </object>
+                                  <packing>
+                                    <property name="expand">True</property>
+                                    <property name="fill">True</property>
+                                    <property name="position">1</property>
+                                  </packing>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="imagesupplier-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Image Supplier</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                            <property name="y_padding">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <placeholder/>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">2</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="admin-label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Administration</property>
+          </object>
+          <packing>
+            <property name="position">2</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+        <child>
+          <object class="GtkVBox" id="vbox3">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <child>
+              <object class="GtkScrolledWindow" id="scrolledwindow4">
+                <property name="visible">True</property>
+                <property name="can_focus">True</property>
+                <property name="hscrollbar_policy">never</property>
+                <child>
+                  <object class="GtkViewport" id="viewport4">
+                    <property name="visible">True</property>
+                    <property name="can_focus">False</property>
+                    <child>
+                      <object class="GtkTable" id="table12">
+                        <property name="visible">True</property>
+                        <property name="can_focus">False</property>
+                        <property name="n_rows">8</property>
+                        <property name="n_columns">2</property>
+                        <child>
+                          <placeholder/>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="imagecreator-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment11">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table13">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">4</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="imagecreator-name-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Image creator 
name</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="imagecreator-id-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Image creator ID</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="imagecreator-name-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="imagecreator-id-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox6">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkButton" id="imagecreator-button-plus">
+                                            <property name="label" translatable="yes">+</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="imagecreator-button-minus">
+                                            <property name="label" translatable="yes">-</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment36">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkComboBox" id="imagecreator-combo">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="model">imagecreator-liststore</property>
+                                            <child>
+                                              <object class="GtkCellRendererText" id="cellrenderertext9"/>
+                                              <attributes>
+                                                <attribute name="text">0</attribute>
+                                              </attributes>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="imagecreator-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Image creator</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                            <property name="y_padding">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator7">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">1</property>
+                            <property name="bottom_attach">2</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="copyrightowner-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="spacing">6</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment12">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table14">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">4</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="copyrightowner-name-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Copyright owner 
name</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="copyrightowner-id-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Copyright owner 
ID</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="copyrightowner-name-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="copyrightowner-id-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox7">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkButton" id="copyrightowner-button-plus">
+                                            <property name="label" translatable="yes">+</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="copyrightowner-button-minus">
+                                            <property name="label" translatable="yes">-</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment37">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkComboBox" id="copyrightowner-combo">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="model">copyrightowner-liststore</property>
+                                            <child>
+                                              <object class="GtkCellRendererText" id="cellrenderertext10"/>
+                                              <attributes>
+                                                <attribute name="text">0</attribute>
+                                              </attributes>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                    <child>
+                                      <placeholder/>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="copyrightowner-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Copyright owner</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">2</property>
+                            <property name="bottom_attach">3</property>
+                            <property name="x_options">GTK_EXPAND | GTK_SHRINK | GTK_FILL</property>
+                            <property name="y_padding">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator8">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">3</property>
+                            <property name="bottom_attach">4</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkExpander" id="licensor-expander">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment13">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table15">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">14</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">8</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-name-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Name</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-id-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">ID</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-streetaddress-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Address</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-extendedaddress-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Extended address</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-city-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">City</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-region-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Region</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-name-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-id-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">2</property>
+                                        <property name="bottom_attach">3</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-streetaddress-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">3</property>
+                                        <property name="bottom_attach">4</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-extendedaddress-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">4</property>
+                                        <property name="bottom_attach">5</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-city-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">5</property>
+                                        <property name="bottom_attach">6</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-region-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">6</property>
+                                        <property name="bottom_attach">7</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkHBox" id="hbox8">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="homogeneous">True</property>
+                                        <child>
+                                          <object class="GtkButton" id="licensor-button-plus">
+                                            <property name="label" translatable="yes">+</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">0</property>
+                                          </packing>
+                                        </child>
+                                        <child>
+                                          <object class="GtkButton" id="licensor-button-minus">
+                                            <property name="label" translatable="yes">-</property>
+                                            <property name="width_request">20</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="receives_default">True</property>
+                                          </object>
+                                          <packing>
+                                            <property name="expand">False</property>
+                                            <property name="fill">False</property>
+                                            <property name="position">1</property>
+                                          </packing>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">13</property>
+                                        <property name="bottom_attach">14</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment38">
+                                        <property name="width_request">350</property>
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkComboBox" id="licensor-combo">
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">False</property>
+                                            <property name="model">licensor-liststore</property>
+                                            <child>
+                                              <object class="GtkCellRendererText" id="cellrenderertext11"/>
+                                              <attributes>
+                                                <attribute name="text">0</attribute>
+                                              </attributes>
+                                            </child>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="x_options">GTK_SHRINK | GTK_FILL</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed8">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                    </child>
+                                    <child>
+                                      <object class="GtkFixed" id="fixed9">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">13</property>
+                                        <property name="bottom_attach">14</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-postalcode-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Postal code</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">7</property>
+                                        <property name="bottom_attach">8</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-country-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Country</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">8</property>
+                                        <property name="bottom_attach">9</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-telephone1-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Telephone 1</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">9</property>
+                                        <property name="bottom_attach">10</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-telephone2-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Telephone 2</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">10</property>
+                                        <property name="bottom_attach">11</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-email-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">Email</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">11</property>
+                                        <property name="bottom_attach">12</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="licensor-url-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="xpad">3</property>
+                                        <property name="label" translatable="yes">URL</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">12</property>
+                                        <property name="bottom_attach">13</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-postalcode-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">7</property>
+                                        <property name="bottom_attach">8</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-country-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">8</property>
+                                        <property name="bottom_attach">9</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-telephone1-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">9</property>
+                                        <property name="bottom_attach">10</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-telephone2-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">10</property>
+                                        <property name="bottom_attach">11</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-email-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">11</property>
+                                        <property name="bottom_attach">12</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkEntry" id="licensor-url-entry">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">True</property>
+                                        <property name="invisible_char">●</property>
+                                        <property name="invisible_char_set">True</property>
+                                        <property name="primary_icon_activatable">False</property>
+                                        <property name="secondary_icon_activatable">False</property>
+                                        <property name="primary_icon_sensitive">True</property>
+                                        <property name="secondary_icon_sensitive">True</property>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">12</property>
+                                        <property name="bottom_attach">13</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="licensor-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Licensor</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">4</property>
+                            <property name="bottom_attach">5</property>
+                            <property name="y_padding">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFrame" id="frame3">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                            <property name="label_xalign">0</property>
+                            <property name="shadow_type">none</property>
+                            <child>
+                              <object class="GtkAlignment" id="alignment14">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="left_padding">12</property>
+                                <property name="right_padding">4</property>
+                                <child>
+                                  <object class="GtkTable" id="table16">
+                                    <property name="visible">True</property>
+                                    <property name="can_focus">False</property>
+                                    <property name="n_rows">2</property>
+                                    <property name="n_columns">2</property>
+                                    <property name="column_spacing">16</property>
+                                    <property name="row_spacing">2</property>
+                                    <child>
+                                      <object class="GtkLabel" id="release-id-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Release ID</property>
+                                      </object>
+                                      <packing>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkLabel" id="release-status-label">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="xalign">0</property>
+                                        <property name="label" translatable="yes">Release status</property>
+                                      </object>
+                                      <packing>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="x_options">GTK_FILL</property>
+                                        <property name="y_options"/>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkComboBox" id="release-status-combobox">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <property name="model">release-status-liststore</property>
+                                        <child>
+                                          <object class="GtkCellRendererText" id="cellrenderertext12"/>
+                                          <attributes>
+                                            <attribute name="text">0</attribute>
+                                          </attributes>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="top_attach">1</property>
+                                        <property name="bottom_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                    <child>
+                                      <object class="GtkAlignment" id="alignment15">
+                                        <property name="visible">True</property>
+                                        <property name="can_focus">False</property>
+                                        <child>
+                                          <object class="GtkEntry" id="release-id-entry">
+                                            <property name="width_request">350</property>
+                                            <property name="visible">True</property>
+                                            <property name="can_focus">True</property>
+                                            <property name="invisible_char">●</property>
+                                            <property name="invisible_char_set">True</property>
+                                            <property name="primary_icon_activatable">False</property>
+                                            <property name="secondary_icon_activatable">False</property>
+                                            <property name="primary_icon_sensitive">True</property>
+                                            <property name="secondary_icon_sensitive">True</property>
+                                          </object>
+                                        </child>
+                                      </object>
+                                      <packing>
+                                        <property name="left_attach">1</property>
+                                        <property name="right_attach">2</property>
+                                        <property name="y_options">GTK_EXPAND</property>
+                                      </packing>
+                                    </child>
+                                  </object>
+                                </child>
+                              </object>
+                            </child>
+                            <child type="label">
+                              <object class="GtkLabel" id="realease-label">
+                                <property name="visible">True</property>
+                                <property name="can_focus">False</property>
+                                <property name="xpad">4</property>
+                                <property name="label" translatable="yes">Release</property>
+                                <property name="use_markup">True</property>
+                              </object>
+                            </child>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">6</property>
+                            <property name="bottom_attach">7</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkFixed" id="fixed10">
+                            <property name="height_request">150</property>
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="top_attach">7</property>
+                            <property name="bottom_attach">8</property>
+                          </packing>
+                        </child>
+                        <child>
+                          <object class="GtkHSeparator" id="hseparator9">
+                            <property name="visible">True</property>
+                            <property name="can_focus">False</property>
+                          </object>
+                          <packing>
+                            <property name="right_attach">2</property>
+                            <property name="top_attach">5</property>
+                            <property name="bottom_attach">6</property>
+                            <property name="x_options">GTK_FILL</property>
+                            <property name="y_options"/>
+                          </packing>
+                        </child>
+                      </object>
+                    </child>
+                  </object>
+                </child>
+              </object>
+              <packing>
+                <property name="expand">True</property>
+                <property name="fill">True</property>
+                <property name="position">0</property>
+              </packing>
+            </child>
+          </object>
+          <packing>
+            <property name="position">3</property>
+          </packing>
+        </child>
+        <child type="tab">
+          <object class="GtkLabel" id="rights-label">
+            <property name="visible">True</property>
+            <property name="can_focus">False</property>
+            <property name="label" translatable="yes">Rights</property>
+          </object>
+          <packing>
+            <property name="position">3</property>
+            <property name="tab_fill">False</property>
+          </packing>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">True</property>
+        <property name="fill">True</property>
+        <property name="position">1</property>
+      </packing>
+    </child>
+    <child>
+      <object class="GtkHBox" id="hbox1">
+        <property name="visible">True</property>
+        <property name="can_focus">False</property>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+        <child>
+          <placeholder/>
+        </child>
+      </object>
+      <packing>
+        <property name="expand">False</property>
+        <property name="fill">True</property>
+        <property name="position">2</property>
+      </packing>
+    </child>
+  </object>
+  <object class="GtkListStore" id="registryid-liststore">
+    <columns>
+      <!-- column-name Registry -->
+      <column type="gchararray"/>
+    </columns>
+  </object>
+</interface>
diff --git a/po-plug-ins/POTFILES.in b/po-plug-ins/POTFILES.in
index 93dc7ff..e512d53 100644
--- a/po-plug-ins/POTFILES.in
+++ b/po-plug-ins/POTFILES.in
@@ -6,6 +6,7 @@
 plug-ins/common/align-layers.c
 plug-ins/common/animation-optimize.c
 plug-ins/common/animation-play.c
+plug-ins/common/attributes.c
 plug-ins/common/blinds.c
 plug-ins/common/blur.c
 plug-ins/common/blur-gauss-selective.c
@@ -87,7 +88,6 @@ plug-ins/common/lcms.c
 plug-ins/common/lens-flare.c
 plug-ins/common/mail.c
 plug-ins/common/max-rgb.c
-plug-ins/common/metadata.c
 plug-ins/common/newsprint.c
 plug-ins/common/nl-filter.c
 plug-ins/common/noise-solid.c
@@ -171,7 +171,8 @@ plug-ins/gimpressionist/utils.c
 [type: gettext/glade]plug-ins/ui/plug-in-file-gif.ui
 [type: gettext/glade]plug-ins/ui/plug-in-file-png.ui
 [type: gettext/glade]plug-ins/ui/plug-in-file-tiff.ui
-[type: gettext/glade]plug-ins/ui/plug-in-metadata.ui
+[type: gettext/glade]plug-ins/ui/plug-in-metainfo.ui
+[type: gettext/glade]plug-ins/ui/plug-in-attributes.ui
 plug-ins/gradient-flare/gradient-flare.c
 plug-ins/help-browser/dialog.c
 plug-ins/help-browser/help-browser.c
@@ -233,6 +234,11 @@ plug-ins/maze/maze-algorithms.c
 plug-ins/maze/maze-dialog.c
 plug-ins/maze/maze.c
 plug-ins/maze/maze.h
+plug-ins/metainfo/interface.c
+plug-ins/metainfo/page-administration.c
+plug-ins/metainfo/page-rights.c
+plug-ins/metainfo/page-description.c
+plug-ins/metainfo/page-artwork.c
 plug-ins/pagecurl/pagecurl.c
 plug-ins/print/print-draw-page.c
 plug-ins/print/print-page-layout.c
diff --git a/tools/pdbgen/pdb/image.pdb b/tools/pdbgen/pdb/image.pdb
index be468f8..73237bb 100644
--- a/tools/pdbgen/pdb/image.pdb
+++ b/tools/pdbgen/pdb/image.pdb
@@ -1625,11 +1625,11 @@ CODE
     );
 }
 
-sub image_get_metadata {
-    $blurb = "Returns the image's metadata.";
-    $help  = 'Returns exif/iptc/xmp metadata from the image.';
+sub image_get_attributes {
+    $blurb = "Returns the image's attributes.";
+    $help  = 'Returns attributes from the image.';
 
-    &std_pdb_misc('2013', '2.10');
+    &std_pdb_misc('2014', '2.10');
 
     @inargs = (
         { name => 'image', type => 'image',
@@ -1637,44 +1637,44 @@ sub image_get_metadata {
     );
 
     @outargs = (
-       { name => 'metadata_string', type => 'string', wrap => 1,
-         desc => 'The exif/ptc/xmp metadata as a string'}
+       { name => 'attributes_string', type => 'string', wrap => 1,
+         desc => 'The attributes as a xml string'}
     );
 
     %invoke = (
        code => <<'CODE'
 {
-  GimpMetadata *metadata = gimp_image_get_metadata (image);
+  GimpAttributes *attributes = gimp_image_get_attributes (image);
 
-  if (metadata)
-    metadata_string = gimp_metadata_serialize (metadata);
+  if (attributes)
+    attributes_string = gimp_attributes_serialize (attributes);
 }
 CODE
     );
 }
 
-sub image_set_metadata {
-    $blurb = "Set the image's metadata.";
-    $help  = 'Sets exif/iptc/xmp metadata on the image.';
+sub image_set_attributes {
+    $blurb = "Set the image's attributes.";
+    $help  = 'Sets attributes on the image.';
 
-    &std_pdb_misc('2013', '2.10');
+    &std_pdb_misc('2014', '2.10');
 
     @inargs = (
         { name => 'image', type => 'image',
           desc => 'The image' },
-       { name => 'metadata_string', type => 'string', wrap => 1,
-         desc => 'The exif/ptc/xmp metadata as a string' }
+       { name => 'attributes_string', type => 'string', wrap => 1,
+         desc => 'The attributes as a xml string' }
     );
 
     %invoke = (
        code => <<'CODE'
 {
-  GimpMetadata *metadata = gimp_metadata_deserialize (metadata_string);
+  GimpAttributes *attributes = gimp_attributes_deserialize (attributes_string);
 
-  gimp_image_set_metadata (image, metadata, TRUE);
+  gimp_image_set_attributes (image, attributes, TRUE);
 
-  if (metadata)
-    g_object_unref (metadata);
+  if (attributes)
+    g_object_unref (attributes);
 }
 CODE
     );
@@ -3095,7 +3095,7 @@ CODE
             image_flatten image_merge_visible_layers image_merge_down
             image_add_layer_mask image_remove_layer_mask
             image_get_colormap image_set_colormap
-            image_get_metadata image_set_metadata
+            image_set_attributes image_get_attributes
             image_clean_all image_is_dirty
             image_thumbnail
             image_get_active_layer image_set_active_layer
diff --git a/tools/pdbgen/pdb/item.pdb b/tools/pdbgen/pdb/item.pdb
index 6d99a51..7eaac52 100644
--- a/tools/pdbgen/pdb/item.pdb
+++ b/tools/pdbgen/pdb/item.pdb
@@ -734,6 +734,61 @@ CODE
     );
 }
 
+sub item_get_attributes {
+    $blurb = "Returns the item's attributes.";
+    $help  = 'Returns attributes from the item.';
+
+    &std_pdb_misc('2014', '2.10');
+
+    @inargs = (
+        { name => 'item', type => 'item',
+          desc => 'The item' }
+    );
+
+    @outargs = (
+       { name => 'attributes_string', type => 'string', wrap => 1,
+         desc => 'The attributes as a xml string'}
+    );
+
+    %invoke = (
+       code => <<'CODE'
+{
+  GimpAttributes *attributes = gimp_item_get_attributes (item);
+
+  if (attributes)
+    attributes_string = gimp_attributes_serialize (attributes);
+}
+CODE
+    );
+}
+
+sub item_set_attributes {
+    $blurb = "Set the item's attributes.";
+    $help  = 'Sets attributes on the item.';
+
+    &std_pdb_misc('2014', '2.10');
+
+    @inargs = (
+        { name => 'item', type => 'item',
+          desc => 'The item' },
+       { name => 'attributes_string', type => 'string', wrap => 1,
+         desc => 'The attributes as a xml string' }
+    );
+
+    %invoke = (
+       code => <<'CODE'
+{
+  GimpAttributes *attributes = gimp_attributes_deserialize (attributes_string);
+
+  gimp_item_set_attributes (item, attributes, TRUE);
+
+  if (attributes)
+    g_object_unref (attributes);
+}
+CODE
+    );
+}
+
 sub item_attach_parasite {
     $blurb = 'Add a parasite to an item.';
 
@@ -847,10 +902,12 @@ CODE
 }
 
 @headers = qw("core/gimplayermask.h"
+              "libgimpbase/gimpbase.h"
               "core/gimplist.h"
               "core/gimpselection.h"
+              "core/gimpitem-metadata.h"
               "text/gimptextlayer.h"
-             "vectors/gimpvectors.h"
+              "vectors/gimpvectors.h"
               "gimppdb-utils.h"
               "gimppdbcontext.h"
               "gimp-intl.h");
@@ -861,22 +918,23 @@ CODE
             item_is_drawable
             item_is_layer
             item_is_text_layer
-           item_is_channel
-           item_is_layer_mask
-           item_is_selection
-           item_is_vectors
-           item_is_group
+            item_is_channel
+            item_is_layer_mask
+            item_is_selection
+            item_is_vectors
+            item_is_group
             item_get_parent
-           item_get_children
+            item_get_children
             item_get_name item_set_name
             item_get_visible item_set_visible
             item_get_linked item_set_linked
             item_get_lock_content item_set_lock_content
             item_get_lock_position item_set_lock_position
             item_get_tattoo item_set_tattoo
-           item_attach_parasite item_detach_parasite
-           item_get_parasite
-           item_get_parasite_list);
+            item_get_attributes item_set_attributes
+            item_attach_parasite item_detach_parasite
+            item_get_parasite
+            item_get_parasite_list);
 
 %exports = (app => [ procs], lib => [ procs]);
 
diff --git a/tools/pdbgen/pdb/viewable.pdb b/tools/pdbgen/pdb/viewable.pdb
new file mode 100644
index 0000000..ba80b52
--- /dev/null
+++ b/tools/pdbgen/pdb/viewable.pdb
@@ -0,0 +1,109 @@
+# GIMP - The GNU Image Manipulation Program
+# Copyright (C) 1995 Spencer Kimball and Peter Mattis
+
+# 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 <http://www.gnu.org/licenses/>.
+
+# "Perlized" from C source by Manish Singh <yosh gimp org>
+
+sub viewable_get_attributes {
+    $blurb = "Returns the viewables's attributes.";
+    $help = <<'HELP';
+This procedure returns the stored attributes of a viewable
+GimpViewable is one of the lowest class in gimp, that other
+clsses are derived from.
+That is:
+image
+Layer
+Layer mask
+Grouplayer
+Brush/BrushPipe
+HELP
+
+    &std_pdb_misc('2014', '2.10');
+
+    @inargs = (
+        { name => 'object', type => 'GObject',
+          desc => 'The object' }
+    );
+
+    @outargs = (
+       { name => 'attributes_string', type => 'string', wrap => 1,
+         desc => 'The attributes as a xml string'}
+    );
+
+    %invoke = (
+       code => <<'CODE'
+{
+  GimpAttributes *attributes = gimp_viewable_get_attributes (object);
+
+  if (attributes)
+    attributes_string = gimp_attributes_serialize (metadata);
+}
+CODE
+    );
+}
+
+sub viewable_set_attributes {
+    $blurb = "Set the viewables attributes.";
+    $help = <<'HELP';
+This procedure set attributes of a viewable.
+GimpViewable is one of the lowest class in gimp, that other
+clsses are derived from.
+That is:
+image
+Layer
+Layer mask
+Grouplayer
+Brush/BrushPipe
+HELP
+
+    &std_pdb_misc('2014', '2.10');
+
+    @inargs = (
+        { name => 'object', type => 'GObject',
+          desc => 'The image' },
+       { name => 'attributes_string', type => 'string', wrap => 1,
+         desc => 'The attributes as a xml string' }
+    );
+
+    %invoke = (
+       code => <<'CODE'
+{
+  GimpAttributes *attributes = gimp_attributes_deserialize (NULL, attributes_string);
+
+  gimp_viewable_set_attributes (image, attributes);
+
+  if (attributes)
+    g_object_unref (attributes);
+}
+CODE
+    );
+}
+
+
+ headers = qw("libgimpbase/gimpbase.h"
+              "core/gimp.h"
+              "core/gimpviewable.h");
+
+ procs = qw(image_get_attributes
+            image_set_attributes);
+
+%exports = (app => [ procs], lib => [ procs]);
+
+$desc = 'Viewable attributes';
+$doc_title = 'viewableattributes';
+$doc_short_desc = 'Operations related to viewable attribuites.';
+$doc_long_desc = 'Operations related to viewable attribuites.';
+
+1;


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