Add support for GPSInfo - patch by Klaus Ethgen
authorVladimir Nadvornik <nadvornik@suse.cz>
Wed, 1 Oct 2008 20:57:56 +0000 (20:57 +0000)
committerVladimir Nadvornik <nadvornik@suse.cz>
Wed, 1 Oct 2008 20:57:56 +0000 (20:57 +0000)
src/bar_exif.c
src/exif-common.c
src/exif.c
src/exif.h
src/exiv2.cc

index d46ee58..accba86 100644 (file)
@@ -46,6 +46,8 @@ ExifUI ExifUIList[]={
        { 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}
index 66c8606..9660e53 100644 (file)
@@ -429,6 +429,78 @@ static gchar *exif_build_formatted_ColorProfile(ExifData *exif)
        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 @@ ExifFormattedText ExifFormattedList[] = {
        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 @@ ExifRational *exif_get_rational(ExifData *exif, const gchar *key, gint *sign)
        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)
index 273e909..58f06b3 100644 (file)
  *  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 @@ ExifFormatAttrib ExifFormatList[] = {
 /* tags that are special, or need special treatment */
 #define TAG_EXIFOFFSET          0x8769
 #define TAG_EXIFMAKERNOTE      0x927c
+#define TAG_GPSOFFSET          0x8825
 
 
 /*
@@ -437,6 +438,44 @@ ExifMarker ExifKnownMarkersList[] = {
 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 @@ static gint exif_parse_IFD_entry(ExifData *exif, guchar *tiff, guint offset,
                        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 @@ 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)
 {
        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 @@ const gchar *exif_get_tag_description_by_key(const gchar *key)
                i++;
                }
 
+       i = 0;
+       while (ExifKnownGPSInfoMarkersList[i].tag > 0)
+       {
+          if (strcmp(key, ExifKnownGPSInfoMarkersList[i].key) == 0) return _(ExifKnownGPSInfoMarkersList[i].description);
+          i++;
+       }
+
        return NULL;
 }
 
index e9e99c6..cd0afeb 100644 (file)
@@ -133,7 +133,7 @@ guint exif_item_get_format_id(ExifItem *item);
 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);
 
index c578875..9c5d9e7 100644 (file)
@@ -512,11 +512,12 @@ 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)
 {
        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;