PHP extract GPS EXIF data

2019-01-10 00:22发布

I would like to extract the GPS EXIF tag from pictures using php. I'm using the exif_read_data() that returns a array of all tags + data :

GPS.GPSLatitudeRef: N
GPS.GPSLatitude:Array ( [0] => 46/1 [1] => 5403/100 [2] => 0/1 ) 
GPS.GPSLongitudeRef: E
GPS.GPSLongitude:Array ( [0] => 7/1 [1] => 880/100 [2] => 0/1 ) 
GPS.GPSAltitudeRef: 
GPS.GPSAltitude: 634/1

I don't know how to interpret 46/1 5403/100 and 0/1 ? 46 might be 46° but what about the rest especially 0/1 ?

angle/1 5403/100 0/1

What is this structure about ?

How to convert them to "standard" ones (like 46°56′48″N 7°26′39″E from wikipedia) ? I would like to pass thoses coordinates to the google maps api to display the pictures positions on a map !

13条回答
萌系小妹纸
2楼-- · 2019-01-10 01:10

To get the altitude value, you can use the following 3 lines:

$data     = exif_read_data($path_to_your_photo, 0, TRUE);
$alt      = explode('/', $data["GPS"]["GPSAltitude"]);
$altitude = (isset($alt[1])) ? ($alt[0] / $alt[1]) : $alt[0];
查看更多
在下西门庆
3楼-- · 2019-01-10 01:12

I'm using the modified version from Gerald Kaszuba but it's not accurate. so i change the formula a bit.

from:

return $flip * ($degrees + $minutes / 60);

changed to:

return floatval($flip * ($degrees +($minutes/60)+($seconds/3600)));

It works for me.

查看更多
倾城 Initia
4楼-- · 2019-01-10 01:16

This is an old question but felt it could use a more eloquent solution (OOP approach and lambda to process the fractional parts)

/**
 * Example coordinate values
 *
 * Latitude - 49/1, 4/1, 2881/100, N
 * Longitude - 121/1, 58/1, 4768/100, W
 */
protected function _toDecimal($deg, $min, $sec, $ref) {

    $float = function($v) {
        return (count($v = explode('/', $v)) > 1) ? $v[0] / $v[1] : $v[0];
    };

    $d = $float($deg) + (($float($min) / 60) + ($float($sec) / 3600));
    return ($ref == 'S' || $ref == 'W') ? $d *= -1 : $d;
}


public function getCoordinates() {

    $exif = @exif_read_data('image_with_exif_data.jpeg');

    $coord = (isset($exif['GPSLatitude'], $exif['GPSLongitude'])) ? implode(',', array(
        'latitude' => sprintf('%.6f', $this->_toDecimal($exif['GPSLatitude'][0], $exif['GPSLatitude'][1], $exif['GPSLatitude'][2], $exif['GPSLatitudeRef'])),
        'longitude' => sprintf('%.6f', $this->_toDecimal($exif['GPSLongitude'][0], $exif['GPSLongitude'][1], $exif['GPSLongitude'][2], $exif['GPSLongitudeRef']))
    )) : null;

}
查看更多
爱情/是我丢掉的垃圾
5楼-- · 2019-01-10 01:19

In case you need a function to read Coordinates from Imagick Exif here we go, I hope it saves you time. Tested under PHP 7.

function create_gps_imagick($coordinate, $hemi) {

  $exifCoord = explode(', ', $coordinate);

  $degrees = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
  $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0;
  $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0;

  $flip = ($hemi == 'W' or $hemi == 'S') ? -1 : 1;

  return $flip * ($degrees + $minutes / 60 + $seconds / 3600);

}

function gps2Num($coordPart) {

    $parts = explode('/', $coordPart);

    if (count($parts) <= 0)
        return 0;

    if (count($parts) == 1)
        return $parts[0];

    return floatval($parts[0]) / floatval($parts[1]);
}
查看更多
可以哭但决不认输i
6楼-- · 2019-01-10 01:19

i have seen nobody mentioned this: https://pypi.python.org/pypi/LatLon/1.0.2

from fractions import Fraction
from LatLon import LatLon, Longitude, Latitude

latSigned = GPS.GPSLatitudeRef == "N" ? 1 : -1
longSigned = GPS.GPSLongitudeRef == "E" ? 1 : -1

latitudeObj = Latitude(
              degree = float(Fraction(GPS.GPSLatitude[0]))*latSigned , 
              minute = float(Fraction(GPS.GPSLatitude[0]))*latSigned , 
              second = float(Fraction(GPS.GPSLatitude[0])*latSigned)
longitudeObj = Latitude(
              degree = float(Fraction(GPS.GPSLongitude[0]))*longSigned , 
              minute = float(Fraction(GPS.GPSLongitude[0]))*longSigned , 
              second = float(Fraction(GPS.GPSLongitude[0])*longSigned )
Coordonates = LatLon(latitudeObj, longitudeObj )

now using the Coordonates objecct you can do what you want: Example:

(like 46°56′48″N 7°26′39″E from wikipedia)

print Coordonates.to_string('d%°%m%′%S%″%H')

You than have to convert from ascii, and you are done:

('5\xc2\xb052\xe2\x80\xb259.88\xe2\x80\xb3N', '162\xc2\xb04\xe2\x80\xb259.88\xe2\x80\xb3W')

and than printing example:

print "Latitude:" + Latitude.to_string('d%°%m%′%S%″%H')[0].decode('utf8')

>> Latitude: 5°52′59.88″N
查看更多
Fickle 薄情
7楼-- · 2019-01-10 01:23

This is my modified version. The other ones didn't work for me. It will give you the decimal versions of the GPS coordinates.

The code to process the EXIF data:

$exif = exif_read_data($filename);
$lon = getGps($exif["GPSLongitude"], $exif['GPSLongitudeRef']);
$lat = getGps($exif["GPSLatitude"], $exif['GPSLatitudeRef']);
var_dump($lat, $lon);

Prints out in this format:

float(-33.8751666667)
float(151.207166667)

Here are the functions:

function getGps($exifCoord, $hemi) {

    $degrees = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;
    $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0;
    $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0;

    $flip = ($hemi == 'W' or $hemi == 'S') ? -1 : 1;

    return $flip * ($degrees + $minutes / 60 + $seconds / 3600);

}

function gps2Num($coordPart) {

    $parts = explode('/', $coordPart);

    if (count($parts) <= 0)
        return 0;

    if (count($parts) == 1)
        return $parts[0];

    return floatval($parts[0]) / floatval($parts[1]);
}
查看更多
登录 后发表回答