PHP EXIF ​​Raw Data

I would like to extract GPS EXIF ​​tag from images using php. I use exif_read_data() , which returns an 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 do not know how to interpret 46/1 5403/100 and 0/1? 46 can 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" (for example, 46 ° 56'48 "N 7 ° 26'39" E from Wikipedia)? I would like to transfer thoses coordinates to google maps api to display the position of images on a map!

+44
php metadata exif gps
Mar 26 '10 at 19:53
source share
12 answers

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 seconds gives 46 ° 54'1.8" N.

This code below should work until you get negative coordinates (given that you get N / S and E / W as a separate coordinate, you should never have negative coordinates). Let me know if there is an error (at the moment I do not have a PHP environment).

 //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]); } 
+18
Mar 26 '10 at 20:11
source share

This is my modified version. Others did not work for me. It will give you decimal versions of GPS coordinates.

Code for EXIF ​​data processing:

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

Printed 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]); } 
+77
Apr 03 '10 at 23:11
source share

This is a reorganized version of Gerald Kashuba's code (currently the most widely accepted answer). The result should be identical, but I made several micro-optimizations and combined two separate functions into one. In my test testing, this version shaved off about 5 microseconds from the runtime, which is probably insignificant for most applications, but may be useful for applications that involve a large number of recalculations.

 $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); } 
+13
May 08 '13 at 10:05
source share

I know this question was asked a long time ago, but I ran into it during a google search, and the solutions offered here did not work for me. So, after further searching, here is what worked for me.

I put it here so that anyone who comes here through some kind of search engine can find different approaches to solving 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
Nov 14 '10 at 18:10
source share

The code I used in the past is something like (in fact, 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; } } 
+1
Mar 26
source share

To get the height 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]; 
+1
May 10 '16 at 9:38
source share

If you need a function to read coordinates from Imagick Exif, we will go, I hope this 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]); } 
+1
Aug 6 '16 at 8:24
source share

I am using a modified version of Gerald Kaszuba, but this is not accurate. so I'm changing the formula a little bit.

from

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

changed to:

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

This works for me.

0
Oct 27 '10 at 8:43
source share

This is the javascript port of the PHP code published by @Gerald above. This way you can determine the location of the image without loading the image, in combination with libraries such as 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 }; }); 
0
Jun 25 '14 at 14:14
source share

story. The first part of N Leave a score, multiply the minutes by 60, divide the seconds by 100. Count the grades, minutes and seconds with each other.

The second part of E Leave a score, multiply the minutes by 60, divide the seconds by ... 1000 read the ratings, minutes and seconds with each other.

0
Feb 24 '15 at 21:31
source share

I saw that no one 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 Coordinates object, you can do what you want: Example:

(e.g. 46 ° 56'48 "N 7 ° 26'39" E from Wikipedia)

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

What you need to convert from ascii, and you did:

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

and than print example:

 print "Latitude:" + Latitude.to_string('d%°%m%′%S%″%H')[0].decode('utf8') >> Latitude: 5°5259.88″N 
0
Dec 22 '16 at 21:00
source share

Using GPS data:

  ["GPSLatitudeRef"]=> string(1) "N" ["GPSLatitude"]=> array(3) { [0]=> string(7) "65539/0" [1]=> string(17) "-1542717440/65539" [2]=> string(8) "196608/0" } ["GPSLongitudeRef"]=> string(1) "E" ["GPSLongitude"]=> array(3) { [0]=> string(20) "39321600/-1166016512" [1]=> string(21) "1111490956/1811939343" [2]=> string(22) "1111491292/-1725956081" } 

Using the code above (thanks to Gerald), I get these latitude and longitude values:

 -392.31537456069,-0.023678137550796 

This is not true. It makes my head since the code works, but the answer is incorrect in this case! Many other images work fine, it seems that some logic is missing to satisfy something in this. For example, when I upload an image to iPhoto (sorry for the Apple example without Mac computers), it gets the answer correctly; This EXIF ​​data is for images near the Red Sea.

-one
Aug 16 '13 at 10:40
source share



All Articles