Je voudrais extraire le tag GPS EXIF à partir d'images en utilisant php . J'utilise le exif_read_data()
qui renvoie un tableau contenant tous les tags + données
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
Je ne sais pas comment interpréter 46/1 5403/100 et 0/1? 46 pourrait être 46 ° mais qu'en est-il du reste surtout 0/1?
angle/1 5403/100 0/1
De quoi parle cette structure?
Comment les convertir en "standards" (46 ° 56′48 ″ N 7 ° 26′39 ″ E de wikipedia, par exemple)? J'aimerais transmettre ces coordonnées à l'API Google Maps pour afficher les positions des images sur une carte!
Selon http://en.wikipedia.org/wiki/Geotagging , ( [0] => 46/1 [1] => 5403/100 [2] => 0/1 )
devrait signifier 46/1 degrés, 5403/100 minutes, 0/1 secondes, soit 46 ° 54.03′0 ″ N. La normalisation des secondes donne 46 ° 54′1.8 ″ N.
Ce code ci-dessous devrait fonctionner tant que vous n'obtenez pas de coordonnées négatives (étant donné que vous obtenez N/S et E/W en tant que coordonnées séparées, vous ne devriez jamais avoir de coordonnées négatives). Faites-moi savoir s'il y a un bogue (je n'ai pas d'environnement PHP à portée de main pour le 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]);
}
Ceci est ma version modifiée. Les autres n'ont pas fonctionné pour moi. Il vous donnera les versions décimales des coordonnées GPS.
Le code pour traiter les données EXIF:
$exif = exif_read_data($filename);
$lon = getGps($exif["GPSLongitude"], $exif['GPSLongitudeRef']);
$lat = getGps($exif["GPSLatitude"], $exif['GPSLatitudeRef']);
var_dump($lat, $lon);
Imprime dans ce format:
float(-33.8751666667)
float(151.207166667)
Voici les fonctions:
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]);
}
Ceci est une version refactorisée du code de Gerald Kaszuba (actuellement la réponse la plus largement acceptée). Le résultat devrait être identique, mais j'ai effectué plusieurs micro-optimisations et combiné les deux fonctions distinctes en une. Lors de mes tests d'évaluation, cette version a réduit d'environ 5 microsecondes le temps d'exécution, ce qui est probablement négligeable pour la plupart des applications, mais peut être utile pour les applications qui impliquent un grand nombre de calculs répétés.
$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);
}
Je sais que cette question a été posée il y a longtemps, mais je l'ai trouvée lors d'une recherche dans google et les solutions proposées ici n'ont pas fonctionné pour moi. Donc, après plus de recherches, voici ce qui a fonctionné pour moi.
Je le mets ici pour que quiconque vient ici par google, puisse trouver différentes approches pour résoudre le même problème:
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);
}
C'est une vieille question, mais elle a estimé qu'une solution plus éloquente pourrait être utilisée (approche OOP et lambda pour traiter les fractions).
/**
* 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;
}
Le code que j'ai utilisé par le passé ressemble à quelque chose du genre (en réalité, il vérifie également que les données sont vaguement valides):
// 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 );
Où vous avez aussi:
function defraction( $fraction )
{
list( $nominator, $denominator ) = explode( "/", $fraction );
if( $denominator )
{
return ( $nominator / $denominator );
}
else
{
return $fraction;
}
}
Pour obtenir la valeur d'altitude, vous pouvez utiliser les 3 lignes suivantes:
$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];
Au cas où vous auriez besoin d’une fonction pour lire les coordonnées d’Imagick Exif, nous espérons que cela vous fera gagner du temps. Testé sous 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]);
}
j'ai vu personne ne l'a mentionné: 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 )
maintenant, en utilisant l’objet Coordonates, vous pouvez faire ce que vous voulez: Exemple:
(comme 46 ° 56′48 ″ N 7 ° 26′39 ″ E de wikipedia)
print Coordonates.to_string('d%°%m%′%S%″%H')
Vous devez ensuite convertir d'asci et vous avez terminé:
('5\xc2\xb052\xe2\x80\xb259.88\xe2\x80\xb3N', '162\xc2\xb04\xe2\x80\xb259.88\xe2\x80\xb3W')
et que l'impression exemple:
print "Latitude:" + Latitude.to_string('d%°%m%′%S%″%H')[0].decode('utf8')
>> Latitude: 5°52′59.88″N
J'utilise la version modifiée de Gerald Kaszuba mais elle n'est pas précise .. donc je change un peu la formule.
de:
return $flip * ($degrees + $minutes / 60);
changé en:
return floatval($flip * ($degrees +($minutes/60)+($seconds/3600)));
Ça marche pour moi.
histoire courte . Première partie N Quitter la note multiplier les minutes par 60 diviser les secondes par 100 .. compter les notes, minutes et secondes les unes avec les autres.
Deuxième partie E Laisser la note Multiplier les minutes par 60 Diviser les secondes avec ... 1000 Appeler les notes, les minutes et les secondes les unes avec les autres
Ceci est un port javascript du code PHP affiché par @Gerald ci-dessus. De cette façon, vous pouvez déterminer l'emplacement d'une image sans la télécharger, en association avec des bibliothèques comme dropzone.js et 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
};
});