MENU 
Photos of Code

How I Added Photo Location Data to 75CentralPhotography.Com

February 17, 2019  |    1 comment  |  Code GPS Logs Site-related

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. (I swear I thought I’d done a write-up on how I do this, but I can’t seem to find it. I have posted some of the track logs in the past however…you can see them here .)

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:

KeyValue
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 Created2019:02:16 21:03:14
Exposure Time 1/80 sec
F-Number f/4.5
Exposure Program Normal Program
ISO Speed Rating100
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 Pointer266
Compression Scheme JPEG Compression (Thumbnail)
Horizontal Resolution 72 dpi
Vertical Resolution 72 dpi
Resolution Unit i
Offset to JPEG SOI1044
Bytes of JPEG Data19487
Exif Version2.3
Image Generated2019:02:16 07:52:16
Image Digitized2019: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 Ratio1
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.


My 500px Randomizer

January 27, 2012  |    0 comments  |  Apps Code

I’ve mentioned this before, but I thought I’d revisit it since I’ve recently rolled out a few changes.

In the last year or so, 500px has exploded to become the “serious” alternative to Flickr—a place where you show off your best work while not being crowded out by the kinds of people on Flickr that upload every lame snapshot of their kids or dump their entire CF or SD card into their stream everytime they come back from an outing.

Unfortunately, one of the big problems with 500px is that there’s no “good” way to randomly view images, save for a link at the bottom of their homepage inviting you to “StumbleThru 500px”, which simply uses user-submitted links on third-party service StumbleUpon.

I found this to be inadequate, as it only relied on photos that users had bothered to “Stumble”.  This meant that the number of images were somewhat limited as well as confined to mostly the more popular images—ones that the hive mind of the 500px viewership community had decided were “the best” and worthy of linking to.  After a few clicks on the Stumble button, I found that I was getting the same few images over and over again—some of them were even months old.

What I wanted to do was see truly random images from 500px, so I set out to make a tool to do the randomizing for me.

My first iteration was simple.  Since, at the time, 500px didn’t have a publicly-exposed API, I had to be “kludgey”.  A bit of poking around revealed that 500px simply numbers photos sequentially as they are uploaded—in fact, you can easily go see the first photo uploaded publicly thanks to the ridiculously-easy-to-reverse-engineer URL convention of http://500px.com/photo/<number of photo>.  This made it extremely easy to create a php application that would simply generate a random number between 1 and whatever the largest number used is.  The php code is easy:

$iPic =  mt_rand(  1 , $iMax );
return “http://500px.com/photo/”.$iPic;

Where $iMax is whatever the largest number used is. Since I didn’t want to have to bother writing an overly-long script to figure out what the latest number used was, I’d simply manually update $iMax every couple of days with the photo ID of the first image on 500px’s Fresh page.

In my app, I embedded an iFrame to hold the photo’s page while the app acted as a wrapper around it, keeping the “Randomize” button and “Permalink” link visible at all times.  And this worked great, but I wasn’t happy.  I quickly found that while 500px has tons of great work on it, there’s a lot of cruft.  Especially amongst the older photos submitted before the community really “took off”.  What I really wanted was to be able to randomly browse photos that were of a bit higher quality and were on the newer side (and this, I suppose, is where my application lost it’s complete randomness).  Unfortunately, this wasn’t really possible at the time, so I let the project sit on the backburner for a while.

Then 500px opened up its API.  And I leveraged it.  I quickly figured out how to use JSON queries to return arrays of recent photos in the Fresh, Editors’ Choice, Upcoming and Favorites categories.  Not really caring about Fresh since that’s the initial “dumping ground” for everything uploaded, I concentrated on the other categories.  I quickly produced some code that queried the API and returned a random photo from the user’s choice of categories, replacing my previous code that haphazardly propelled you around 500px and instead allowed you to randomly view more-curated photos.

A bit of Javascript trickery also allowed me to make a feature to view the photographer’s 500px homepage using a window blind effect so that a user can quickly check out other photos by that photographer as well as follow them without leaving my app.

So, there you have it, the story behind my 500px Randomizer.  Feel free to use it all you want;  just keep in mind that it’s still a work in progress and if you find any bugs, feel free to send me an email at lefty@leftyrodriguez.com to let me know.


Importing Your Flickr Comments to Your WordPress Blog

March 7, 2011  |    0 comments  |  Code Site-related

If you go to my photoblog, you’ll notice that my pictures have a lot of comments that are actually comments on that photo from my Flickr photostream.  Pretty cool, eh?  I achieve this by using a WordPress plugin called Live Flickr Comment Importer that lets you add a photo’s flickr ID to a custom field in a WordPress post, then on the next load of that post, it pulls all the comments for that Flickr ID from Flickr and creates WordPress comments from them.

The only drawback to this plugin as originally written by the developer is that the “author URL” of the commenter linked back to that comment on Flickr.  Which, in my opinion, is useless.  I’d much rather see their photostream rather than a comment on my own photo.  So I decided I’d fix this problem.  I started looking at the code and discovered that the way the developer was determining if a comment was already pulled was if the URL for the comment already existed in the WordPress database comments table:

$test_dupes = $wpdb->get_results( “SELECT comment_ID FROM {$wpdb->comments} WHERE comment_author_url='{$comment[‘permalink’]}'”, ARRAY_N);

So, basically, they were using the comment_author_url as the unique key for determining and rejecting duplicate comments.  This works, but I wanted to use comment_author_url to store the commenter’s photostream URL.  But just shoving their photostream URL into that field would cause the function that determines duplicates to break, since a Flickr user might comment on any of my photos more than once.

Fortunately, the WordPress comments table has another (almost) unique field:  comment_date.  If I used this as a unique key, the only time that I’d miss importing a comment from Flickr to WordPress would be if two Flickr commenters posted their comments at the exact same second as each other.  I could live with this possibility, as it was close enough to zero that it might as well be zero.  So I modified the code a bit and got my modified version of the plugin working.  If you want to use it, you can download my modded version here.

 


© 1993-2019 Matt Harvey/75Central Photography - All Rights Reserved • Contact license@75central.com for image licensing and other queries.