PHP extract GPS EXIF data

匿名 (未验证) 提交于 2019-12-03 02:13:02

问题:

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 !

回答1:

According to http://en.wikipedia.org/wiki/Geotagging, ( [0] => 46/1 [1] => 5403/100 [2] => 0/1 ) should mean 46/1 degrees, 5403/100 minutes, 0/1 seconds, i.e. 46°54.03′0〃N. Normalizing the seconds gives 46°54′1.8〃N.

This code below should work, as long as you don't get negative coordinates (given that you get N/S and E/W as a separate coordinate, you shouldn't ever have negative coordinates). Let me know if there is a bug (I don't have a PHP environment handy at the moment).

//Pass in GPS.GPSLatitude or GPS.GPSLongitude or something in that format function getGps($exifCoord) {   $degrees = count($exifCoord) > 0 ? gps2Num($exifCoord[0]) : 0;   $minutes = count($exifCoord) > 1 ? gps2Num($exifCoord[1]) : 0;   $seconds = count($exifCoord) > 2 ? gps2Num($exifCoord[2]) : 0;    //normalize   $minutes += 60 * ($degrees - floor($degrees));   $degrees = floor($degrees);    $seconds += 60 * ($minutes - floor($minutes));   $minutes = floor($minutes);    //extra normalization, probably not necessary unless you get weird data   if($seconds >= 60)   {     $minutes += floor($seconds/60.0);     $seconds -= 60*floor($seconds/60.0);   }    if($minutes >= 60)   {     $degrees += floor($minutes/60.0);     $minutes -= 60*floor($minutes/60.0);   }    return array('degrees' => $degrees, 'minutes' => $minutes, 'seconds' => $seconds); }  function gps2Num($coordPart) {   $parts = explode('/', $coordPart);    if(count($parts) <= 0)// jic     return 0;   if(count($parts) == 1)     return $parts[0];    return floatval($parts[0]) / floatval($parts[1]); }


回答2:

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]); }


回答3:

This is a refactored version of Gerald Kaszuba's code (currently the most widely accepted answer). The result should be identical, but I've made several micro-optimizations and combined the two separate functions into one. In my benchmark testing, this version shaved about 5 microseconds off the runtime, which is probably negligible for most applications, but might be useful for applications which involve a large number of repeated calculations.

$exif = exif_read_data($filename); $latitude = gps($exif["GPSLatitude"], $exif['GPSLatitudeRef']); $longitude = gps($exif["GPSLongitude"], $exif['GPSLongitudeRef']);  function gps($coordinate, $hemisphere) {   if (is_string($coordinate)) {     $coordinate = array_map("trim", explode(",", $coordinate));   }   for ($i = 0; $i < 3; $i++) {     $part = explode('/', $coordinate[$i]);     if (count($part) == 1) {       $coordinate[$i] = $part[0];     } else if (count($part) == 2) {       $coordinate[$i] = floatval($part[0])/floatval($part[1]);     } else {       $coordinate[$i] = 0;     }   }   list($degrees, $minutes, $seconds) = $coordinate;   $sign = ($hemisphere == 'W' || $hemisphere == 'S') ? -1 : 1;   return $sign * ($degrees + $minutes/60 + $seconds/3600); }


回答4:

I know this question has been asked a long time ago, but I came across it while searching in google and the solutions proposed here did not worked for me. So, after further searching, here is what worked for me.

I'm putting it here so that anybody who comes here through some googling, can find different approaches to solve the same problem:

function triphoto_getGPS($fileName, $assoc = false) {     //get the EXIF     $exif = exif_read_data($fileName);      //get the Hemisphere multiplier     $LatM = 1; $LongM = 1;     if($exif["GPSLatitudeRef"] == 'S')     {     $LatM = -1;     }     if($exif["GPSLongitudeRef"] == 'W')     {     $LongM = -1;     }      //get the GPS data     $gps['LatDegree']=$exif["GPSLatitude"][0];     $gps['LatMinute']=$exif["GPSLatitude"][1];     $gps['LatgSeconds']=$exif["GPSLatitude"][2];     $gps['LongDegree']=$exif["GPSLongitude"][0];     $gps['LongMinute']=$exif["GPSLongitude"][1];     $gps['LongSeconds']=$exif["GPSLongitude"][2];      //convert strings to numbers     foreach($gps as $key => $value)     {     $pos = strpos($value, '/');     if($pos !== false)     {         $temp = explode('/',$value);         $gps[$key] = $temp[0] / $temp[1];     }     }      //calculate the decimal degree     $result['latitude'] = $LatM * ($gps['LatDegree'] + ($gps['LatMinute'] / 60) + ($gps['LatgSeconds'] / 3600));     $result['longitude'] = $LongM * ($gps['LongDegree'] + ($gps['LongMinute'] / 60) + ($gps['LongSeconds'] / 3600));      if($assoc)     {     return $result;     }      return json_encode($result); }


回答5:

The code I've used in the past is something like (in reality, it also checks that the data is vaguely valid):

// Latitude $northing = -1; if( $gpsblock['GPSLatitudeRef'] && 'N' == $gpsblock['GPSLatitudeRef'] ) {     $northing = 1; }  $northing *= defraction( $gpsblock['GPSLatitude'][0] ) + ( defraction($gpsblock['GPSLatitude'][1] ) / 60 ) + ( defraction( $gpsblock['GPSLatitude'][2] ) / 3600 );  // Longitude $easting = -1; if( $gpsblock['GPSLongitudeRef'] && 'E' == $gpsblock['GPSLongitudeRef'] ) {     $easting = 1; }  $easting *= defraction( $gpsblock['GPSLongitude'][0] ) + ( defraction( $gpsblock['GPSLongitude'][1] ) / 60 ) + ( defraction( $gpsblock['GPSLongitude'][2] ) / 3600 );

Where you also have:

function defraction( $fraction ) {     list( $nominator, $denominator ) = explode( "/", $fraction );      if( $denominator )     {         return ( $nominator / $denominator );     }     else     {         return $fraction;     } }


回答6:

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];


回答7:

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]); }


回答8:

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.



回答9:

This is a javascript port of the PHP-code posted @Gerald above. This way you can figure out the location of an image without ever uploading the image, in conjunction with libraries like dropzone.js and Javascript-Load-Image

define(function(){      function parseExif(map) {         var gps = {             lng : getGps(map.get('GPSLongitude'), data.get('GPSLongitudeRef')),             lat : getGps(map.get('GPSLatitude'), data.get('GPSLatitudeRef'))         }         return gps;     }      function getGps(exifCoord, hemi) {         var degrees = exifCoord.length > 0 ? parseFloat(gps2Num(exifCoord[0])) : 0,             minutes = exifCoord.length > 1 ? parseFloat(gps2Num(exifCoord[1])) : 0,             seconds = exifCoord.length > 2 ? parseFloat(gps2Num(exifCoord[2])) : 0,             flip = (/w|s/i.test(hemi)) ? -1 : 1;         return flip * (degrees + (minutes / 60) + (seconds / 3600));     }      function gps2Num(coordPart) {         var parts = (""+coordPart).split('/');         if (parts.length <= 0) {             return 0;         }         if (parts.length === 1) {             return parts[0];         }         return parts[0] / parts[1];     }             return {         parseExif: parseExif     };  });


回答10:

short story. First part N Leave the grade multiply the minutes with 60 devide the seconds with 100. count the grades,minuts and seconds with eachother.



回答11:

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:

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!