esac
AM_CONDITIONAL([GEOCACHES], [test x$ac_cv_enable_geocaches = xyes])
+# Geotagging
+AC_ARG_WITH(libexif, AC_HELP_STRING([--with-libexif], [Force usage of libexif instead of libgexiv2]))
AC_ARG_ENABLE(geotag, AC_HELP_STRING([--enable-geotag],
[enable Geotag Support (default is enable).]),
[ac_cv_enable_geotag=$enableval],
[ac_cv_enable_geotag], [ac_cv_enable_geotag=yes])
case $ac_cv_enable_geotag in
yes)
- AC_CHECK_LIB(exif,exif_loader_new,,AC_MSG_ERROR([libexif is needed for Geotag features[,] but is not found. The feature can be disabled with --disable-geotag]))
+ AS_IF([test x$with_libexif = xyes],
+ AC_CHECK_HEADER([libexif/exif-data.h],[],AC_MSG_ERROR([exif-data.h is needed but not found - you will need to install package 'libexif-dev' or similar]))
+ AC_CHECK_LIB(exif,exif_loader_new,, AC_MSG_ERROR([libexif is not found but it has been forcibly required])),
+ # gexiv2.h relies on glib so a simple compile check fails.
+ #AC_CHECK_HEADER([gexiv2/gexiv2.h],,AC_MSG_ERROR([Error msg...]))
+ AC_CHECK_LIB(gexiv2,gexiv2_metadata_new,, AC_MSG_ERROR([libgexiv2 is needed but not found - you will need to install package 'libgexiv2-dev' or similar. The feature can be disabled with --disable-geotag]))
+ )
AC_DEFINE(VIK_CONFIG_GEOTAG, [], [GEOTAG STUFF])
;;
esac
AM_CONDITIONAL([GEOTAG], [test x$ac_cv_enable_geotag = xyes])
+AM_CONDITIONAL([GEXIV2], [test x$ac_cv_lib_gexiv2_gexiv2_metadata_new = xyes] )
+# Tested with gexiv2 0.10.2, but probably would work with older versions; may be all of them...
+#AM_COND_IF([GEXIV2], [PKG_CHECK_MODULES([GEXIV2], [gexiv2 >= 0.6.1])])
+AM_CONDITIONAL([LIBEXIF], [test x$ac_cv_lib_exif_exif_loader_new = xyes] )
AC_ARG_ENABLE(dem24k, AC_HELP_STRING([--enable-dem24k],
[enable USGS 24k DEM (default is disable) download source. Requires dem24k.pl script in path.]),
echo "BlueMarble : $ac_cv_enable_bluemarble"
echo "Geonames : $ac_cv_enable_geonames"
echo "Geocaches Acquire : $ac_cv_enable_geocaches"
-echo "Geotag Support : $ac_cv_enable_geotag"
+echo "Geotag Support : $ac_cv_enable_geotag (libgexiv2=$ac_cv_lib_gexiv2_gexiv2_metadata_new libexif=$ac_cv_lib_exif_exif_loader_new)"
echo "USGS 24k DEM : $ac_cv_enable_dem24k"
echo "Realtime GPS Tracking : $ac_cv_enable_realtimegpstracking"
echo "bzip2 Support : $ac_cv_enable_bzip2"
/*
* This uses EXIF information from images to create waypoints at those positions
*
- * For the implementation I have chosen to use libexif, which keeps Viking a pure C program
- * For an alternative implementation (a la gpscorrelate), one could use libeviv2 but it appears to be C++ only.
+ * The intial implementation uses libexif, which keeps Viking a pure C program.
+ * Now libgexiv2 is available (in C as a wrapper around the more powerful libexiv2 [C++]) so this is the preferred build.
+ * The attentative reader will notice the use of gexiv2 is a lot simpler as well.
+ * For the time being the libexif code + build is still made available.
*/
#include <string.h>
#include "geotag_exif.h"
+#include "config.h"
#include "globals.h"
#include "file.h"
#include <math.h>
#include <glib/gi18n.h>
#include <glib/gstdio.h>
+#ifdef HAVE_LIBGEXIV2
+#include <gexiv2/gexiv2.h>
+#endif
+#ifdef HAVE_LIBEXIF
#include <libexif/exif-data.h>
#include "libjpeg/jpeg-data.h"
+#endif
+#ifdef HAVE_LIBGEXIV2
+/**
+ * Attempt to get a single comment from the various exif fields
+ */
+static gchar* geotag_get_exif_comment ( GExiv2Metadata *gemd )
+{
+ //
+ // Try various options to create a comment
+ //
+ if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.ImageDescription" ) )
+ return g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.ImageDescription" ) );
+
+ if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.XPComment" ) )
+ return g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.XPComment" ) );
+
+ if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.XPSubject" ) )
+ return g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.XPSubject" ) );
+
+ if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.DateTimeOriginal" ) )
+ return g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.DateTimeOriginal" ) );
+
+ // Otherwise nothing found
+ return NULL;
+}
+#endif
+
+#ifdef HAVE_LIBEXIF
/**
* Attempt to get a single comment from the various exif fields
*/
exif_entry_get_value ( ee, str, 128 );
return g_strdup ( str );
}
-
+
// Otherwise nothing found
return NULL;
}
return ll;
}
+#endif
/**
* a_geotag_get_position:
{
struct LatLon ll = { 0.0, 0.0 };
+#ifdef HAVE_LIBGEXIV2
+ GExiv2Metadata *gemd = gexiv2_metadata_new ();
+ if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
+ gdouble lat;
+ gdouble lon;
+ gdouble alt;
+ if ( gexiv2_metadata_get_gps_info ( gemd, &lon, &lat, &alt ) ) {
+ ll.lat = lat;
+ ll.lon = lon;
+ }
+ }
+ gexiv2_metadata_free ( gemd );
+#else
+#ifdef HAVE_LIBEXIF
// open image with libexif
ExifData *ed = exif_data_new_from_file ( filename );
MyReturn0:
// Finished with EXIF
exif_data_free ( ed );
+#endif
+#endif
return ll;
}
*name = NULL;
VikWaypoint *wp = NULL;
+#ifdef HAVE_LIBGEXIV2
+ GExiv2Metadata *gemd = gexiv2_metadata_new ();
+ if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
+ gdouble lat;
+ gdouble lon;
+ gdouble alt;
+ if ( gexiv2_metadata_get_gps_info ( gemd, &lon, &lat, &alt ) ) {
+ struct LatLon ll;
+ ll.lat = lat;
+ ll.lon = lon;
+
+ //
+ // Now create Waypoint with acquired information
+ //
+ wp = vik_waypoint_new();
+ wp->visible = TRUE;
+ // Set info from exif values
+ // Location
+ vik_coord_load_from_latlon ( &(wp->coord), vcmode, &ll );
+ // Altitude
+ wp->altitude = alt;
+
+ if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.XPTitle" ) )
+ *name = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.XPTitle" ) );
+ wp->comment = geotag_get_exif_comment ( gemd );
+
+ vik_waypoint_set_image ( wp, filename );
+ }
+ }
+ gexiv2_metadata_free ( gemd );
+#else
+#ifdef HAVE_LIBEXIF
// TODO use log?
//ExifLog *log = NULL;
MyReturn:
// Finished with EXIF
exif_data_free ( ed );
+#endif
+#endif
return wp;
}
wp->coord = coord;
wp->altitude = alt;
+#ifdef HAVE_LIBGEXIV2
+ GExiv2Metadata *gemd = gexiv2_metadata_new ();
+ if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
+ wp->comment = geotag_get_exif_comment ( gemd );
+ if ( gexiv2_metadata_has_tag ( gemd, "Exif.Image.XPTitle" ) )
+ *name = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.XPTitle" ) );
+ }
+ gexiv2_metadata_free ( gemd );
+#else
+#ifdef HAVE_LIBEXIF
ExifData *ed = exif_data_new_from_file ( filename );
// Set info from exif values
// Finished with EXIF
exif_data_free ( ed );
}
+#endif
+#endif
vik_waypoint_set_image ( wp, filename );
gchar* datetime = NULL;
*has_GPS_info = FALSE;
+#ifdef HAVE_LIBGEXIV2
+ GExiv2Metadata *gemd = gexiv2_metadata_new ();
+ if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
+ gdouble lat, lon;
+ *has_GPS_info = ( gexiv2_metadata_get_gps_longitude(gemd,&lon) && gexiv2_metadata_get_gps_latitude(gemd,&lat) );
+
+ // Prefer 'Photo' version over 'Image'
+ if ( gexiv2_metadata_has_tag ( gemd, "Exif.Photo.DateTimeOriginal" ) )
+ datetime = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Photo.DateTimeOriginal" ) );
+ else
+ datetime = g_strdup ( gexiv2_metadata_get_tag_interpreted_string ( gemd, "Exif.Image.DateTimeOriginal" ) );
+ }
+ gexiv2_metadata_free ( gemd );
+#else
+#ifdef HAVE_LIBEXIF
ExifData *ed = exif_data_new_from_file ( filename );
// Detect EXIF load failure
*has_GPS_info = FALSE;
exif_data_free ( ed );
-
+#endif
+#endif
return datetime;
}
+#ifdef HAVE_LIBEXIF
/**! If the entry doesn't exist, create it.
* Based on exif command line action_create_value function in exif 0.6.20
*/
if ( value_p )
g_warning (_("Warning; Too many components specified!"));
}
+#endif
/**
* a_geotag_write_exif_gps:
if ( no_change_mtime )
stat ( filename, &stat_save );
+#ifdef HAVE_LIBGEXIV2
+ GExiv2Metadata *gemd = gexiv2_metadata_new ();
+ if ( gexiv2_metadata_open_path ( gemd, filename, NULL ) ) {
+ struct LatLon ll;
+ vik_coord_to_latlon ( &coord, &ll );
+ if ( ! gexiv2_metadata_set_gps_info ( gemd, ll.lon, ll.lat, alt ) ) {
+ result = 1; // Failed
+ }
+ else {
+ GError *error = NULL;
+ if ( ! gexiv2_metadata_save_file ( gemd, filename, &error ) ) {
+ result = 2;
+ g_warning ( "Write EXIF failure:%s" , error->message );
+ g_error_free ( error );
+ }
+ }
+ }
+ gexiv2_metadata_free ( gemd );
+#else
+#ifdef HAVE_LIBEXIF
/*
Appears libexif doesn't actually support writing EXIF data directly to files
Thus embed command line exif writing method within Viking
result = 2;
}
+ exif_data_free ( ed );
+#endif
+#endif
+
if ( no_change_mtime ) {
// Restore mtime, using the saved value
struct stat stat_tmp;
utime ( filename, &utb );
}
- exif_data_free ( ed );
-
return result;
}