PHP提取GPS EXIF数据

我想从使用php的图片中提取GPS EXIF标签。 我使用exif_read_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 

我不知道如何解释46/1 5403/100和0/1? 46可能是46°,但其余的尤其是0/1呢?

 angle/1 5403/100 0/1 

这个结构是什么?

如何将它们转换成“标准”(如来自wikipedia的46°56'48“N 7°26'39”E)? 我想通过坐标到谷歌地图API来显示在地图上的图片位置!

根据http://en.wikipedia.org/wiki/Geotagging,(%5B0 ( [0] => 46/1 [1] => 5403/100 [2] => 0/1 )应该是46/1度,5403 / 100分钟,0/1秒,即46°54.03'0“N。 正常化的秒数为46°54'1.8“N。

下面的代码应该工作,只要你没有得到负坐标(假设你得到N / S和E / W作为一个单独的坐标,你不应该有负坐标)。 让我知道是否有一个错误(我目前没有PHP的环境方便)。

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

这是我的修改版本。 其他的没有为我工作。 它会给你的GPS坐标的十进制版本。

处理EXIF数据的代码:

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

打印出这种格式:

 float(-33.8751666667) float(151.207166667) 

这里是function:

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

这是Gerald Kaszuba的代码的重构版本(目前被广泛接受的答案)。 结果应该是一样的,但我已经做了几个微观优化,并将两个独立的function合并为一个。 在我的基准testing中,这个版本的运行时间大约减less了5微秒,这对大多数应用来说可能是微不足道的,但是对于涉及大量重复计算的应用来说可能是有用的。

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

我知道这个问题已经被很久以前问过了,但是我在谷歌search中遇到了这个问题,这里提出的解决scheme并没有为我工作。 所以,经过进一步的search,这里是我的工作。

我把它放在这里,以便任何通过Googlesearch来到这里的人都能find不同的方法来解决同样的问题:

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

我过去使用的代码就像(实际上,它也检查数据是否有效):

 // 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 ); 

你也有:

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

要获得高度值,可以使用以下3行:

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

如果你需要一个函数来读取Imagick Exif中的坐标,我们希望它能节省你的时间。 在PHP 7下testing

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

我正在使用Gerald Kaszuba的修改版本,但并不准确。 所以我改变一下公式

从:

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

变成:

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

这个对我有用。

这是上面提到的@Gerald的PHP代码的JavaScript端口。 通过这种方式,您可以在不需要上传图像的情况下查找图像的位置,以及像dropzone.js和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 }; }); 

短篇故事。 第一部分N等分乘以60的分数与100分秒。用相互的数值来计数等级,分数和秒数。

第二部分E分数乘以60分钟分秒… … 1000分钟的成绩,分钟和秒钟彼此

我看到没有人提到这个: 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 ) 

现在使用Coordonates物品,你可以做你想要的:例如:

(如维基百科46°56'48“N 7°26'39”E)

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

你必须从ascii转换,而你已经完成:

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

并比打印示例:

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

有了这个GPS数据:

  ["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" } 

使用上面的代码(谢谢杰拉尔德)我得到这些纬度和经度值:

 -392.31537456069,-0.023678137550796 

这是不正确的。 在代码工作的时候,它正在做我的头脑,但是在这种情况下答案是错误的! 许多其他图像工作正常,似乎有一些逻辑缺失,以满足这个数据中的东西。 例如,当我将图像加载到iPhoto(抱歉苹果示例为那些没有Mac的人)时,得到的答案是正确的; 这EXIF数据是在红海附近的图片。