Skip to content

Commit 79b04dc

Browse files
committed
limit GPS coordinates to decimal degrees
1 parent a6d58bb commit 79b04dc

File tree

6 files changed

+44
-204
lines changed

6 files changed

+44
-204
lines changed

lib/PHPExif/Adapter/Exiftool.php

Lines changed: 7 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -181,24 +181,11 @@ public function mapData(array $source)
181181
$longitude = $this->extractGPSCoordinates($source['GPSLongitude']);
182182

183183
if ($latitude !== false && $longitude !== false) {
184-
$gpsLocation = array();
185-
186-
$gpsLocation['latitude'] = array_merge(
187-
$latitude,
188-
array(strtoupper($source['GPSLatitudeRef'][0]))
189-
);
190-
$gpsLocation['longitude'] = array_merge(
191-
$longitude,
192-
array(strtoupper($source['GPSLongitudeRef'][0]))
184+
$gpsLocation = sprintf(
185+
'%s,%s',
186+
(strtoupper($source['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude,
187+
(strtoupper($source['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude
193188
);
194-
195-
if (isset($source['GPSAltitudeRef'])
196-
&& preg_match('!^([0-9]+) m!', $source['GPSAltitude'], $matches)) {
197-
$gpsLocation['altitude'] = array(
198-
$matches[1],
199-
preg_match('!^Above!', $source['GPSAltitudeRef']) ? 0 : -1,
200-
);
201-
}
202189
}
203190
}
204191

@@ -236,32 +223,21 @@ public function mapData(array $source)
236223
}
237224

238225
/**
239-
* Extract GPS coordinates from formattedstring
226+
* Extract GPS coordinates from formatted string
240227
*
241228
* @param string $coordinates
242229
* @return array
243230
*/
244231
protected function extractGPSCoordinates($coordinates)
245232
{
246233
if ($this->numeric === true) {
247-
$coordinates *= (int) $coordinates < 0 ? -1 : 1;
248-
249-
$degrees = (int) $coordinates;
250-
$decimalMinutes = ($coordinates - $degrees) * 60;
251-
$minutes = (int) $decimalMinutes;
252-
$seconds = round(($decimalMinutes - $minutes) * 60, 6);
253-
254-
return array(
255-
$degrees,
256-
$minutes,
257-
$seconds,
258-
);
234+
return abs((float) $coordinates);
259235
} else {
260236
if (!preg_match('!^([0-9.]+) deg ([0-9.]+)\' ([0-9.]+)"!', $coordinates, $matches)) {
261237
return false;
262238
}
263239

264-
return array_slice($matches, 1);
240+
return intval($matches[1]) + (intval($matches[2]) / 60) + (floatval($matches[3]) / 3600);
265241
}
266242
}
267243
}

lib/PHPExif/Adapter/Native.php

Lines changed: 26 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -264,22 +264,14 @@ public function mapData(array $source)
264264

265265
$gpsLocation = false;
266266
if (isset($source['GPSLatitudeRef']) && isset($source['GPSLongitudeRef'])) {
267-
$gpsLocation = array();
267+
$latitude = $this->extractGPSCoordinate($source['GPSLatitude']);
268+
$longitude = $this->extractGPSCoordinate($source['GPSLongitude']);
268269

269-
$gpsLocation['latitude'] = array_merge(
270-
$this->normalizeGPSCoordinate($source['GPSLatitude']),
271-
array(strtoupper($source['GPSLatitudeRef']))
270+
$gpsLocation = sprintf(
271+
'%s,%s',
272+
(strtoupper($source['GPSLatitudeRef'][0]) === 'S' ? -1 : 1) * $latitude,
273+
(strtoupper($source['GPSLongitudeRef'][0]) === 'W' ? -1 : 1) * $longitude
272274
);
273-
$gpsLocation['longitude'] = array_merge(
274-
$this->normalizeGPSCoordinate($source['GPSLongitude']),
275-
array(strtoupper($source['GPSLongitudeRef']))
276-
);
277-
278-
if (isset($source['GPSAltitudeRef'])) {
279-
$altitude = $this->normalizeGPSCoordinate(array($source['GPSAltitude']));
280-
281-
$gpsLocation['altitude'] = array($altitude[0], (int) $source['GPSAltitudeRef']);
282-
}
283275
}
284276

285277
return array(
@@ -368,19 +360,28 @@ public function mapData(array $source)
368360
}
369361

370362
/**
371-
* Normalize array GPS coordinates
363+
* Extract GPS coordinates from components array
372364
*
373-
* @param array $coordinates
374-
* @return array
365+
* @param array $components
366+
* @return float
375367
*/
376-
protected function normalizeGPSCoordinate(array $coordinates)
368+
protected function extractGPSCoordinate(array $components)
377369
{
378-
return array_map(
379-
function ($component) {
380-
$parts = explode('/', $component);
381-
return count($parts) === 1 ? $parts[0] : (int) reset($parts) / (int) end($parts);
382-
},
383-
$coordinates
384-
);
370+
$components = array_map(array($this, 'normalizeGPSComponent'), $components);
371+
372+
return intval($components[0]) + (intval($components[1]) / 60) + (floatval($components[2]) / 3600);
373+
}
374+
375+
/**
376+
* Normalize GPS coordinates components
377+
*
378+
* @param mixed $component
379+
* @return int|float
380+
*/
381+
protected function normalizeGPSComponent($component)
382+
{
383+
$parts = explode('/', $component);
384+
385+
return count($parts) === 1 ? $parts[0] : (int) reset($parts) / (int) end($parts);
385386
}
386387
}

lib/PHPExif/Exif.php

Lines changed: 1 addition & 103 deletions
Original file line numberDiff line numberDiff line change
@@ -486,7 +486,7 @@ public function getOrientation()
486486
}
487487

488488
/**
489-
* Returns raw GPS coordinates, if it exists
489+
* Returns GPS coordinates, if it exists
490490
*
491491
* @return array|boolean
492492
*/
@@ -498,106 +498,4 @@ public function getGPS()
498498

499499
return $this->data[self::GPS];
500500
}
501-
502-
/**
503-
* Returns GPS in degrees, minutes and seconds, if it exists
504-
*
505-
* @return string|boolean
506-
*/
507-
public function getGPSDegMinSec()
508-
{
509-
return $this->getFormattedGPS('degrees_minutes_seconds');
510-
}
511-
512-
/**
513-
* Returns GPS in degrees, and decimal minutes, if it exists
514-
*
515-
* @return string|boolean
516-
*/
517-
public function getGPSDecMinutes()
518-
{
519-
return $this->getFormattedGPS('decimal_minutes');
520-
}
521-
522-
/**
523-
* Returns GPS in decimal degrees, if it exists
524-
*
525-
* @return string|boolean
526-
*/
527-
public function getGPSDecDegrees()
528-
{
529-
return $this->getFormattedGPS('decimal_degrees');
530-
}
531-
532-
/**
533-
* Returns formatted GPS coordinates, if it exists
534-
*
535-
* @param string $format
536-
* @return string|boolean
537-
*/
538-
public function getFormattedGPS($format = 'decimal_minutes')
539-
{
540-
if (!isset($this->data[self::GPS]) || $this->data[self::GPS] === false) {
541-
return false;
542-
}
543-
544-
if ($format === 'degrees_minutes_seconds') {
545-
$gps = $this->data[self::GPS];
546-
547-
return sprintf(
548-
'%d° %d\' %s" %s, %d° %d\' %s" %s',
549-
$gps['latitude'][0],
550-
$gps['latitude'][1],
551-
$gps['latitude'][2],
552-
$gps['latitude'][3],
553-
$gps['longitude'][0],
554-
$gps['longitude'][1],
555-
$gps['longitude'][2],
556-
$gps['longitude'][3]
557-
);
558-
}
559-
560-
return $this->getGPSDecimal($format);
561-
}
562-
563-
/**
564-
* Returns decimal formatted GPS coordinates, if it exists
565-
*
566-
* @param string $format
567-
* @return string
568-
* @throws \InvalidArgumentException If the the format is not valid
569-
*/
570-
protected function getGPSDecimal($format)
571-
{
572-
$gps = $this->data[self::GPS];
573-
574-
$latMinutes = $gps['latitude'][1] / 60 + $gps['latitude'][2] / 3600;
575-
$lonMinutes = $gps['longitude'][1] / 60 + $gps['longitude'][2] / 3600;
576-
577-
switch ($format) {
578-
case 'decimal_minutes':
579-
return sprintf(
580-
'%d° %f\' %s, %d° %f\' %s',
581-
$gps['latitude'][0],
582-
$latMinutes,
583-
$gps['latitude'][3],
584-
$gps['longitude'][0],
585-
$lonMinutes,
586-
$gps['longitude'][3]
587-
);
588-
break;
589-
590-
case 'decimal_degrees':
591-
return sprintf(
592-
'%f, %f',
593-
($gps['latitude'][3] === 'S' ? -1 : 1) * ($gps['latitude'][0] + $latMinutes),
594-
($gps['longitude'][3] === 'W' ? -1 : 1) * ($gps['longitude'][0] + $lonMinutes)
595-
);
596-
break;
597-
598-
default:
599-
throw new \InvalidArgumentException(sprintf('GPS format "%s" is not valid', $format));
600-
break;
601-
}
602-
}
603501
}

tests/PHPExif/Adapter/ExiftoolTest.php

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -137,21 +137,14 @@ public function testMapDataCreationDegGPSIsCalculated()
137137
$this->adapter->setNumeric(false);
138138
$result = $this->adapter->mapData(
139139
array(
140-
'GPSLatitudeRef' => 'North',
141140
'GPSLatitude' => '40 deg 20\' 0.42857" N',
142-
'GPSLongitudeRef' => 'West',
141+
'GPSLatitudeRef' => 'North',
143142
'GPSLongitude' => '20 deg 10\' 2.33333" W',
144-
'GPSAltitudeRef' => 'Above Sea Level',
145-
'GPSAltitude' => '1 m Above Sea Level'
143+
'GPSLongitudeRef' => 'West',
146144
)
147145
);
148146

149-
$expected = array(
150-
'latitude' => array(40, 20, 0.42857, 'N'),
151-
'longitude' => array(20, 10, 2.33333, 'W'),
152-
'altitude' => array(1, 0),
153-
);
154-
147+
$expected = '40.333452380556,-20.167314813889';
155148
$this->assertEquals($expected, $result[\PHPExif\Exif::GPS]);
156149
}
157150

@@ -163,21 +156,14 @@ public function testMapDataCreationNumericGPSIsCalculated()
163156
{
164157
$result = $this->adapter->mapData(
165158
array(
166-
'GPSLatitudeRef' => 'North',
167159
'GPSLatitude' => '40.333452381',
168-
'GPSLongitudeRef' => 'West',
160+
'GPSLatitudeRef' => 'North',
169161
'GPSLongitude' => '20.167314814',
170-
'GPSAltitudeRef' => 'Below Sea Level',
171-
'GPSAltitude' => '1 m Above Sea Level'
162+
'GPSLongitudeRef' => 'West',
172163
)
173164
);
174165

175-
$expected = array(
176-
'latitude' => array(40, 20, 0.428572, 'N'),
177-
'longitude' => array(20, 10, 2.33333, 'W'),
178-
'altitude' => array(1, -1),
179-
);
180-
166+
$expected = '40.333452381,-20.167314814';
181167
$this->assertEquals($expected, $result[\PHPExif\Exif::GPS]);
182168
}
183169

tests/PHPExif/Adapter/NativeTest.php

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -328,21 +328,14 @@ public function testMapDataCreationGPSIsCalculated()
328328
{
329329
$result = $this->adapter->mapData(
330330
array(
331-
'GPSLatitudeRef' => 'N',
332331
'GPSLatitude' => array('40/1', '20/1', '15/35'),
333-
'GPSLongitudeRef' => 'W',
332+
'GPSLatitudeRef' => 'N',
334333
'GPSLongitude' => array('20/1', '10/1', '35/15'),
335-
'GPSAltitudeRef' => '\000',
336-
'GPSAltitude' => '1'
334+
'GPSLongitudeRef' => 'W',
337335
)
338336
);
339337

340-
$expected = array(
341-
'latitude' => array(40, 20, 0.42857142857143, 'N'),
342-
'longitude' => array(20, 10, 2.3333333333333, 'W'),
343-
'altitude' => array(1, 0),
344-
);
345-
338+
$expected = '40.333452380952,-20.167314814815';
346339
$this->assertEquals($expected, $result[\PHPExif\Exif::GPS]);
347340
}
348341
}

tests/PHPExif/ExifTest.php

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -449,27 +449,13 @@ public function testGetOrientation()
449449
/**
450450
* @group exif
451451
* @covers \PHPExif\Exif::getGPS
452-
* @covers \PHPExif\Exif::getGPSDegMinSec
453-
* @covers \PHPExif\Exif::getGPSDecMinutes
454-
* @covers \PHPExif\Exif::getGPSDecDegrees
455-
* @expectedException InvalidArgumentException
456452
*/
457453
public function testGetGPS()
458454
{
459-
$expected = array(
460-
'latitude' => array(40, 20, 10, 'N'),
461-
'longitude' => array(10, 5, 1, 'W'),
462-
'altitude' => array(0, 0),
463-
);
455+
$expected = '40.333452380556,-20.167314813889';
464456
$data[\PHPExif\Exif::GPS] = $expected;
465457
$this->exif->setData($data);
466458
$this->assertEquals($expected, $this->exif->getGPS());
467-
468-
$this->assertEquals('40° 20\' 10" N, 10° 5\' 1" W', $this->exif->getGPSDegMinSec());
469-
$this->assertEquals('40° 0.336111\' N, 10° 0.083611\' W', $this->exif->getGPSDecMinutes());
470-
$this->assertEquals('40.336111, -10.083611', $this->exif->getGPSDecDegrees());
471-
472-
$this->exif->getFormattedGPS('unknown_format');
473459
}
474460

475461
/**

0 commit comments

Comments
 (0)