/** * a_geotag_write_exif_gps: * @filename: The image file to save information in * @coord: The location * @alt: The elevation * * Returns: A value indicating success: 0, or some other value for failure * */ gint a_geotag_write_exif_gps ( const gchar *filename, VikCoord coord, gdouble alt, gboolean no_change_mtime ) { gint result = 0; // OK so far... // Save mtime for later use struct stat stat_save; if ( no_change_mtime ) stat ( filename, &stat_save ); /* Appears libexif doesn't actually support writing EXIF data directly to files Thus embed command line exif writing method within Viking (for example this is done by Enlightment - http://www.enlightenment.org/ ) This appears to be JPEG only, but is probably 99% of our use case Alternatively consider using libexiv2 and C++... */ // Actual EXIF settings here... JPEGData *jdata; /* Parse the JPEG file. */ jdata = jpeg_data_new (); jpeg_data_load_file (jdata, filename); // Get current values ExifData *ed = exif_data_new_from_file ( filename ); if ( !ed ) ed = exif_data_new (); // Update ExifData with our new settings ExifEntry *ee; // // I don't understand it, but when saving the 'ed' nothing gets set after putting in the GPS ID tag - so it must come last // (unless of course there is some bug in the setting of the ID, that prevents subsequent tags) // ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, alt, ee, exif_data_get_byte_order(ed) ); // byte 0 meaning "sea level" or 1 if the value is negative. ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_IFD_GPS); convert_to_entry ( alt < 0.0 ? "1" : "0", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_IFD_GPS); // see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/GPS.html convert_to_entry ( "MANUAL", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_MAP_DATUM, EXIF_IFD_GPS); convert_to_entry ( "WGS-84", 0.0, ee, exif_data_get_byte_order(ed) ); struct LatLon ll; vik_coord_to_latlon ( &coord, &ll ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE_REF, EXIF_IFD_GPS); // N or S convert_to_entry ( ll.lat < 0.0 ? "S" : "N", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, ll.lat, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_IFD_GPS); // E or W convert_to_entry ( ll.lon < 0.0 ? "W" : "E", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, ll.lon, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_VERSION_ID, EXIF_IFD_GPS); //convert_to_entry ( "2 0 0 0", 0.0, ee, exif_data_get_byte_order(ed) ); convert_to_entry ( "2 2 0 0", 0.0, ee, exif_data_get_byte_order(ed) ); jpeg_data_set_exif_data (jdata, ed); if ( jdata ) { /* Save the modified image. */ result = jpeg_data_save_file (jdata, filename); // Convert result from 1 for success, 0 for failure into our scheme result = !result; jpeg_data_unref (jdata); } else { // Epic fail - file probably not a JPEG result = 2; } if ( no_change_mtime ) { // Restore mtime, using the saved value struct stat stat_tmp; struct utimbuf utb; stat ( filename, &stat_tmp ); utb.actime = stat_tmp.st_atime; utb.modtime = stat_save.st_mtime; utime ( filename, &utb ); } return result; }
/* todo: less on this side, like add track */ gchar *a_dialog_waypoint ( GtkWindow *parent, gchar *default_name, VikTrwLayer *vtl, VikWaypoint *wp, VikCoordMode coord_mode, gboolean is_new, gboolean *updated ) { GtkWidget *dialog = gtk_dialog_new_with_buttons (_("Waypoint Properties"), parent, GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, GTK_STOCK_OK, GTK_RESPONSE_ACCEPT, NULL); struct LatLon ll; GtkWidget *latlabel, *lonlabel, *namelabel, *latentry, *lonentry, *altentry, *altlabel, *nameentry=NULL; GtkWidget *commentlabel, *commententry, *descriptionlabel, *descriptionentry, *imagelabel, *imageentry, *symbollabel, *symbolentry; GtkWidget *sourcelabel = NULL, *sourceentry = NULL; GtkWidget *typelabel = NULL, *typeentry = NULL; GtkWidget *timelabel = NULL; GtkWidget *timevaluebutton = NULL; GtkWidget *hasGeotagCB = NULL; GtkWidget *consistentGeotagCB = NULL; GtkWidget *direction_sb = NULL; GtkWidget *direction_hb = NULL; GtkListStore *store; gchar *lat, *lon, *alt; vik_coord_to_latlon ( &(wp->coord), &ll ); lat = g_strdup_printf ( "%f", ll.lat ); lon = g_strdup_printf ( "%f", ll.lon ); vik_units_height_t height_units = a_vik_get_units_height (); switch (height_units) { case VIK_UNITS_HEIGHT_METRES: alt = g_strdup_printf ( "%f", wp->altitude ); break; case VIK_UNITS_HEIGHT_FEET: alt = g_strdup_printf ( "%f", VIK_METERS_TO_FEET(wp->altitude) ); break; default: alt = g_strdup_printf ( "%f", wp->altitude ); g_critical("Houston, we've had a problem. height=%d", height_units); } *updated = FALSE; namelabel = gtk_label_new (_("Name:")); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), namelabel, FALSE, FALSE, 0); // Name is now always changeable nameentry = gtk_entry_new (); if ( default_name ) gtk_entry_set_text( GTK_ENTRY(nameentry), default_name ); g_signal_connect_swapped ( nameentry, "activate", G_CALLBACK(a_dialog_response_accept), GTK_DIALOG(dialog) ); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), nameentry, FALSE, FALSE, 0); latlabel = gtk_label_new (_("Latitude:")); latentry = gtk_entry_new (); gtk_entry_set_text ( GTK_ENTRY(latentry), lat ); g_free ( lat ); lonlabel = gtk_label_new (_("Longitude:")); lonentry = gtk_entry_new (); gtk_entry_set_text ( GTK_ENTRY(lonentry), lon ); g_free ( lon ); altlabel = gtk_label_new (_("Altitude:")); altentry = gtk_entry_new (); gtk_entry_set_text ( GTK_ENTRY(altentry), alt ); g_free ( alt ); if ( wp->comment && !strncmp(wp->comment, "http", 4) ) commentlabel = gtk_link_button_new_with_label (wp->comment, _("Comment:") ); else commentlabel = gtk_label_new (_("Comment:")); commententry = gtk_entry_new (); gchar *cmt = NULL; // Auto put in some kind of 'name' as a comment if one previously 'goto'ed this exact location cmt = a_vik_goto_get_search_string_for_this_place(VIK_WINDOW(parent)); if (cmt) gtk_entry_set_text(GTK_ENTRY(commententry), cmt); if ( wp->description && !strncmp(wp->description, "http", 4) ) descriptionlabel = gtk_link_button_new_with_label (wp->description, _("Description:") ); else descriptionlabel = gtk_label_new (_("Description:")); descriptionentry = gtk_entry_new (); sourcelabel = gtk_label_new (_("Source:")); if ( wp->source ) { sourceentry = gtk_entry_new (); gtk_entry_set_text(GTK_ENTRY(sourceentry), wp->source); } typelabel = gtk_label_new (_("Type:")); if ( wp->type ) { typeentry = gtk_entry_new (); gtk_entry_set_text(GTK_ENTRY(typeentry), wp->type); } imagelabel = gtk_label_new (_("Image:")); imageentry = vik_file_entry_new (GTK_FILE_CHOOSER_ACTION_OPEN, VF_FILTER_IMAGE, NULL, NULL); { GtkCellRenderer *r; symbollabel = gtk_label_new (_("Symbol:")); GtkTreeIter iter; store = gtk_list_store_new(3, G_TYPE_STRING, GDK_TYPE_PIXBUF, G_TYPE_STRING); symbolentry = gtk_combo_box_new_with_model(GTK_TREE_MODEL(store)); gtk_combo_box_set_wrap_width(GTK_COMBO_BOX(symbolentry), 6); g_signal_connect(symbolentry, "changed", G_CALLBACK(symbol_entry_changed_cb), store); gtk_list_store_append (store, &iter); gtk_list_store_set (store, &iter, 0, NULL, 1, NULL, 2, _("(none)"), -1); a_populate_sym_list(store); r = gtk_cell_renderer_pixbuf_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (symbolentry), r, FALSE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (symbolentry), r, "pixbuf", 1, NULL); r = gtk_cell_renderer_text_new (); gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (symbolentry), r, FALSE); gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (symbolentry), r, "text", 2, NULL); if ( !is_new && wp->symbol ) { gboolean ok; gchar *sym; for (ok = gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &iter ); ok; ok = gtk_tree_model_iter_next ( GTK_TREE_MODEL(store), &iter)) { gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 ); if (sym && !strcmp(sym, wp->symbol)) { g_free(sym); break; } else { g_free(sym); } } // Ensure is it a valid symbol in the given symbol set (large vs small) // Not all symbols are available in both // The check prevents a Gtk Critical message if ( iter.stamp ) gtk_combo_box_set_active_iter(GTK_COMBO_BOX(symbolentry), &iter); } } if ( !is_new && wp->comment ) gtk_entry_set_text ( GTK_ENTRY(commententry), wp->comment ); if ( !is_new && wp->description ) gtk_entry_set_text ( GTK_ENTRY(descriptionentry), wp->description ); if ( !edit_wp ) edit_wp = vik_waypoint_new (); edit_wp = vik_waypoint_copy ( wp ); if ( !is_new && wp->image ) { vik_file_entry_set_filename ( VIK_FILE_ENTRY(imageentry), wp->image ); #ifdef VIK_CONFIG_GEOTAG // Geotag Info [readonly] hasGeotagCB = gtk_check_button_new_with_label ( _("Has Geotag") ); gtk_widget_set_sensitive ( hasGeotagCB, FALSE ); gboolean hasGeotag; gchar *ignore = a_geotag_get_exif_date_from_file ( wp->image, &hasGeotag ); g_free ( ignore ); gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(hasGeotagCB), hasGeotag ); consistentGeotagCB = gtk_check_button_new_with_label ( _("Consistent Position") ); gtk_widget_set_sensitive ( consistentGeotagCB, FALSE ); if ( hasGeotag ) { struct LatLon ll = a_geotag_get_position ( wp->image ); VikCoord coord; vik_coord_load_from_latlon ( &coord, coord_mode, &ll ); gtk_toggle_button_set_active ( GTK_TOGGLE_BUTTON(consistentGeotagCB), vik_coord_equalish(&coord, &wp->coord) ); } // ATM the direction value box is always shown, even when there is no information. // It would be nice to be able to hide it until the 'Add' has been performed, // however I've not been able to achieve this. // Thus simply sensistizing it instead. GtkWidget *direction_label = gtk_label_new ( _("Image Direction:") ); direction_hb = gtk_hbox_new ( FALSE, 0 ); gtk_box_pack_start (GTK_BOX(direction_hb), direction_label, FALSE, FALSE, 0); direction_sb = gtk_spin_button_new ( (GtkAdjustment*)gtk_adjustment_new (0, 0.0, 359.9, 5.0, 1, 0 ), 1, 1 ); if ( !is_new && !isnan(wp->image_direction) ) { GtkWidget *direction_ref = gtk_label_new ( NULL ); if ( wp->image_direction_ref == WP_IMAGE_DIRECTION_REF_MAGNETIC ) gtk_label_set_label ( GTK_LABEL(direction_ref), _("Magnetic") ); else gtk_label_set_label ( GTK_LABEL(direction_ref), _("True") ); gtk_box_pack_start (GTK_BOX(direction_hb), direction_ref, TRUE, FALSE, 0); gtk_spin_button_set_value ( GTK_SPIN_BUTTON(direction_sb), wp->image_direction ); } else { GtkWidget *direction_ref_button = gtk_button_new (); gtk_button_set_relief ( GTK_BUTTON(direction_ref_button), GTK_RELIEF_NONE ); GtkWidget *img = gtk_image_new_from_stock ( GTK_STOCK_ADD, GTK_ICON_SIZE_MENU ); gtk_button_set_image ( GTK_BUTTON(direction_ref_button), img ); gtk_box_pack_start (GTK_BOX(direction_hb), direction_ref_button, TRUE, FALSE, 0); gtk_widget_set_sensitive ( direction_sb, FALSE ); direction_signal_id = g_signal_connect ( G_OBJECT(direction_ref_button), "button-release-event", G_CALLBACK(direction_add_click), direction_sb ); } #endif } timelabel = gtk_label_new ( _("Time:") ); timevaluebutton = gtk_button_new(); gtk_button_set_relief ( GTK_BUTTON(timevaluebutton), GTK_RELIEF_NONE ); // TODO: Consider if there should be a remove time button... if ( !is_new && wp->has_timestamp ) { update_time ( timevaluebutton, wp ); } else { GtkWidget *img = gtk_image_new_from_stock ( GTK_STOCK_ADD, GTK_ICON_SIZE_MENU ); gtk_button_set_image ( GTK_BUTTON(timevaluebutton), img ); // Initially use current time or otherwise whatever the last value used was if ( edit_wp->timestamp == 0 ) { time ( &edit_wp->timestamp ); } } g_signal_connect ( G_OBJECT(timevaluebutton), "button-release-event", G_CALLBACK(time_edit_click), edit_wp ); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latlabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), latentry, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonlabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), lonentry, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), timelabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), timevaluebutton, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altlabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), altentry, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), commentlabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), commententry, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), descriptionlabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), descriptionentry, FALSE, FALSE, 0); if ( wp->source ) { gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), sourcelabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), sourceentry, FALSE, FALSE, 0); } if ( wp->type ) { gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), typelabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), typeentry, FALSE, FALSE, 0); } gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), imagelabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), imageentry, FALSE, FALSE, 0); if ( hasGeotagCB ) { GtkWidget *hbox = gtk_hbox_new ( FALSE, 0 ); gtk_box_pack_start (GTK_BOX(hbox), hasGeotagCB, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(hbox), consistentGeotagCB, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), hbox, FALSE, FALSE, 0); } if ( direction_hb ) gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), direction_hb, FALSE, FALSE, 0); if ( direction_sb ) gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), direction_sb, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), symbollabel, FALSE, FALSE, 0); gtk_box_pack_start (GTK_BOX(gtk_dialog_get_content_area(GTK_DIALOG(dialog))), GTK_WIDGET(symbolentry), FALSE, FALSE, 0); gtk_dialog_set_default_response ( GTK_DIALOG(dialog), GTK_RESPONSE_ACCEPT ); gtk_widget_show_all ( gtk_dialog_get_content_area(GTK_DIALOG(dialog)) ); if ( !is_new ) { // Shift left<->right to try not to obscure the waypoint. trw_layer_dialog_shift ( vtl, GTK_WINDOW(dialog), &(wp->coord), FALSE ); } while ( gtk_dialog_run ( GTK_DIALOG(dialog) ) == GTK_RESPONSE_ACCEPT ) { if ( strlen((gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) )) == 0 ) /* TODO: other checks (isalpha or whatever ) */ a_dialog_info_msg ( parent, _("Please enter a name for the waypoint.") ); else { // NB: No check for unique names - this allows generation of same named entries. gchar *entered_name = g_strdup ( (gchar*)gtk_entry_get_text ( GTK_ENTRY(nameentry) ) ); /* Do It */ ll.lat = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(latentry) ) ); ll.lon = convert_dms_to_dec ( gtk_entry_get_text ( GTK_ENTRY(lonentry) ) ); vik_coord_load_from_latlon ( &(wp->coord), coord_mode, &ll ); // Always store in metres switch (height_units) { case VIK_UNITS_HEIGHT_METRES: wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ); break; case VIK_UNITS_HEIGHT_FEET: wp->altitude = VIK_FEET_TO_METERS(atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) )); break; default: wp->altitude = atof ( gtk_entry_get_text ( GTK_ENTRY(altentry) ) ); g_critical("Houston, we've had a problem. height=%d", height_units); } if ( g_strcmp0 ( wp->comment, gtk_entry_get_text ( GTK_ENTRY(commententry) ) ) ) vik_waypoint_set_comment ( wp, gtk_entry_get_text ( GTK_ENTRY(commententry) ) ); if ( g_strcmp0 ( wp->description, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) ) ) vik_waypoint_set_description ( wp, gtk_entry_get_text ( GTK_ENTRY(descriptionentry) ) ); if ( g_strcmp0 ( wp->image, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) ) ) vik_waypoint_set_image ( wp, vik_file_entry_get_filename ( VIK_FILE_ENTRY(imageentry) ) ); if ( sourceentry && g_strcmp0 ( wp->source, gtk_entry_get_text ( GTK_ENTRY(sourceentry) ) ) ) vik_waypoint_set_source ( wp, gtk_entry_get_text ( GTK_ENTRY(sourceentry) ) ); if ( typeentry && g_strcmp0 ( wp->type, gtk_entry_get_text ( GTK_ENTRY(typeentry) ) ) ) vik_waypoint_set_type ( wp, gtk_entry_get_text ( GTK_ENTRY(typeentry) ) ); if ( wp->image && *(wp->image) && (!a_thumbnails_exists(wp->image)) ) a_thumbnails_create ( wp->image ); if ( edit_wp->timestamp ) { wp->timestamp = edit_wp->timestamp; wp->has_timestamp = TRUE; } if ( direction_sb ) { if ( gtk_widget_get_sensitive (direction_sb) ) { wp->image_direction = gtk_spin_button_get_value ( GTK_SPIN_BUTTON(direction_sb) ); if ( wp->image_direction != edit_wp->image_direction ) a_geotag_write_exif_gps ( wp->image, wp->coord, wp->altitude, wp->image_direction, wp->image_direction_ref, TRUE ); } } GtkTreeIter iter, first; gtk_tree_model_get_iter_first ( GTK_TREE_MODEL(store), &first ); if ( !gtk_combo_box_get_active_iter ( GTK_COMBO_BOX(symbolentry), &iter ) || !memcmp(&iter, &first, sizeof(GtkTreeIter)) ) { vik_waypoint_set_symbol ( wp, NULL ); } else { gchar *sym; gtk_tree_model_get ( GTK_TREE_MODEL(store), &iter, 0, (void *)&sym, -1 ); vik_waypoint_set_symbol ( wp, sym ); g_free(sym); } gtk_widget_destroy ( dialog ); if ( is_new ) return entered_name; else { *updated = TRUE; // See if name has been changed if ( g_strcmp0 (default_name, entered_name ) ) return entered_name; else return NULL; } } } gtk_widget_destroy ( dialog ); return NULL; }
/** * Automatic attempt to find out where you are using: * 1. http://www.hostip.info ++ * 2. if not specific enough fallback to using the default goto tool with a country name * ++ Using returned JSON information * c.f. with googlesearch.c - similar implementation is used here * * returns: * 0 if failed to locate anything * 1 if exact latitude/longitude found * 2 if position only as precise as a city * 3 if position only as precise as a country * @name: Contains the name of place found. Free this string after use. */ gint a_vik_goto_where_am_i ( VikViewport *vvp, struct LatLon *ll, gchar **name ) { gint result = 0; *name = NULL; gchar *tmpname = a_download_uri_to_tmp_file ( "http://api.hostip.info/get_json.php?position=true", NULL ); //gchar *tmpname = g_strdup ("../test/hostip2.json"); if (!tmpname) { return result; } ll->lat = 0.0; ll->lon = 0.0; gchar *pat; GMappedFile *mf; gchar *ss; gint fragment_len; gchar lat_buf[32], lon_buf[32]; lat_buf[0] = lon_buf[0] = '\0'; gchar *country = NULL; gchar *city = NULL; if ((mf = g_mapped_file_new(tmpname, FALSE, NULL)) == NULL) { g_critical(_("couldn't map temp file")); goto tidy; } gsize len = g_mapped_file_get_length(mf); gchar *text = g_mapped_file_get_contents(mf); if ((pat = g_strstr_len(text, len, HOSTIP_COUNTRY_PATTERN))) { pat += strlen(HOSTIP_COUNTRY_PATTERN); fragment_len = 0; ss = pat; while (*pat != '"') { fragment_len++; pat++; } country = g_strndup(ss, fragment_len); } if ((pat = g_strstr_len(text, len, HOSTIP_CITY_PATTERN))) { pat += strlen(HOSTIP_CITY_PATTERN); fragment_len = 0; ss = pat; while (*pat != '"') { fragment_len++; pat++; } city = g_strndup(ss, fragment_len); } if ((pat = g_strstr_len(text, len, HOSTIP_LATITUDE_PATTERN))) { pat += strlen(HOSTIP_LATITUDE_PATTERN); ss = lat_buf; if (*pat == '-') *ss++ = *pat++; while ((ss < (lat_buf + sizeof(lat_buf))) && (pat < (text + len)) && (g_ascii_isdigit(*pat) || (*pat == '.'))) *ss++ = *pat++; *ss = '\0'; ll->lat = g_ascii_strtod(lat_buf, NULL); } if ((pat = g_strstr_len(text, len, HOSTIP_LONGITUDE_PATTERN))) { pat += strlen(HOSTIP_LONGITUDE_PATTERN); ss = lon_buf; if (*pat == '-') *ss++ = *pat++; while ((ss < (lon_buf + sizeof(lon_buf))) && (pat < (text + len)) && (g_ascii_isdigit(*pat) || (*pat == '.'))) *ss++ = *pat++; *ss = '\0'; ll->lon = g_ascii_strtod(lon_buf, NULL); } if ( ll->lat != 0.0 && ll->lon != 0.0 ) { if ( ll->lat > -90.0 && ll->lat < 90.0 && ll->lon > -180.0 && ll->lon < 180.0 ) { // Found a 'sensible' & 'precise' location result = 1; *name = g_strdup ( _("Locality") ); //Albeit maybe not known by an actual name! } } else { // Hopefully city name is unique enough to lookup position on // Maybe for American places where hostip appends the State code on the end // But if the country code is not appended if could easily get confused // e.g. 'Portsmouth' could be at least // Portsmouth, Hampshire, UK or // Portsmouth, Viginia, USA. // Try city name lookup if ( city ) { g_debug ( "%s: found city %s", __FUNCTION__, city ); if ( strcmp ( city, "(Unknown city)" ) != 0 ) { VikCoord new_center; if ( vik_goto_place ( NULL, vvp, city, &new_center ) ) { // Got something vik_coord_to_latlon ( &new_center, ll ); result = 2; *name = city; goto tidy; } } } // Try country name lookup if ( country ) { g_debug ( "%s: found country %s", __FUNCTION__, country ); if ( strcmp ( country, "(Unknown Country)" ) != 0 ) { VikCoord new_center; if ( vik_goto_place ( NULL, vvp, country, &new_center ) ) { // Finally got something vik_coord_to_latlon ( &new_center, ll ); result = 3; *name = country; goto tidy; } } } } tidy: g_mapped_file_unref ( mf ); g_remove ( tmpname ); g_free ( tmpname ); return result; }
static gboolean dem_layer_download_release ( VikDEMLayer *vdl, GdkEventButton *event, VikViewport *vvp ) { VikCoord coord; static struct LatLon ll; gchar *full_path; gchar *dem_file = NULL; vik_viewport_screen_to_coord ( vvp, event->x, event->y, &coord ); vik_coord_to_latlon ( &coord, &ll ); if ( vdl->source == DEM_SOURCE_SRTM ) dem_file = srtm_lat_lon_to_dest_fn ( ll.lat, ll.lon ); #ifdef VIK_CONFIG_DEM24K else if ( vdl->source == DEM_SOURCE_DEM24K ) dem_file = dem24k_lat_lon_to_dest_fn ( ll.lat, ll.lon ); #endif if ( ! dem_file ) return TRUE; full_path = g_strdup_printf("%s%s", MAPS_CACHE_DIR, dem_file ); g_debug("%s: %s", __FUNCTION__, full_path); if ( event->button == 1 ) { // TODO: check if already in filelist if ( ! dem_layer_add_file(vdl, full_path) ) { gchar *tmp = g_strdup_printf ( _("Downloading DEM %s"), dem_file ); DEMDownloadParams *p = g_malloc(sizeof(DEMDownloadParams)); p->dest = g_strdup(full_path); p->lat = ll.lat; p->lon = ll.lon; p->vdl = vdl; p->mutex = g_mutex_new(); p->source = vdl->source; g_object_weak_ref(G_OBJECT(p->vdl), weak_ref_cb, p ); a_background_thread ( VIK_GTK_WINDOW_FROM_LAYER(vdl), tmp, (vik_thr_func) dem_download_thread, p, (vik_thr_free_func) free_dem_download_params, NULL, 1 ); g_free ( tmp ); } else vik_layer_emit_update ( VIK_LAYER(vdl) ); } else { if ( !vdl->right_click_menu ) { GtkWidget *item; vdl->right_click_menu = GTK_MENU ( gtk_menu_new () ); item = gtk_image_menu_item_new_with_mnemonic ( _("_Show DEM File Information") ); gtk_image_menu_item_set_image ( (GtkImageMenuItem*)item, gtk_image_new_from_stock (GTK_STOCK_INFO, GTK_ICON_SIZE_MENU) ); g_signal_connect ( G_OBJECT(item), "activate", G_CALLBACK(dem_layer_file_info), &ll ); gtk_menu_shell_append (GTK_MENU_SHELL(vdl->right_click_menu), item); } gtk_menu_popup ( vdl->right_click_menu, NULL, NULL, NULL, NULL, event->button, event->time ); gtk_widget_show_all ( GTK_WIDGET(vdl->right_click_menu) ); } g_free ( dem_file ); g_free ( full_path ); return TRUE; }
static void a_gpspoint_write_trackpoint ( VikTrackpoint *tp, TP_write_info_type *write_info ) { struct LatLon ll; gchar s_lat[COORDS_STR_BUFFER_SIZE]; gchar s_lon[COORDS_STR_BUFFER_SIZE]; gchar s_alt[COORDS_STR_BUFFER_SIZE]; vik_coord_to_latlon ( &(tp->coord), &ll ); FILE *f = write_info->f; a_coords_dtostr_buffer ( ll.lat, s_lat ); a_coords_dtostr_buffer ( ll.lon, s_lon ); fprintf ( f, "type=\"%spoint\" latitude=\"%s\" longitude=\"%s\"", write_info->is_route ? "route" : "track", s_lat, s_lon ); if ( tp->name ) { gchar *name = slashdup(tp->name); fprintf ( f, " name=\"%s\"", name ); g_free(name); } if ( tp->altitude != VIK_DEFAULT_ALTITUDE ) { a_coords_dtostr_buffer ( tp->altitude, s_alt ); fprintf ( f, " altitude=\"%s\"", s_alt ); } if ( tp->has_timestamp ) fprintf ( f, " unixtime=\"%ld\"", tp->timestamp ); if ( tp->newsegment ) fprintf ( f, " newsegment=\"yes\"" ); if (!isnan(tp->speed) || !isnan(tp->course) || tp->nsats > 0) { fprintf ( f, " extended=\"yes\"" ); if (!isnan(tp->speed)) { gchar s_speed[COORDS_STR_BUFFER_SIZE]; a_coords_dtostr_buffer ( tp->speed, s_speed ); fprintf ( f, " speed=\"%s\"", s_speed ); } if (!isnan(tp->course)) { gchar s_course[COORDS_STR_BUFFER_SIZE]; a_coords_dtostr_buffer ( tp->course, s_course ); fprintf ( f, " course=\"%s\"", s_course ); } if (tp->nsats > 0) fprintf ( f, " sat=\"%d\"", tp->nsats ); if (tp->fix_mode > 0) fprintf ( f, " fix=\"%d\"", tp->fix_mode ); if ( tp->hdop != VIK_DEFAULT_DOP ) { gchar ss[COORDS_STR_BUFFER_SIZE]; a_coords_dtostr_buffer ( tp->hdop, ss ); fprintf ( f, " hdop=\"%s\"", ss ); } if ( tp->vdop != VIK_DEFAULT_DOP ) { gchar ss[COORDS_STR_BUFFER_SIZE]; a_coords_dtostr_buffer ( tp->vdop, ss ); fprintf ( f, " vdop=\"%s\"", ss ); } if ( tp->pdop != VIK_DEFAULT_DOP ) { gchar ss[COORDS_STR_BUFFER_SIZE]; a_coords_dtostr_buffer ( tp->pdop, ss ); fprintf ( f, " pdop=\"%s\"", ss ); } } fprintf ( f, "\n" ); }
static void a_gpspoint_write_waypoint ( const gpointer id, const VikWaypoint *wp, FILE *f ) { struct LatLon ll; gchar s_lat[COORDS_STR_BUFFER_SIZE]; gchar s_lon[COORDS_STR_BUFFER_SIZE]; // Sanity clauses if ( !wp ) return; if ( !(wp->name) ) return; vik_coord_to_latlon ( &(wp->coord), &ll ); a_coords_dtostr_buffer ( ll.lat, s_lat ); a_coords_dtostr_buffer ( ll.lon, s_lon ); gchar *tmp_name = slashdup(wp->name); fprintf ( f, "type=\"waypoint\" latitude=\"%s\" longitude=\"%s\" name=\"%s\"", s_lat, s_lon, tmp_name ); g_free ( tmp_name ); if ( wp->altitude != VIK_DEFAULT_ALTITUDE ) { gchar s_alt[COORDS_STR_BUFFER_SIZE]; a_coords_dtostr_buffer ( wp->altitude, s_alt ); fprintf ( f, " altitude=\"%s\"", s_alt ); } if ( wp->has_timestamp ) fprintf ( f, " unixtime=\"%ld\"", wp->timestamp ); if ( wp->comment ) { gchar *tmp_comment = slashdup(wp->comment); fprintf ( f, " comment=\"%s\"", tmp_comment ); g_free ( tmp_comment ); } if ( wp->description ) { gchar *tmp_description = slashdup(wp->description); fprintf ( f, " description=\"%s\"", tmp_description ); g_free ( tmp_description ); } if ( wp->source ) { gchar *tmp_source = slashdup(wp->source); fprintf ( f, " source=\"%s\"", tmp_source ); g_free ( tmp_source ); } if ( wp->type ) { gchar *tmp_type = slashdup(wp->type); fprintf ( f, " xtype=\"%s\"", tmp_type ); g_free ( tmp_type ); } if ( wp->image ) { gchar *tmp_image = NULL; gchar *cwd = NULL; if ( a_vik_get_file_ref_format() == VIK_FILE_REF_FORMAT_RELATIVE ) { cwd = g_get_current_dir(); if ( cwd ) tmp_image = g_strdup ( file_GetRelativeFilename ( cwd, wp->image ) ); } // if cwd not available - use image filename as is // this should be an absolute path as set in thumbnails if ( !cwd ) tmp_image = slashdup(wp->image); if ( tmp_image ) fprintf ( f, " image=\"%s\"", tmp_image ); g_free ( cwd ); g_free ( tmp_image ); } if ( wp->symbol ) { // Due to changes in garminsymbols - the symbol name is now in Title Case // However to keep newly generated .vik files better compatible with older Viking versions // The symbol names will always be lowercase gchar *tmp_symbol = g_utf8_strdown(wp->symbol, -1); fprintf ( f, " symbol=\"%s\"", tmp_symbol ); g_free ( tmp_symbol ); } if ( ! wp->visible ) fprintf ( f, " visible=\"n\"" ); fprintf ( f, "\n" ); }
/** * vu_trackpoint_formatted_message: * @format_code: String describing the message to generate * @trkpt: The trackpoint for which the message is generated about * @trkpt_prev: A trackpoint (presumed previous) for interpolating values with the other trackpoint (such as speed) * @trk: The track in which the trackpoints reside * @climb: Vertical speed (Out of band (i.e. not in a trackpoint) value for display currently only for GPSD usage) * * TODO: One day replace this cryptic format code with some kind of tokenizer parsing * thus would make it more user friendly and maybe even GUI controlable. * However for now at least there is some semblance of user control */ gchar* vu_trackpoint_formatted_message ( gchar *format_code, VikTrackpoint *trkpt, VikTrackpoint *trkpt_prev, VikTrack *trk, gdouble climb ) { if ( !trkpt ) return NULL; gint len = 0; if ( format_code ) len = strlen ( format_code ); if ( len > FMT_MAX_NUMBER_CODES ) len = FMT_MAX_NUMBER_CODES; gchar* values[FMT_MAX_NUMBER_CODES]; int i; for ( i = 0; i < FMT_MAX_NUMBER_CODES; i++ ) { values[i] = '\0'; } gchar *speed_units_str = NULL; vik_units_speed_t speed_units = a_vik_get_units_speed (); switch (speed_units) { case VIK_UNITS_SPEED_MILES_PER_HOUR: speed_units_str = g_strdup ( _("mph") ); break; case VIK_UNITS_SPEED_METRES_PER_SECOND: speed_units_str = g_strdup ( _("m/s") ); break; case VIK_UNITS_SPEED_KNOTS: speed_units_str = g_strdup ( _("knots") ); break; default: // VIK_UNITS_SPEED_KILOMETRES_PER_HOUR: speed_units_str = g_strdup ( _("km/h") ); break; } gchar *separator = g_strdup ( " | " ); for ( i = 0; i < len; i++ ) { switch ( g_ascii_toupper ( format_code[i] ) ) { case 'G': values[i] = g_strdup ( _("GPSD") ); break; // GPS Preamble case 'K': values[i] = g_strdup ( _("Trkpt") ); break; // Trkpt Preamble case 'S': { gdouble speed = 0.0; gchar *speedtype = NULL; if ( isnan(trkpt->speed) && trkpt_prev ) { if ( trkpt->has_timestamp && trkpt_prev->has_timestamp ) { if ( trkpt->timestamp != trkpt_prev->timestamp ) { // Work out from previous trackpoint location and time difference speed = vik_coord_diff(&(trkpt->coord), &(trkpt_prev->coord)) / ABS(trkpt->timestamp - trkpt_prev->timestamp); speedtype = g_strdup ( "*" ); // Interpolated } else speedtype = g_strdup ( "**" ); } else speedtype = g_strdup ( "**" ); } else { speed = trkpt->speed; speedtype = g_strdup ( "" ); } switch (speed_units) { case VIK_UNITS_SPEED_KILOMETRES_PER_HOUR: speed = VIK_MPS_TO_KPH(speed); break; case VIK_UNITS_SPEED_MILES_PER_HOUR: speed = VIK_MPS_TO_MPH(speed); break; case VIK_UNITS_SPEED_KNOTS: speed = VIK_MPS_TO_KNOTS(speed); break; default: // VIK_UNITS_SPEED_METRES_PER_SECOND: // Already in m/s so nothing to do break; } values[i] = g_strdup_printf ( _("%sSpeed%s %.1f%s"), separator, speedtype, speed, speed_units_str ); g_free ( speedtype ); break; } case 'B': { gdouble speed = 0.0; gchar *speedtype = NULL; if ( isnan(climb) && trkpt_prev ) { if ( trkpt->has_timestamp && trkpt_prev->has_timestamp ) { if ( trkpt->timestamp != trkpt_prev->timestamp ) { // Work out from previous trackpoint altitudes and time difference // 'speed' can be negative if going downhill speed = (trkpt->altitude - trkpt_prev->altitude) / ABS(trkpt->timestamp - trkpt_prev->timestamp); speedtype = g_strdup ( "*" ); // Interpolated } else speedtype = g_strdup ( "**" ); // Unavailable } else speedtype = g_strdup ( "**" ); } else { speed = climb; speedtype = g_strdup ( "" ); } switch (speed_units) { case VIK_UNITS_SPEED_KILOMETRES_PER_HOUR: speed = VIK_MPS_TO_KPH(speed); break; case VIK_UNITS_SPEED_MILES_PER_HOUR: speed = VIK_MPS_TO_MPH(speed); break; case VIK_UNITS_SPEED_KNOTS: speed = VIK_MPS_TO_KNOTS(speed); break; default: // VIK_UNITS_SPEED_METRES_PER_SECOND: // Already in m/s so nothing to do break; } // Go for 2dp as expect low values for vertical speeds values[i] = g_strdup_printf ( _("%sClimb%s %.2f%s"), separator, speedtype, speed, speed_units_str ); g_free ( speedtype ); break; } case 'A': { vik_units_height_t height_units = a_vik_get_units_height (); switch (height_units) { case VIK_UNITS_HEIGHT_FEET: values[i] = g_strdup_printf ( _("%sAlt %dfeet"), separator, (int)round(VIK_METERS_TO_FEET(trkpt->altitude)) ); break; default: //VIK_UNITS_HEIGHT_METRES: values[i] = g_strdup_printf ( _("%sAlt %dm"), separator, (int)round(trkpt->altitude) ); break; } break; } case 'C': { gint heading = isnan(trkpt->course) ? 0 : (gint)round(trkpt->course); values[i] = g_strdup_printf ( _("%sCourse %03d\302\260" ), separator, heading ); break; } case 'P': { if ( trkpt_prev ) { gint diff = (gint) round ( vik_coord_diff ( &(trkpt->coord), &(trkpt_prev->coord) ) ); gchar *dist_units_str = NULL; vik_units_distance_t dist_units = a_vik_get_units_distance (); // expect the difference between track points to be small hence use metres or yards switch (dist_units) { case VIK_UNITS_DISTANCE_MILES: case VIK_UNITS_DISTANCE_NAUTICAL_MILES: dist_units_str = g_strdup ( _("yards") ); break; default: // VIK_UNITS_DISTANCE_KILOMETRES: dist_units_str = g_strdup ( _("m") ); break; } values[i] = g_strdup_printf ( _("%sDistance diff %d%s"), separator, diff, dist_units_str ); g_free ( dist_units_str ); } break; } case 'T': { gchar *msg; if ( trkpt->has_timestamp ) { // Compact date time format msg = vu_get_time_string ( &(trkpt->timestamp), "%x %X", &(trkpt->coord), NULL ); } else msg = g_strdup ("--"); values[i] = g_strdup_printf ( _("%sTime %s"), separator, msg ); g_free ( msg ); break; } case 'M': { if ( trkpt_prev ) { if ( trkpt->has_timestamp && trkpt_prev->has_timestamp ) { time_t t_diff = trkpt->timestamp - trkpt_prev->timestamp; values[i] = g_strdup_printf ( _("%sTime diff %lds"), separator, t_diff ); } } break; } case 'X': values[i] = g_strdup_printf ( _("%sNo. of Sats %d"), separator, trkpt->nsats ); break; case 'F': { if ( trk ) { // Distance to the end 'Finish' (along the track) gdouble distd = vik_track_get_length_to_trackpoint (trk, trkpt); gdouble diste = vik_track_get_length_including_gaps ( trk ); gdouble dist = diste - distd; gchar *dist_units_str = NULL; vik_units_distance_t dist_units = a_vik_get_units_distance (); switch (dist_units) { case VIK_UNITS_DISTANCE_MILES: dist_units_str = g_strdup ( _("miles") ); dist = VIK_METERS_TO_MILES(dist); break; case VIK_UNITS_DISTANCE_NAUTICAL_MILES: dist_units_str = g_strdup ( _("NM") ); dist = VIK_METERS_TO_NAUTICAL_MILES(dist); break; default: // VIK_UNITS_DISTANCE_KILOMETRES: dist_units_str = g_strdup ( _("km") ); dist = dist / 1000.0; break; } values[i] = g_strdup_printf ( _("%sTo End %.2f%s"), separator, dist, dist_units_str ); g_free ( dist_units_str ); } break; } case 'D': { if ( trk ) { // Distance from start (along the track) gdouble distd = vik_track_get_length_to_trackpoint (trk, trkpt); gchar *dist_units_str = NULL; vik_units_distance_t dist_units = a_vik_get_units_distance (); switch (dist_units) { case VIK_UNITS_DISTANCE_MILES: dist_units_str = g_strdup ( _("miles") ); distd = VIK_METERS_TO_MILES(distd); break; case VIK_UNITS_DISTANCE_NAUTICAL_MILES: dist_units_str = g_strdup ( _("NM") ); distd = VIK_METERS_TO_NAUTICAL_MILES(distd); break; default: // VIK_UNITS_DISTANCE_KILOMETRES: dist_units_str = g_strdup ( _("km") ); distd = distd / 1000.0; break; } values[i] = g_strdup_printf ( _("%sDistance along %.2f%s"), separator, distd, dist_units_str ); g_free ( dist_units_str ); } break; } case 'L': { // Location (Lat/Long) gchar *lat = NULL, *lon = NULL; struct LatLon ll; vik_coord_to_latlon (&(trkpt->coord), &ll); a_coords_latlon_to_string ( &ll, &lat, &lon ); values[i] = g_strdup_printf ( "%s%s %s", separator, lat, lon ); g_free ( lat ); g_free ( lon ); break; } case 'N': // Name of track values[i] = g_strdup_printf ( _("%sTrack: %s"), separator, trk->name ); break; case 'E': // Name of trackpoint if available if ( trkpt->name ) values[i] = g_strdup_printf ( "%s%s", separator, trkpt->name ); else values[i] = g_strdup ( "" ); break; default: break; } } g_free ( separator ); g_free ( speed_units_str ); gchar *msg = g_strconcat ( values[0], values[1], values[2], values[3], values[4], values[5], values[6], values[7], values[8], NULL ); for ( i = 0; i < FMT_MAX_NUMBER_CODES; i++ ) { if ( values[i] != '\0' ) g_free ( values[i] ); } return msg; }
/** * a_geotag_write_exif_gps: * @filename: The image file to save information in * @coord: The location * @alt: The elevation * @direction: The image direction (if NAN then these direction fields are not written) * @direction_ref: The image direction value type * * Returns: A value indicating success: 0, or some other value for failure * */ gint a_geotag_write_exif_gps ( const gchar *filename, VikCoord coord, gdouble alt, gdouble direction, VikWaypointImageDirectionRef direction_ref, gboolean no_change_mtime ) { gint result = 0; // OK so far... // Save mtime for later use struct stat stat_save; if ( no_change_mtime ) if ( stat ( filename, &stat_save ) != 0 ) g_warning ( "%s couldn't read: %s", __FUNCTION__, filename ); #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 { if ( !isnan(direction) ) { gint nom = (gint)round(direction * 10.0); gboolean set_d = gexiv2_metadata_set_exif_tag_rational ( gemd, EXIF_GPS_IMGDIR, nom, 10 ); if ( !set_d ) result = 1; // Failed gboolean set_r = gexiv2_metadata_set_tag_string ( gemd, EXIF_GPS_IMGDIR_REF, direction_ref == WP_IMAGE_DIRECTION_REF_TRUE ? "T" : "M" ); if ( !set_r ) result = 1; // Failed } // Still OK to save - no fails yet if ( result == 0 ) { 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 ); } } } } 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 (for example this is done by Enlightment - http://www.enlightenment.org/ ) This appears to be JPEG only, but is probably 99% of our use case Alternatively consider using libexiv2 and C++... */ // Actual EXIF settings here... JPEGData *jdata; /* Parse the JPEG file. */ jdata = jpeg_data_new (); jpeg_data_load_file (jdata, filename); // Get current values ExifData *ed = exif_data_new_from_file ( filename ); if ( !ed ) ed = exif_data_new (); // Update ExifData with our new settings ExifEntry *ee; // // I don't understand it, but when saving the 'ed' nothing gets set after putting in the GPS ID tag - so it must come last // (unless of course there is some bug in the setting of the ID, that prevents subsequent tags) // ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, alt, ee, exif_data_get_byte_order(ed) ); // byte 0 meaning "sea level" or 1 if the value is negative. ee = my_exif_create_value (ed, EXIF_TAG_GPS_ALTITUDE_REF, EXIF_IFD_GPS); convert_to_entry ( alt < 0.0 ? "1" : "0", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_PROCESSING_METHOD, EXIF_IFD_GPS); // see http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/GPS.html convert_to_entry ( "MANUAL", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_MAP_DATUM, EXIF_IFD_GPS); convert_to_entry ( "WGS-84", 0.0, ee, exif_data_get_byte_order(ed) ); struct LatLon ll; vik_coord_to_latlon ( &coord, &ll ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE_REF, EXIF_IFD_GPS); // N or S convert_to_entry ( ll.lat < 0.0 ? "S" : "N", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LATITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, ll.lat, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE_REF, EXIF_IFD_GPS); // E or W convert_to_entry ( ll.lon < 0.0 ? "W" : "E", 0.0, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_LONGITUDE, EXIF_IFD_GPS); convert_to_entry ( NULL, ll.lon, ee, exif_data_get_byte_order(ed) ); ee = my_exif_create_value (ed, EXIF_TAG_GPS_VERSION_ID, EXIF_IFD_GPS); //convert_to_entry ( "2 0 0 0", 0.0, ee, exif_data_get_byte_order(ed) ); convert_to_entry ( "2 2 0 0", 0.0, ee, exif_data_get_byte_order(ed) ); jpeg_data_set_exif_data (jdata, ed); if ( jdata ) { /* Save the modified image. */ result = jpeg_data_save_file (jdata, filename); // Convert result from 1 for success, 0 for failure into our scheme result = !result; jpeg_data_unref (jdata); } else { // Epic fail - file probably not a JPEG result = 2; } exif_data_free ( ed ); #endif #endif if ( no_change_mtime ) { // Restore mtime, using the saved value struct stat stat_tmp; struct utimbuf utb; (void)stat ( filename, &stat_tmp ); utb.actime = stat_tmp.st_atime; utb.modtime = stat_save.st_mtime; // Not security critical, thus potential Time of Check Time of Use race condition is not bad // coverity[toctou] if ( g_utime ( filename, &utb ) != 0 ) g_warning ( "%s couldn't set time on: %s", __FUNCTION__, filename ); } return result; }
static void gpx_write_trackpoint ( VikTrackpoint *tp, GpxWritingContext *context ) { FILE *f = context->file; static struct LatLon ll; gchar *s_lat,*s_lon, *s_alt, *s_dop; gchar *time_iso8601; vik_coord_to_latlon ( &(tp->coord), &ll ); if ( tp->newsegment ) fprintf ( f, " </trkseg>\n <trkseg>\n" ); s_lat = a_coords_dtostr( ll.lat ); s_lon = a_coords_dtostr( ll.lon ); fprintf ( f, " <trkpt lat=\"%s\" lon=\"%s\">\n", s_lat, s_lon ); g_free ( s_lat ); s_lat = NULL; g_free ( s_lon ); s_lon = NULL; s_alt = NULL; if ( tp->altitude != VIK_DEFAULT_ALTITUDE ) { s_alt = a_coords_dtostr ( tp->altitude ); } else if ( context->options != NULL && context->options->force_ele ) { s_alt = a_coords_dtostr ( 0 ); } if (s_alt != NULL) fprintf ( f, " <ele>%s</ele>\n", s_alt ); g_free ( s_alt ); s_alt = NULL; time_iso8601 = NULL; if ( tp->has_timestamp ) { GTimeVal timestamp; timestamp.tv_sec = tp->timestamp; timestamp.tv_usec = 0; time_iso8601 = g_time_val_to_iso8601 ( ×tamp ); } else if ( context->options != NULL && context->options->force_time ) { GTimeVal current; g_get_current_time ( ¤t ); time_iso8601 = g_time_val_to_iso8601 ( ¤t ); } if ( time_iso8601 != NULL ) fprintf ( f, " <time>%s</time>\n", time_iso8601 ); g_free(time_iso8601); time_iso8601 = NULL; if (!isnan(tp->course)) { gchar *s_course = a_coords_dtostr(tp->course); fprintf ( f, " <course>%s</course>\n", s_course ); g_free(s_course); } if (!isnan(tp->speed)) { gchar *s_speed = a_coords_dtostr(tp->speed); fprintf ( f, " <speed>%s</speed>\n", s_speed ); g_free(s_speed); } if (tp->fix_mode == VIK_GPS_MODE_2D) fprintf ( f, " <fix>2d</fix>\n"); if (tp->fix_mode == VIK_GPS_MODE_3D) fprintf ( f, " <fix>3d</fix>\n"); if (tp->nsats > 0) fprintf ( f, " <sat>%d</sat>\n", tp->nsats ); s_dop = NULL; if ( tp->hdop != VIK_DEFAULT_DOP ) { s_dop = a_coords_dtostr ( tp->hdop ); } if (s_dop != NULL) fprintf ( f, " <hdop>%s</hdop>\n", s_dop ); g_free ( s_dop ); s_dop = NULL; if ( tp->vdop != VIK_DEFAULT_DOP ) { s_dop = a_coords_dtostr ( tp->vdop ); } if (s_dop != NULL) fprintf ( f, " <vdop>%s</vdop>\n", s_dop ); g_free ( s_dop ); s_dop = NULL; if ( tp->pdop != VIK_DEFAULT_DOP ) { s_dop = a_coords_dtostr ( tp->pdop ); } if (s_dop != NULL) fprintf ( f, " <pdop>%s</pdop>\n", s_dop ); g_free ( s_dop ); s_dop = NULL; fprintf ( f, " </trkpt>\n" ); }