2010-03-26 8 views
45

Ich möchte das GPS EXIF-Tag aus Bildern mit PHP extrahieren. Ich bin mit dem exif_read_data(), die eine Array aller Tags + Daten zurückgibt:PHP extrahieren GPS EXIF ​​Daten

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 

Ich weiß nicht, wie 46/1 5403/100 und 0/1 zu interpretieren? 46 könnte 46 ° sein, aber was ist mit dem Rest vor allem 0/1?

angle/1 5403/100 0/1 

Worum geht es in dieser Struktur?

Wie konvertiert man sie zu "Standard" (wie 46 ° 56'48 "N 7 ° 26'39" E aus Wikipedia)? Ich möchte diese Koordinaten an die Google Maps API weitergeben, um die Bilder auf einer Karte anzuzeigen!

+1

@Kami: Ich aktualisiert meine Antwort mit einigen Code – Kip

Antwort

18

Gemäß http://en.wikipedia.org/wiki/Geotagging sollte ([0] => 46/1 [1] => 5403/100 [2] => 0/1) 46/1 Grad, 5403/100 Minuten, 0/1 Sekunden, d. H. 46 ° 54,03'0 "N bedeuten. Normalisieren der Sekunden ergibt 46 ° 54'1.8 "N.

Dieser Code sollte funktionieren, solange Sie keine negativen Koordinaten erhalten (vorausgesetzt, Sie erhalten N/S und E/W als separate Koordinaten, sollten Sie niemals negative Koordinaten haben). Lass es mich wissen, wenn es einen Bug gibt (ich habe momentan keine PHP-Umgebung zur Hand).

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

Der Code, den ich in der Vergangenheit verwendet habe, ist so etwas wie (in Wirklichkeit ist es überprüft auch, dass die Daten vage gültig ist):

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

Wo Sie auch haben:

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

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

Jede Idee, warum wurde diese downvoted? Ich würde gerne meinen Code bei Bedarf reparieren können. –

77

Dies ist meine modifizierte Version. Die anderen haben nicht für mich gearbeitet. Es gibt Ihnen die Dezimalversionen der GPS-Koordinaten.

Der Code, um die EXIF-Daten zu verarbeiten:

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

Drucken in diesem Format:

float(-33.8751666667) 
float(151.207166667) 

Hier sind die Funktionen:

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

Ich habe festgestellt, dass die neuesten Versionen von PHP eine zusätzliche Array-Schicht im Exif-Objekt haben, die wie folgt aufgerufen werden muss: getGps ($ exif ['GPS'] ["GPSLongitude"], $ exif ['GPS'] [' GPSLongitudeRef ']) –

+0

@OrbitingEden Dieses Verhalten wird durch den 3. Parameter aktiviert. Standardmäßig deaktiviert –

0

Ich bin mit dem modifizierten Version von Gerald Kaszuba, aber es ist nicht korrekt. also ändere ich die Formel ein wenig.

aus:

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

geändert:

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

Es funktioniert für mich.

5

Ich weiß, dass diese Frage vor langer Zeit gestellt wurde, aber ich stieß auf sie bei der Suche in Google und die hier vorgeschlagenen Lösungen funktionierten nicht für mich. Also, nach weiterer Suche, hier ist, was für mich funktioniert hat.

Ich stelle es hier so, dass jeder, der hier durch einige googeln kommt, können verschiedene Ansätze finden das gleiche Problem zu lösen:

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

Ich habe diese Antwort verwendet und es war großartig! Denken Sie daran, das neue PHP macht das Exif-Array so, dass GPS seinen eigenen Schlüssel hat. ZB '$ gps ['LatDegree'] = $ exif [" GPSLatitude "] [0];' wird '$ gps ['LatDegree'] = $ exif [" GPS "] [" GPSLatitude "] [0];' –

+1

Diese Lösung hat für mich funktioniert und ich habe diese Antwort in ein Composer-Paket umgesetzt - mit ein paar Änderungen. Sie können es hier finden: https://github.com/diversen/gps-from-exif – dennis

14

Dies ist eine Refactoring-Version von Gerald Kaszuba Code (derzeit am meisten weitgehend akzeptierte Antwort). Das Ergebnis sollte identisch sein, aber ich habe mehrere Mikro-Optimierungen gemacht und die zwei separaten Funktionen zu einer kombiniert. In meinem Benchmarktest hat diese Version ungefähr 5 Mikrosekunden von der Laufzeit abgeschnitten, was wahrscheinlich für die meisten Anwendungen vernachlässigbar ist, aber für Anwendungen nützlich sein könnte, die eine große Anzahl von wiederholten Berechnungen beinhalten.

$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. Ich habe PHP-Exif-Code-Schnipsel seit Tagen blind aus dem Stack-Overflow kopiert und eingefügt, ohne eigene Recherchen anzustellen. (_really_) Und sie haben alle von sorta falsch bis wirklich wirklich falsch gelegen. Unterschiedliche Grade von falschen Daten erzeugen. * DIESES FUNKTIONIERT. * Die einzige Sache, die ich tat, war, die Ausgabe gegen bekannte gute Quelle zu überprüfen. Und dieser ist zu 100% korrekt. 10/10 würde Pasta wieder kopieren. – Adam

-1

Mit diesen GPS-Daten:

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

den obigen Code verwenden (Dank Gerald) bekomme ich diese Latitude & Longitude Werte:

-392.31537456069,-0.023678137550796 

Dies ist nicht korrekt. Es tut mir leid, dass der Code funktioniert, aber in diesem Fall ist die Antwort falsch! Viele andere Bilder funktionieren gut, es scheint nur etwas Logik zu fehlen, um etwas in diesem Dat zu berücksichtigen. Zum Beispiel, wenn ich das Bild in iPhoto (Entschuldigung für das Apple-Beispiel zu denjenigen ohne Macs) lade, erhält es die richtige Antwort; Diese EXIF-Daten sind für ein Bild in der Nähe des Roten Meeres.

+1

Immer noch nicht auf den Grund gehen. Aber gibt es etwas in der Tatsache, dass die zweite Hälfte von 'GPSLatitude [0]' 0 ist? Vielleicht ein Division-by-Zero-Problem? – Pete

0

Dies ist ein Javascript-Port des PHP-Codes, der oben auf @Gerald gepostet wurde. Auf diese Weise kann die Position eines Bild herausfinden, ohne jemals das Bild hochladen, in Verbindung mit Bibliotheken wie dropzone.js und 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

Kurzgeschichte. Erster Teil N Lassen Sie die Note multiplizieren Sie die Minuten mit 60 teilen Sie die Sekunden mit 100. zählen Sie die Noten, Minuten und Sekunden miteinander.

Zweiter Teil E Lassen Sie die Klasse die Minuten mit 60 Devide die Sekunden mit ... 1000 Zähle die Qualitäten, Minuten und Sekunden miteinander

1

Um den Höhenwert zu erhalten multiplizieren, können Sie die folgenden drei Zeilen:

$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

Im Fall, dass Sie eine Funktion Koordinaten von Imagick Exif hier lesen wir gehen, ich hoffe, es spart Ihnen Zeit. Getestet unter 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

Ich habe gesehen, niemand dies erwähnt: 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) 

jetzt den Coordonates mit objecct Sie tun können, was Sie wollen: Beispiel:

(wie 46 ° 56'48 "N 7 ° 26'39 "E aus wikipedia)

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

Sie müssen als Konv ert von ascii, und Sie sind fertig:

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

und als Druckbeispiel:

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

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

Ja, denn das ist eine Python-Antwort auf eine PHP-Frage – CodeBrauer

+0

Aha, Sie haben Recht – Thanatos11th