[tracker-miners/wip/rishi/exiv2] tracker-extract: Add GExiv2 based extractor for RAW files
- From: Debarshi Ray <debarshir src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [tracker-miners/wip/rishi/exiv2] tracker-extract: Add GExiv2 based extractor for RAW files
- Date: Wed, 4 Oct 2017 09:52:57 +0000 (UTC)
commit a5cc6efdb2f9241734c887768e64481ee61c1c32
Author: Debarshi Ray <debarshir gnome org>
Date: Tue Sep 12 17:13:57 2017 +0200
tracker-extract: Add GExiv2 based extractor for RAW files
https://bugzilla.gnome.org/show_bug.cgi?id=787589
configure.ac | 36 +++
meson.build | 2 +
src/tracker-extract/10-raw.rule | 4 +
src/tracker-extract/Makefile.am | 20 ++-
src/tracker-extract/meson.build | 4 +
src/tracker-extract/tracker-extract-raw.c | 381 +++++++++++++++++++++++++++++
6 files changed, 446 insertions(+), 1 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 8b33336..5cfdc27 100644
--- a/configure.ac
+++ b/configure.ac
@@ -226,6 +226,7 @@ LIBOSINFO_REQUIRED=0.2.9
EXEMPI_REQUIRED=2.1.0
TAGLIB_REQUIRED=1.6
LIBGRSS_REQUIRED=0.7
+GEXIV2_REQUIRED="any version"
GSTREAMER_REQUIRED=0.10.31
GUPNP_DLNA_REQUIRED=0.9.4
LIBPNG_REQUIRED=1.2
@@ -966,6 +967,40 @@ fi
AM_CONDITIONAL(HAVE_LIBXML2, test "x$have_libxml2" = "xyes")
+##################################################################
+# Check for tracker-extract: gexiv2
+##################################################################
+
+AC_ARG_ENABLE(gexiv2,
+ AS_HELP_STRING([--enable-gexiv2],
+ [enable extractor for RAW metadata [[default=auto]]]),
+ [enable_gexiv2=$enableval],
+ [enable_gexiv2=auto])
+
+if test "x$enable_gexiv2" != "xno" ; then
+ PKG_CHECK_MODULES(GEXIV2,
+ [gexiv2],
+ [have_gexiv2=yes],
+ [have_gexiv2=no])
+
+ AC_SUBST(GEXIV2_CFLAGS)
+ AC_SUBST(GEXIV2_LIBS)
+
+ if test "x$have_gexiv2" = "xyes"; then
+ AC_DEFINE(HAVE_GEXIV2, [], [Define if we have gexiv2])
+ fi
+else
+ have_gexiv2="no (disabled)"
+fi
+
+if test "x$enable_gexiv2" = "xyes"; then
+ if test "x$have_gexiv2" != "xyes"; then
+ AC_MSG_ERROR([Could not find gexiv2.])
+ fi
+fi
+
+AM_CONDITIONAL(HAVE_GEXIV2, test "x$have_gexiv2" = "xyes")
+
####################################################################
# Check for tracker-extract: gstreamer/etc
####################################################################
@@ -1859,6 +1894,7 @@ Metadata Extractors:
Support XPS: $have_libgxps
Support GIF: $have_libgif (xmp: $have_exempi)
Support JPEG: $have_libjpeg (xmp: $have_exempi, exif: $have_libexif, iptc:
$have_libiptcdata)
+ Support RAW: $have_gexiv2
Support TIFF: $have_libtiff (xmp: $have_exempi, exif: yes, iptc:
$have_libiptcdata)
Support Vorbis (ogg/etc): $have_libvorbis
Support Flac: $have_libflac
diff --git a/meson.build b/meson.build
index b8a8ade..01c05a3 100644
--- a/meson.build
+++ b/meson.build
@@ -17,6 +17,7 @@ avutil = dependency('libavutil', version: '>= 0.8.4', required: false)
dbus = dependency('dbus-1', version: '> 1.3.1')
exempi = dependency('exempi-2.0', version: '> 2.1.0', required: false)
flac = dependency('flac', version: '> 1.2.1', required: false)
+gexiv2 = dependency('gexiv2', required: false)
gio = dependency('gio-2.0', version: '>' + glib_required)
gio_unix = dependency('gio-unix-2.0', version: '>' + glib_required)
glib = dependency('glib-2.0', version: '>' + glib_required)
@@ -390,6 +391,7 @@ if have_tracker_extract
' Support GIF: @0@ (xmp: @1@)'.format(libgif.found().to_string(),
exempi.found().to_string()),
' Support JPEG: @0@ (xmp: @1@, exif: @2@, iptc: @3@)'.format(
libjpeg.found().to_string(), exempi.found().to_string(), libexif.found().to_string(),
libiptcdata.found().to_string()),
+ ' Support RAW: ' + gexiv2.found().to_string(),
' Support TIFF: @0@ (xmp: @1@, exif: @2@, iptc: @3@)'.format(
libtiff.found().to_string(), exempi.found().to_string(), libexif.found().to_string(),
libiptcdata.found().to_string()),
' Support Vorbis (ogg/etc): ' + libvorbis.found().to_string(),
diff --git a/src/tracker-extract/10-raw.rule b/src/tracker-extract/10-raw.rule
new file mode 100644
index 0000000..c395b38
--- /dev/null
+++ b/src/tracker-extract/10-raw.rule
@@ -0,0 +1,4 @@
+[ExtractorRule]
+ModulePath=libextract-raw.so
+MimeTypes=image/x-canon-cr2;image/x-canon-crw;image/x-epson-erf;image/x-fuji-raf;image/x-minolta-mrw;image/x-nikon-nef;image/x-olympus-orf;image/x-pentax-pef;image/x-sony-arw;
+FallbackRdfTypes=nfo:Image;nmm:Photo;
diff --git a/src/tracker-extract/Makefile.am b/src/tracker-extract/Makefile.am
index 674223f..f201a2a 100644
--- a/src/tracker-extract/Makefile.am
+++ b/src/tracker-extract/Makefile.am
@@ -35,6 +35,7 @@ rules_files = \
10-pdf.rule \
10-png.rule \
10-ps.rule \
+ 10-raw.rule \
10-svg.rule \
10-tiff.rule \
10-vorbis.rule \
@@ -120,6 +121,11 @@ extractmodules_LTLIBRARIES += libextract-pdf.la
rules_DATA += 10-pdf.rule
endif
+if HAVE_GEXIV2
+extractmodules_LTLIBRARIES += libextract-raw.la
+rules_DATA += 10-raw.rule
+endif
+
if HAVE_GSTREAMER
extractmodules_LTLIBRARIES += libextract-gstreamer.la
rules_DATA += 10-svg.rule 15-gstreamer-guess.rule 90-gstreamer-image-generic.rule
90-gstreamer-audio-generic.rule 90-gstreamer-video-generic.rule
@@ -269,7 +275,6 @@ libextract_png_la_LIBADD = \
$(TRACKER_EXTRACT_MODULES_LIBS) \
$(LIBPNG_LIBS)
-
# PS
libextract_ps_la_SOURCES = tracker-extract-ps.c
libextract_ps_la_CFLAGS = $(TRACKER_EXTRACT_MODULES_CFLAGS)
@@ -363,6 +368,19 @@ libextract_dvi_la_LIBADD = \
$(BUILD_LIBS) \
$(TRACKER_EXTRACT_MODULES_LIBS)
+# GEXIV2
+libextract_raw_la_SOURCES = tracker-extract-raw.c
+libextract_raw_la_CFLAGS = \
+ $(TRACKER_EXTRACT_MODULES_CFLAGS) \
+ $(GEXIV2_CFLAGS)
+libextract_raw_la_LDFLAGS = $(module_flags)
+libextract_raw_la_LIBADD = \
+ $(top_builddir)/src/libtracker-extract/libtracker-extract.la \
+ $(top_builddir)/src/libtracker-common/libtracker-common.la \
+ $(BUILD_LIBS) \
+ $(TRACKER_EXTRACT_MODULES_LIBS) \
+ $(GEXIV2_LIBS)
+
# GStreamer
libextract_gstreamer_la_SOURCES = \
tracker-extract-gstreamer.c \
diff --git a/src/tracker-extract/meson.build b/src/tracker-extract/meson.build
index 2f429e2..d814162 100644
--- a/src/tracker-extract/meson.build
+++ b/src/tracker-extract/meson.build
@@ -28,6 +28,10 @@ if flac.found()
modules += [['extract-flac', 'tracker-extract-flac.c', '10-flac.rule', [flac, tracker_common_dep]]]
endif
+if gexiv2.found()
+ modules += [['extract-raw', 'tracker-extract-raw.c', '10-raw.rule', [gexiv2, tracker_common_dep]]]
+endif
+
if libgif.found()
modules += [['extract-gif', 'tracker-extract-gif.c', '10-gif.rule', [libgif, tracker_common_dep]]]
endif
diff --git a/src/tracker-extract/tracker-extract-raw.c b/src/tracker-extract/tracker-extract-raw.c
new file mode 100644
index 0000000..505fcbd
--- /dev/null
+++ b/src/tracker-extract/tracker-extract-raw.c
@@ -0,0 +1,381 @@
+/*
+ * Copyright (C) 2017 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include <gexiv2/gexiv2.h>
+
+#include <libtracker-common/tracker-common.h>
+#include <libtracker-extract/tracker-extract.h>
+#include <libtracker-sparql/tracker-sparql.h>
+
+#include "tracker-main.h"
+
+#define CM_TO_INCH 0.393700787
+#define EXIF_DATE_FORMAT "%Y:%m:%d %H:%M:%S"
+
+typedef struct {
+ const gchar *make;
+ const gchar *model;
+ const gchar *title;
+ const gchar *orientation;
+ const gchar *copyright;
+ const gchar *white_balance;
+ const gchar *fnumber;
+ const gchar *flash;
+ const gchar *focal_length;
+ const gchar *artist;
+ const gchar *exposure_time;
+ const gchar *iso_speed_ratings;
+ const gchar *date;
+ const gchar *description;
+ const gchar *metering_mode;
+ const gchar *creator;
+ const gchar *comment;
+ const gchar *city;
+ const gchar *state;
+ const gchar *address;
+ const gchar *country;
+ const gchar *gps_altitude;
+ const gchar *gps_latitude;
+ const gchar *gps_longitude;
+ const gchar *gps_direction;
+} MergeData;
+
+static gchar *
+convert_exiv2_orientation_to_nfo (GExiv2Orientation orientation)
+{
+ gchar *retval = NULL;
+
+ switch (orientation) {
+ case GEXIV2_ORIENTATION_NORMAL:
+ retval = g_strdup ("nfo:orientation-top");
+ break;
+ case GEXIV2_ORIENTATION_HFLIP:
+ retval = g_strdup ("nfo:orientation-top-mirror");
+ break;
+ case GEXIV2_ORIENTATION_ROT_180:
+ retval = g_strdup ("nfo:orientation-bottom");
+ break;
+ case GEXIV2_ORIENTATION_VFLIP:
+ retval = g_strdup ("nfo:orientation-bottom-mirror");
+ break;
+ case GEXIV2_ORIENTATION_ROT_90_HFLIP:
+ retval = g_strdup ("nfo:orientation-left-mirror");
+ break;
+ case GEXIV2_ORIENTATION_ROT_90:
+ retval = g_strdup ("nfo:orientation-right");
+ break;
+ case GEXIV2_ORIENTATION_ROT_90_VFLIP:
+ retval = g_strdup ("nfo:orientation-right-mirror");
+ break;
+ case GEXIV2_ORIENTATION_ROT_270:
+ retval = g_strdup ("nfo:orientation-left");
+ break;
+ default:
+ retval = g_strdup ("nfo:orientation-top");
+ break;
+ }
+
+ return retval;
+}
+
+static gchar *
+parse_exposure_time (const gchar *exposure_time_buf)
+{
+ const gchar *sep;
+
+ sep = strchr (exposure_time_buf, '/');
+
+ if (sep != NULL) {
+ gdouble fraction;
+
+ fraction = g_ascii_strtod (sep + 1, NULL);
+
+ if (fraction > 0.0) {
+ gchar buf[G_ASCII_DTOSTR_BUF_SIZE];
+
+ fraction = 1.0f / fraction;
+ g_ascii_dtostr (buf, sizeof(buf), fraction);
+
+ return g_strdup (buf);
+ }
+ }
+
+ return g_strdup (exposure_time_buf);
+}
+
+static gchar *
+parse_flash (gushort flash_value)
+{
+ gchar *flash = NULL;
+
+ switch (flash_value) {
+ case 0x0000: /* No flash */
+ case 0x0005: /* Without strobe */
+ case 0x0008: /* Flash did not fire */
+ case 0x0010: /* Flash in compulsory mode, did not fire */
+ case 0x0018: /* Flash in auto mode, did not fire */
+ case 0x0058: /* Only red-eye reduction mode */
+ flash = g_strdup ("nmm:flash-off");
+ break;
+ default:
+ flash = g_strdup ("nmm:flash-on");
+ break;
+ }
+
+ return flash;
+}
+
+static gchar *
+parse_metering_mode (gushort metering_mode_value)
+{
+ gchar *metering_mode = NULL;
+
+ switch (metering_mode_value) {
+ case 1:
+ metering_mode = g_strdup ("nmm:metering-mode-average");
+ break;
+ case 2:
+ metering_mode = g_strdup ("nmm:metering-mode-center-weighted-average");
+ break;
+ case 3:
+ metering_mode = g_strdup ("nmm:metering-mode-spot");
+ break;
+ case 4:
+ metering_mode = g_strdup ("nmm:metering-mode-multispot");
+ break;
+ case 5:
+ metering_mode = g_strdup ("nmm:metering-mode-pattern");
+ break;
+ case 6:
+ metering_mode = g_strdup ("nmm:metering-mode-partial");
+ break;
+ default:
+ metering_mode = g_strdup ("nmm:metering-mode-other");
+ break;
+ }
+
+ return metering_mode;
+}
+
+static gchar *
+parse_white_balance (gushort white_balance_value)
+{
+ gchar *white_balance = NULL;
+
+ if (white_balance_value == 0)
+ white_balance = g_strdup ("nmm:white-balance-auto");
+ else
+ white_balance = g_strdup ("nmm:white-balance-manual");
+
+ return white_balance;
+}
+
+static TrackerExifData *
+parse_exif_data (GExiv2Metadata *metadata)
+{
+ TrackerExifData *ed = NULL;
+ gchar *time = NULL;
+ gchar *time_original = NULL;
+ gint exposure_time_den;
+ gint exposure_time_nom;
+ glong flash = G_MAXLONG;
+ glong metering_mode = G_MAXLONG;
+ glong white_balance = G_MAXLONG;
+
+ ed = g_new0 (TrackerExifData, 1);
+ ed->exposure_time = -1.0;
+ ed->fnumber = -1.0;
+ ed->focal_length = -1.0;
+ ed->iso_speed_ratings = -1.0;
+
+ if (!gexiv2_metadata_has_exif (metadata))
+ goto out;
+
+ ed->document_name = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.DocumentName");
+
+ time = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.DateTime");
+ if (time != NULL) {
+ ed->time = tracker_date_format_to_iso8601 (time, EXIF_DATE_FORMAT);
+ }
+
+ time_original = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.DateTimeOriginal");
+ if (time_original == NULL)
+ time_original = gexiv2_metadata_get_tag_string (metadata, "Exif.Photo.DateTimeOriginal");
+ if (time_original != NULL)
+ ed->time_original = tracker_date_format_to_iso8601 (time_original, EXIF_DATE_FORMAT);
+
+ ed->artist = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.Artist");
+ ed->user_comment = gexiv2_metadata_get_tag_string (metadata, "Exif.Photo.UserComment");
+ ed->description = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.ImageDescription");
+ ed->make = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.Make");
+ ed->model = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.Model");
+
+ if (gexiv2_metadata_get_exposure_time (metadata, &exposure_time_nom, &exposure_time_den))
+ ed->exposure_time = (gdouble) exposure_time_nom / (double) exposure_time_den;
+
+ ed->fnumber = gexiv2_metadata_get_fnumber (metadata);
+
+ if (gexiv2_metadata_has_tag (metadata, "Exif.Image.Flash"))
+ flash = gexiv2_metadata_get_tag_long (metadata, "Exif.Image.Flash");
+ else if (gexiv2_metadata_has_tag (metadata, "Exif.Photo.Flash"))
+ flash = gexiv2_metadata_get_tag_long (metadata, "Exif.Photo.Flash");
+ if (flash != G_MAXLONG)
+ ed->flash = parse_flash ((gushort) flash);
+
+ ed->focal_length = gexiv2_metadata_get_focal_length (metadata);
+
+ if (gexiv2_metadata_has_tag (metadata, "Exif.Photo.ISOSpeedRatings"))
+ ed->iso_speed_ratings = (gdouble) gexiv2_metadata_get_iso_speed (metadata);
+
+ if (gexiv2_metadata_has_tag (metadata, "Exif.Image.MeteringMode"))
+ metering_mode = gexiv2_metadata_get_tag_long (metadata, "Exif.Image.MeteringMode");
+ else if (gexiv2_metadata_has_tag (metadata, "Exif.Photo.MeteringMode"))
+ metering_mode = gexiv2_metadata_get_tag_long (metadata, "Exif.Photo.MeteringMode");
+ if (metering_mode != G_MAXLONG)
+ ed->metering_mode = parse_metering_mode ((gushort) metering_mode);
+
+ if (gexiv2_metadata_has_tag (metadata, "Exif.Photo.WhiteBalance"))
+ white_balance = gexiv2_metadata_get_tag_long (metadata, "Exif.Photo.WhiteBalance");
+ if (white_balance != G_MAXLONG)
+ ed->white_balance = parse_white_balance ((gushort) white_balance);
+
+ ed->copyright = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.Copyright");
+ ed->software = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.Software");
+ ed->resolution_unit = (gint) gexiv2_metadata_get_tag_long (metadata, "Exif.Image.ResolutionUnit");
+ ed->x_resolution = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.XResolution");
+ ed->y_resolution = gexiv2_metadata_get_tag_string (metadata, "Exif.Image.YResolution");
+
+out:
+ g_free (time);
+ g_free (time_original);
+ return ed;
+}
+
+G_MODULE_EXPORT gboolean
+tracker_extract_get_metadata (TrackerExtractInfo *info)
+{
+ GError *error;
+ GExiv2Metadata *metadata = NULL;
+ GExiv2Orientation orientation;
+ TrackerExifData *ed = NULL;
+ TrackerResource *resource = NULL;
+ MergeData md = { 0 };
+ GFile *file;
+ gchar *filename = NULL;
+ gchar *nfo_orientation = NULL;
+ gchar *uri = NULL;
+ gboolean retval = FALSE;
+
+ metadata = gexiv2_metadata_new ();
+ file = tracker_extract_info_get_file (info);
+ filename = g_file_get_path (file);
+
+ error = NULL;
+ if (!gexiv2_metadata_open_path (metadata, filename, &error)) {
+ g_warning ("Could not open %s for reading metadata: %s", filename, error->message);
+ g_error_free (error);
+ goto out;
+ }
+
+ resource = tracker_resource_new (NULL);
+ tracker_resource_add_uri (resource, "rdf:type", "nfo:Image");
+ tracker_resource_add_uri (resource, "rdf:type", "nmm:Photo");
+
+ orientation = gexiv2_metadata_get_orientation (metadata);
+ nfo_orientation = convert_exiv2_orientation_to_nfo (orientation);
+ tracker_resource_set_uri (resource, "nfo:orientation", nfo_orientation);
+
+ ed = parse_exif_data (metadata);
+
+ if (ed->make != NULL || ed->model != NULL) {
+ TrackerResource *equipment;
+
+ equipment = tracker_extract_new_equipment (ed->make, ed->model);
+ tracker_resource_add_relation (resource, "nfo:equipment", equipment);
+ g_object_unref (equipment);
+ }
+
+ tracker_guarantee_resource_title_from_file (resource, "nie:title", ed->document_name, uri, NULL);
+
+ if (ed->copyright != NULL) {
+ tracker_resource_set_string (resource, "nie:copyright", ed->copyright);
+ }
+
+ if (ed->white_balance != NULL) {
+ tracker_resource_set_uri (resource, "nmm:whiteBalance", ed->white_balance);
+ }
+
+ if (ed->fnumber != -1.0) {
+ tracker_resource_set_double (resource, "nmm:fnumber", ed->fnumber);
+ }
+
+ if (ed->flash != NULL) {
+ tracker_resource_set_uri (resource, "nmm:flash", ed->flash);
+ }
+
+ if (ed->focal_length != -1.0) {
+ tracker_resource_set_double (resource, "nmm:focalLength", ed->focal_length);
+ }
+
+ if (ed->artist != NULL) {
+ TrackerResource *artist;
+
+ artist = tracker_extract_new_contact (ed->artist);
+ tracker_resource_add_relation (resource, "nco:contributor", artist);
+ g_object_unref (artist);
+ }
+
+ if (ed->exposure_time != -1.0) {
+ tracker_resource_set_double (resource, "nmm:exposureTime", ed->exposure_time);
+ }
+
+ if (ed->iso_speed_ratings != -1.0) {
+ tracker_resource_set_double (resource, "nmm:isoSpeed", ed->iso_speed_ratings);
+ }
+
+ tracker_guarantee_resource_title_from_file (resource, "nie:contentCreated", /*date*/, uri);
+
+ if (ed->description != NULL) {
+ tracker_resource_set_string (resource, "nie:description", ed->description);
+ }
+
+ if (ed->metering_mode != NULL) {
+ tracker_resource_set_uri (resource, "nmm:meteringMode", ed->metering_mode);
+ }
+
+ if (ed->user_comment) {
+ tracker_guarantee_resource_utf8_string (resource, "nie:comment", ed->user_comment);
+ }
+
+ tracker_extract_info_set_resource (info, resource);
+ retval = TRUE;
+
+out:
+ g_clear_object (&metadata);
+ g_clear_object (&resource);
+ g_clear_pointer (&ed, (GDestroyNotify) tracker_exif_free);
+ g_free (filename);
+ g_free (nfo_orientation);
+ g_free (uri);
+ return retval;
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]