53 votes

PHP extraire les données GPS EXIF

Je voudrais extraire la balise GPS EXIF des photos en utilisant php. Je utilise le exif_read_data() qui retourne un tableau de toutes les balises + 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 coordonnées "standard" (comme 46°5648N 7°2639E de wikipedia) ? Je voudrais transmettre ces coordonnées à l'API google maps pour afficher les positions des photos sur une carte !

1 votes

@Kami: J'ai mis à jour ma réponse avec un peu de code

94voto

Gerald Kaszuba Points 9769

Ceci est ma version modifiée. Les autres n'ont pas fonctionné pour moi. Cela 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]);
}

3 votes

J'ai trouvé que les dernières versions de PHP ont une couche supplémentaire de tableau dans l'objet exif qui nécessite de les appeler comme suit : getGps($exif['GPS']["GPSLongitude"], $exif['GPS']['GPSLongitudeRef'])

0 votes

@OrbitingEden Ce comportement est activé par 3ème paramètre. Désactivé par défaut.

27voto

David Points 2158

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 apporté plusieurs micro-optimisations et combiné les deux fonctions séparées en une seule. Dans mes tests de benchmark, 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 pourrait être utile pour les applications impliquant 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);
}

0 votes

Cccceeeccciiii. J'ai été aveuglément copier-coller des extraits de code PHP exif de Stack overflow depuis des jours maintenant sans faire de recherche par moi-même. (vraiment) Et ils allaient de légèrement incorrects à vraiment vraiment incorrects. Produisant des degrés variables de données incorrectes. CELUI-CI FONCTIONNE. La seule chose que j'ai FAITE était de vérifier la sortie par rapport à des sources connues et fiables. Et celui-ci est à 100% correct. 10/10 copierait à nouveau.

0 votes

Merci David (et Gerald). Votre modification est de loin la plus précise et fonctionne à 100% dès le départ. La seule chose que je voudrais souligner est qu'exif_read_data() retourne maintenant les résultats sous la forme de $exif['GPS']['GPSLatitude'] - donc vous devrez peut-être modifier un peu votre code d'appel.

23voto

Kip Points 37013

Selon http://en.wikipedia.org/wiki/Geotagging, ( [0] => 46/1 [1] => 5403/100 [2] => 0/1 ) devrait signifier 46/1 degré, 5403/100 minutes, 0/1 secondes, c'est-à-dire 46°54.03′0″N. En normalisant les secondes, cela donne 46°54′1.8″N.

Le 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/O comme une coordonnée séparée, vous ne devriez jamais avoir de coordonnées négatives). Faites-moi savoir s'il y a un bug (Je n'ai pas actuellement d'environnement PHP à portée de main).

//Passer en paramètre GPS.GPSLatitude ou GPS.GPSLongitude ou quelque chose dans ce 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;

  //normalisation
  $minutes += 60 * ($degrees - floor($degrees));
  $degrees = floor($degrees);

  $seconds += 60 * ($minutes - floor($minutes));
  $minutes = floor($minutes);

  //normalisation supplémentaire, probablement pas nécessaire sauf si vous obtenez des données étranges
  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('degrés' => $degrees, 'minutes' => $minutes, 'secondes' => $seconds);
}

function gps2Num($coordPart)
{
  $parts = explode('/', $coordPart);

  if(count($parts) <= 0)// au cas où
    return 0;
  if(count($parts) == 1)
    return $parts[0];

  return floatval($parts[0]) / floatval($parts[1]);
}

5voto

Hassan Al-Jeshi Points 300

Je sais que cette question a été posée il y a longtemps, mais je suis tombé dessus en cherchant sur Google et les solutions proposées ici n'ont pas fonctionné pour moi. Donc, après des recherches supplémentaires, voici ce qui a fonctionné pour moi.

Je le mets ici pour que toute personne qui arrive ici en faisant une recherche sur Google puisse trouver différentes approches pour résoudre le même problème :

function triphoto_getGPS($fileName, $assoc = false)
{
    //obtenir les données EXIF
    $exif = exif_read_data($fileName);

    //obtenir le multiplicateur de l'hémisphère
    $LatM = 1; $LongM = 1;
    if($exif["GPSLatitudeRef"] == 'S')
    {
    $LatM = -1;
    }
    if($exif["GPSLongitudeRef"] == 'W')
    {
    $LongM = -1;
    }

    //obtenir les données GPS
    $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];

    //convertir les chaînes de caractères en nombres
    foreach($gps as $key => $value)
    {
    $pos = strpos($value, '/');
    if($pos !== false)
    {
        $temp = explode('/',$value);
        $gps[$key] = $temp[0] / $temp[1];
    }
    }

    //calculer le degré décimal
    $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);
}

0 votes

J'ai utilisé cette réponse et c'était génial! N'oubliez pas, le nouveau PHP fait en sorte que le tableau exif ait sa propre clé pour le GPS. Par exemple $gps['LatDegree']=$exif["GPSLatitude"][0]; devient $gps['LatDegree']=$exif["GPS"]["GPSLatitude"][0];

1 votes

Cette solution a fonctionné pour moi, et j'ai transformé cette réponse en un package composer - avec quelques modifications. Vous pouvez le trouver ici : github.com/diversen/gps-from-exif

2voto

Rowland Shaw Points 22860

Le code que j'ai utilisé dans le passé est quelque chose comme (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 également :

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

    if( $denominator )
    {
        return ( $nominator / $denominator );
    }
    else
    {
        return $fraction;
    }
}

0 votes

Avez-vous une idée de pourquoi cela a été downvoté? J'aimerais pouvoir corriger mon code si nécessaire.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X