2010-03-26 13 views
45

Vorrei estrarre il tag GPS EXIF ​​dalle immagini utilizzando php. Sto utilizzando il exif_read_data() che restituisce un array di tutti i tag + dati:Estratto PHP Dati GPS EXIF ​​

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 

non so come interpretare 46/1 5403/100 e 0/1? 46 potrebbe essere 46 ° ma per quanto riguarda il resto in particolare 0/1?

angle/1 5403/100 0/1 

Di cosa tratta questa struttura?

Come convertirli in "standard" (come 46 ° 56'48 "N 7 ° 26'39" E da wikipedia)? Vorrei passare queste coordinate alla API di google maps per visualizzare le posizioni delle immagini su una mappa!

+1

@Kami: Ho aggiornato la mia risposta con un codice – Kip

risposta

18

Secondo http://en.wikipedia.org/wiki/Geotagging, ([0] => 46/1 [1] => 5403/100 [2] => 0/1) dovrebbe significare 46/1 gradi, 5403/100 minuti, 0/1 secondi, cioè 46 ° 54.03'0 "N. Normalizzare i secondi dà 46 ° 54'1.8 "N.

Questo codice di seguito dovrebbe funzionare, purché non si ottengano coordinate negative (dato che si ottengono N/S ed E/O come coordinate separate, non si dovrebbero mai avere coordinate negative). Fammi sapere se c'è un bug (non ho un ambiente PHP a portata di mano al momento).

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

Il codice che ho usato in passato è qualcosa di simile (in realtà, controlla anche che i dati sono vagamente valido):

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

Dove hai anche:

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

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

Qualsiasi idea del perché questo ha downvoted? Mi piacerebbe essere in grado di correggere il mio codice, se necessario. –

77

Questa è la mia versione modificata. Gli altri non hanno funzionato per me. Vi darà le versioni decimali delle coordinate GPS.

Il codice per elaborare i dati EXIF:

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

Stampe in questo formato:

float(-33.8751666667) 
float(151.207166667) 

Qui ci sono le funzioni:

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

Ho scoperto che le ultime versioni di PHP hanno un ulteriore livello di array nell'oggetto exif che richiede che vengano chiamate come: getGps ($ exif ['GPS'] ["GPSLongitude"], $ exif ['GPS'] [' GPSLongitudeRef ']) –

+0

@OrbitingEden Questo comportamento è abilitato dal 3 ° parametro. Disabilitato per impostazione predefinita. –

0

sto usando il modificati versione da Gerald Kaszuba ma non è accurata. quindi cambio leggermente la formula.

da:

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

cambiato a:

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

Funziona per me.

5

So che questa domanda è stata posta molto tempo fa, ma l'ho trovata durante la ricerca su google e le soluzioni proposte qui non hanno funzionato per me. Quindi, dopo ulteriori ricerche, ecco cosa ha funzionato per me.

sto mettendo qui in modo che chiunque viene qui per un po 'googling, può trovare diversi approcci per risolvere lo stesso problema:

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

Ho usato questa risposta ed è stato fantastico! Ricorda, il nuovo PHP rende l'array exif in modo che il GPS abbia la sua chiave. EG '$ gps ['LatDegree'] = $ exif [" GPSLatitude "] [0];' diventa '$ gps ['LatDegree'] = $ exif [" GPS "] [" GPSLatitude "] [0];' –

+1

Questa soluzione ha funzionato per me, e ho fatto questa risposta in un pacchetto di compositore - con alcune modifiche. Puoi trovarlo qui: https://github.com/diversen/gps-from-exif – dennis

14

Questa è una versione refactoring del codice di Gerald Kaszuba (attualmente il più risposta ampiamente accettata). Il risultato dovrebbe essere identico, ma ho realizzato diverse micro-ottimizzazioni e combinato le due funzioni separate in una sola. Nei miei test di benchmark, questa versione rasava circa 5 microsecondi dal runtime, che è probabilmente trascurabile per la maggior parte delle applicazioni, ma potrebbe essere utile per applicazioni che implicano un numero elevato di calcoli ripetuti.

$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

tthhiiisss. Sono stato copiato ciecamente e incollando frammenti di codice exif PHP da Stack Overflow per giorni senza fare alcuna ricerca personale. (_really_) E hanno tutti variato da qualcosa di sbagliato a veramente veramente sbagliato. Produrre diversi gradi di dati errati. * QUESTO FUNZIONA. * L'unica cosa che ho fatto è stata verificare l'output contro il bene conosciuto. E questo è corretto al 100%. 10/10 copierà di nuovo la pasta. – Adam

-1

Con questi dati 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" 
    } 

Utilizzando il codice di cui sopra (grazie Gerald) ottengo questi Latitudine Longitudine & valori:

-392.31537456069,-0.023678137550796 

Questo non è corretto. Sta facendo la mia testa mentre il codice funziona, ma la risposta è sbagliata in questo caso! Molte altre immagini funzionano bene, sembra esserci qualche logica mancante per soddisfare qualcosa in questo dat. Ad esempio, quando carico l'immagine in iPhoto (mi spiace per l'esempio di Apple per quelli senza Mac) ottiene la risposta giusta; questo dato EXIF ​​è per una foto vicino al Mar Rosso.

+1

Ancora non riesci ad arrivare in fondo a questo. Ma c'è qualcosa nel fatto che la seconda metà di 'GPSLatitude [0]' è 0? Forse una divisione per zero problema? – Pete

0

Questa è una porta javascript del codice PHP pubblicato sopra @Gerald. In questo modo si può capire la posizione di un'immagine senza mai caricando l'immagine, in collaborazione con le biblioteche come dropzone.js e 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

racconto. Prima parte N Lasciare il grado moltiplicare i minuti con 60 dividere i secondi con 100. contare i gradi, i minuti ei secondi l'uno con l'altro.

Seconda parte E Lascia il grado moltiplicano i minuti con il 60 devide i secondi con ... 1000 contare i gradi, i minuti ei secondi con l'altro

1

Per ottenere il valore di altitudine, è possibile utilizzare i seguenti 3 linee:

$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

in caso di necessità di una funzione per leggere le coordinate da Imagick Exif qui andiamo, spero che consente di risparmiare tempo. Testato sotto 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]); 
} 
0

ho visto nessuno ha menzionato questo: 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) 

ora utilizzando i Coordonates objecct si può fare quello che vuoi: Esempio:

(come 46 ° 56'48 "N 7 ° 26'39 "E da wikipedia)

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

È necessario convocare ERT da ASCII, e si è fatto:

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

e di esempio la stampa:

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

>> Latitude: 5°52′59.88″N 
+2

Sì, perché questa è una risposta python su una domanda php – CodeBrauer

+0

aha, hai ragione – Thanatos11th

Problemi correlati