From 41f4abac2125c3551d0056e6a7c67f93b0437eb1 Mon Sep 17 00:00:00 2001 From: Rob Norris Date: Sat, 28 Sep 2013 11:42:07 +0100 Subject: [PATCH] SF Features#115: Part 1. Add the ability to Geotag multiple images against a Waypoint. Reuse the general Geotagging Dialog and disable the create/update waypoint options when invoked on a waypoint. When run against waypoints simply use the position of the waypoint to geotag each image (no interpolation required). Add feedback to the statusbar should writing the EXIF fail. Update the manual accordingly. --- help/C/viking.xml | 11 ++++-- src/viktrwlayer.c | 30 ++++++++++++---- src/viktrwlayer_geotag.c | 74 +++++++++++++++++++++++++++++++++++----- src/viktrwlayer_geotag.h | 5 ++- 4 files changed, 102 insertions(+), 18 deletions(-) diff --git a/help/C/viking.xml b/help/C/viking.xml index 3141ab19..c041934b 100644 --- a/help/C/viking.xml +++ b/help/C/viking.xml @@ -1319,6 +1319,13 @@ This centers the viewport on the selected waypoint. +
Geotag Images... + +This opens the Geotag Dialog to allow Geotagging multiple images to the position of this waypoint. +In this circumstance creation of waypoint options are disabled and only the options related to writing the EXIF information are available. + +
+
Visit Webpage If the waypoint's comment (or description) starts with http: then this option is available and allows launching a web browser to go to the webpage. @@ -1341,10 +1348,10 @@ Same as the layer New Waypoint.
Version1.3+: Geotag Images -This dialog allows geotagging images (normally taken with a digital camera) via interpolation against a specific track or all tracks in the TrackWaypoint layer - depending on how it is invoked. +This dialog allows geotagging images (normally taken with a digital camera) against a specific waypoint or via interpolation against a specific track or all tracks in the TrackWaypoint layer - depending on how it is invoked. -Images need to have an EXIF DATE_TIME_ORIGINAL (nearly always set by a camera). This timestamp is then used to find the location when the image(s) was taken by searching through the track(s) to find the nearest time - interpolating between points if necessary to set the location. +When geotagging against tracks, images need to have an EXIF DATE_TIME_ORIGINAL (nearly always set by a camera). This timestamp is then used to find the location when the image(s) was taken by searching through the track(s) to find the nearest time - interpolating between points if necessary to set the location. diff --git a/src/viktrwlayer.c b/src/viktrwlayer.c index d7e97ded..7eeae31c 100644 --- a/src/viktrwlayer.c +++ b/src/viktrwlayer.c @@ -3311,9 +3311,20 @@ static void trw_layer_geotagging_track ( gpointer pass_along[6] ) vtl->has_verified_thumbnails = FALSE; trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - vtl, - track, - track->name ); + vtl, + NULL, + track ); +} + +static void trw_layer_geotagging_waypoint ( gpointer pass_along[6] ) +{ + VikTrwLayer *vtl = VIK_TRW_LAYER(pass_along[0]); + VikWaypoint *wpt = g_hash_table_lookup ( VIK_TRW_LAYER(pass_along[0])->waypoints, pass_along[3] ); + + trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl), + vtl, + wpt, + NULL ); } static void trw_layer_geotagging ( gpointer lav[2] ) @@ -3323,9 +3334,9 @@ static void trw_layer_geotagging ( gpointer lav[2] ) vtl->has_verified_thumbnails = FALSE; trw_layer_geotag_dialog ( VIK_GTK_WINDOW_FROM_LAYER(vtl), - vtl, - NULL, - NULL); + vtl, + NULL, + NULL ); } #endif @@ -7288,6 +7299,13 @@ static gboolean trw_layer_sublayer_add_menu_items ( VikTrwLayer *l, GtkMenu *men gtk_menu_shell_append ( GTK_MENU_SHELL(menu), item ); gtk_widget_show ( item ); } +#ifdef VIK_CONFIG_GEOTAG + item = gtk_menu_item_new_with_mnemonic ( _("Geotag _Images...") ); + g_signal_connect_swapped ( G_OBJECT(item), "activate", G_CALLBACK(trw_layer_geotagging_waypoint), pass_along ); + gtk_menu_shell_append (GTK_MENU_SHELL (menu), item); + gtk_widget_set_tooltip_text (item, _("Geotag multiple images against this waypoint")); + gtk_widget_show ( item ); +#endif } if ( wp && wp->image ) diff --git a/src/viktrwlayer_geotag.c b/src/viktrwlayer_geotag.c index 71234b2b..bf653472 100644 --- a/src/viktrwlayer_geotag.c +++ b/src/viktrwlayer_geotag.c @@ -91,6 +91,7 @@ typedef struct { GtkWidget *dialog; VikFileList *files; VikTrwLayer *vtl; // to pass on + VikWaypoint *wpt; // Use specified waypoint or otherwise the track(s) if NULL VikTrack *track; // Use specified track or all tracks if NULL GtkCheckButton *create_waypoints_b; GtkLabel *overwrite_waypoints_l; // Referenced so the sensitivity can be changed @@ -132,6 +133,7 @@ typedef struct { typedef struct { VikTrwLayer *vtl; gchar *image; + VikWaypoint *wpt; // Use specified waypoint or otherwise the track(s) if NULL VikTrack *track; // Use specified track or all tracks if NULL // User options... option_values_t ov; @@ -265,7 +267,28 @@ static void trw_layer_geotag_track ( const gpointer id, VikTrack *track, geotag_ options->altitude = trkpt->altitude + ((trkpt_next->altitude - trkpt->altitude) * scale); break; } - + } +} + +/** + * Simply align the images the waypoint position + */ +static void trw_layer_geotag_waypoint ( geotag_options_t *options ) +{ + // Write EXIF if specified - although a fairly useless process if you've turned it off! + if ( options->ov.write_exif ) { + gboolean has_gps_exif = FALSE; + gchar* datetime = a_geotag_get_exif_date_from_file ( options->image, &has_gps_exif ); + // If image already has gps info - don't attempt to change it unless forced + if ( options->ov.overwrite_gps_exif || !has_gps_exif ) { + gint ans = a_geotag_write_exif_gps ( options->image, options->wpt->coord, options->wpt->altitude, options->ov.no_change_mtime ); + if ( ans != 0 ) { + gchar *message = g_strdup_printf ( _("Failed updating EXIF on %s"), options->image ); + vik_window_statusbar_update ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(options->vtl)), message, VIK_STATUSBAR_INFO ); + g_free ( message ); + } + } + g_free ( datetime ); } } @@ -280,6 +303,11 @@ static void trw_layer_geotag_process ( geotag_options_t *options ) if ( !options->image ) return; + if ( options->wpt ) { + trw_layer_geotag_waypoint ( options ); + return; + } + gboolean has_gps_exif = FALSE; gchar* datetime = a_geotag_get_exif_date_from_file ( options->image, &has_gps_exif ); @@ -382,7 +410,12 @@ static void trw_layer_geotag_process ( geotag_options_t *options ) // Write EXIF if specified if ( options->ov.write_exif ) { - a_geotag_write_exif_gps ( options->image, options->coord, options->altitude, options->ov.no_change_mtime ); + gint ans = a_geotag_write_exif_gps ( options->image, options->coord, options->altitude, options->ov.no_change_mtime ); + if ( ans != 0 ) { + gchar *message = g_strdup_printf ( _("Failed updating EXIF on %s"), options->image ); + vik_window_statusbar_update ( VIK_WINDOW(VIK_GTK_WINDOW_FROM_LAYER(options->vtl)), message, VIK_STATUSBAR_INFO ); + g_free ( message ); + } } } } @@ -446,6 +479,7 @@ static void trw_layer_geotag_response_cb ( GtkDialog *dialog, gint resp, GeoTagW // Get options geotag_options_t *options = g_malloc ( sizeof(geotag_options_t) ); options->vtl = widgets->vtl; + options->wpt = widgets->wpt; options->track = widgets->track; // Values extracted from the widgets: options->ov.create_waypoints = gtk_toggle_button_get_active ( GTK_TOGGLE_BUTTON(widgets->create_waypoints_b) ); @@ -539,7 +573,10 @@ static void create_waypoints_b_cb ( GtkWidget *gw, GeoTagWidgets *gtw ) * @track: Optional - The particular track to use (if specified) for correlating images * @track_name: Optional - The name of specified track to use */ -void trw_layer_geotag_dialog ( GtkWindow *parent, VikTrwLayer *vtl, VikTrack *track, const gchar *track_name ) +void trw_layer_geotag_dialog ( GtkWindow *parent, + VikTrwLayer *vtl, + VikWaypoint *wpt, + VikTrack *track ) { GeoTagWidgets *widgets = geotag_widgets_new(); @@ -555,6 +592,7 @@ void trw_layer_geotag_dialog ( GtkWindow *parent, VikTrwLayer *vtl, VikTrack *tr widgets->files = VIK_FILE_LIST(vik_file_list_new ( _("Images"), filter )); widgets->vtl = vtl; + widgets->wpt = wpt; widgets->track = track; widgets->create_waypoints_b = GTK_CHECK_BUTTON ( gtk_check_button_new () ); widgets->overwrite_waypoints_l = GTK_LABEL ( gtk_label_new ( _("Overwrite Existing Waypoints:") ) ); @@ -594,7 +632,8 @@ void trw_layer_geotag_dialog ( GtkWindow *parent, VikTrwLayer *vtl, VikTrack *tr g_signal_connect ( G_OBJECT(widgets->create_waypoints_b), "toggled", G_CALLBACK(create_waypoints_b_cb), widgets ); GtkWidget *cw_hbox = gtk_hbox_new ( FALSE, 0 ); - gtk_box_pack_start ( GTK_BOX(cw_hbox), gtk_label_new ( _("Create Waypoints:") ), FALSE, FALSE, 5 ); + GtkWidget *create_waypoints_l = gtk_label_new ( _("Create Waypoints:") ); + gtk_box_pack_start ( GTK_BOX(cw_hbox), create_waypoints_l, FALSE, FALSE, 5 ); gtk_box_pack_start ( GTK_BOX(cw_hbox), GTK_WIDGET(widgets->create_waypoints_b), FALSE, FALSE, 5 ); GtkWidget *ow_hbox = gtk_hbox_new ( FALSE, 0 ); @@ -614,22 +653,39 @@ void trw_layer_geotag_dialog ( GtkWindow *parent, VikTrwLayer *vtl, VikTrack *tr gtk_box_pack_start ( GTK_BOX(fm_hbox), GTK_WIDGET(widgets->no_change_mtime_b), FALSE, FALSE, 5 ); GtkWidget *is_hbox = gtk_hbox_new ( FALSE, 0 ); - gtk_box_pack_start ( GTK_BOX(is_hbox), gtk_label_new ( _("Interpolate Between Track Segments:") ), FALSE, FALSE, 5 ); + GtkWidget *interpolate_segments_l = gtk_label_new ( _("Interpolate Between Track Segments:") ); + gtk_box_pack_start ( GTK_BOX(is_hbox), interpolate_segments_l, FALSE, FALSE, 5 ); gtk_box_pack_start ( GTK_BOX(is_hbox), GTK_WIDGET(widgets->interpolate_segments_b), FALSE, FALSE, 5 ); GtkWidget *to_hbox = gtk_hbox_new ( FALSE, 0 ); - gtk_box_pack_start ( GTK_BOX(to_hbox), gtk_label_new ( _("Image Time Offset (Seconds):") ), FALSE, FALSE, 5 ); + GtkWidget *time_offset_l = gtk_label_new ( _("Image Time Offset (Seconds):") ); + gtk_box_pack_start ( GTK_BOX(to_hbox), time_offset_l, FALSE, FALSE, 5 ); gtk_box_pack_start ( GTK_BOX(to_hbox), GTK_WIDGET(widgets->time_offset_b), FALSE, FALSE, 5 ); gtk_widget_set_tooltip_text ( GTK_WIDGET(widgets->time_offset_b), _("The number of seconds to ADD to the photos time to make it match the GPS data. Calculate this with (GPS - Photo). Can be negative or positive. Useful to adjust times when a camera's timestamp was incorrect.") ); GtkWidget *tz_hbox = gtk_hbox_new ( FALSE, 0 ); - gtk_box_pack_start ( GTK_BOX(tz_hbox), gtk_label_new ( _("Image Timezone:") ), FALSE, FALSE, 5 ); + GtkWidget *time_zone_l = gtk_label_new ( _("Image Timezone:") ); + gtk_box_pack_start ( GTK_BOX(tz_hbox), time_zone_l, FALSE, FALSE, 5 ); gtk_box_pack_start ( GTK_BOX(tz_hbox), GTK_WIDGET(widgets->time_zone_b), FALSE, FALSE, 5 ); gtk_widget_set_tooltip_text ( GTK_WIDGET(widgets->time_zone_b), _("The timezone that was used when the images were created. For example, if a camera is set to AWST or +8:00 hours. Enter +8:00 here so that the correct adjustment to the images' time can be made. GPS data is always in UTC.") ); gchar *track_string = NULL; - if ( widgets->track ) - track_string = g_strdup_printf ( _("Using track: %s"), track_name ); + if ( widgets->wpt ) { + track_string = g_strdup_printf ( _("Using waypoint: %s"), wpt->name ); + // Control sensitivities + gtk_widget_set_sensitive ( GTK_WIDGET(widgets->create_waypoints_b), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(create_waypoints_l), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(widgets->overwrite_waypoints_b), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(widgets->overwrite_waypoints_l), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(widgets->interpolate_segments_b), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(interpolate_segments_l), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(widgets->time_offset_b), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(time_offset_l), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(widgets->time_zone_b), FALSE ); + gtk_widget_set_sensitive ( GTK_WIDGET(time_zone_l), FALSE ); + } + else if ( widgets->track ) + track_string = g_strdup_printf ( _("Using track: %s"), track->name ); else track_string = g_strdup_printf ( _("Using all tracks in: %s"), VIK_LAYER(widgets->vtl)->name ); diff --git a/src/viktrwlayer_geotag.h b/src/viktrwlayer_geotag.h index 9bb259a5..8b1ea698 100644 --- a/src/viktrwlayer_geotag.h +++ b/src/viktrwlayer_geotag.h @@ -29,7 +29,10 @@ G_BEGIN_DECLS // To be only called from within viktrwlayer -void trw_layer_geotag_dialog ( GtkWindow *parent, VikTrwLayer *vtl, VikTrack *track, const gchar *track_name ); +void trw_layer_geotag_dialog ( GtkWindow *parent, + VikTrwLayer *vtl, + VikWaypoint *wpt, + VikTrack *track ); G_END_DECLS -- 2.39.5