Domanda

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

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

In cosa consiste questa struttura?

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

È stato utile?

Soluzione

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.Normalizzando i secondi si ottiene 46°54′1.8″N.

Il codice riportato 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]);
}

Altri suggerimenti

Questa è la mia versione modificata.Gli altri non hanno funzionato per me.Ti fornirà 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);

Viene stampato in questo formato:

float(-33.8751666667)
float(151.207166667)

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

Questa è una versione rifattorizzata del codice di Gerald Kaszuba (attualmente la risposta più ampiamente accettata).Il risultato dovrebbe essere identico, ma ho apportato diverse micro-ottimizzazioni e combinato le due funzioni separate in una sola.Nei miei test di benchmark, questa versione ha ridotto di circa 5 microsecondi il tempo di esecuzione, il che è probabilmente trascurabile per la maggior parte delle applicazioni, ma potrebbe essere utile per applicazioni che comportano un gran numero 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);
}

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

Lo inserisco qui in modo che chiunque arrivi qui cercando su Google possa trovare approcci diversi 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);
}

Questa è una vecchia domanda ma ritengo che potrebbe essere utilizzata una soluzione più eloquente (approccio OOP e lambda per elaborare le parti frazionarie)

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

}

Il codice che ho utilizzato in passato è qualcosa del tipo (in realtà controlla anche che i dati siano vagamente validi):

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

Per ottenere il valore dell'altitudine è possibile utilizzare le seguenti 3 righe:

$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];

Nel caso in cui tu abbia bisogno di una funzione per leggere le coordinate da Imagick Exif eccoci qui, spero che ti faccia risparmiare tempo.Testato con 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]);
}

Sto usando la versione modificata di Gerald Kaszuba ma non è precisa.quindi cambio un po' la formula.

da:

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

cambiato in:

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

Per me funziona.

Questo è un port javascript del codice PHP pubblicato sopra @Gerald.In questo modo puoi capire la posizione di un'immagine senza mai caricare l'immagine, insieme a librerie come dropzone.js E Javascript-Carica-immagine

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
    };

});

storia breve.Prima parte n Lasciare il grado moltiplica i minuti con 60 Devide i secondi con 100.contare i voti, i minuti e i secondi tra loro.

La seconda parte E lascia il grado moltiplica i minuti con 60 Devide i secondi con ... 1000 CHUNT I voti, i minuti e i secondi tra loro

non ho visto nessuno menzionare 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 l'oggetto Coordonates puoi fare quello che vuoi:Esempio:

(come 46°56′48″N 7°26′39″E da wikipedia)

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

Devi quindi convertire da ascii e il gioco è fatto:

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

e poi stampando l'esempio:

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

>> Latitude: 5°52′59.88″N

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

Usando il codice sopra (grazie Gerald) ottengo questi valori di latitudine e longitudine:

-392.31537456069,-0.023678137550796

Questo non è corretto.Mi sta dando alla testa il funzionamento del codice, ma in questo caso la risposta è sbagliata!Molte altre immagini funzionano bene, sembra semplicemente che manchi una logica per soddisfare qualcosa in questi dati.Ad esempio, quando carico l'immagine in iPhoto (scusate l'esempio Apple per chi non ha Mac) ottiene la risposta giusta;questi dati EXIF ​​si riferiscono a un'immagine vicino al Mar Rosso.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top