exiftag: Increase serialized geo precision
authorPaulo Neves <pneves@airborneprojects.com>
Sat, 11 Jun 2016 15:11:30 +0000 (17:11 +0200)
committerSebastian Dröge <sebastian@centricular.com>
Mon, 13 Jun 2016 06:29:52 +0000 (09:29 +0300)
The serialization of double typed geographical
coordinates to DMS system supported by the exif
standards was previously truncated without need.

The previous code truncated the seconds part of
the coordinate to a fraction with denominator
equal to 1 causing a bug on the deserialization
when the test for the coordinate to be serialized
was more precise.

This patch applies a 10E6 multiplier to the numerator
equal to the denominator of the rational number.

Eg. Latitude = 89.5688643 Serialization

DMS Old code = 89/1 deg, 34/1 min, 7/1 sec
DMS New code = 89/1 deg, 34/1 min, 79114800UL/10000000UL

Deserialization

DMS Old code = 89.5686111111
DMS New code = 89.5688643

The new test tries to serialize a higher precision
coordinate.

The types of the coordinates are also guint32 instead
of gint like previously. guint32 is the type of the
fraction components in the exif.

https://bugzilla.gnome.org/show_bug.cgi?id=767537

gst-libs/gst/tag/gstexiftag.c
tests/check/libs/tag.c

index 895727f..bcdcdde 100644 (file)
@@ -2090,9 +2090,9 @@ serialize_geo_coordinate (GstExifWriter * writer, const GstTagList * taglist,
 {
   gboolean latitude;
   gdouble value;
-  gint degrees;
-  gint minutes;
-  gint seconds;
+  guint32 degrees;
+  guint32 minutes;
+  guint32 seconds_numerator, seconds_denominator;
   guint32 offset;
 
   latitude = exiftag->exif_tag == EXIF_TAG_GPS_LATITUDE;        /* exif tag for latitude */
@@ -2120,21 +2120,24 @@ serialize_geo_coordinate (GstExifWriter * writer, const GstTagList * taglist,
   }
 
   /* now write the degrees stuff */
-  GST_LOG ("Converting geo location %lf to degrees", value);
-  degrees = (gint) value;
+  GST_DEBUG ("Converting %lf degrees geo location to HMS", value);
+  degrees = (guint32) value;
   value -= degrees;
-  minutes = (gint) (value * 60);
+  minutes = (guint32) (value * 60);
   value = (value * 60) - minutes;
-  seconds = (gint) (value * 60);
-  GST_LOG ("Converted geo location to %d.%d'%d'' degrees", degrees,
-      minutes, seconds);
+  seconds_denominator = 10000000UL;
+  seconds_numerator = (guint32) (value * 60 * seconds_denominator);
+
+  GST_DEBUG ("Converted rational geo location to %u/%u %u/%u %u/%u degrees ",
+      degrees, 1U, minutes, 1U, seconds_numerator, seconds_denominator);
 
   offset = gst_byte_writer_get_size (&writer->datawriter);
   gst_exif_writer_write_tag_header (writer, exiftag->exif_tag,
       EXIF_TYPE_RATIONAL, 3, offset, NULL);
   gst_exif_writer_write_rational_data (writer, degrees, 1);
   gst_exif_writer_write_rational_data (writer, minutes, 1);
-  gst_exif_writer_write_rational_data (writer, seconds, 1);
+  gst_exif_writer_write_rational_data (writer, seconds_numerator,
+      seconds_denominator);
 }
 
 static gint
@@ -2251,12 +2254,11 @@ deserialize_geo_coordinate (GstExifReader * exif_reader,
   gst_util_fraction_to_double (degrees_n, degrees_d, &degrees);
   gst_util_fraction_to_double (minutes_n, minutes_d, &minutes);
   gst_util_fraction_to_double (seconds_n, seconds_d, &seconds);
-
   minutes += seconds / 60;
   degrees += minutes / 60;
   degrees *= multiplier;
 
-  GST_DEBUG ("Adding %s tag: %lf", exiftag->gst_tag, degrees);
+  GST_DEBUG ("Adding %s tag: %lf degrees", exiftag->gst_tag, degrees);
   gst_tag_list_add (exif_reader->taglist, GST_TAG_MERGE_REPLACE,
       exiftag->gst_tag, degrees, NULL);
 
index c176531..992b198 100644 (file)
@@ -1676,10 +1676,11 @@ GST_START_TEST (test_exif_tags_serialization_deserialization)
   g_value_unset (&value);
 
   g_value_init (&value, G_TYPE_DOUBLE);
-  g_value_set_double (&value, 30.5);
+  g_value_set_double (&value, 40.3456784);
   do_simple_exif_tag_serialization_deserialization
       (GST_TAG_GEO_LOCATION_LATITUDE, &value);
-  g_value_set_double (&value, -12.125);
+  g_value_set_double (&value, -12.1250865);
+
   do_simple_exif_tag_serialization_deserialization
       (GST_TAG_GEO_LOCATION_LATITUDE, &value);
   g_value_set_double (&value, 0);