25.09.2008

Geo informationen aus den EXIF-Infos von Bildern auslesen

Heute wollte ich einmal testen, ob ich ohne Weiteres die Geoinformationen aus Bildern auslesen kann, die ich mit meinem iPhone 3G gemacht habe... Foto gemacht und auf den Rechner gezogen.

Wie komme ich aber nun für eine weitere Verarbeitung (zum Beispiel im Web) an die Informationen? Der Schlüssel lautet "Exchangeable image information" (kurz EXIF). Als PHP-Fuzzi tippte ich einfach mal php.net/exif ein und wurde prompt fündig:

function exif_read_data($filename) : array

Leider enthielt das zurückgegebene Array keine einfach weiter zu verwendenden Koordinaten, sondern leicht verworrene Infos:

  1. [GPSLatitudeRef] => N
  2. [GPSLatitude] => Array
  3. (
  4. [0] => 52/1
  5. [1] => 3367/100
  6. [2] => 0/1
  7. )
  8.  
  9. [GPSLongitudeRef] => E
  10. [GPSLongitude] => Array
  11. (
  12. [0] => 13/1
  13. [1] => 2460/100
  14. [2] => 0/1
  15. )

Um diese Infos in Dezimalwerte zu überführen, kann man folgende Funktion nutzen:

  1. function exifGeoCoordinateToDecimal($reference, array $coordinate)
  2. {
  3. list($a,$b) = explode("/", $coordinate[0]);
  4. list($c,$d) = explode("/", $coordinate[1]);
  5. list($e,$f) = explode("/", $coordinate[2]);
  6. $prefix = $reference == 'S' || $reference == 'W' ? -1 : 1;
  7.  
  8. $a = $b > 0 ? $a / $b : $a;
  9. $c = $d > 0 ? $c / $d : $c;
  10. $e = $f > 0 ? $e / $f : $e;
  11.  
  12. return $prefix * round(($a + ($c * 60 + $e) / 3600), 6);
  13. }

Und 1-fix-3 wird aus "52/1, 3367/100, 0/1 N" ein normaler Wert: 52.561167. Wem das nicht genug ist, hier eine fertige Variante zum Kopieren: geopoint.php

  1. /**
  2.  * @author Florian Sternke, www.bananenhand.de/blog/
  3.  * @version 1.0.0.0
  4.  */
  5. class GeoPoint
  6. {
  7. /**
  8.   * Longitude
  9.   *
  10.   * @var double
  11.   */
  12. protected $dblLongitude = 0.0;
  13. /**
  14.   * Latitude
  15.   *
  16.   * @var double
  17.   */
  18. protected $dblLatitude = 0.0;
  19.  
  20. /**
  21.   * Initialize an instance of GeoPoint
  22.   *
  23.   * @param double $dblLon Longitude
  24.   * @param double $dblLat Latitude
  25.   */
  26. public function __construct($dblLon, $dblLat)
  27. {
  28. // Option: check against a regexp to filter crap like 180.1
  29. $this->dblLongitude = (double)$dblLon;
  30. $this->dblLatitude = (double)$dblLat;
  31. }
  32.  
  33. /**
  34.   * Output the point as string (lon,lat)
  35.   *
  36.   * Some strange people (like Google) display coordinates like
  37.   * y,x instead of the logical x,y-way (see cartesian coordinate
  38.   * system). If you prefer the first way, feel free to switch both...
  39.   *
  40.   * @return string
  41.   */
  42. public function __toString()
  43. {
  44. return "({$this->dblLongitude},{$this->dblLatitude})";
  45. }
  46.  
  47. /**
  48.   * Returns the latitude of the geo coord
  49.   *
  50.   * @return double
  51.   */
  52. public function getLatitude()
  53. {
  54. return $this->dblLatitude;
  55. }
  56.  
  57. /**
  58.   * Returns the longitude of the geo coord
  59.   *
  60.   * @return double
  61.   */
  62. public function getLongitude()
  63. {
  64. return $this->dblLongitude;
  65. }
  66.  
  67. /**
  68.   * Transforms the EXIF geo cood array into a decimal format
  69.   *
  70.   * Array
  71.   * (
  72.   * [0] => 52/1
  73.   * [1] => 3367/100
  74.   * [2] => 0/1
  75.   * )
  76.   *
  77.   * to 52.561167
  78.   *
  79.   * @param string $reference N, E, W or S
  80.   * @param array $coordinate Coordinate
  81.   */
  82. protected static function exifGeoCoordinateToDecimal($reference, array $coordinate)
  83. {
  84. list($a,$b) = explode("/", $coordinate[0]);
  85. list($c,$d) = explode("/", $coordinate[1]);
  86. list($e,$f) = explode("/", $coordinate[2]);
  87. $prefix = $reference == 'S' || $reference == 'W' ? -1 : 1;
  88.  
  89. $a = $b > 0 ? $a / $b : $a;
  90. $c = $d > 0 ? $c / $d : $c;
  91. $e = $f > 0 ? $e / $f : $e;
  92.  
  93. return $prefix * round(($a + ($c * 60 + $e) / 3600), 6);
  94. }
  95.  
  96. /**
  97.   * Reads an image file and returns the extracted geo information
  98.   *
  99.   * Reads an image file, transforms the exif geo information into
  100.   * a reusable geo point object
  101.   *
  102.   * @param string $strFilename File name
  103.   * @return GeoPoint
  104.   * @throws UnexpectedValueException, Exception
  105.   */
  106. public static function constructFromImageFile($strFilename)
  107. {
  108. if (file_exists($strFilename))
  109. {
  110. $arrInfos = exif_read_data($strFilename, "EXIF");
  111.  
  112. if (is_array($arrInfos["GPSLatitude"]) && is_array($arrInfos["GPSLongitude"]))
  113. {
  114. $dblLat = self::exifGeoCoordinateToDecimal($arrInfos["GPSLatitudeRef"], $arrInfos["GPSLatitude"]);
  115. $dblLon = self::exifGeoCoordinateToDecimal($arrInfos["GPSLongitudeRef"], $arrInfos["GPSLongitude"]);
  116.  
  117. return new self($dblLon, $dblLat);
  118. }
  119. else throw new UnexpectedValueException("Exchangeable image information (EXIF) without GPS data");
  120. }
  121. else throw new Exception("File not found");
  122. }
  123. }
  124.  
  125. echo GeoPoint::constructFromImageFile("img_0013.jpg");

Hinterlasse einen Kommentar

Dein Kommentar:

Kategorien