# HG changeset patch # User nadvornik # Date 1222894676 0 # Node ID 338c21c87ff526d832e0978f467f1f885a70c525 # Parent 2a02fa29478bda4658e57d4e650a480d62c25132 Add support for GPSInfo - patch by Klaus Ethgen diff -r 2a02fa29478b -r 338c21c87ff5 src/bar_exif.c --- a/src/bar_exif.c Mon Sep 29 21:17:19 2008 +0000 +++ b/src/bar_exif.c Wed Oct 01 20:57:56 2008 +0000 @@ -46,6 +46,8 @@ { 0, 0, EXIF_UI_IFSET, "formatted.SubjectDistance"}, { 0, 0, EXIF_UI_IFSET, "formatted.Resolution"}, { 0, 0, EXIF_UI_IFSET, "Exif.Image.Orientation"}, + { 0, 0, EXIF_UI_IFSET, "formatted.GPSPosition"}, + { 0, 0, EXIF_UI_IFSET, "formatted.GPSAltitude"}, { 0, 0, EXIF_UI_IFSET, "Exif.Image.ImageDescription"}, { 0, 0, EXIF_UI_IFSET, "Exif.Image.Copyright"}, { 0, 0, EXIF_UI_OFF, NULL} diff -r 2a02fa29478b -r 338c21c87ff5 src/exif-common.c --- a/src/exif-common.c Mon Sep 29 21:17:19 2008 +0000 +++ b/src/exif-common.c Wed Oct 01 20:57:56 2008 +0000 @@ -429,6 +429,78 @@ return g_strdup_printf("%s (%s)", name, source); } +static gchar *exif_build_formatted_GPSPosition(ExifData *exif) +{ + GString *string; + gchar *text, *ref; + ExifRational *value; + ExifItem *item; + guint i; + gdouble p, p3; + gulong p1, p2; + + string = g_string_new(""); + + item = exif_get_item(exif, "Exif.GPSInfo.GPSLatitude"); + ref = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLatitudeRef"); + if (item && ref) + { + p = 0; + for (i = 0; i < exif_item_get_elements(item); i++) + { + value = exif_item_get_rational(item, NULL, i); + if (value && value->num && value->den) + p += (gdouble)value->num / (gdouble)value->den / pow(60.0, (gdouble)i); + } + p1 = (gint)p; + p2 = (gint)((p - p1)*60); + p3 = ((p - p1)*60 - p2)*60; + + g_string_append_printf(string, "%0d° %0d' %0.2f\" %.1s", p1, p2, p3, ref); + } // if (item && ref) + + item = exif_get_item(exif, "Exif.GPSInfo.GPSLongitude"); + ref = exif_get_data_as_text(exif, "Exif.GPSInfo.GPSLongitudeRef"); + if (item && ref) + { + p = 0; + for (i = 0; i < exif_item_get_elements(item); i++) + { + value = exif_item_get_rational(item, NULL, i); + if (value && value->num && value->den) + p += (gdouble)value->num / (gdouble)value->den / pow(60.0, (gdouble)i); + } + p1 = (gint)p; + p2 = (gint)((p - p1)*60); + p3 = ((p - p1)*60 - p2)*60; + + g_string_append_printf(string, ", %0d° %0d' %0.2f\" %.1s", p1, p2, p3, ref); + } // if (item && ref) + + text = string->str; + g_string_free(string, FALSE); + + return text; +} // static gchar *exif_build_forma... + +static gchar *exif_build_formatted_GPSAltitude(ExifData *exif) +{ + ExifRational *r; + ExifItem *item; + gdouble alt; + gint ref; + + item = exif_get_item(exif, "Exif.GPSInfo.GPSAltitudeRef"); + r = exif_get_rational(exif, "Exif.GPSInfo.GPSAltitude", NULL); + + if (!r || !item) return NULL; + + alt = exif_rational_to_double(r, 0); + exif_item_get_integer(item, &ref); + + return g_strdup_printf("%0.f m %s", alt, (ref==0)?_("Above Sea Level"):_("Below Sea Level")); +} + /* List of custom formatted pseudo-exif tags */ #define EXIF_FORMATTED_TAG(name, label) { "formatted."#name, label, exif_build_formatted##_##name } @@ -446,6 +518,8 @@ EXIF_FORMATTED_TAG(Flash, N_("Flash")), EXIF_FORMATTED_TAG(Resolution, N_("Resolution")), EXIF_FORMATTED_TAG(ColorProfile, N_("Color profile")), + EXIF_FORMATTED_TAG(GPSPosition, N_("GPS position")), + EXIF_FORMATTED_TAG(GPSAltitude, N_("GPS altitude")), { NULL, NULL, NULL } }; @@ -497,7 +571,7 @@ ExifItem *item; item = exif_get_item(exif, key); - return exif_item_get_rational(item, sign); + return exif_item_get_rational(item, sign, 0); } gchar *exif_get_data_as_text(ExifData *exif, const gchar *key) diff -r 2a02fa29478b -r 338c21c87ff5 src/exif.c --- a/src/exif.c Mon Sep 29 21:17:19 2008 +0000 +++ b/src/exif.c Wed Oct 01 20:57:56 2008 +0000 @@ -28,12 +28,12 @@ * Unsupported at this time: * IFD1 (thumbnail) * MakerNote - * GPSInfo * * TODO: * Convert data to useable form in the ??_as_text function for: * ComponentsConfiguration * UserComment (convert this to UTF-8?) + * Add support for marker tag 0x0000 * This program is free software; you can redistribute it and/or modify @@ -103,6 +103,7 @@ /* tags that are special, or need special treatment */ #define TAG_EXIFOFFSET 0x8769 #define TAG_EXIFMAKERNOTE 0x927c +#define TAG_GPSOFFSET 0x8825 /* @@ -437,6 +438,44 @@ EXIF_MARKER_LIST_END }; +ExifMarker ExifKnownGPSInfoMarkersList[] = { + /* The following do not work at the moment as the tag value 0x0000 has a + * special meaning. */ + /* { 0x0000, EXIF_FORMAT_BYTE, -1, "Exif.GPSInfo.GPSVersionID", NULL, NULL }, */ + { 0x0001, EXIF_FORMAT_STRING, 2, "Exif.GPSInfo.GPSLatitudeRef", NULL, NULL }, + { 0x0002, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSLatitude", NULL, NULL }, + { 0x0003, EXIF_FORMAT_STRING, 2, "Exif.GPSInfo.GPSLongitudeRef", NULL, NULL }, + { 0x0004, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSLongitude", NULL, NULL }, + { 0x0005, EXIF_FORMAT_BYTE_UNSIGNED, 1, "Exif.GPSInfo.GPSAltitudeRef", NULL, NULL }, + { 0x0006, EXIF_FORMAT_RATIONAL_UNSIGNED, 1, "Exif.GPSInfo.GPSAltitude", NULL, NULL }, + { 0x0007, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSTimeStamp", NULL, NULL }, + { 0x0008, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSSatellites", NULL, NULL }, + { 0x0009, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSStatus", NULL, NULL }, + { 0x000a, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSMeasureMode", NULL, NULL }, + { 0x000b, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDOP", NULL, NULL }, + { 0x000c, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSSpeedRef", NULL, NULL }, + { 0x000d, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSSpeed", NULL, NULL }, + { 0x000e, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSTrackRef", NULL, NULL }, + { 0x000f, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSTrack", NULL, NULL }, + { 0x0010, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSImgDirectionRef", NULL, NULL }, + { 0x0011, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSImgDirection", NULL, NULL }, + { 0x0012, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSMapDatum", NULL, NULL }, + { 0x0013, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestLatitudeRef", NULL, NULL }, + { 0x0014, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestLatitude", NULL, NULL }, + { 0x0015, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestLongitudeRef", NULL, NULL }, + { 0x0016, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestLongitude", NULL, NULL }, + { 0x0017, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestBearingRef", NULL, NULL }, + { 0x0018, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestBearing", NULL, NULL }, + { 0x0019, EXIF_FORMAT_STRING, -1, "Exif.GPSInfo.GPSDestDistanceRef", NULL, NULL }, + { 0x001a, EXIF_FORMAT_RATIONAL_UNSIGNED, -1, "Exif.GPSInfo.GPSDestDistance", NULL, NULL }, + { 0x001b, EXIF_FORMAT_UNDEFINED, -1, "Exif.GPSInfo.GPSProcessingMethod", NULL, NULL }, + { 0x001c, EXIF_FORMAT_UNDEFINED, -1, "Exif.GPSInfo.GPSAreaInformation", NULL, NULL }, + { 0x001d, EXIF_FORMAT_RATIONAL_UNSIGNED, 3, "Exif.GPSInfo.GPSDateStamp", NULL, NULL }, + { 0x001e, EXIF_FORMAT_SHORT, -1, "Exif.GPSInfo.GPSDifferential", NULL, NULL }, + + EXIF_MARKER_LIST_END +}; + ExifMarker ExifUnknownMarkersList[] = { { 0x0000, EXIF_FORMAT_UNKNOWN, 0, "unknown", NULL, NULL }, { 0x0000, EXIF_FORMAT_BYTE_UNSIGNED, -1, "unknown", NULL, NULL }, @@ -911,6 +950,9 @@ case TAG_EXIFOFFSET: exif_parse_IFD_table(exif, tiff, data_val, size, bo, level + 1, list); break; + case TAG_GPSOFFSET: + exif_parse_IFD_table(exif, tiff, data_val, size, bo, level + 1, ExifKnownGPSInfoMarkersList); + break; case TAG_EXIFMAKERNOTE: format_exif_makernote_parse(exif, tiff, data_val, size, bo); break; @@ -1436,15 +1478,16 @@ } -ExifRational *exif_item_get_rational(ExifItem *item, gint *sign) +ExifRational *exif_item_get_rational(ExifItem *item, gint *sign, gint n) { if (!item) return NULL; + if (n >= (gint)item->elements) return NULL; if (item->format == EXIF_FORMAT_RATIONAL || item->format == EXIF_FORMAT_RATIONAL_UNSIGNED) { if (sign) *sign = (item->format == EXIF_FORMAT_RATIONAL); - return &((ExifRational *)(item->data))[0]; + return &((ExifRational *)(item->data))[n]; } return NULL; @@ -1463,6 +1506,13 @@ i++; } + i = 0; + while (ExifKnownGPSInfoMarkersList[i].tag > 0) + { + if (strcmp(key, ExifKnownGPSInfoMarkersList[i].key) == 0) return _(ExifKnownGPSInfoMarkersList[i].description); + i++; + } + return NULL; } diff -r 2a02fa29478b -r 338c21c87ff5 src/exif.h --- a/src/exif.h Mon Sep 29 21:17:19 2008 +0000 +++ b/src/exif.h Wed Oct 01 20:57:56 2008 +0000 @@ -133,7 +133,7 @@ const gchar *exif_item_get_format_name(ExifItem *item, gint brief); gchar *exif_item_get_data_as_text(ExifItem *item); gint exif_item_get_integer(ExifItem *item, gint *value); -ExifRational *exif_item_get_rational(ExifItem *item, gint *sign); +ExifRational *exif_item_get_rational(ExifItem *item, gint *sign, gint n); gchar *exif_item_get_string(ExifItem *item, gint idx); diff -r 2a02fa29478b -r 338c21c87ff5 src/exiv2.cc --- a/src/exiv2.cc Mon Sep 29 21:17:19 2008 +0000 +++ b/src/exiv2.cc Wed Oct 01 20:57:56 2008 +0000 @@ -512,11 +512,12 @@ } } -ExifRational *exif_item_get_rational(ExifItem *item, gint *sign) +ExifRational *exif_item_get_rational(ExifItem *item, gint *sign, gint n) { try { if (!item) return NULL; - Exiv2::Rational v = ((Exiv2::Metadatum *)item)->toRational(); + if (n >= exif_item_get_elements(item)) return NULL; + Exiv2::Rational v = ((Exiv2::Metadatum *)item)->toRational(n); static ExifRational ret; ret.num = v.first; ret.den = v.second;