diff options
-rw-r--r-- | doc/reference/Makefile.am | 2 | ||||
-rw-r--r-- | po/POTFILES.in | 2 | ||||
-rw-r--r-- | src/Makefile.am | 15 | ||||
-rw-r--r-- | src/eom-exif-details.c | 665 | ||||
-rw-r--r-- | src/eom-exif-details.h | 72 | ||||
-rw-r--r-- | src/eom-metadata-details.c | 665 | ||||
-rw-r--r-- | src/eom-metadata-details.h | 72 | ||||
-rw-r--r-- | src/eom-properties-dialog.c | 8 |
8 files changed, 751 insertions, 750 deletions
diff --git a/doc/reference/Makefile.am b/doc/reference/Makefile.am index 9c5aa63..e6fc457 100644 --- a/doc/reference/Makefile.am +++ b/doc/reference/Makefile.am @@ -58,7 +58,7 @@ if !HAVE_EXIF if !HAVE_EXEMPI IGNORE_HFILES += \ eom-exif-util.h \ - eom-exif-details.h + eom-metadata-details.h endif endif diff --git a/po/POTFILES.in b/po/POTFILES.in index 7e62f4c..efd637e 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -20,7 +20,7 @@ src/eom-file-chooser.c src/eom-image.c src/eom-image-jpeg.c src/eom-error-message-area.c -src/eom-exif-details.c +src/eom-metadata-details.c src/eom-exif-util.c src/eom-metadata-sidebar.c src/eom-preferences-dialog.c diff --git a/src/Makefile.am b/src/Makefile.am index 8f9cab7..912fe1c 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -111,23 +111,24 @@ libeom_la_SOURCES = \ if HAVE_EXIF INST_H_FILES += \ - eom-exif-util.h \ - eom-exif-details.h + eom-metadata-details.h \ + eom-exif-util.h + libeom_c_files += \ - eom-exif-util.c \ - eom-exif-details.c + eom-metadata-details.c \ + eom-exif-util.c endif if HAVE_EXEMPI -# We need to make sure eom-exif-details.h +# We need to make sure eom-metadata-details.h # is only listed once in INST_H_FILES # or the build will break with automake-1.11 if !HAVE_EXIF INST_H_FILES += \ - eom-exif-details.h + eom-metadata-details.h endif !HAVE_EXIF libeom_la_SOURCES += \ - eom-exif-details.c + eom-metadata-details.c endif HAVE_EXEMPI libeom_la_CPPFLAGS = \ diff --git a/src/eom-exif-details.c b/src/eom-exif-details.c deleted file mode 100644 index 2203a60..0000000 --- a/src/eom-exif-details.c +++ /dev/null @@ -1,665 +0,0 @@ -/* Eye Of Mate - EOM Image Exif Details - * - * Copyright (C) 2006 The Free Software Foundation - * - * Author: Lucas Rocha <[email protected]> - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifdef HAVE_CONFIG_H -#include <config.h> -#endif - -#include "eom-exif-details.h" -#include "eom-util.h" - -#if HAVE_EXIF -#include <libexif/exif-entry.h> -#include <libexif/exif-utils.h> -#endif -#if HAVE_EXEMPI -#include <exempi/xmp.h> -#include <exempi/xmpconsts.h> -#endif - -#include <glib/gi18n.h> -#include <gtk/gtk.h> - -#include <string.h> - -typedef enum { - EXIF_CATEGORY_CAMERA, - EXIF_CATEGORY_IMAGE_DATA, - EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS, - EXIF_CATEGORY_GPS_DATA, - EXIF_CATEGORY_MAKER_NOTE, - EXIF_CATEGORY_OTHER, -#ifdef HAVE_EXEMPI - XMP_CATEGORY_EXIF, - XMP_CATEGORY_IPTC, - XMP_CATEGORY_RIGHTS, - XMP_CATEGORY_OTHER -#endif -} ExifCategory; - -typedef struct { - char *label; - char *path; -} ExifCategoryInfo; - -static ExifCategoryInfo exif_categories[] = { - { N_("Camera"), "0" }, - { N_("Image Data"), "1" }, - { N_("Image Taking Conditions"), "2" }, - { N_("GPS Data"), "3" }, - { N_("Maker Note"), "4" }, - { N_("Other"), "5" }, -#ifdef HAVE_EXEMPI - { N_("XMP Exif"), "6" }, - { N_("XMP IPTC"), "7" }, - { N_("XMP Rights Management"), "8" }, - { N_("XMP Other"), "9" }, -#endif - { NULL, NULL } -}; - -typedef struct { - int id; - ExifCategory category; -} ExifTagCategory; - -#ifdef HAVE_EXIF -static ExifTagCategory exif_tag_category_map[] = { - { EXIF_TAG_INTEROPERABILITY_INDEX, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_INTEROPERABILITY_VERSION, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_IMAGE_WIDTH, EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_IMAGE_LENGTH , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_BITS_PER_SAMPLE ,EXIF_CATEGORY_CAMERA }, - { EXIF_TAG_COMPRESSION , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_PHOTOMETRIC_INTERPRETATION , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_FILL_ORDER , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_DOCUMENT_NAME , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_IMAGE_DESCRIPTION , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_MAKE , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_MODEL , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_STRIP_OFFSETS , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_ORIENTATION , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_SAMPLES_PER_PIXEL , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_ROWS_PER_STRIP , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_STRIP_BYTE_COUNTS , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_X_RESOLUTION , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_Y_RESOLUTION , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_PLANAR_CONFIGURATION , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_RESOLUTION_UNIT , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_TRANSFER_FUNCTION , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_SOFTWARE , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_DATE_TIME , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_ARTIST , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_WHITE_POINT , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_PRIMARY_CHROMATICITIES, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_TRANSFER_RANGE , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_JPEG_PROC , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, }, - { EXIF_TAG_YCBCR_COEFFICIENTS , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_YCBCR_SUB_SAMPLING , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_YCBCR_POSITIONING , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_REFERENCE_BLACK_WHITE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_RELATED_IMAGE_FILE_FORMAT,EXIF_CATEGORY_OTHER}, - { EXIF_TAG_RELATED_IMAGE_WIDTH , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_RELATED_IMAGE_LENGTH , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_CFA_REPEAT_PATTERN_DIM, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_CFA_PATTERN , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_BATTERY_LEVEL , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_COPYRIGHT , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_EXPOSURE_TIME , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_FNUMBER , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_IPTC_NAA , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_EXIF_IFD_POINTER , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_INTER_COLOR_PROFILE , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_EXPOSURE_PROGRAM , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_SPECTRAL_SENSITIVITY , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_GPS_INFO_IFD_POINTER , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_ISO_SPEED_RATINGS , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_OECF , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_EXIF_VERSION , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_DATE_TIME_ORIGINAL , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_DATE_TIME_DIGITIZED , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_COMPONENTS_CONFIGURATION , EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_SHUTTER_SPEED_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_APERTURE_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_BRIGHTNESS_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_EXPOSURE_BIAS_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_MAX_APERTURE_VALUE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_SUBJECT_DISTANCE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_METERING_MODE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_LIGHT_SOURCE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_FLASH , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_FOCAL_LENGTH , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_SUBJECT_AREA , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_MAKER_NOTE , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_USER_COMMENT , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_SUBSEC_TIME , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_FLASH_PIX_VERSION , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_COLOR_SPACE , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_PIXEL_X_DIMENSION , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_PIXEL_Y_DIMENSION , EXIF_CATEGORY_IMAGE_DATA}, - { EXIF_TAG_RELATED_SOUND_FILE , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_INTEROPERABILITY_IFD_POINTER, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_FLASH_ENERGY ,EXIF_CATEGORY_OTHER }, - { EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_FOCAL_PLANE_X_RESOLUTION, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_SUBJECT_LOCATION, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_EXPOSURE_INDEX, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_SENSING_METHOD, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_FILE_SOURCE , EXIF_CATEGORY_OTHER}, - { EXIF_TAG_SCENE_TYPE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_NEW_CFA_PATTERN, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_CUSTOM_RENDERED, EXIF_CATEGORY_OTHER}, - { EXIF_TAG_EXPOSURE_MODE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_WHITE_BALANCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_DIGITAL_ZOOM_RATIO, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_SCENE_CAPTURE_TYPE , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_GAIN_CONTROL , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_CONTRAST , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_SATURATION , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_SHARPNESS , EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_DEVICE_SETTING_DESCRIPTION, EXIF_CATEGORY_CAMERA}, - { EXIF_TAG_SUBJECT_DISTANCE_RANGE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, - { EXIF_TAG_IMAGE_UNIQUE_ID , EXIF_CATEGORY_IMAGE_DATA}, - { -1, -1 } -}; -#endif - -#define MODEL_COLUMN_ATTRIBUTE 0 -#define MODEL_COLUMN_VALUE 1 - -struct _EomExifDetailsPrivate { - GtkTreeModel *model; - - GHashTable *id_path_hash; - GHashTable *id_path_hash_mnote; -}; - -static char* set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value); - -static void eom_exif_details_reset (EomExifDetails *exif_details); - -G_DEFINE_TYPE_WITH_PRIVATE (EomExifDetails, eom_exif_details, GTK_TYPE_TREE_VIEW) - -static void -eom_exif_details_dispose (GObject *object) -{ - EomExifDetailsPrivate *priv; - - priv = EOM_EXIF_DETAILS (object)->priv; - - if (priv->model) { - g_object_unref (priv->model); - priv->model = NULL; - } - - if (priv->id_path_hash) { - g_hash_table_destroy (priv->id_path_hash); - priv->id_path_hash = NULL; - } - - if (priv->id_path_hash_mnote) { - g_hash_table_destroy (priv->id_path_hash_mnote); - priv->id_path_hash_mnote = NULL; - } - G_OBJECT_CLASS (eom_exif_details_parent_class)->dispose (object); -} - -static void -eom_exif_details_init (EomExifDetails *exif_details) -{ - EomExifDetailsPrivate *priv; - GtkTreeViewColumn *column; - GtkCellRenderer *cell; - - exif_details->priv = eom_exif_details_get_instance_private (exif_details); - - priv = exif_details->priv; - - priv->model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING)); - priv->id_path_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); - priv->id_path_hash_mnote = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); - - /* Tag name column */ - cell = gtk_cell_renderer_text_new (); - column = gtk_tree_view_column_new_with_attributes (_("Tag"), cell, - "text", MODEL_COLUMN_ATTRIBUTE, - NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (exif_details), column); - - /* Value column */ - cell = gtk_cell_renderer_text_new (); - g_object_set (cell, - "editable", TRUE, - NULL); - column = gtk_tree_view_column_new_with_attributes (_("Value"), cell, - "text", MODEL_COLUMN_VALUE, - NULL); - gtk_tree_view_append_column (GTK_TREE_VIEW (exif_details), column); - - eom_exif_details_reset (exif_details); - - gtk_tree_view_set_model (GTK_TREE_VIEW (exif_details), - GTK_TREE_MODEL (priv->model)); -} - -static void -eom_exif_details_class_init (EomExifDetailsClass *klass) -{ - GObjectClass *object_class = (GObjectClass*) klass; - - object_class->dispose = eom_exif_details_dispose; -} - -#ifdef HAVE_EXIF -static ExifCategory -get_exif_category (ExifEntry *entry) -{ - ExifCategory cat = EXIF_CATEGORY_OTHER; - int i; - - /* Some GPS tag IDs overlap with other ones, so check the IFD */ - if (exif_entry_get_ifd (entry) == EXIF_IFD_GPS) { - return EXIF_CATEGORY_GPS_DATA; - } - - for (i = 0; exif_tag_category_map [i].id != -1; i++) { - if (exif_tag_category_map[i].id == (int) entry->tag) { - cat = exif_tag_category_map[i].category; - break; - } - } - - return cat; -} -#endif - -static char* -set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value) -{ - GtkTreeIter iter; - gchar *utf_attribute = NULL; - gchar *utf_value = NULL; - gboolean iter_valid = FALSE; - - if (!attribute) return NULL; - - if (path != NULL) { - iter_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path); - } - - if (!iter_valid) { - GtkTreePath *tree_path; - GtkTreeIter parent_iter; - gboolean parent_valid = FALSE; - - if (parent != NULL) { - parent_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), - &parent_iter, - parent); - } - - gtk_tree_store_append (store, &iter, parent_valid ? &parent_iter : NULL); - - if (path == NULL) { - tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); - - if (tree_path != NULL) { - path = gtk_tree_path_to_string (tree_path); - gtk_tree_path_free (tree_path); - } - } - } - - utf_attribute = eom_util_make_valid_utf8 (attribute); - - gtk_tree_store_set (store, &iter, MODEL_COLUMN_ATTRIBUTE, utf_attribute, -1); - g_free (utf_attribute); - - if (value != NULL) { - utf_value = eom_util_make_valid_utf8 (value); - gtk_tree_store_set (store, &iter, MODEL_COLUMN_VALUE, utf_value, -1); - g_free (utf_value); - } - - return path; -} - -#ifdef HAVE_EXIF - -static const char * -eom_exif_entry_get_value (ExifEntry *e, - char *buf, - guint n_buf) -{ - ExifByteOrder bo; - - /* For now we only want to reformat some GPS values */ - if (G_LIKELY (exif_entry_get_ifd (e) != EXIF_IFD_GPS)) - return exif_entry_get_value (e, buf, n_buf); - - bo = exif_data_get_byte_order (e->parent->parent); - - /* Cast to number to avoid warnings about values not in enumeration */ - switch ((guint16) e->tag) { - case EXIF_TAG_GPS_LATITUDE: - case EXIF_TAG_GPS_LONGITUDE: - { - gsize rational_size; - ExifRational r; - gfloat h = 0., m = 0.; - - - rational_size = exif_format_get_size (EXIF_FORMAT_RATIONAL); - if (G_UNLIKELY (e->components != 3 || - e->format != EXIF_FORMAT_RATIONAL)) - return exif_entry_get_value (e, buf, n_buf); - - r = exif_get_rational (e->data, bo); - if (r.denominator != 0) - h = (gfloat)r.numerator / r.denominator; - - r = exif_get_rational (e->data + rational_size, bo); - if (r.denominator != 0) - m = (gfloat)r.numerator / (gfloat)r.denominator; - - r = exif_get_rational (e->data + (2 * rational_size), - bo); - if (r.numerator != 0 && r.denominator != 0) { - gfloat s; - - s = (gfloat)r.numerator / (gfloat)r.denominator; - g_snprintf (buf, n_buf, - "%.0f° %.0f' %.2f\"", - h, m, s); - } else { - g_snprintf (buf, n_buf, - "%.0f° %.2f'", - h, m); - } - - break; - } - case EXIF_TAG_GPS_LATITUDE_REF: - case EXIF_TAG_GPS_LONGITUDE_REF: - { - if (G_UNLIKELY (e->components != 2 || - e->format != EXIF_FORMAT_ASCII)) - return exif_entry_get_value (e, buf, n_buf); - - switch (e->data[0]) { - case 'N': - g_snprintf (buf, n_buf, "%s", _("North")); - break; - case 'E': - g_snprintf (buf, n_buf, "%s", _("East")); - break; - case 'W': - g_snprintf (buf, n_buf, "%s", _("West")); - break; - case 'S': - g_snprintf (buf, n_buf, "%s", _("South")); - break; - default: - return exif_entry_get_value (e, buf, n_buf); - break; - } - break; - } - default: - return exif_entry_get_value (e, buf, n_buf); - break; - } - - return buf; -} - -static void -exif_entry_cb (ExifEntry *entry, gpointer data) -{ - GtkTreeStore *store; - EomExifDetails *view; - EomExifDetailsPrivate *priv; - ExifCategory cat; - ExifIfd ifd = exif_entry_get_ifd (entry); - char *path; - char b[1024]; - const gint key = ifd << 16 | entry->tag; - - /* This should optimize away if comparision is correct */ - g_warn_if_fail (EXIF_IFD_COUNT <= G_MAXUINT16); - - view = EOM_EXIF_DETAILS (data); - priv = view->priv; - - store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); - - /* Take the tag's IFD into account when caching their GtkTreePaths. - * That should fix key collisions for tags that have the same number - * but are stored in different IFDs. Exif tag numbers are 16-bit - * values so we should be able to set the high word to the IFD number. - */ - path = g_hash_table_lookup (priv->id_path_hash, GINT_TO_POINTER (key)); - - if (path != NULL) { - set_row_data (store, - path, - NULL, - exif_tag_get_name_in_ifd (entry->tag, ifd), - eom_exif_entry_get_value (entry, b, sizeof(b))); - } else { - - ExifMnoteData *mnote = (entry->tag == EXIF_TAG_MAKER_NOTE ? - exif_data_get_mnote_data (entry->parent->parent) : NULL); - - if (mnote) { - // Supported MakerNote Found - unsigned int i, c = exif_mnote_data_count (mnote); - - for (i = 0; i < c; i++) { - path = g_hash_table_lookup (priv->id_path_hash_mnote, GINT_TO_POINTER (i)); - if (path != NULL) { - set_row_data (store, path, NULL, - exif_mnote_data_get_title (mnote, i), - exif_mnote_data_get_value (mnote, i, b, sizeof(b))); - } else { - path = set_row_data (store, - NULL, - exif_categories[EXIF_CATEGORY_MAKER_NOTE].path, - exif_mnote_data_get_title (mnote, i), - exif_mnote_data_get_value (mnote, i, b, sizeof(b))); - g_hash_table_insert (priv->id_path_hash_mnote, GINT_TO_POINTER (i), path); - } - } - } else { - cat = get_exif_category (entry); - - path = set_row_data (store, - NULL, - exif_categories[cat].path, - exif_tag_get_name_in_ifd (entry->tag, ifd), - eom_exif_entry_get_value (entry, b, - sizeof(b))); - - g_hash_table_insert (priv->id_path_hash, - GINT_TO_POINTER (key), - path); - } - } -} -#endif - -#ifdef HAVE_EXIF -static void -exif_content_cb (ExifContent *content, gpointer data) -{ - exif_content_foreach_entry (content, exif_entry_cb, data); -} -#endif - -GtkWidget * -eom_exif_details_new (void) -{ - GObject *object; - - object = g_object_new (EOM_TYPE_EXIF_DETAILS, NULL); - - return GTK_WIDGET (object); -} - -static void -eom_exif_details_reset (EomExifDetails *exif_details) -{ - int i; - EomExifDetailsPrivate *priv = exif_details->priv; - - gtk_tree_store_clear (GTK_TREE_STORE (priv->model)); - - g_hash_table_remove_all (priv->id_path_hash); - g_hash_table_remove_all (priv->id_path_hash_mnote); - - for (i = 0; exif_categories [i].label != NULL; i++) { - char *translated_string; - - translated_string = gettext (exif_categories[i].label); - - set_row_data (GTK_TREE_STORE (priv->model), - exif_categories[i].path, - NULL, - translated_string, - NULL); - } -} - -#ifdef HAVE_EXIF -void -eom_exif_details_update (EomExifDetails *exif_details, ExifData *data) -{ - g_return_if_fail (EOM_IS_EXIF_DETAILS (exif_details)); - - eom_exif_details_reset (exif_details); - if (data) { - exif_data_foreach_content (data, exif_content_cb, exif_details); - } -} -#endif /* HAVE_EXIF */ - -#ifdef HAVE_EXEMPI -typedef struct { - const char *id; - ExifCategory category; -} XmpNsCategory; - -static XmpNsCategory xmp_ns_category_map[] = { - { NS_EXIF, XMP_CATEGORY_EXIF}, - { NS_TIFF, XMP_CATEGORY_EXIF}, - { NS_XAP, XMP_CATEGORY_EXIF}, - { NS_XAP_RIGHTS, XMP_CATEGORY_RIGHTS}, - { NS_EXIF_AUX, XMP_CATEGORY_EXIF}, - { NS_DC, XMP_CATEGORY_IPTC}, - { NS_IPTC4XMP, XMP_CATEGORY_IPTC}, - { NS_CC, XMP_CATEGORY_RIGHTS}, - { NULL, -1} -}; - -static ExifCategory -get_xmp_category (XmpStringPtr schema) -{ - ExifCategory cat = XMP_CATEGORY_OTHER; - const char *s = xmp_string_cstr(schema); - int i; - - for (i = 0; xmp_ns_category_map[i].id != NULL; i++) { - if (strcmp (xmp_ns_category_map[i].id, s) == 0) { - cat = xmp_ns_category_map[i].category; - break; - } - } - - return cat; -} - -static void -xmp_entry_insert (EomExifDetails *view, XmpStringPtr xmp_schema, - XmpStringPtr xmp_path, XmpStringPtr xmp_prop) -{ - GtkTreeStore *store; - EomExifDetailsPrivate *priv; - ExifCategory cat; - char *path; - gchar *key; - - priv = view->priv; - - key = g_strconcat (xmp_string_cstr (xmp_schema), ":", - xmp_string_cstr (xmp_path), NULL); - - store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); - - path = g_hash_table_lookup (priv->id_path_hash, key); - - if (path != NULL) { - set_row_data (store, path, NULL, - xmp_string_cstr (xmp_path), - xmp_string_cstr (xmp_prop)); - - g_free(key); - } - else { - cat = get_xmp_category (xmp_schema); - - path = set_row_data (store, NULL, exif_categories[cat].path, - xmp_string_cstr(xmp_path), - xmp_string_cstr(xmp_prop)); - - g_hash_table_insert (priv->id_path_hash, key, path); - } -} - -void -eom_exif_details_xmp_update (EomExifDetails *view, XmpPtr data) -{ - g_return_if_fail (EOM_IS_EXIF_DETAILS (view)); - - if (data) { - XmpIteratorPtr iter = xmp_iterator_new(data, NULL, NULL, XMP_ITER_JUSTLEAFNODES); - XmpStringPtr the_schema = xmp_string_new (); - XmpStringPtr the_path = xmp_string_new (); - XmpStringPtr the_prop = xmp_string_new (); - - while (xmp_iterator_next (iter, the_schema, the_path, the_prop, NULL)) { - xmp_entry_insert (view, the_schema, the_path, the_prop); - } - - xmp_string_free (the_prop); - xmp_string_free (the_path); - xmp_string_free (the_schema); - xmp_iterator_free (iter); - } -} -#endif diff --git a/src/eom-exif-details.h b/src/eom-exif-details.h deleted file mode 100644 index b58af49..0000000 --- a/src/eom-exif-details.h +++ /dev/null @@ -1,72 +0,0 @@ -/* Eye Of Mate - EOM Image Exif Details - * - * Copyright (C) 2006 The Free Software Foundation - * - * Author: Lucas Rocha <[email protected]> - * - * 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 2 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, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. - */ - -#ifndef __EOM_EXIF_DETAILS__ -#define __EOM_EXIF_DETAILS__ - -#include <glib-object.h> -#include <gtk/gtk.h> -#if HAVE_EXIF -#include <libexif/exif-data.h> -#endif -#if HAVE_EXEMPI -#include <exempi/xmp.h> -#endif - -G_BEGIN_DECLS - -typedef struct _EomExifDetails EomExifDetails; -typedef struct _EomExifDetailsClass EomExifDetailsClass; -typedef struct _EomExifDetailsPrivate EomExifDetailsPrivate; - -#define EOM_TYPE_EXIF_DETAILS (eom_exif_details_get_type ()) -#define EOM_EXIF_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_EXIF_DETAILS, EomExifDetails)) -#define EOM_EXIF_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_EXIF_DETAILS, EomExifDetailsClass)) -#define EOM_IS_EXIF_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_EXIF_DETAILS)) -#define EOM_IS_EXIF_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_EXIF_DETAILS)) -#define EOM_EXIF_DETAILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_EXIF_DETAILS, EomExifDetailsClass)) - -struct _EomExifDetails { - GtkTreeView parent; - - EomExifDetailsPrivate *priv; -}; - -struct _EomExifDetailsClass { - GtkTreeViewClass parent_class; -}; - -GType eom_exif_details_get_type (void) G_GNUC_CONST; - -GtkWidget *eom_exif_details_new (void); - -#if HAVE_EXIF -void eom_exif_details_update (EomExifDetails *view, - ExifData *data); -#endif -#if HAVE_EXEMPI -void eom_exif_details_xmp_update (EomExifDetails *view, - XmpPtr xmp_data); -#endif - -G_END_DECLS - -#endif /* __EOM_EXIF_DETAILS__ */ diff --git a/src/eom-metadata-details.c b/src/eom-metadata-details.c new file mode 100644 index 0000000..ebb63bb --- /dev/null +++ b/src/eom-metadata-details.c @@ -0,0 +1,665 @@ +/* Eye Of Mate - EOM Metadata Details + * + * Copyright (C) 2006 The Free Software Foundation + * + * Author: Lucas Rocha <[email protected]> + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include "eom-metadata-details.h" +#include "eom-util.h" + +#if HAVE_EXIF +#include <libexif/exif-entry.h> +#include <libexif/exif-utils.h> +#endif +#if HAVE_EXEMPI +#include <exempi/xmp.h> +#include <exempi/xmpconsts.h> +#endif + +#include <glib/gi18n.h> +#include <gtk/gtk.h> + +#include <string.h> + +typedef enum { + EXIF_CATEGORY_CAMERA, + EXIF_CATEGORY_IMAGE_DATA, + EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS, + EXIF_CATEGORY_GPS_DATA, + EXIF_CATEGORY_MAKER_NOTE, + EXIF_CATEGORY_OTHER, +#ifdef HAVE_EXEMPI + XMP_CATEGORY_EXIF, + XMP_CATEGORY_IPTC, + XMP_CATEGORY_RIGHTS, + XMP_CATEGORY_OTHER +#endif +} MetadataCategory; + +typedef struct { + char *label; + char *path; +} ExifCategoryInfo; + +static ExifCategoryInfo exif_categories[] = { + { N_("Camera"), "0" }, + { N_("Image Data"), "1" }, + { N_("Image Taking Conditions"), "2" }, + { N_("GPS Data"), "3" }, + { N_("Maker Note"), "4" }, + { N_("Other"), "5" }, +#ifdef HAVE_EXEMPI + { N_("XMP Exif"), "6" }, + { N_("XMP IPTC"), "7" }, + { N_("XMP Rights Management"), "8" }, + { N_("XMP Other"), "9" }, +#endif + { NULL, NULL } +}; + +typedef struct { + int id; + MetadataCategory category; +} ExifTagCategory; + +#ifdef HAVE_EXIF +static ExifTagCategory exif_tag_category_map[] = { + { EXIF_TAG_INTEROPERABILITY_INDEX, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_INTEROPERABILITY_VERSION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_IMAGE_WIDTH, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_IMAGE_LENGTH, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_BITS_PER_SAMPLE, EXIF_CATEGORY_CAMERA }, + { EXIF_TAG_COMPRESSION, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_PHOTOMETRIC_INTERPRETATION, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_FILL_ORDER, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_DOCUMENT_NAME, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_IMAGE_DESCRIPTION, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_MAKE, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_MODEL, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_STRIP_OFFSETS, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_ORIENTATION, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_SAMPLES_PER_PIXEL, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_ROWS_PER_STRIP, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_STRIP_BYTE_COUNTS, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_X_RESOLUTION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_Y_RESOLUTION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_PLANAR_CONFIGURATION, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_RESOLUTION_UNIT, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_TRANSFER_FUNCTION, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_SOFTWARE, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_DATE_TIME, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_ARTIST, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_WHITE_POINT, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_PRIMARY_CHROMATICITIES, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_TRANSFER_RANGE, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_JPEG_PROC, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_JPEG_INTERCHANGE_FORMAT, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_JPEG_INTERCHANGE_FORMAT_LENGTH, }, + { EXIF_TAG_YCBCR_COEFFICIENTS, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_YCBCR_SUB_SAMPLING, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_YCBCR_POSITIONING, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_REFERENCE_BLACK_WHITE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_RELATED_IMAGE_FILE_FORMAT, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_RELATED_IMAGE_WIDTH, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_RELATED_IMAGE_LENGTH, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_CFA_REPEAT_PATTERN_DIM, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_CFA_PATTERN, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_BATTERY_LEVEL, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_COPYRIGHT, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_EXPOSURE_TIME, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_FNUMBER, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_IPTC_NAA, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_EXIF_IFD_POINTER, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_INTER_COLOR_PROFILE, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_EXPOSURE_PROGRAM, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_SPECTRAL_SENSITIVITY, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_GPS_INFO_IFD_POINTER, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_ISO_SPEED_RATINGS, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_OECF, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_EXIF_VERSION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_DATE_TIME_ORIGINAL, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_DATE_TIME_DIGITIZED, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_COMPONENTS_CONFIGURATION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_COMPRESSED_BITS_PER_PIXEL, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_SHUTTER_SPEED_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_APERTURE_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_BRIGHTNESS_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_EXPOSURE_BIAS_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_MAX_APERTURE_VALUE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_SUBJECT_DISTANCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_METERING_MODE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_LIGHT_SOURCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_FLASH, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_FOCAL_LENGTH, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_SUBJECT_AREA, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_MAKER_NOTE, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_USER_COMMENT, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_SUBSEC_TIME, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_SUB_SEC_TIME_ORIGINAL, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_SUB_SEC_TIME_DIGITIZED, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_FLASH_PIX_VERSION, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_COLOR_SPACE, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_PIXEL_X_DIMENSION, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_PIXEL_Y_DIMENSION, EXIF_CATEGORY_IMAGE_DATA}, + { EXIF_TAG_RELATED_SOUND_FILE, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_INTEROPERABILITY_IFD_POINTER, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_FLASH_ENERGY, EXIF_CATEGORY_OTHER }, + { EXIF_TAG_SPATIAL_FREQUENCY_RESPONSE, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_FOCAL_PLANE_X_RESOLUTION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_FOCAL_PLANE_Y_RESOLUTION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_FOCAL_PLANE_RESOLUTION_UNIT, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_SUBJECT_LOCATION, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_EXPOSURE_INDEX, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_SENSING_METHOD, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_FILE_SOURCE, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_SCENE_TYPE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_NEW_CFA_PATTERN, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_CUSTOM_RENDERED, EXIF_CATEGORY_OTHER}, + { EXIF_TAG_EXPOSURE_MODE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_WHITE_BALANCE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_DIGITAL_ZOOM_RATIO, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_FOCAL_LENGTH_IN_35MM_FILM, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_SCENE_CAPTURE_TYPE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_GAIN_CONTROL, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_CONTRAST, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_SATURATION, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_SHARPNESS, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_DEVICE_SETTING_DESCRIPTION, EXIF_CATEGORY_CAMERA}, + { EXIF_TAG_SUBJECT_DISTANCE_RANGE, EXIF_CATEGORY_IMAGE_TAKING_CONDITIONS}, + { EXIF_TAG_IMAGE_UNIQUE_ID, EXIF_CATEGORY_IMAGE_DATA}, + { -1, -1 } +}; +#endif + +#define MODEL_COLUMN_ATTRIBUTE 0 +#define MODEL_COLUMN_VALUE 1 + +struct _EomMetadataDetailsPrivate { + GtkTreeModel *model; + + GHashTable *id_path_hash; + GHashTable *id_path_hash_mnote; +}; + +static char* set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value); + +static void eom_metadata_details_reset (EomMetadataDetails *exif_details); + +G_DEFINE_TYPE_WITH_PRIVATE (EomMetadataDetails, eom_metadata_details, GTK_TYPE_TREE_VIEW) + +static void +eom_metadata_details_dispose (GObject *object) +{ + EomMetadataDetailsPrivate *priv; + + priv = EOM_METADATA_DETAILS (object)->priv; + + if (priv->model) { + g_object_unref (priv->model); + priv->model = NULL; + } + + if (priv->id_path_hash) { + g_hash_table_destroy (priv->id_path_hash); + priv->id_path_hash = NULL; + } + + if (priv->id_path_hash_mnote) { + g_hash_table_destroy (priv->id_path_hash_mnote); + priv->id_path_hash_mnote = NULL; + } + G_OBJECT_CLASS (eom_metadata_details_parent_class)->dispose (object); +} + +static void +eom_metadata_details_init (EomMetadataDetails *details) +{ + EomMetadataDetailsPrivate *priv; + GtkTreeViewColumn *column; + GtkCellRenderer *cell; + + details->priv = eom_metadata_details_get_instance_private (details); + + priv = details->priv; + + priv->model = GTK_TREE_MODEL (gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING)); + priv->id_path_hash = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + priv->id_path_hash_mnote = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free); + + /* Tag name column */ + cell = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("Tag"), cell, + "text", MODEL_COLUMN_ATTRIBUTE, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (details), column); + + /* Value column */ + cell = gtk_cell_renderer_text_new (); + g_object_set (cell, + "editable", TRUE, + NULL); + column = gtk_tree_view_column_new_with_attributes (_("Value"), cell, + "text", MODEL_COLUMN_VALUE, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (details), column); + + eom_metadata_details_reset (details); + + gtk_tree_view_set_model (GTK_TREE_VIEW (details), + GTK_TREE_MODEL (priv->model)); +} + +static void +eom_metadata_details_class_init (EomMetadataDetailsClass *klass) +{ + GObjectClass *object_class = (GObjectClass*) klass; + + object_class->dispose = eom_metadata_details_dispose; +} + +#ifdef HAVE_EXIF +static MetadataCategory +get_exif_category (ExifEntry *entry) +{ + MetadataCategory cat = EXIF_CATEGORY_OTHER; + int i; + + /* Some GPS tag IDs overlap with other ones, so check the IFD */ + if (exif_entry_get_ifd (entry) == EXIF_IFD_GPS) { + return EXIF_CATEGORY_GPS_DATA; + } + + for (i = 0; exif_tag_category_map [i].id != -1; i++) { + if (exif_tag_category_map[i].id == (int) entry->tag) { + cat = exif_tag_category_map[i].category; + break; + } + } + + return cat; +} +#endif + +static char* +set_row_data (GtkTreeStore *store, char *path, char *parent, const char *attribute, const char *value) +{ + GtkTreeIter iter; + gchar *utf_attribute = NULL; + gchar *utf_value = NULL; + gboolean iter_valid = FALSE; + + if (!attribute) return NULL; + + if (path != NULL) { + iter_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), &iter, path); + } + + if (!iter_valid) { + GtkTreePath *tree_path; + GtkTreeIter parent_iter; + gboolean parent_valid = FALSE; + + if (parent != NULL) { + parent_valid = gtk_tree_model_get_iter_from_string (GTK_TREE_MODEL (store), + &parent_iter, + parent); + } + + gtk_tree_store_append (store, &iter, parent_valid ? &parent_iter : NULL); + + if (path == NULL) { + tree_path = gtk_tree_model_get_path (GTK_TREE_MODEL (store), &iter); + + if (tree_path != NULL) { + path = gtk_tree_path_to_string (tree_path); + gtk_tree_path_free (tree_path); + } + } + } + + utf_attribute = eom_util_make_valid_utf8 (attribute); + + gtk_tree_store_set (store, &iter, MODEL_COLUMN_ATTRIBUTE, utf_attribute, -1); + g_free (utf_attribute); + + if (value != NULL) { + utf_value = eom_util_make_valid_utf8 (value); + gtk_tree_store_set (store, &iter, MODEL_COLUMN_VALUE, utf_value, -1); + g_free (utf_value); + } + + return path; +} + +#ifdef HAVE_EXIF + +static const char * +eom_exif_entry_get_value (ExifEntry *e, + char *buf, + guint n_buf) +{ + ExifByteOrder bo; + + /* For now we only want to reformat some GPS values */ + if (G_LIKELY (exif_entry_get_ifd (e) != EXIF_IFD_GPS)) + return exif_entry_get_value (e, buf, n_buf); + + bo = exif_data_get_byte_order (e->parent->parent); + + /* Cast to number to avoid warnings about values not in enumeration */ + switch ((guint16) e->tag) { + case EXIF_TAG_GPS_LATITUDE: + case EXIF_TAG_GPS_LONGITUDE: + { + gsize rational_size; + ExifRational r; + gfloat h = 0., m = 0.; + + + rational_size = exif_format_get_size (EXIF_FORMAT_RATIONAL); + if (G_UNLIKELY (e->components != 3 || + e->format != EXIF_FORMAT_RATIONAL)) + return exif_entry_get_value (e, buf, n_buf); + + r = exif_get_rational (e->data, bo); + if (r.denominator != 0) + h = (gfloat)r.numerator / r.denominator; + + r = exif_get_rational (e->data + rational_size, bo); + if (r.denominator != 0) + m = (gfloat)r.numerator / (gfloat)r.denominator; + + r = exif_get_rational (e->data + (2 * rational_size), + bo); + if (r.numerator != 0 && r.denominator != 0) { + gfloat s; + + s = (gfloat)r.numerator / (gfloat)r.denominator; + g_snprintf (buf, n_buf, + "%.0f° %.0f' %.2f\"", + h, m, s); + } else { + g_snprintf (buf, n_buf, + "%.0f° %.2f'", + h, m); + } + + break; + } + case EXIF_TAG_GPS_LATITUDE_REF: + case EXIF_TAG_GPS_LONGITUDE_REF: + { + if (G_UNLIKELY (e->components != 2 || + e->format != EXIF_FORMAT_ASCII)) + return exif_entry_get_value (e, buf, n_buf); + + switch (e->data[0]) { + case 'N': + g_snprintf (buf, n_buf, "%s", _("North")); + break; + case 'E': + g_snprintf (buf, n_buf, "%s", _("East")); + break; + case 'W': + g_snprintf (buf, n_buf, "%s", _("West")); + break; + case 'S': + g_snprintf (buf, n_buf, "%s", _("South")); + break; + default: + return exif_entry_get_value (e, buf, n_buf); + break; + } + break; + } + default: + return exif_entry_get_value (e, buf, n_buf); + break; + } + + return buf; +} + +static void +exif_entry_cb (ExifEntry *entry, gpointer data) +{ + GtkTreeStore *store; + EomMetadataDetails *view; + EomMetadataDetailsPrivate *priv; + MetadataCategory cat; + ExifIfd ifd = exif_entry_get_ifd (entry); + char *path; + char b[1024]; + const gint key = ifd << 16 | entry->tag; + + /* This should optimize away if comparision is correct */ + g_warn_if_fail (EXIF_IFD_COUNT <= G_MAXUINT16); + + view = EOM_METADATA_DETAILS (data); + priv = view->priv; + + store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); + + /* Take the tag's IFD into account when caching their GtkTreePaths. + * That should fix key collisions for tags that have the same number + * but are stored in different IFDs. Exif tag numbers are 16-bit + * values so we should be able to set the high word to the IFD number. + */ + path = g_hash_table_lookup (priv->id_path_hash, GINT_TO_POINTER (key)); + + if (path != NULL) { + set_row_data (store, + path, + NULL, + exif_tag_get_name_in_ifd (entry->tag, ifd), + eom_exif_entry_get_value (entry, b, sizeof(b))); + } else { + + ExifMnoteData *mnote = (entry->tag == EXIF_TAG_MAKER_NOTE ? + exif_data_get_mnote_data (entry->parent->parent) : NULL); + + if (mnote) { + // Supported MakerNote Found + unsigned int i, c = exif_mnote_data_count (mnote); + + for (i = 0; i < c; i++) { + path = g_hash_table_lookup (priv->id_path_hash_mnote, GINT_TO_POINTER (i)); + if (path != NULL) { + set_row_data (store, path, NULL, + exif_mnote_data_get_title (mnote, i), + exif_mnote_data_get_value (mnote, i, b, sizeof(b))); + } else { + path = set_row_data (store, + NULL, + exif_categories[EXIF_CATEGORY_MAKER_NOTE].path, + exif_mnote_data_get_title (mnote, i), + exif_mnote_data_get_value (mnote, i, b, sizeof(b))); + g_hash_table_insert (priv->id_path_hash_mnote, GINT_TO_POINTER (i), path); + } + } + } else { + cat = get_exif_category (entry); + + path = set_row_data (store, + NULL, + exif_categories[cat].path, + exif_tag_get_name_in_ifd (entry->tag, ifd), + eom_exif_entry_get_value (entry, b, + sizeof(b))); + + g_hash_table_insert (priv->id_path_hash, + GINT_TO_POINTER (key), + path); + } + } +} +#endif + +#ifdef HAVE_EXIF +static void +exif_content_cb (ExifContent *content, gpointer data) +{ + exif_content_foreach_entry (content, exif_entry_cb, data); +} +#endif + +GtkWidget * +eom_metadata_details_new (void) +{ + GObject *object; + + object = g_object_new (EOM_TYPE_METADATA_DETAILS, NULL); + + return GTK_WIDGET (object); +} + +static void +eom_metadata_details_reset (EomMetadataDetails *details) +{ + EomMetadataDetailsPrivate *priv = details->priv; + int i; + + gtk_tree_store_clear (GTK_TREE_STORE (priv->model)); + + g_hash_table_remove_all (priv->id_path_hash); + g_hash_table_remove_all (priv->id_path_hash_mnote); + + for (i = 0; exif_categories [i].label != NULL; i++) { + char *translated_string; + + translated_string = gettext (exif_categories[i].label); + + set_row_data (GTK_TREE_STORE (priv->model), + exif_categories[i].path, + NULL, + translated_string, + NULL); + } +} + +#ifdef HAVE_EXIF +void +eom_metadata_details_update (EomMetadataDetails *details, ExifData *data) +{ + g_return_if_fail (EOM_IS_METADATA_DETAILS (details)); + + eom_metadata_details_reset (details); + if (data) { + exif_data_foreach_content (data, exif_content_cb, details); + } +} +#endif /* HAVE_EXIF */ + +#ifdef HAVE_EXEMPI +typedef struct { + const char *id; + MetadataCategory category; +} XmpNsCategory; + +static XmpNsCategory xmp_ns_category_map[] = { + { NS_EXIF, XMP_CATEGORY_EXIF}, + { NS_TIFF, XMP_CATEGORY_EXIF}, + { NS_XAP, XMP_CATEGORY_EXIF}, + { NS_XAP_RIGHTS, XMP_CATEGORY_RIGHTS}, + { NS_EXIF_AUX, XMP_CATEGORY_EXIF}, + { NS_DC, XMP_CATEGORY_IPTC}, + { NS_IPTC4XMP, XMP_CATEGORY_IPTC}, + { NS_CC, XMP_CATEGORY_RIGHTS}, + { NULL, -1} +}; + +static MetadataCategory +get_xmp_category (XmpStringPtr schema) +{ + MetadataCategory cat = XMP_CATEGORY_OTHER; + const char *s = xmp_string_cstr(schema); + int i; + + for (i = 0; xmp_ns_category_map[i].id != NULL; i++) { + if (strcmp (xmp_ns_category_map[i].id, s) == 0) { + cat = xmp_ns_category_map[i].category; + break; + } + } + + return cat; +} + +static void +xmp_entry_insert (EomMetadataDetails *view, XmpStringPtr xmp_schema, + XmpStringPtr xmp_path, XmpStringPtr xmp_prop) +{ + GtkTreeStore *store; + EomMetadataDetailsPrivate *priv; + MetadataCategory cat; + char *path; + gchar *key; + + priv = view->priv; + + key = g_strconcat (xmp_string_cstr (xmp_schema), ":", + xmp_string_cstr (xmp_path), NULL); + + store = GTK_TREE_STORE (gtk_tree_view_get_model (GTK_TREE_VIEW (view))); + + path = g_hash_table_lookup (priv->id_path_hash, key); + + if (path != NULL) { + set_row_data (store, path, NULL, + xmp_string_cstr (xmp_path), + xmp_string_cstr (xmp_prop)); + + g_free(key); + } + else { + cat = get_xmp_category (xmp_schema); + + path = set_row_data (store, NULL, exif_categories[cat].path, + xmp_string_cstr(xmp_path), + xmp_string_cstr(xmp_prop)); + + g_hash_table_insert (priv->id_path_hash, key, path); + } +} + +void +eom_metadata_details_xmp_update (EomMetadataDetails *view, XmpPtr data) +{ + g_return_if_fail (EOM_IS_METADATA_DETAILS (view)); + + if (data) { + XmpIteratorPtr iter = xmp_iterator_new(data, NULL, NULL, XMP_ITER_JUSTLEAFNODES); + XmpStringPtr the_schema = xmp_string_new (); + XmpStringPtr the_path = xmp_string_new (); + XmpStringPtr the_prop = xmp_string_new (); + + while (xmp_iterator_next (iter, the_schema, the_path, the_prop, NULL)) { + xmp_entry_insert (view, the_schema, the_path, the_prop); + } + + xmp_string_free (the_prop); + xmp_string_free (the_path); + xmp_string_free (the_schema); + xmp_iterator_free (iter); + } +} +#endif diff --git a/src/eom-metadata-details.h b/src/eom-metadata-details.h new file mode 100644 index 0000000..a86e537 --- /dev/null +++ b/src/eom-metadata-details.h @@ -0,0 +1,72 @@ +/* Eye Of Mate - EOM Image Exif Details + * + * Copyright (C) 2006 The Free Software Foundation + * + * Author: Lucas Rocha <[email protected]> + * + * 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 2 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, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA. + */ + +#ifndef __EOM_METADATA_DETAILS__ +#define __EOM_METADATA_DETAILS__ + +#include <glib-object.h> +#include <gtk/gtk.h> +#if HAVE_EXIF +#include <libexif/exif-data.h> +#endif +#if HAVE_EXEMPI +#include <exempi/xmp.h> +#endif + +G_BEGIN_DECLS + +typedef struct _EomMetadataDetails EomMetadataDetails; +typedef struct _EomMetadataDetailsClass EomMetadataDetailsClass; +typedef struct _EomMetadataDetailsPrivate EomMetadataDetailsPrivate; + +#define EOM_TYPE_METADATA_DETAILS (eom_metadata_details_get_type ()) +#define EOM_METADATA_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EOM_TYPE_METADATA_DETAILS, EomMetadataDetails)) +#define EOM_METADATA_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass), EOM_TYPE_METADATA_DETAILS, EomMetadataDetailsClass)) +#define EOM_IS_METADATA_DETAILS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EOM_TYPE_METADATA_DETAILS)) +#define EOM_IS_METADATA_DETAILS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EOM_TYPE_METADATA_DETAILS)) +#define EOM_METADATA_DETAILS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EOM_TYPE_METADATA_DETAILS, EomMetadataDetailsClass)) + +struct _EomMetadataDetails { + GtkTreeView parent; + + EomMetadataDetailsPrivate *priv; +}; + +struct _EomMetadataDetailsClass { + GtkTreeViewClass parent_class; +}; + +GType eom_metadata_details_get_type (void) G_GNUC_CONST; + +GtkWidget *eom_metadata_details_new (void); + +#if HAVE_EXIF +void eom_metadata_details_update (EomMetadataDetails *details, + ExifData *data); +#endif +#if HAVE_EXEMPI +void eom_metadata_details_xmp_update (EomMetadataDetails *details, + XmpPtr xmp_data); +#endif + +G_END_DECLS + +#endif /* __EOM_METADATA_DETAILS__ */ diff --git a/src/eom-properties-dialog.c b/src/eom-properties-dialog.c index 1999040..afe852c 100644 --- a/src/eom-properties-dialog.c +++ b/src/eom-properties-dialog.c @@ -48,7 +48,7 @@ #endif #if HAVE_METADATA -#include "eom-exif-details.h" +#include "eom-metadata-details.h" #endif enum { @@ -320,7 +320,7 @@ pd_update_metadata_tab (EomPropertiesDialog *prop_dlg, eom_exif_util_set_label_text (GTK_LABEL (priv->exif_date_label), exif_data, EXIF_TAG_DATE_TIME_ORIGINAL); - eom_exif_details_update (EOM_EXIF_DETAILS (priv->exif_details), + eom_metadata_details_update (EOM_METADATA_DETAILS (priv->exif_details), exif_data); /* exif_data_unref can handle NULL-values */ @@ -356,7 +356,7 @@ pd_update_metadata_tab (EomPropertiesDialog *prop_dlg, "rights", priv->xmp_rights_label); - eom_exif_details_xmp_update (EOM_EXIF_DETAILS (priv->exif_details), xmp_data); + eom_metadata_details_xmp_update (EOM_METADATA_DETAILS (priv->exif_details), xmp_data); xmp_free (xmp_data); } else { @@ -690,7 +690,7 @@ eom_properties_dialog_init (EomPropertiesDialog *prop_dlg) GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); - priv->exif_details = eom_exif_details_new (); + priv->exif_details = eom_metadata_details_new (); gtk_widget_set_size_request (priv->exif_details, -1, 170); gtk_container_set_border_width (GTK_CONTAINER (sw), 6); gtk_widget_set_vexpand (priv->exif_details, TRUE); |