In order to improve the support for metadata (XMP and EXIF), I would
like to move some of the code that is currently located in the
plug-ins/metadata directory into a new library, "libgimpmetadata".
This library would be linked with all file plug-ins that support
metadata.  This includes JPEG, PNG, TIFF and maybe GIF, PSD, SVG and
other file formats.

The metadata is stored internally as an XMP packet inside a gimp image
parasite (so it is transparently saved in xcf files).  Instead of
manipulating this parasite directly, the file plug-ins can use the
libgimpmetadata library for getting or setting individual properties
in the XMP packet, for merging EXIF data into the XMP packet or for
generating an EXIF block from parts of the XMP data.  Due to the need
to generate JPEG thumbnails, the library adds a dependency on libjpeg.

Sven asked for a review of the proposed API for this library, so here
it is.  Note that the library does not define new gobject classes or
anything like that.  This is simply a set of functions for accessing
the metadata that is attached to the image (in a parasite that should
be mostly opaque for the user).

/* decode the given XMP packet (read from a file) and merge it into the 
metadata parasite. */
gimp_metadata_decode_xmp  (gint32        image_ID,
                           const gchar  *xmp_packet);

/* generate an XMP packet from the metadata parasite */
const gchar *
gimp_metadata_encode_xmp  (gint32        image_ID);

/* decode the given EXIF block (read from a file) and merge it into the 
metadata parasite. */
gimp_metadata_decode_exif (gint32        image_ID,
                           guint         exif_size,
                           const gchar  *exif_block);

/* generate an EXIF block from the EXIF-compatible parts of the metadata 
parasite */
gimp_metadata_encode_exif (gint32        image_ID,
                           guint        *exif_size,
                           const gchar **exif_block);

/* get the value(s) of a single XMP property */
gimp_metadata_get         (gint32               image_ID,
                           const gchar         *schema,
                           const gchar         *property,
                           GimpXMPPropertyType *type,
                           gint                *num_values,
                           const gchar       ***values);

/* set the value(s) of a single XMP property */
gimp_metadata_set         (gint32               image_ID,
                           const gchar         *schema,
                           const gchar         *property,
                           GimpXMPPropertyType  type,
                           gint                 num_values,
                           const gchar        **values);

/* delete a single XMP property */
gimp_metadata_delete      (gint32               image_ID,
                           const gchar         *schema,
                           const gchar         *property);

/* same as gimp_metadata_get() but simpler, for scalar properties */
const gchar *
gimp_metadata_get_scalar  (gint32               image_ID,
                           const gchar         *schema,
                           const gchar         *property);

/* same as gimp_metadata_set() but simpler, for scalar properties */
gimp_metadata_set_scalar  (gint32               image_ID,
                           const gchar         *schema,
                           const gchar         *property,
                           const gchar         *value);

/* register a non-standard XMP schema prefix for use in get/set procs */
gimp_metadata_add_schema  (gint32               image_ID,
                           const gchar         *schema,
                           const gchar         *schema_prefix);

Example of use:
- An image containing both XMP and EXIF information is loaded
- Call gimp_metadata_encode_exif (image, exif_size, exif_block) to
  load the EXIF block into the gimp metadata parasite.
- Call gimp_metadata_encode_xmp (image, xmp_packet) to merge the XMP
  information into the gimp metadata parasite.  If some properties are
  present in both XMP and EXIF (this is very likely), the old EXIF
  information is overwritten: XMP always takes precedence.
- Call gimp_metadata_set_scalar (image, "dc", "contributor", "John Doe");
  to set the "dc:contributor" property.
- Call gimp_metadata_set_scalar (image, "";,
  "UserComment", "foo!"); to set the "exif:UserComment" property.  Here,
  the full schema URI is used but it would also be possible to use the
  "exif" prefix because this is a known prefix (standardized).
- Call xmp_packet = gimp_metadata_encode_xmp (image); to generate a
  new XMP packet suitable for saving into a file.

Most of the functions listed above are currently implemented in the
metadata plug-in and exported in the PDB.  So you can find a slightly
longer description of these functions by looking in the Procedure
Browser and searching for "metadata".  If you are curious, you can
also look in the code: plug-ins/metadata/metadata.c is where these
functions are registered and plug-ins/metadata/xmp-model.c is where
they are implemented.  After moving these functions in the new
libgimpmetadata library, they would still be exported to the PDB but
probably renamed gimp-metadata-* instead of plug-in-metadata-*.

The type GimpXMPPropertyType is an enum that is currently defined as
"XMPType" in plug-ins/metadata/xmp-schemas.h.  That file would be
moved into libgimpmetadata and changed accordingly (XMPProperty and
XMPSchema would become private types).

The functions gimp_metadata_get/set_scalar() are simpler versions of
the get/set() functions that are easier to use.  In this proposed API,
all scalar types would be converted to/from strings.  Many proporties
are text strings (XMP_TYPE_TEXT, XMP_TYPE_URI), but some of them are
integers (XMP_TYPE_INTEGER), booleans (XMP_TYPE_BOOLEAN) or slightly
more complex types that are "almost" scalar (XMP_TYPE_DATE,
XMP_TYPE_MIME_TYPE, XMP_TYPE_RATIONAL).  I am not sure if converting
these types to/from strings is the best option but that seems
reasonable to me.  Another option would be to have a special case for
integers and booleans: add gimp_metadata_get/set_integer() and maybe
rename get/set_scalar() to get/set_string().

The functions for converting to/from EXIF are not ready yet.  I have
started implementing them but did not go very far yet.  I would like
to avoid a dependency on libexif or on libtiff (EXIF is actually a
TIFF block with a JPEG thumbnail, usually stored inside a JPEG file)
because converting EXIF to XMP only requires a small subset of the API
provided by these libraries.

The XMP and EXIF thumbnails will be generated as a side-effect of
calling gimp_metadata_encode_xmp() or gimp_metadata_encode_exif().
These functions will also update all the other fields that must be
automatically updated according to the XMP and EXIF specifications:
image dimensions, resolution, modification date, metadata modification
date.  The XMP specifications also require the MIME type ("dc:format")
to be updated automatically, but this can only be done by the file
plug-in when saving the file.  One option is that all file save
plug-ins would call gimp_metadata_set_scalar(image, "dc", "format"...)
before requesting the full XMP or EXIF data.  Another option would be
to add a new function in the API for updating the thumbnail and other
metadata explicitely instead of doing it implicitely inside
gimp_metadata_encode_xmp/exif().  This function could look like this:

gimp_metadata_update (gint32        image_ID,
                      gboolean      update_thumbnail,
                      const gchar  *mime_type);

Once the code is clearly split between the core (library for managing
the metadata parasite, XMP and EXIF) and the GUI (metadata editor), I
think that it will be easier for me to finish the EXIF parts.  I would
then welcome some help for the GUI, which is currently a disaster.

Gimp-developer mailing list

Reply via email to