Using EXIF and IPTC Photo Location Information in WordPress

WordPress Filter’s to the Rescue!

WordPress is great in the way that it supports ‘filters‘. The output of standard WordPress functions can be modified by applying a filter to them.

We can add a ‘filter’ to change the behaviour of wp_read_image_metadata. This is the function that pulls the metadata from the image when it is first uploaded. A little searching on the web led me to kristarella.com’s guide to “Add image EXIF metadata to WordPress”. She supplied the following code that can be pasted into a WordPress theme’s functions.php file. It supplies the latitude and longitude information from the image EXIF when the wp_get_attachment_metadata() function is used:

function add_geo_exif($meta,$file,$sourceImageType) {
  $exif = @exif_read_data( $file );
  if (!empty($exif['GPSLatitude']))
    $meta['latitude'] = $exif['GPSLatitude'] ;
  if (!empty($exif['GPSLatitudeRef']))
    $meta['latitude_ref'] = trim( $exif['GPSLatitudeRef'] );
  if (!empty($exif['GPSLongitude']))
    $meta['longitude'] = $exif['GPSLongitude'] ;
  if (!empty($exif['GPSLongitudeRef']))
    $meta['longitude_ref'] = trim( $exif['GPSLongitudeRef'] );
  return $meta;
}
add_filter('wp_read_image_metadata', 'add_geo_exif','',3);

So that neatly takes care of getting the latitude and longitude information! Right? Er, no. It turns out latitude and longitude are returned as an array containing degrees, minutes and seconds, not as a decimal which I’ll need later for displaying a Google map. So….

[GARD]

Converting Degrees, Minutes and Seconds to Decimal

A StackOverflow answer provided a php function to convert to decimal. A quick modification gave two functions, one that would provide a ‘machine-readable’ value as a signed decimal, and a ‘human-readable’ version, indicating which hemisphere we’re in by adding W, E, N or S to the value.

/**
 * Helper function to convert exif_read_data's deg min secs into decimal
 */
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 getHumanGps($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;

  return round($degrees + $minutes / 60 + $seconds / 3600, 3) . ' ' . $hemi;
}

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

I had a look at the output of the exif_read_data php function to see if we could pull any more useful information, but unfortunately it turns out that everything else that I want is stored as IPTC data. Nothing’s ever simple!

Next Page: Reading IPTC Data

[GARD]


COMMENTS