I like to geotag my photos. Almost every time I go on a phototrek/drive/adventure/walk, I log my locations so that I can merge my geotagged data with my photos and know exactly where each photo was taken.
Since I have this data sitting around and it’s embedded in each photo on 75CentralPhotography.Com, I thought it would be fun for visitors to the site to see exactly where in the world each photo was taken. But how to do this?
WordPress—the backend system for the site—helpfully provides a function to store EXIF data (basically the metadata in a photo that shows interesting things like shutter speed, aperture, ISO and a ton of other stuff) but only stores the basics, whereas the EXIF standard has scores of datapoints (colorspace, exposure bias, YCbCr positioning—whatever that is—to name a few). Unfortunately, this means that they don’t include location data as part of this limited scope.
Luckily, some kind soul has already solved part of the problem for us with a built-in function in PHP (WordPress’ programming language). This function, exif_read_data(), will let us read any part of a photo’s EXIF data and use it how we want. In this case, that would be to link to Google Maps and show a place marker of where the photo was taken.
Here’s how I leveraged that function to add a link on each photo’s page to the related location on Google Maps.
First, we need to get the photo’s EXIF data. Since exif_read_data() will only accept a local file as a parameter, we need to get the local path to the image relative to the page where we are executing the code/displaying the link. Fortunately, WordPress has us covered with a couple of functions: attachment_url_to_postid() and get_attached_file().
attachment_url_to_postid takes the URL of an attachment (i.e. a photo attached to a post) and returns the ID of that photo. To get the attachment’s URL, we use our old friend catch_that_image(), which resolves the URL of the first photo on a post (and, since we only ever post one photo at a time on the site, the only image on a post). Then, we take the result of that function and pass it to get_attached_file(), which returns the aforementioned local path of the photo file:
$attachment_id = attachment_url_to_postid( catch_that_image() );
$fullsize_path = get_attached_file( $attachment_id );
We then take this local path and pass it to exif_read_data() for parsing of the photo’s EXIF data:
$exif = exif_read_data($fullsize_path);
This function returns an array of values where the first value is the EXIF data label and the second is the EXIF data itself (you might think of this as a keyset). So, a particular photo’s data might look something like this:
Key | Value |
---|---|
Equipment Make | SONY |
Camera Model | ILCE-7RM2 |
Camera Software | Adobe Photoshop Lightroom Classic 8.2 (Macintosh) |
Photographer | Matt Harvey |
Maximum Lens Aperture | f/2.8 |
Focal Length (35mm Equiv) | 44 mm |
Horizontal Resolution | 96 dpi |
Vertical Resolution | 96 dpi |
Image Created | 2019:02:16 21:03:14 |
Exposure Time | 1/80 sec |
F-Number | f/4.5 |
Exposure Program | Normal Program |
ISO Speed Rating | 100 |
Lens Aperture | f/4.5 |
Brightness | 7.2 EV |
Exposure Bias | 0 EV |
Metering Mode | Pattern |
Light Source | Unknown |
Flash | No Flash, Compulsory |
Focal Length | 44.00 mm |
Color Space Information | sRGB |
Exposure Mode | Auto |
White Balance | Auto |
Scene Capture Type | Standard |
Contrast | Normal |
Saturation | Normal |
Sharpness | Normal |
Latitude | N 33° 3.9174′ |
Longitude | W 96° 58.2118′ |
Resolution Unit | i |
Exif IFD Pointer | 266 |
Compression Scheme | JPEG Compression (Thumbnail) |
Horizontal Resolution | 72 dpi |
Vertical Resolution | 72 dpi |
Resolution Unit | i |
Offset to JPEG SOI | 1044 |
Bytes of JPEG Data | 19487 |
Exif Version | 2.3 |
Image Generated | 2019:02:16 07:52:16 |
Image Digitized | 2019:02:16 07:52:16 |
Shutter Speed | 1/80 sec |
Focal Plane Horiz Resolution | 2164 dpcm |
Focal Plane Vert Resolution | 2164 dpcm |
Focal Plane Res Unit | cm |
File Source | Digital Still Camera |
Scene Type | Directly Photographed |
Digital Zoom Ratio | 1 |
GPS Info Version | 2.2.0.0 |
Latitude Reference | N |
Longitude Reference | W |
In the context of this project, we only care about two elements of this data: Latitude and Longitude. So, to extract individual data points, we use a couple of functions to extract the coordinates and convert to decimal:
$lon = getGps($exif["GPSLongitude"], $exif['GPSLongitudeRef']);
$lat = getGps($exif["GPSLatitude"], $exif['GPSLatitudeRef']);
Which calls:
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]);
}
So we finally have a specific photo’s GPS location. Our final step is to verify that we have valid data for GPS (i.e. neither the latitude or longitude are 0, because that’s what’s returned when no GPS data is available and there could be, but shouldn’t be, photos on the site without location data). If the verification passes, we link to Google Maps with our coordinates:
if($lat <> 0 && $lon <>0)
{
echo '<a href="https://www.google.com/maps/search/?api=1&query='.$lat.','.$lon.'" target ="_blank" title="Location data may be innacurate or fuzzed in certain cases">View This Photo\'s Location on Google Maps</a></br> ';
}
Note that we added a title element to the anchor tag for the link that states that photo data may be inaccurate or “fuzzed” for some photos. This is because some photos were tagged “after the fact” instead of using an actual GPS log or were tagged en masse with a fairly-accurate location or were tagged with a general location to preserve privacy (i.e. photos I’ve taken at home or other people’s homes).
To view any photo’s location on the site, go to the individual page for a photo and click the “View This Photo’s Location on Google Maps” link under the photo’s tags.
If you find any bugs or photos without GPS data or have any ideas for improvements, please let me know at matt@75central.com.
One thought on “How I Added Photo Location Data to 75CentralPhotography.Com”