[gimp/gimpmetadata-new-wip] plug-ins: adding attributes and iptc
- From: Hartmut Kuhse <hartmutkuhse src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gimp/gimpmetadata-new-wip] plug-ins: adding attributes and iptc
- Date: Thu, 5 Jan 2017 19:20:18 +0000 (UTC)
commit e6853696f1dc3262c8871fd4d3bfc5ad20301daf
Author: Hartmut Kuhse <hk_priv gmx de>
Date: Thu Jan 5 20:19:44 2017 +0100
plug-ins: adding attributes and iptc
plug-ins/common/attributes.c | 949 ++++++++++++++++++++++++++++++++++++++++++
plug-ins/common/iptc.c | 467 +++++++++++++++++++++
2 files changed, 1416 insertions(+), 0 deletions(-)
---
diff --git a/plug-ins/common/attributes.c b/plug-ins/common/attributes.c
new file mode 100644
index 0000000..f3ff915
--- /dev/null
+++ b/plug-ins/common/attributes.c
@@ -0,0 +1,949 @@
+/* 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>
+#include <gio/gio.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 <libgimpbase/gimpbase.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_HELP "plug-in-attributes-viewer"
+#define PLUG_IN_BINARY "attributes"
+
+#define THUMB_SIZE 48
+#define RESPONSE_EXPORT 1
+#define RESPONSE_GPS 3
+
+typedef enum
+{
+ ATT_IMAGE,
+ ATT_LAYER,
+ ATT_CHANNEL
+} AttributesSource;
+
+enum
+{
+ C_IFD = 0,
+ C_TAG,
+ C_VALUE,
+ C_SORT,
+ 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,
+ GimpMetadata *metadata);
+static void attributes_dialog_set_attributes (GimpMetadata *metadata,
+ 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,
+ GimpMetadata *metadata);
+static void attributes_export_dialog_response (GtkWidget *dlg,
+ gint response_id,
+ gpointer data);
+static void attributes_show_gps (GtkWidget *parent,
+ GimpMetadata *metadata);
+
+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;
+
+static gchar *item_name = NULL;
+
+static GtkWidget *gps_button;
+static gdouble gps_latitude = 0.0;
+static gdouble gps_longitude = 0.0;
+static gchar *gps_latitude_ref = "N";
+static gchar *gps_longitude_ref = "W";
+
+/* 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" }
+ };
+
+ gimp_install_procedure (PLUG_IN_IMAGE_PROC,
+ N_("View image metadata (Exif, IPTC, XMP, ...)"),
+ "View metadata information attached to the "
+ "current image. This can include Exif, IPTC, "
+ "XMP and/or other information. Some or all of these "
+ "metadata will be saved in the file, depending on "
+ "the output file format.",
+ "Hartmut Kuhse",
+ "Hartmut Kuhse",
+ "2014",
+ N_("Image 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_plugin_icon_register (PLUG_IN_IMAGE_PROC, GIMP_ICON_TYPE_ICON_NAME,
+ (const guint8 *) GIMP_STOCK_IMAGE_METADATA);
+
+ gimp_install_procedure (PLUG_IN_LAYER_PROC,
+ N_("View layer metadata (Exif, IPTC, XMP, ...)"),
+ "View metadata information attached to the "
+ "current layer. This can include Exif, IPTC, "
+ "XMP and/or other information.",
+ "Hartmut Kuhse",
+ "Hartmut Kuhse",
+ "2014",
+ N_("Layer Metadata"),
+ "*",
+ GIMP_PLUGIN,
+ G_N_ELEMENTS (layer_attribs_args), 0,
+ layer_attribs_args, NULL);
+
+ gimp_plugin_menu_register (PLUG_IN_LAYER_PROC, "<Layers>");
+ gimp_plugin_icon_register (PLUG_IN_LAYER_PROC, GIMP_ICON_TYPE_ICON_NAME,
+ (const guint8 *) GIMP_STOCK_IMAGE_METADATA);
+
+}
+
+static void
+run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ GimpMetadata *metadata;
+ 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;
+
+ metadata = gimp_image_get_metadata (item_ID);
+ source = ATT_IMAGE;
+
+ status = GIMP_PDB_SUCCESS;
+ }
+ else if (! strcmp (name, PLUG_IN_LAYER_PROC))
+ {
+ item_ID = param[2].data.d_layer;
+
+ metadata = gimp_item_get_metadata (item_ID);
+ source = ATT_LAYER;
+
+ status = GIMP_PDB_SUCCESS;
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+ if (metadata)
+ {
+ 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, metadata);
+ }
+ else
+ {
+ g_message (_("This image has no attributes attached to it."));
+ }
+
+ if (metadata)
+ g_object_unref (metadata);
+
+ 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)
+{
+
+ GimpMetadata *metadata = (GimpMetadata *) data;
+ switch (response_id)
+ {
+ case RESPONSE_EXPORT:
+ attributes_file_export_dialog (widget, metadata);
+ break;
+ case RESPONSE_GPS:
+ attributes_show_gps (widget, metadata);
+ break;
+
+ default:
+ gtk_widget_destroy (widget);
+ break;
+ }
+}
+
+static gboolean
+attributes_dialog (gint32 item_id,
+ AttributesSource source,
+ GimpMetadata *metadata)
+{
+ 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 *role;
+ GError *error = NULL;
+
+ gimp_ui_init (PLUG_IN_BINARY, FALSE);
+
+ switch (source)
+ {
+ case ATT_IMAGE:
+ item_name = 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:
+ item_name = 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;
+ default:
+ item_name = 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", item_name);
+
+ 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);
+
+ gps_button = gtk_dialog_add_button (GTK_DIALOG (dialog), _("_Show GPS..."), RESPONSE_GPS);
+ gtk_widget_set_sensitive (GTK_WIDGET (gps_button), FALSE);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (attributes_dialog_response),
+ metadata);
+
+ 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_GPS,
+ 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), item_name);
+
+ g_free (header);
+
+ 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 (metadata, builder);
+
+ gtk_widget_show (GTK_WIDGET (dialog));
+
+ gtk_main ();
+
+ return TRUE;
+}
+
+
+/* private functions */
+
+static void
+attributes_dialog_set_attributes (GimpMetadata *metadata,
+ GtkBuilder *builder)
+{
+ GtkTreeStore *exif_store;
+ GtkTreeStore *xmp_store;
+ GtkTreeStore *iptc_store;
+ GtkTreeView *exif_treeview;
+ GtkTreeView *xmp_treeview;
+ GtkTreeView *iptc_treeview;
+ GtkWidget *attributes_notebook;
+ GList *iter_list = NULL;
+ GimpAttribute *attribute = NULL;
+ gboolean gps_lat = FALSE;
+ gboolean gps_lon = FALSE;
+
+ 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"));
+
+ gimp_metadata_iter_init (metadata, &iter_list);
+
+ while (gimp_metadata_iter_next (metadata, &attribute, &iter_list))
+ {
+ const gchar *name;
+ const gchar *type;
+ const gchar *ifd;
+ const gchar *tag;
+ const gchar *value;
+ const gchar *tag_sorted;
+ gchar *value_utf;
+ GtkTreeIter *parent = NULL;
+ GtkTreeIter *iter = g_slice_new (GtkTreeIter);
+
+ 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);
+ tag_sorted = gimp_attribute_get_sortable_name (attribute);
+ value = gimp_attribute_get_interpreted_string (attribute);
+
+ if (! g_utf8_validate (value, -1, NULL))
+ value_utf = g_locale_to_utf8 (value, -1, NULL, NULL, NULL);
+ else
+ value_utf = g_strdup (value);
+
+ parent = attributes_get_parent (type, ifd);
+
+ if (! g_strcmp0 (name, "Exif.GPSInfo.GPSLatitude"))
+ {
+ gps_lat = TRUE;
+ gps_latitude = gimp_attribute_get_gps_degree (attribute);
+ if (gps_latitude < 0.0 && !gps_latitude_ref)
+ {
+ gps_latitude = gps_latitude * -1.0;
+ gps_latitude_ref = "S";
+ }
+
+ }
+ if (! g_strcmp0 (name, "Exif.GPSInfo.GPSLatitudeRef"))
+ {
+ gps_latitude_ref = gimp_attribute_get_string (attribute);
+ }
+ if (! g_strcmp0 (name, "Exif.GPSInfo.GPSLongitude"))
+ {
+ gps_lon = TRUE;
+ gps_longitude = gimp_attribute_get_gps_degree (attribute);
+ if (gps_longitude < 0.0 && !gps_longitude_ref)
+ {
+ gps_longitude = gps_longitude * -1.0;
+ gps_longitude_ref = "W";
+ }
+ }
+ if (! g_strcmp0 (name, "Exif.GPSInfo.GPSLongitudeRef"))
+ {
+ gps_longitude_ref = gimp_attribute_get_string (attribute);
+ }
+
+ if (gps_lat && gps_lon)
+ {
+ gtk_widget_set_sensitive (gps_button, TRUE);
+ gps_lat = FALSE;
+ gps_lon = FALSE;
+ }
+
+ 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, "",
+ C_SORT, "",
+ -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,
+ C_SORT, tag_sorted,
+ -1);
+ attributes_add_parent (type, ifd, parent);
+ }
+ else
+ {
+
+ gtk_tree_store_set (exif_store, iter,
+ C_IFD, "",
+ C_TAG, tag,
+ C_VALUE, value_utf,
+ C_SORT, tag_sorted,
+ -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, "",
+ C_SORT, "",
+ -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,
+ C_SORT, tag_sorted,
+ -1);
+ attributes_add_parent (type, ifd, parent);
+ }
+ else
+ {
+
+ gtk_tree_store_set (xmp_store, iter,
+ C_IFD, "",
+ C_TAG, tag,
+ C_VALUE, value_utf,
+ C_SORT, tag_sorted,
+ -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, "",
+ C_SORT, "",
+ -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,
+ C_SORT, tag_sorted,
+ -1);
+ attributes_add_parent (type, ifd, parent);
+ }
+ else
+ {
+
+ gtk_tree_store_set (iptc_store, iter,
+ C_IFD, "",
+ C_TAG, tag,
+ C_VALUE, value_utf,
+ C_SORT, tag_sorted,
+ -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_SORT, GTK_SORT_ASCENDING);
+
+ gtk_tree_view_expand_all (xmp_treeview);
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(xmp_store),
+ C_SORT, GTK_SORT_ASCENDING);
+ gtk_tree_view_expand_all (iptc_treeview);
+ gtk_tree_sortable_set_sort_column_id(GTK_TREE_SORTABLE(iptc_store),
+ C_SORT, 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,
+ GimpMetadata *metadata)
+{
+ static GtkWidget *dlg = NULL;
+ gchar *suggest_file;
+// GTK_WINDOW (parent),
+
+ suggest_file = g_strdup_printf ("%s.xmp", item_name);
+
+ 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);
+
+ gtk_file_chooser_set_current_name (GTK_FILE_CHOOSER (dlg), suggest_file);
+
+ g_signal_connect (dlg, "destroy",
+ G_CALLBACK (gtk_widget_destroyed),
+ &dlg);
+ g_signal_connect (dlg, "response",
+ G_CALLBACK (attributes_export_dialog_response),
+ metadata);
+
+ g_free (suggest_file);
+ }
+ gtk_window_present (GTK_WINDOW (dlg));
+}
+
+/* call default browser for google maps */
+static void
+attributes_show_gps (GtkWidget *parent,
+ GimpMetadata *metadata)
+{
+ GError *error = NULL;
+ gchar *uri = NULL;
+ gchar lat_buf[G_ASCII_DTOSTR_BUF_SIZE];
+ gchar lon_buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+ if (!g_strcmp0 (gps_latitude_ref, "S"))
+ gps_latitude = gps_latitude * -1.0;
+ if (!g_strcmp0 (gps_longitude_ref, "W"))
+ gps_longitude = gps_longitude * -1.0;
+
+ g_ascii_formatd (lat_buf, G_ASCII_DTOSTR_BUF_SIZE, "%.6f",
+ gps_latitude);
+ g_ascii_formatd (lon_buf, G_ASCII_DTOSTR_BUF_SIZE, "%.6f",
+ gps_longitude);
+
+ uri = g_strdup_printf ("http://maps.google.com?q=%s,%s&z=15",
+ lat_buf,
+ lon_buf);
+
+ g_app_info_launch_default_for_uri (uri, NULL, &error);
+ if (error)
+ {
+ attributes_message_dialog (GTK_MESSAGE_ERROR, GTK_WINDOW (parent),
+ _("GPS failure"),
+ error->message);
+ }
+
+
+}
+
+/* save XMP metadata to a file (only XMP, nothing else) */
+static void
+attributes_export_dialog_response (GtkWidget *dlg,
+ gint response_id,
+ gpointer data)
+{
+ GimpMetadata *metadata = (GimpMetadata *) data;
+
+ g_return_if_fail (metadata != NULL);
+
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ GString *buffer;
+ const gchar *xmp_data = NULL;
+ gchar *filename = NULL;
+ int fd;
+
+ xmp_data = gimp_metadata_to_xmp_packet (metadata, "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/iptc.c b/plug-ins/common/iptc.c
new file mode 100644
index 0000000..d140152
--- /dev/null
+++ b/plug-ins/common/iptc.c
@@ -0,0 +1,467 @@
+/* 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_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,
+ GimpMetadata *metadata,
+ AttributesSource source,
+ GtkBuilder *builder);
+
+static void iptc_dialog_set_iptc (GimpMetadata *metadata,
+ GtkBuilder *builder);
+
+static void iptc_change_iptc (GimpMetadata *metadata,
+ 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" }
+ };
+
+ 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>");
+}
+
+static void
+run (const gchar *name,
+ gint nparams,
+ const GimpParam *param,
+ gint *nreturn_vals,
+ GimpParam **return_vals)
+{
+ GimpMetadata *metadata;
+ 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;
+
+ metadata = gimp_image_get_metadata (item_ID);
+ source = ATT_IMAGE;
+
+ status = GIMP_PDB_SUCCESS;
+ }
+ else if (! strcmp (name, PLUG_IN_LAYER_PROC))
+ {
+ item_ID = param[2].data.d_layer;
+
+ metadata = gimp_item_get_metadata (item_ID);
+ source = ATT_LAYER;
+
+ status = GIMP_PDB_SUCCESS;
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+ if (! metadata)
+ {
+ metadata = gimp_metadata_new();
+ }
+
+ builder = gtk_builder_new ();
+
+ if (status == GIMP_PDB_SUCCESS && iptc_dialog (item_ID, metadata, source, builder))
+ {
+
+ iptc_change_iptc (metadata, builder);
+
+ if (! strcmp (name, PLUG_IN_IMAGE_PROC))
+ {
+ gimp_image_set_metadata (item_ID, metadata);
+ }
+ else if (! strcmp (name, PLUG_IN_LAYER_PROC))
+ {
+ gimp_item_set_metadata (item_ID, metadata);
+ }
+ status = GIMP_PDB_SUCCESS;
+ }
+ else
+ {
+ status = GIMP_PDB_CALLING_ERROR;
+ }
+
+ g_object_unref (metadata);
+
+ values[0].data.d_status = status;
+}
+
+static gboolean
+iptc_dialog (gint32 item_id,
+ GimpMetadata *metadata,
+ 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;
+ default:
+ fname = g_strdup_printf ("unknown");
+ header = g_strdup_printf ("Unknown");
+ title = g_strdup_printf ("Metadata : %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 (metadata, builder);
+
+ run = (gimp_dialog_run (GIMP_DIALOG (dialog)) == GTK_RESPONSE_OK);
+
+ return run;
+}
+
+
+/* private functions */
+
+static void
+iptc_dialog_set_iptc (GimpMetadata *metadata,
+ GtkBuilder *builder)
+{
+ gchar *value;
+ gint i;
+
+ for (i = 0; i < G_N_ELEMENTS (iptc_tags); i++)
+ {
+ GimpAttribute *attribute = NULL;
+ GtkWidget *widget = NULL;
+
+ attribute = gimp_metadata_get_attribute (metadata, 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 (GimpMetadata *metadata,
+ 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_metadata_add_attribute (metadata, attribute);
+ }
+ else
+ {
+ gimp_metadata_remove_attribute (metadata, 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_metadata_add_attribute (metadata, attribute);
+ }
+ else
+ {
+ gimp_metadata_remove_attribute (metadata, iptc_tags[i].tag);
+ }
+
+ g_free (text);
+ }
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]