Page MenuHomePhabricator

13172_roundRat.patch

Authored By
bzimport
Nov 21 2014, 10:02 PM
Size
9 KB
Referenced Files
None
Subscribers
None

13172_roundRat.patch

Index: includes/Exif.php
===================================================================
--- includes/Exif.php (revision 61759)
+++ includes/Exif.php (working copy)
@@ -255,13 +255,13 @@
'gps' => array(
'GPSVersionID' => Exif::BYTE, # GPS tag version
'GPSLatitudeRef' => Exif::ASCII, # North or South Latitude #p52-53
- 'GPSLatitude' => Exif::RATIONAL, # Latitude
+ 'GPSLatitude' => Exif::RATIONAL, # Latitude (special workaround handling)
'GPSLongitudeRef' => Exif::ASCII, # East or West Longitude #p53
- 'GPSLongitude' => Exif::RATIONAL, # Longitude
- 'GPSAltitudeRef' => Exif::BYTE, # Altitude reference
+ 'GPSLongitude' => Exif::RATIONAL, # Longitude (special workaround handling)
+ 'GPSAltitudeRef' => Exif::BYTE, # Altitude reference
'GPSAltitude' => Exif::RATIONAL, # Altitude
'GPSTimeStamp' => Exif::RATIONAL, # GPS time (atomic clock)
- 'GPSSatellites' => Exif::ASCII, # Satellites used for measurement
+ 'GPSSatellites' => Exif::ASCII, # Satellites used for measurement
'GPSStatus' => Exif::ASCII, # Receiver status #p54
'GPSMeasureMode' => Exif::ASCII, # Measurement mode #p54-55
'GPSDOP' => Exif::RATIONAL, # Measurement precision
@@ -273,16 +273,16 @@
'GPSImgDirection' => Exif::RATIONAL, # Direction of image
'GPSMapDatum' => Exif::ASCII, # Geodetic survey data used
'GPSDestLatitudeRef' => Exif::ASCII, # Reference for latitude of destination #p56
- 'GPSDestLatitude' => Exif::RATIONAL, # Latitude destination
+ 'GPSDestLatitude' => Exif::RATIONAL, # Latitude destination (special workaround handling)
'GPSDestLongitudeRef' => Exif::ASCII, # Reference for longitude of destination #p57
- 'GPSDestLongitude' => Exif::RATIONAL, # Longitude of destination
+ 'GPSDestLongitude' => Exif::RATIONAL, # Longitude of destination (special workaround handling)
'GPSDestBearingRef' => Exif::ASCII, # Reference for bearing of destination #p57
'GPSDestBearing' => Exif::RATIONAL, # Bearing of destination
'GPSDestDistanceRef' => Exif::ASCII, # Reference for distance to destination #p57-58
'GPSDestDistance' => Exif::RATIONAL, # Distance to destination
'GPSProcessingMethod' => Exif::UNDEFINED, # Name of GPS processing method
'GPSAreaInformation' => Exif::UNDEFINED, # Name of GPS area
- 'GPSDateStamp' => Exif::ASCII, # GPS date
+ 'GPSDateStamp' => Exif::ASCII, # GPS date
'GPSDifferential' => Exif::SHORT, # GPS differential correction
),
);
@@ -348,6 +348,39 @@
}
}
+ // Work around a bug in the definitions above: GPS coordinates may be arrays of degree-minutes-seconds
+ // If we find such a coordinate, we convert it here to single a fractional degree.
+ // This work-around fixes bug 13172 without changing the metadata format at all. (But leaves the
+ // other fields in the metadata that also should be arrays untouched.)
+ foreach( array( 'GPSLatitude' => 90, 'GPSLongitude' => 180, 'GPSDestLatitude' => 90, 'GPSDestLongitude' => 180) as $gpsTag => $max) {
+ if( !array_key_exists( $gpsTag, $this->mFilteredExifData ) ) continue;
+ $data = $this->mFilteredExifData[$gpsTag];
+ if( !is_array( $data ) ) continue;
+ $val = 0;
+ $divisor = 1;
+ foreach( $data as $v ) {
+ $m = array();
+ if( !preg_match( '/^(\d+)\/(\d+)$/', $v, $m ) || $m[2] == 0 ) break;
+ $val += ( $m[1] / $m[2] ) / $divisor;
+ $divisor *= 60;
+ if( $divisor > 3600 ) break;
+ }
+ if( $val <= 0.0 ) {
+ $num = 0; $denom = 1;
+ } else {
+ // 7 digits is more than enough. It corresponds to an accuracy of about 1cm,
+ // which is more than the current GPS systems can deliver in terms of
+ // precision. Even if more precise locations should appear in the future
+ // in EXIF data, 1cm is surely precise enough to pinpoint a photographer's
+ // location.
+ $val = round( $val, 7 );
+ if ( $val > $max ) $val = $max;
+ $denom = 10000000; // 10**7
+ $num = intval( $val * $denom );
+ }
+ $this->mFilteredExifData[$gpsTag] = $num . "/" . $denom;
+ }
+
foreach( $this->mFilteredExifData as $k => $v ) {
if ( !$this->validate($k, $v) ) {
$this->debug( $v, __FUNCTION__, "'$k' contained invalid data" );
@@ -613,6 +646,14 @@
var $mExif;
/**
+ * Values for the geolocation coordinate references
+ *
+ * @var array
+ * @private
+ */
+ var $mGeoReferences;
+
+ /**
* Constructor
*
* @param $exif Array: the Exif data to format ( as returned by
@@ -620,6 +661,13 @@
*/
function FormatExif( $exif ) {
$this->mExif = $exif;
+ $this->mGeoReferences = array(
+ 'GPSLatitudeRef' => null
+ ,'GPSLongitudeRef' => null
+ ,'GPSDestLatitudeRef' => null
+ ,'GPSDestLongitudeRef' => null
+ ,'GPSAltitudeRef' => 0 // Default: above sea level
+ );
}
/**
@@ -638,6 +686,11 @@
$resolutionunit = !isset( $tags['ResolutionUnit'] ) || $tags['ResolutionUnit'] == 2 ? 2 : 3;
unset( $tags['ResolutionUnit'] );
+ foreach( $this->mGeoReferences as $gpsRefTag => $value) {
+ if( !array_key_exists( $gpsRefTag, $tags ) ) continue;
+ $this->mGeoReferences[$gpsRefTag] = $tags[$gpsRefTag];
+ }
+
foreach( $tags as $tag => $val ) {
switch( $tag ) {
case 'Compression':
@@ -967,6 +1020,28 @@
}
break;
+ case 'GPSLatitude':
+ case 'GPSDestLatitude':
+ case 'GPSLongitude':
+ case 'GPSDestLongitude':
+ $tags[$tag] = $this->formatCoordinate( $val, $this->mGeoReferences[$tag . 'Ref'] );
+ break;
+
+ case 'GPSAltitudeRef':
+ switch( $val ) {
+ case 0: case 1:
+ $tags[$tag] = $this->msg( 'GPSAltitude', $val );
+ break;
+ default:
+ $tags[$tag] = $val;
+ break;
+ }
+ break;
+
+ case 'GPSAltitude' :
+ $tags[$tag] = $this->msg( 'GPSAltitudeValue', $this->mGeoReferences[$tag . 'Ref'], $this->formatNum ( $val ) );
+ break;
+
case 'GPSStatus':
switch( $val ) {
case 'A': case 'V':
@@ -990,7 +1065,6 @@
break;
case 'GPSSpeedRef':
- case 'GPSDestDistanceRef':
switch( $val ) {
case 'K': case 'M': case 'N':
$tags[$tag] = $this->msg( 'GPSSpeed', $val );
@@ -1001,6 +1075,17 @@
}
break;
+ case 'GPSDestDistanceRef':
+ switch( $val ) {
+ case 'K': case 'M': case 'N':
+ $tags[$tag] = $this->msg( 'GPSDestDistance', $val );
+ break;
+ default:
+ $tags[$tag] = $val;
+ break;
+ }
+ break;
+
case 'GPSTrackRef':
case 'GPSImgDirectionRef':
case 'GPSDestBearingRef':
@@ -1120,6 +1205,39 @@
}
/**
+ * Format a coordinate value.
+ *
+ * @param $num Mixed: coordinate value in degrees
+ * @param $direction String (optional): 'N', 'S', 'E', or 'W'
+ * @return String: coordinate value in degrees, minutes and seconds
+ * @private
+ */
+ function formatCoordinate( $num, $direction=null ) {
+ global $wgContLang;
+
+ $m = array();
+ if ( is_numeric( $num ) ) {
+ $den = 1; // we use fmod() below so that $num can be a float too
+ $fnum = $this->formatNum( round ( $num, 7 ) );
+ } else if ( preg_match( '/^(\d+)\/(\d+)$/', $num, $m ) && $m[2] != 0 ) {
+ $num = $m[1]; $den = $m[2];
+ $fnum = $this->formatNum( round ( $num / $den , 7 ) );
+ } else {
+ return $this->formatNum( $num );
+ }
+ $deg = intval( $num / $den );
+ $num = 60 * fmod( $num, $den );
+ $min = intval( $num / $den );
+ $num = 60 * fmod( $num, $den );
+ // Limit seconds to at most 3 fractional digits: that's already in the
+ // millimeter range!
+ $sec = $this->formatNum( round ( $num / $den , 3 ) );
+ $tag = 'exif-coordinate-format';
+ if ( $direction != null ) $tag .= '-' . $wgContLang->lc( $direction );
+ return wfMsg( $tag, $deg, $min, $sec, $fnum );
+ }
+
+ /**
* Calculate the greatest common divisor of two integers.
*
* @param $a Integer: FIXME
@@ -1145,6 +1263,7 @@
}
return $a;
}
+
}
/**
Index: languages/messages/MessagesEn.php
===================================================================
--- languages/messages/MessagesEn.php (revision 61756)
+++ languages/messages/MessagesEn.php (working copy)
@@ -3674,6 +3674,13 @@
'exif-gpsdatestamp' => 'GPS date',
'exif-gpsdifferential' => 'GPS differential correction',
+# Coordinate value in deg/min/sec, used for GPS location data. $4 is same in decimal degrees.
+'exif-coordinate-format' => '$1° $2\' $3"',
+'exif-coordinate-format-n' => '$1° $2\' $3" N',
+'exif-coordinate-format-s' => '$1° $2\' $3" S',
+'exif-coordinate-format-e' => '$1° $2\' $3" E',
+'exif-coordinate-format-w' => '$1° $2\' $3" W',
+
# Make & model, can be wikified in order to link to the camera and model name
'exif-make-value' => '$1', # do not translate or duplicate this message to other languages
'exif-model-value' => '$1', # do not translate or duplicate this message to other languages
@@ -3840,6 +3847,19 @@
'exif-gpsspeed-m' => 'Miles per hour',
'exif-gpsspeed-n' => 'Knots',
+# Pseudotags used for GPSDestDistanceRef
+'exif-gpsdestdistance-k' => 'Kilometers',
+'exif-gpsdestdistance-m' => 'Miles',
+'exif-gpsdestdistance-n' => 'Nautical miles',
+
+# Pseudotags used for GPSAltitudeRef
+'exif-gpsaltitude-0' => 'Meters above sea level',
+'exif-gpsaltitude-1' => 'Meters below sea level',
+
+# Pseudotags used for GPSAltitudeRef
+'exif-gpsaltitudevalue-0' => '+ $1 m',
+'exif-gpsaltitudevalue-1' => '- $1 m',
+
# Pseudotags used for GPSTrackRef, GPSImgDirectionRef and GPSDestBearingRef
'exif-gpsdirection-t' => 'True direction',
'exif-gpsdirection-m' => 'Magnetic direction',

File Metadata

Mime Type
text/x-diff
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
4198
Default Alt Text
13172_roundRat.patch (9 KB)

Event Timeline