Make your way to the Exif

Location, camera, lens, ISO… Get it all!

A picture tells a thousand words, sure. Sometimes though, the audience wants more. They want to know where you were when you took the photo, what camera you used, what lens, what ISO… The details, child, the fans want the details!

Your average visitor won’t be particularly interested in these details, though. However, there will be a class of visitor that’ll be interested in what goes on behind the curtains; the nuts and bolts; the salacious technical details. This class of visitor will want to know way, way, more than is immediately accessible.

Lets say you’re a photographer and for each of your posts, this — shall we call them, professionally curious — group of visitors likes to know what the set up was. Specifically they very much enjoy seeing the Exif data displayed right along with the photos themselves.

To avoid cluttering the posts, we’ll implement this in the attachment page.

Before we move forward I’ll assume you know that each photo you take, on any camera, at any time will likely have metadata attached to it. This metadata will have detailed specifics about the whens, wheres, and hows associated with the particular photograph. i.e. at a minimum it’ll have information about when the photo was taken, what camera was used, what lens, and what the settings were on the camera. Unaltered, when finally uploaded into a WordPress-powered site, this image will retain the same metadata that, as a theme designer, you can tap into and use.

Naturally, it makes sense to first define a function that does this.

Defining the function

WordPress already has a built-in function for this: wp_get_attachment_metadata(). So as opposed to defining one from scratch, we’ll use that.

First, if you haven’t already, create and open the template file image.php. This is the template that WordPress will use to display single attachments that are images.

At the very top of the file, we’ll retrieve the current image’s meta fields and store them in a variable $metadata which we’ll then use to display our info. Like so:

<?php
  // Retrieve attachment metadata.
  $metadata = wp_get_attachment_metadata();

  get_header();
?>

The $metadata variable is now storing values retrieved by the wp_get_attachment_metadata() function. These values (i.e. the particular attachment’s meta fields) are:

  • width: the attachment’s width.
  • height: the attachment’s height
  • file: path to the attachment file relative to the uploads folder
  • sizes: this is an array of sizes. i.e., the different versions of the image that WordPress generates.
    The key of this array is a slug of the attachments various sizes. e.g. ‘thumbnail’, ‘medium’, ‘large’, etc. For instance, assuming we’re working with the ‘large’ version, the value of these keys is an array containing the following values:
    • file: path to the ‘large’ version of the attachment relative to the uploads folder
    • width: the width of the ‘large’ version of the attachment
    • height: the height of the ‘large’ version of the attachment
    • mime-type: type of image e.g. image/jpeg or image/png
  • image_meta: This is an array that returns a set of Exif and IPTC information such as:
    • camera: the model of the camera used
    • aperture: the size of the ap
    • focal_length: the f-number or f-stop of the lens
    • shutter_speed
    • iso
    • title:
    • credit: if available, this displays the artist/author of the image fields
    • caption: if available, displays the first of the user/image description fields
    • created_timestamp: date when the photo was taken
    • copyright

Using the function

With the above meta information already stored inside the $metadata variable, we can now display it on the page.

To display the information in a definition list, within the loop, include the following code:

<dl>
  <dt>Dimensions:</dt>
  <dd><?php echo $metadata['width']; ?> × <?php echo $metadata['height']; ?></dd>

  <dt>Camera:</dt>
  <dd><?php echo $metadata['image_meta']['camera']; ?></dd>

  <dt>Aperture:</dt>
  <dd><?php echo $metadata['image_meta']['aperture']; ?></dd>

  <dt>Focal length:</dt>
  <dd><?php echo $metadata['image_meta']['focal_length']; ?></dd>

  <dt>Shutter speed:</dt>
  <dd><?php echo $metadata['image_meta']['shutter_speed']; ?></dd>

  <dt>ISO:</dt>
  <dd><?php echo $metadata['image_meta']['iso']; ?></dd>

  <dt>Title:</dt>
  <dd><?php echo $metadata['image_meta']['title']; ?></dd>

  <dt>Credit:</dt>
  <dd><?php echo $metadata['image_meta']['credit']; ?></dd>

  <dt>Caption:</dt>
  <dd><?php echo $metadata['image_meta']['caption']; ?></dd>

  <dt>Created timestamp:</dt>
  <dd><?php echo $metadata['image_meta']['created_timestamp']; ?></dd>
</dl>

With that in place, on the specific image attachment page in a browser, you’ll see an output similar to this:

Dimensions:         2448 × 2448
Camera:             iPhone 5s
Aperture:           2.2
Focal length:       4.12
Shutter speed:      0.0333333333333
ISO:                64
Title:
Credit:
Caption:
Created timestamp:  1398010637

Great first start but you’ll notice a few of the values are empty. In addition, the shutter speed and the timestamp could also use some loving.

To avoid empty fields, wrap the results in the standard if/else statement to ensure only fields with values are displayed. e.g. to only show the ‘title’ field if the field isn’t empty, replace the previous defined call with this:

<?php echo empty($metadata['image_meta']['title']) ? "" : '<dt>Title</dt> <dd>'  . $metadata['image_meta']['title'] . '</dd>'; ?>

If you’re not familiar with the above, its the PHP shorthand notation. Very handy replacement for overlay verbose if/else statements. If you find the above a bit distracting and not very legible in your code, you can use the more standard if/else statement like so:

<?php if ( ! empty($metadata['image_meta']['title']) ) { ?>
  <dt>Title:</dt>
  <dd><?php echo $metadata['image_meta']['title']; ?></dd>
<?php } ?>

Same thing.

Depending on how you want to display the timestamp, use the standard PHP date formats. e.g.

<?php echo date('M jS, Y', $metadata['image_meta']['created_timestamp']); ?>

will yield:

Apr 20th, 2014

Wrangling the Shutter Speed

Shutter speeds are usually displayed as fractions. Currently we have a rather unsightly decimal: 0.0333333333333. To make sense to the viewer, this number should be displayed as 1/30.

To achieve this, we need to define a function that takes our decimal (whatever that happens to be) and gives us a properly formatted fraction in return.

In my research to find the best approach to handling shutter speeds, I found numerous, albeit, old results. However, the best approach that I found was not in an actual article but in a seemingly ignorable comment on an articles. That’s the solution we’ll be implementing.

We need to define a function that will convert the shutter speed that is in decimal form into a fraction, keeping in mind that sometimes the shutter speed as a decimal won’t always output a clean/whole number.

To do so we define the following function inside functions.php:

function butter_convert_decimal_to_fraction ($number) {
  
  list ($whole, $numerator) = explode ('.', $number);
  
  $denominator = 1 . str_repeat (0, strlen ($numerator));
  
  $butter_greatest_common_divisor = butter_greatest_common_divisor ($numerator, $denominator);
  
  $numerator /= $butter_greatest_common_divisor;
  
  $denominator /= $butter_greatest_common_divisor;
  
  if($whole == 0)
    
    return sprintf ('1/%d', round($denominator/$numerator));
  
  return sprintf ('%d 1/%d', $whole, round($denominator/$numerator));
}

function butter_greatest_common_denominator ($a, $b) {
  while ( $b != 0) {
    $remainder = $a % $b;
    $a = $b;
    $b = $remainder;
  }
  return abs ($a);
}

With the above function in place, go back to the image.php file. Where you have a call to:

<?php echo $metadata['image_meta']['shutter_speed']; ?>

replace it with:

<?php printf("%s\n", butter_convert_decimal_to_fraction($metadata['image_meta']['shutter_speed'])); ?>

This will now output your shutter speed in the right format: 1/30.