2010-03-26 64 views
45

Me gustaría extraer la etiqueta GPS EXIF ​​de las imágenes usando php. estoy usando el exif_read_data() que devuelve un conjunto de todos los datos de las etiquetas +:Extracto PHP Datos 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 

No sé cómo interpretar 46/1 y 0/1 5403/100? 46 podría ser 46 °, pero ¿qué pasa con el resto, especialmente 0/1?

angle/1 5403/100 0/1 

¿De qué trata esta estructura?

¿Cómo convertirlos a "estándar" (como 46 ° 56'48 "N 7 ° 26'39" E de la wikipedia)? Me gustaría pasar esas coordenadas a la API de Google Maps para mostrar las posiciones de las imágenes en un mapa.

+1

@Kami: He actualizado mi respuesta con algo de código – Kip

Respuesta

18

Según http://en.wikipedia.org/wiki/Geotagging, ([0] => 46/1 [1] => 5403/100 [2] => 0/1) debe significar 46/1 grados, 5403/100 minutos, 0/1 segundos, es decir 46 ° 54.03'0 "N. La normalización de los segundos da 46 ° 54'1.8 "N.

Este código a continuación debería funcionar, siempre y cuando no obtenga coordenadas negativas (dado que obtiene N/S y E/W como una coordenada separada, nunca debería tener coordenadas negativas). Avíseme si hay un error (no tengo un entorno de PHP a la mano en este 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

El código que he usado en el pasado es algo así como (en realidad, también comprueba que los datos son válidos vagamente):

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

donde también tiene:

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

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

Cualquier idea de por qué esto que downvoted? Me encantaría poder arreglar mi código si es necesario. –

77

Esta es mi versión modificada. Los otros no funcionaron para mí. Le dará las versiones decimales de las coordenadas GPS.

El código para procesar los datos EXIF:

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

se imprime en este formato:

float(-33.8751666667) 
float(151.207166667) 

Estas son las funciones:

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

Descubrí que las últimas versiones de PHP tienen una capa extra de matriz en el objeto exif que requiere que se les llame como: getGps ($ exif ['GPS'] ["GPSLongitude"], $ exif ['GPS'] [' GPSLongitudeRef ']) –

+0

@OrbitingEden Este comportamiento está habilitado por el 3er parámetro. Desactivado por defecto. –

0

Estoy utilizando el modificado versión de Gerald Kaszuba pero no es precisa. así que cambio la fórmula un poco.

de:

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

cambiado a:

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

Funciona para mí.

5

Sé que esta pregunta se ha hecho hace mucho tiempo, pero me encontré al buscar en google y las soluciones propuestas aquí no funcionaron para mí. Entonces, después de una búsqueda más profunda, esto es lo que funcionó para mí.

lo estoy poniendo aquí, así que cualquiera que viene aquí a través de algunas google, puede encontrar diferentes enfoques para resolver el mismo 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

¡Utilicé esta respuesta y fue genial! Solo recuerde, el nuevo PHP hace la matriz exif para que el GPS tenga su propia clave. EG '$ gps ['LatDegree'] = $ exif [" GPSLatitude "] [0];' se convierte en '$ gps ['LatDegree'] = $ exif [" GPS "] [" GPSLatitude "] [0];' –

+1

Esta solución funcionó para mí y convertí esta respuesta en un paquete para compositores, con algunos cambios. Puede encontrarlo aquí: https://github.com/diversen/gps-from-exif – dennis

14

Ésta es una versión refactorizado de código de Gerald Kaszuba (actualmente el más respuesta ampliamente aceptada). El resultado debería ser idéntico, pero hice varias micro optimizaciones y combiné las dos funciones por separado en una. En mi prueba de referencia, esta versión se rajó unos 5 microsegundos fuera del tiempo de ejecución, que es probablemente insignificante para la mayoría de las aplicaciones, pero podría ser útil para aplicaciones que implican una gran cantidad de cálculos repetidos.

$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. He estado copiando y pegando ciegamente fragmentos de código PHP exif del desbordamiento de Stack durante días sin hacer ninguna investigación propia. (_realmente_) Y todos han variado desde algo incorrecto hasta realmente realmente incorrecto. Produciendo diferentes grados de datos incorrectos. * ESTO FUNCIONA. * Lo único que HICE fue verificar la salida en contra de fuentes bien conocidas. Y este es 100% correcto. 10/10 sería copiar pasta de nuevo. – Adam

-1

Con estos datos 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" 
    } 

Usando el código anterior (gracias Gerald) me sale estos valores de latitud y longitud &:

-392.31537456069,-0.023678137550796 

Esto no es correcto. Se me está yendo por la cabeza ya que el código funciona, ¡pero la respuesta es incorrecta en este caso! Muchas otras imágenes funcionan bien, parece que falta algo de lógica para atender algo en este dat. Por ejemplo, cuando cargo la imagen en iPhoto (lo siento por el ejemplo de Apple para los que no tienen Macs) obtiene la respuesta correcta; estos datos EXIF ​​son para una imagen cerca del Mar Rojo.

+1

Todavía no se puede llegar al fondo de esto. Pero, ¿hay algo en el hecho de que la segunda mitad de 'GPSLatitude [0]' es 0? Tal vez una división por cero problema? – Pete

0

Este es un puerto de JavaScript del código PHP publicado en @Gerald arriba. De esta manera se puede averiguar la ubicación de una imagen sin subir jamás la imagen, junto con las bibliotecas como dropzone.js y 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

cuento. Primera parte N Deje la calificación multiplique los minutos con 60 dele los segundos con 100. cuente los grados, los minutos y los segundos entre ellos.

Segunda parte E Deje el grado multiplicar los minutos con 60 devide los segundos con ... 1000 recuento de los grados, minutos y segundos entre sí

1

Para obtener el valor de altitud, puede utilizar las siguientes líneas: 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]; 
1

En caso de que necesite una función para leer las coordenadas de Imagick Exif aquí vamos, espero que le ahorra tiempo. Probado bajo 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

que he visto nadie menciona esto: 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) 

ahora utilizando los Coordonates objecct que puede hacer lo que quiere: Ejemplo:

(como 46 ° 56'48 "N 7 ° 26'39 "E de la wikipedia)

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

Usted que tiene que conv ERT de ASCII, y ya está:

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

y que la impresión de ejemplo:

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

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

Sí, porque esta es una respuesta de Python en una pregunta php – CodeBrauer

+0

aha, tienes razón – Thanatos11th

Cuestiones relacionadas