In EXIF, GPSAltitude is stored as a fraction string like "1/2".
For values below sea level we were negating this value, in order
to represent the sign and the magnitude in the same value. However,
I forgot to convert that to an integer before negating it. PHP was nice
enough to do a best effort conversion of the string to an integer.
This resulted in altitudes below sea level being taken as just the
numerator of the altitude, which gives results that can be significantly
off.
Also add unit tests for the GPS related image metadata stuff. Change the
existing GPS test to use a fractional altitude (Since this issue isn't
appearent if the denominator is 1). Add tests for XMP as well, since
XMP had same issue, and has to do same processing as EXIF stuff does.
In some future time, may want to consider just converting all exif rational values
to real numbers during the extraction process for generally better sanity.
Patchset 2: rebase
Change-Id: I49032b52a4c840b28e667a6a2b8ae23c508df247
* (bug 30390) Suggested file name on Special:Upload should not contain
illegal characters.
* (bug 27111) Cascading foreign file repos now fetch shared descriptions properly
+* EXIF below sea level GPS altitude data is now shown correctly
=== API changes in 1.20 ===
* (bug 34316) Add ability to retrieve maximum upload size from MediaWiki API.
$this->exifGPStoNumber( 'GPSDestLongitude' );
if ( isset( $this->mFilteredExifData['GPSAltitude'] ) && isset( $this->mFilteredExifData['GPSAltitudeRef'] ) ) {
+
+ // We know altitude data is a <num>/<denom> from the validation functions ran earlier.
+ // But multiplying such a string by -1 doesn't work well, so convert.
+ list( $num, $denom ) = explode( '/', $this->mFilteredExifData['GPSAltitude'] );
+ $this->mFilteredExifData['GPSAltitude'] = $num / $denom;
+
if ( $this->mFilteredExifData['GPSAltitudeRef'] === "\1" ) {
$this->mFilteredExifData['GPSAltitude'] *= - 1;
}
unset( $data['xmp-special'] );
// Convert GPSAltitude to negative if below sea level.
- if ( isset( $data['xmp-exif']['GPSAltitudeRef'] ) ) {
- if ( $data['xmp-exif']['GPSAltitudeRef'] == '1'
- && isset( $data['xmp-exif']['GPSAltitude'] )
- ) {
+ if ( isset( $data['xmp-exif']['GPSAltitudeRef'] )
+ && isset( $data['xmp-exif']['GPSAltitude'] )
+ ) {
+
+ // Must convert to a real before multiplying by -1
+ // XMPValidate guarantees there will always be a '/' in this value.
+ list( $nom, $denom ) = explode( '/', $data['xmp-exif']['GPSAltitude'] );
+ $data['xmp-exif']['GPSAltitude'] = $nom / $denom;
+
+ if ( $data['xmp-exif']['GPSAltitudeRef'] == '1' ) {
$data['xmp-exif']['GPSAltitude'] *= -1;
}
unset( $data['xmp-exif']['GPSAltitudeRef'] );
--- /dev/null
+<?php
+
+$result = array( 'xmp-exif' =>
+ array(
+ 'GPSAltitude' => -3.14159265301,
+ 'GPSDOP' => '5/1',
+ 'GPSLatitude' => 88.51805555,
+ 'GPSLongitude' => -21.12356945,
+ 'GPSVersionID' => '2.2.0.0'
+ )
+);
+
--- /dev/null
+<?xpacket begin='' id='W5M0MpCehiHzreSzNTczkc9d'?>
+<x:xmpmeta xmlns:x='adobe:ns:meta/' x:xmptk='Image::ExifTool 7.30'>
+<rdf:RDF xmlns:rdf='http://www.w3.org/1999/02/22-rdf-syntax-ns#'>
+
+ <rdf:Description rdf:about=''
+ xmlns:exif='http://ns.adobe.com/exif/1.0/'>
+ <exif:GPSAltitude>103993/33102</exif:GPSAltitude>
+ <exif:GPSAltitudeRef>1</exif:GPSAltitudeRef>
+ <exif:GPSDOP>5/1</exif:GPSDOP>
+ <exif:GPSLatitude>88,31.083333N</exif:GPSLatitude>
+ <exif:GPSLongitude>21,7.414167W</exif:GPSLongitude>
+ <exif:GPSVersionID>2.2.0.0</exif:GPSVersionID>
+ </rdf:Description>
+
+</rdf:RDF>
+</x:xmpmeta>
+<?xpacket end='w'?>
$expected = array(
'GPSLatitude' => 88.5180555556,
'GPSLongitude' => -21.12357,
- 'GPSAltitude' => -200,
+ 'GPSAltitude' => -3.141592653,
'GPSDOP' => '5/1',
'GPSVersionID' => '2.2.0.0',
);
}
$reader = new XMPReader;
$reader->parse( $xmp );
- $this->assertEquals( $expected, $reader->getResults(), $info );
+ $this->assertEquals( $expected, $reader->getResults(), $info, 0.0000000001 );
}
public function dataXMPParse() {
array( 'utf32BE', 'UTF-32BE encoding' ),
array( 'utf32LE', 'UTF-32LE encoding' ),
array( 'xmpExt', 'Extended XMP missing second part' ),
+ array( 'gps', 'Handling of exif GPS parameters in XMP' ),
);
foreach( $xmpFiles as $file ) {
$xmp = file_get_contents( $xmpPath . $file[0] . '.xmp' );