[frogr] Allow automatic import from tags from XMP metadata.
- From: Mario Sanchez Prada <msanchez src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [frogr] Allow automatic import from tags from XMP metadata.
- Date: Thu, 18 Aug 2011 02:02:38 +0000 (UTC)
commit 6efca9033c5c42d553b9f8e129c4af756ae0d787
Author: Mario Sanchez Prada <msanchez igalia com>
Date: Tue Aug 16 09:39:40 2011 +0200
Allow automatic import from tags from XMP metadata.
This should enable frogr to import keywords and tags as set in other
applications (e.g. shotwell, f-spot...) to use them rightaway when
uploading to flickr.
src/frogr-config.c | 36 ++++++
src/frogr-config.h | 5 +
src/frogr-picture-loader.c | 275 ++++++++++++++++++++++++++++++-------------
src/frogr-settings-dialog.c | 18 +++-
4 files changed, 253 insertions(+), 81 deletions(-)
---
diff --git a/src/frogr-config.c b/src/frogr-config.c
index 64e661f..56bcdae 100644
--- a/src/frogr-config.c
+++ b/src/frogr-config.c
@@ -61,6 +61,8 @@ struct _FrogrConfigPrivate
gboolean tags_autocompletion;
gboolean keep_file_extensions;
+ gboolean import_tags_from_metadata;
+
SortingCriteria mainview_sorting_criteria;
gboolean mainview_sorting_reversed;
gboolean mainview_enable_tooltips;
@@ -263,6 +265,16 @@ _load_settings (FrogrConfig *self, const gchar *config_dir)
xmlFree (content);
}
+ if (!xmlStrcmp (node->name, (const xmlChar*) "import-tags-from-metadata"))
+ {
+ xmlChar *content = NULL;
+
+ content = xmlNodeGetContent (node);
+ priv->import_tags_from_metadata = !xmlStrcmp (content, (const xmlChar*) "1");
+
+ xmlFree (content);
+ }
+
if (!xmlStrcmp (node->name, (const xmlChar*) "mainview-options"))
_load_mainview_options_xml (self, xml, node);
@@ -654,6 +666,7 @@ _save_settings (FrogrConfig *self)
/* Other stuff */
_xml_add_bool_child (root, "tags-autocompletion", priv->tags_autocompletion);
_xml_add_bool_child (root, "keep-file-extensions", priv->keep_file_extensions);
+ _xml_add_bool_child (root, "import-tags-from-metadata", priv->import_tags_from_metadata);
node = xmlNewNode (NULL, (const xmlChar*) "mainview-options");
_xml_add_bool_child (node, "enable-tooltips", priv->mainview_enable_tooltips);
_xml_add_int_child (node, "sorting-criteria", priv->mainview_sorting_criteria);
@@ -914,6 +927,7 @@ frogr_config_init (FrogrConfig *self)
priv->content_type = FSP_CONTENT_TYPE_PHOTO;
priv->tags_autocompletion = TRUE;
priv->keep_file_extensions = FALSE;
+ priv->import_tags_from_metadata = TRUE;
priv->mainview_sorting_criteria = SORT_AS_LOADED;
priv->mainview_sorting_reversed = FALSE;
priv->mainview_enable_tooltips = TRUE;
@@ -1308,6 +1322,28 @@ frogr_config_get_keep_file_extensions (FrogrConfig *self)
}
void
+frogr_config_set_import_tags_from_metadata (FrogrConfig *self, gboolean value)
+{
+ FrogrConfigPrivate * priv = NULL;
+
+ g_return_if_fail (FROGR_IS_CONFIG (self));
+
+ priv = FROGR_CONFIG_GET_PRIVATE (self);
+ priv->import_tags_from_metadata = value;
+}
+
+gboolean
+frogr_config_get_import_tags_from_metadata (FrogrConfig *self)
+{
+ FrogrConfigPrivate *priv = NULL;
+
+ g_return_val_if_fail (FROGR_IS_CONFIG (self), FALSE);
+
+ priv = FROGR_CONFIG_GET_PRIVATE (self);
+ return priv->import_tags_from_metadata;
+}
+
+void
frogr_config_set_mainview_enable_tooltips (FrogrConfig *self, gboolean value)
{
FrogrConfigPrivate * priv = NULL;
diff --git a/src/frogr-config.h b/src/frogr-config.h
index 6f806e7..3efdfaa 100644
--- a/src/frogr-config.h
+++ b/src/frogr-config.h
@@ -26,6 +26,7 @@
#include "frogr-account.h"
+#include <config.h>
#include <glib.h>
#include <glib-object.h>
#include <flicksoup/flicksoup.h>
@@ -124,6 +125,10 @@ void frogr_config_set_keep_file_extensions (FrogrConfig *self, gboolean value);
gboolean frogr_config_get_keep_file_extensions (FrogrConfig *self);
+void frogr_config_set_import_tags_from_metadata (FrogrConfig *self, gboolean value);
+
+gboolean frogr_config_get_import_tags_from_metadata (FrogrConfig *self);
+
void frogr_config_set_mainview_enable_tooltips (FrogrConfig *self, gboolean value);
gboolean frogr_config_get_mainview_enable_tooltips (FrogrConfig *self);
diff --git a/src/frogr-picture-loader.c b/src/frogr-picture-loader.c
index 94f12e8..dfe700f 100644
--- a/src/frogr-picture-loader.c
+++ b/src/frogr-picture-loader.c
@@ -61,6 +61,7 @@ struct _FrogrPictureLoaderPrivate
guint n_pictures;
gboolean keep_file_extensions;
+ gboolean import_tags;
gboolean public_visibility;
gboolean family_visibility;
gboolean friend_visibility;
@@ -95,6 +96,15 @@ static void _load_next_picture_cb (GObject *object,
GAsyncResult *res,
gpointer data);
+static gboolean get_gps_coordinate (ExifData *exif,
+ ExifTag tag,
+ ExifTag reftag,
+ gdouble *coordinate);
+static FspDataLocation *get_location_from_exif (ExifData *exif_data);
+
+static gchar *remove_spaces_from_keyword (const gchar *keyword);
+static gchar *import_tags_from_xmp_keywords (const char *buffer, size_t len);
+
/* Private API */
static void
@@ -197,86 +207,6 @@ _load_next_picture (FrogrPictureLoader *self)
}
}
-/* get_gps_coordinate is from
- * tracker/src/libtracker-extract//tracker-exif.c,
- * Copyright (C) 2009, Nokia <ivan frade nokia com>
- * Licensed under the GNU Lesser General Public License Version 2.1 or later
- */
-static gboolean
-get_gps_coordinate (ExifData *exif,
- ExifTag tag,
- ExifTag reftag,
- gdouble *coordinate)
-{
- ExifEntry *entry = exif_data_get_entry (exif, tag);
- ExifEntry *refentry = exif_data_get_entry (exif, reftag);
-
- g_return_val_if_fail (coordinate != NULL, FALSE);
-
- if (entry && refentry)
- {
- ExifByteOrder order;
- ExifRational c1,c2,c3;
- gfloat f;
- gchar ref;
-
- order = exif_data_get_byte_order (exif);
- c1 = exif_get_rational (entry->data, order);
- c2 = exif_get_rational (entry->data+8, order);
- c3 = exif_get_rational (entry->data+16, order);
- ref = refentry->data[0];
-
- /* Avoid ridiculous values */
- if (c1.denominator == 0 ||
- c2.denominator == 0 ||
- c3.denominator == 0)
- {
- return FALSE;
- }
-
- f = (double)c1.numerator/c1.denominator+
- (double)c2.numerator/(c2.denominator*60)+
- (double)c3.numerator/(c3.denominator*60*60);
-
- if (ref == 'S' || ref == 'W')
- {
- f = -1 * f;
- }
-
- *coordinate = f;
- return TRUE;
- }
-
- return FALSE;
-}
-
-FspDataLocation *get_location_from_exif (ExifData *exif_data)
-{
- FspDataLocation *location;
- gdouble coordinate;
- gboolean found;
-
- if (!exif_data)
- return NULL;
- found = get_gps_coordinate (exif_data, EXIF_TAG_GPS_LATITUDE,
- EXIF_TAG_GPS_LATITUDE_REF, &coordinate);
- if (!found)
- return NULL;
-
- location = FSP_DATA_LOCATION (fsp_data_new (FSP_LOCATION));
- location->latitude = coordinate;
-
- found = get_gps_coordinate (exif_data, EXIF_TAG_GPS_LONGITUDE,
- EXIF_TAG_GPS_LONGITUDE_REF, &location->longitude);
- if (!found)
- {
- fsp_data_free (FSP_DATA (location));
- return NULL;
- }
-
- return location;
-}
-
static void
_load_next_picture_cb (GObject *object,
GAsyncResult *res,
@@ -377,6 +307,7 @@ _load_next_picture_cb (GObject *object,
{
FspDataLocation *location;
+ /* Date and time for picture taken */
exif_entry = exif_data_get_entry (exif_data, EXIF_TAG_DATE_TIME);
if (exif_entry)
{
@@ -391,6 +322,21 @@ _load_next_picture_cb (GObject *object,
else
g_warning ("Found DateTime exif tag of invalid type");
}
+
+ /* Import tags from XMP metadata, if required */
+ if (priv->import_tags)
+ {
+ gchar *imported_tags = NULL;
+
+ imported_tags = import_tags_from_xmp_keywords (contents, length);
+ if (imported_tags)
+ {
+ frogr_picture_set_tags (fpicture, imported_tags);
+ g_free (imported_tags);
+ }
+ }
+
+ /* GPS coordinates */
location = get_location_from_exif (exif_data);
if (location != NULL)
{
@@ -462,6 +408,174 @@ _load_next_picture_cb (GObject *object,
}
}
+
+/* This function was taken from tracker, licensed under the GNU Lesser
+ * General Public License Version 2.1 (Copyright 2009, Nokia Corp.) */
+static gboolean
+get_gps_coordinate (ExifData *exif,
+ ExifTag tag,
+ ExifTag reftag,
+ gdouble *coordinate)
+{
+ ExifEntry *entry = exif_data_get_entry (exif, tag);
+ ExifEntry *refentry = exif_data_get_entry (exif, reftag);
+
+ g_return_val_if_fail (coordinate != NULL, FALSE);
+
+ if (entry && refentry)
+ {
+ ExifByteOrder order;
+ ExifRational c1,c2,c3;
+ gfloat f;
+ gchar ref;
+
+ order = exif_data_get_byte_order (exif);
+ c1 = exif_get_rational (entry->data, order);
+ c2 = exif_get_rational (entry->data+8, order);
+ c3 = exif_get_rational (entry->data+16, order);
+ ref = refentry->data[0];
+
+ /* Avoid ridiculous values */
+ if (c1.denominator == 0 ||
+ c2.denominator == 0 ||
+ c3.denominator == 0)
+ {
+ return FALSE;
+ }
+
+ f = (double)c1.numerator/c1.denominator+
+ (double)c2.numerator/(c2.denominator*60)+
+ (double)c3.numerator/(c3.denominator*60*60);
+
+ if (ref == 'S' || ref == 'W')
+ {
+ f = -1 * f;
+ }
+
+ *coordinate = f;
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static FspDataLocation *
+get_location_from_exif (ExifData *exif_data)
+{
+ FspDataLocation *location;
+ gdouble coordinate;
+ gboolean found;
+
+ if (!exif_data)
+ return NULL;
+ found = get_gps_coordinate (exif_data, EXIF_TAG_GPS_LATITUDE,
+ EXIF_TAG_GPS_LATITUDE_REF, &coordinate);
+ if (!found)
+ return NULL;
+
+ location = FSP_DATA_LOCATION (fsp_data_new (FSP_LOCATION));
+ location->latitude = coordinate;
+
+ found = get_gps_coordinate (exif_data, EXIF_TAG_GPS_LONGITUDE,
+ EXIF_TAG_GPS_LONGITUDE_REF, &location->longitude);
+ if (!found)
+ {
+ fsp_data_free (FSP_DATA (location));
+ return NULL;
+ }
+
+ return location;
+}
+
+static gchar *
+remove_spaces_from_keyword (const gchar *keyword)
+{
+ gchar *new_keyword = NULL;
+
+ if (keyword)
+ {
+ int i = 0;
+ int j = 0;
+
+ new_keyword = g_new0 (gchar, strlen(keyword) + 1);
+ for (i = 0; keyword[i] != '\0'; i++)
+ {
+ if (keyword[i] != ' ')
+ new_keyword[j++] = keyword[i];
+ }
+ new_keyword[j] = '\0';
+ }
+
+ return new_keyword;
+}
+
+static gchar *
+import_tags_from_xmp_keywords (const char *buffer, size_t len)
+{
+ gchar *keywords_start = NULL;
+ gchar *keywords_end = NULL;
+ gchar *result = NULL;
+ int i;
+
+ /* Look for the beginning of the XMP data interesting for as if
+ present, that is, the keywords (aka the 'tags') */
+ for (i = 0; i < len && !keywords_start; i++)
+ {
+ if (g_str_has_prefix (&buffer[i], "<dc:subject>"))
+ keywords_start = g_strdup(&buffer[i+12]);
+ }
+
+ /* Find the end of the interesting XMP data, if found */
+ if (keywords_start)
+ keywords_end = g_strrstr (keywords_start, "</dc:subject>");
+
+ if (keywords_end)
+ {
+ gchar *start = NULL;
+ gchar *end = NULL;
+
+ keywords_end[0] = '\0';
+
+ /* Remove extra not-needed stuff in the string */
+ start = g_strstr_len (keywords_start, -1, "<rdf:li>");
+ end = g_strrstr (keywords_start, "</rdf:li>");
+ if (start && end)
+ {
+ gchar **keywords = NULL;
+ gchar *keyword = NULL;
+ gchar *kw_end = NULL;
+
+ start = &start[8];
+ end[0] = '\0';
+
+ /* Get an array of strings with all the keywords */
+ keywords = g_regex_split_simple ("<rdf:li>", start, G_REGEX_DOTALL, 0);
+
+ /* Remove spaces and trailing '</rdf:li>' elements */
+ for (i = 0; keywords[i]; i++)
+ {
+ keyword = keywords[i];
+
+ /* Remove trailing '</rdf:li>' elements */
+ kw_end = g_strrstr (keyword, "</rdf:li>");
+ if (kw_end)
+ kw_end[0] = '\0';
+
+ /* Remove spaces to normalize to flickr tags */
+ keywords[i] = remove_spaces_from_keyword (keyword);
+ g_free (keyword);
+ }
+
+ result = g_strjoinv (" ", keywords);
+ g_strfreev (keywords);
+ }
+ }
+
+ g_free (keywords_start);
+
+ return result;
+}
+
static void
_frogr_picture_loader_dispose (GObject* object)
{
@@ -523,6 +637,7 @@ frogr_picture_loader_init (FrogrPictureLoader *self)
/* Initialize values from frogr configuration */
priv->keep_file_extensions = frogr_config_get_keep_file_extensions (config);
+ priv->import_tags = frogr_config_get_import_tags_from_metadata (config);
priv->public_visibility = frogr_config_get_default_public (config);
priv->family_visibility = frogr_config_get_default_family (config);
priv->friend_visibility = frogr_config_get_default_friend (config);
diff --git a/src/frogr-settings-dialog.c b/src/frogr-settings-dialog.c
index 767ad0c..2077f8a 100644
--- a/src/frogr-settings-dialog.c
+++ b/src/frogr-settings-dialog.c
@@ -67,6 +67,7 @@ typedef struct _FrogrSettingsDialogPrivate {
GtkWidget *disable_tags_autocompletion_cb;
GtkWidget *keep_file_extensions_cb;
+ GtkWidget *import_tags_cb;
gboolean public_visibility;
gboolean family_visibility;
@@ -75,6 +76,7 @@ typedef struct _FrogrSettingsDialogPrivate {
gboolean send_geolocation_data;
gboolean disable_tags_autocompletion;
gboolean keep_file_extensions;
+ gboolean import_tags;
FspLicense license;
FspSafetyLevel safety_level;
FspContentType content_type;
@@ -516,6 +518,9 @@ _add_misc_page (FrogrSettingsDialog *self, GtkNotebook *notebook)
_add_toggleable_item (self, GTK_BOX (box), NULL, FALSE,
_("_Keep File Extensions in Titles when Loading Pictures"),
&priv->keep_file_extensions_cb);
+ _add_toggleable_item (self, GTK_BOX (box), NULL, FALSE,
+ _("Don't _Import Tags from Pictures Metadata"),
+ &priv->import_tags_cb);
gtk_box_pack_start (GTK_BOX (vbox), box, FALSE, FALSE, 0);
@@ -540,6 +545,7 @@ _fill_dialog_with_data (FrogrSettingsDialog *self)
priv->safety_level = frogr_config_get_default_safety_level (priv->config);
priv->disable_tags_autocompletion = !frogr_config_get_tags_autocompletion (priv->config);
priv->keep_file_extensions = frogr_config_get_keep_file_extensions (priv->config);
+ priv->import_tags = frogr_config_get_import_tags_from_metadata (priv->config);
priv->use_proxy = frogr_config_get_use_proxy (priv->config);
#ifdef HAVE_LIBSOUP_GNOME
priv->use_gnome_proxy = frogr_config_get_use_gnome_proxy (priv->config);
@@ -601,9 +607,10 @@ _fill_dialog_with_data (FrogrSettingsDialog *self)
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->disable_tags_autocompletion_cb),
priv->disable_tags_autocompletion);
-
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->keep_file_extensions_cb),
priv->keep_file_extensions);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->import_tags_cb),
+ !priv->import_tags);
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (priv->use_proxy_cb),
priv->use_proxy);
@@ -647,6 +654,7 @@ _save_data (FrogrSettingsDialog *self)
frogr_config_set_tags_autocompletion (priv->config, !priv->disable_tags_autocompletion);
frogr_config_set_keep_file_extensions (priv->config, priv->keep_file_extensions);
+ frogr_config_set_import_tags_from_metadata (priv->config, priv->import_tags);
frogr_config_set_use_proxy (priv->config, priv->use_proxy);
#ifdef HAVE_LIBSOUP_GNOME
@@ -803,6 +811,12 @@ _on_button_toggled (GtkToggleButton *button, gpointer data)
DEBUG ("Keep file extensions in title set to %s", active ? "TRUE" : "FALSE");
}
+ if (GTK_WIDGET (button) == priv->import_tags_cb)
+ {
+ priv->import_tags = !active;
+ DEBUG ("Don't import tags from pictures metadata set to %s", active ? "TRUE" : "FALSE");
+ }
+
if (GTK_WIDGET (button) == priv->use_proxy_cb)
{
priv->use_proxy = active;
@@ -956,6 +970,7 @@ frogr_settings_dialog_init (FrogrSettingsDialog *self)
priv->restricted_rb = NULL;
priv->disable_tags_autocompletion_cb = NULL;
priv->keep_file_extensions_cb = NULL;
+ priv->import_tags_cb = NULL;
priv->use_proxy_cb = NULL;
priv->use_gnome_proxy_cb = NULL;
priv->proxy_host_label = NULL;
@@ -976,6 +991,7 @@ frogr_settings_dialog_init (FrogrSettingsDialog *self)
priv->content_type = FSP_CONTENT_TYPE_NONE;
priv->disable_tags_autocompletion = FALSE;
priv->keep_file_extensions = FALSE;
+ priv->import_tags = FALSE;
priv->use_proxy = FALSE;
priv->use_gnome_proxy = FALSE;
priv->proxy_host = NULL;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]