Filtering Exifography output

This week I released Exifography 1.1 (Yay! Woohoo!)

Exifography is a rewrite of Thesography, my WordPress plugin, which displays EXIF data for photographs that have been uploaded to WordPress and enables the import of location (and a few other) EXIF.

I was pretty excited about this rewrite. It was something I had been meaning to do for a long time. It represents a significant increase in my PHP abilities, and therefore an increase in the efficiency and elegance of the plugin (I’ve got more to learn, but it’s still an improvement!), and it also uses the WordPress Settings API, which was developed after I originally wrote the plugin. The settings API is cool because it automatically handles saving of theme and plugin settings and helps to separate out the different elements of settings (page layout, form fields, and input validation), making them a bit more manageable.

One of the things I was thinking of building into the plugin, but wasn’t sure how yet was reordering of the EXIF fields. Then as I was coding and looking over emails from users, I saw that one user had totally rearranged how his location data was displayed. I realised that if I allowed users to filter the output of the plugin they could both reorder and replace any content that they wanted to, as well as add or remove content. So, this post shows how you can do those things.

Naturally, if it’s something very simple that you want to add before or after the EXIF data you could just do that in the HTML options for the plugin, but if you want to add dynamic data (something that changes according to the image or the post) you can do it with a filter. These first couple of examples aren’t dynamic though, just show you what is happening in the filter.

Exifography filter format

The filter format to filter Exifography output is as follows.

function add_exif_item($content,$postID,$imgID) {
	$content[] = '<li>This will display after the EXIF data.</li>';
	
	return $content;
}
add_filter('exifography_display_exif','add_exif_item',11,3);

For more about what filters are read the WordPress Codex.
This filter example shows a function with a unique name, and it can receive 3 parameters (sets of information):

  1. $content is an array with all of the EXIF items already formatted for display (by default they are in an unordered list format, but if you have changed the default HTML display options on the options page, they will be in that format).
  2. $postID is the post ID that the function is currently working in. You might want to use that in your filter if you need to fetch post specific information to add to the output.
  3. $imgID is the ID of the image that is currently being referenced. This will be either the first image attached to the post, or the specific image referenced by a template function or shortcode.

The set of square brackets in $content[] is the PHP syntax for adding a new array item to an existing array. So the above filter adds a list item saying “This will display after the EXIF data.” to the end of the list.

You have to return the modified content array in order to give it back to the plugin’s display function so it can use the data you’ve given it.

To apply the filter you need the line add_filter('exifography_display_exif','add_exif_item',11,3);.

  • The first parameter is required and cannot be changed (it is the name of the filter in the plugin).
  • The second parameter is required and is the name of your function.
  • The third parameter is optional and is the priority with which the filter is executed (mainly relevant if you have multiple filters, 1 is executed before 2 etc).
  • The fourth paramater is optional and is the number of parameters that can be used. By default filters only pass one parameter, so if you only need the content from the filter (as shown in the next example), that’s fine, but if you do want the post ID and/or image ID you need to use this parameter.

Add something before the EXIF data

If you would like to add something before the EXIF data you can use the PHP array_unshift function to put your new $content array item at the start of the array.

function add_before_exif($content) {
	$item = '<li>This is before the exif items.</li>';
	array_unshift($content,$item);
	return $content;
}
add_filter('exifography_display_exif','add_before_exif');

Rearrange your EXIF items

By default the exif items are listed in alphabetical order. You can change that by reordering the $content array. The Exifography output is stored as an associative array, which means that each value is stored with a named key, and that named key is the same as the name with which the exif is stored in the database, and the name that Exifography accepts as a parameter in its function and shortcode.

This function uses an array of EXIF fields that you define ($order) to create a new array with the EXIF data in the order that you give it, and then combines the new array and old array (in case there were other EXIF fields that should be shown, but that you didn’t include in your order).

function reorder_exif($content) {
	$order = array('shutter_speed','aperture','iso','camera');
	$new = array();
	foreach ($order as $key) {
		if (isset($content[$key])) {
			$new[$key] = $content[$key];
			unset($content[$key]);
		}
	}
	$new_content = array_merge($new,$content);
	
	return $new_content;
}
add_filter('exifography_display_exif','reorder_exif');

Change an EXIF item

You can change an individual EXIF item to anything you want by redefining the array item with that particular key.

Here is a really simple example to show you just how to change a particular item.

function change_aperture($content) {
	if (isset($content['aperture']))
		$content['aperture'] = '<li>This will display instead of the Aperture item!</li>';

	return $content;
}
add_filter('exifography_display_exif','change_aperture');

The following example is more complicated and includes fetching of image information using the image ID. It changes the location display to show latitude and longitude separately. It also uses some of the functions from within the plugin to format the location data.

function change_location($content,$postID,$imgID) {
	if (class_exists('exifography')) {
		$exif = new exifography();
		$imgmeta = wp_get_attachment_metadata($imgID);
		if (isset($content['location'])) { 
			if ($imgmeta['image_meta']['latitude'])
				$latitude = $imgmeta['image_meta']['latitude'];
			if ($imgmeta['image_meta']['longitude'])
				$longitude = $imgmeta['image_meta']['longitude'];
			if ($imgmeta['image_meta']['latitude_ref'])
				$lat_ref = $imgmeta['image_meta']['latitude_ref'];
			if ($imgmeta['image_meta']['longitude_ref'])
				$lng_ref = $imgmeta['image_meta']['longitude_ref'];
			
			$content['location'] = '<li>Latitude: ' . $exif->geo_pretty_fracs2dec($latitude) . $lat_ref . '</li>
	<li>Longitude: ' . $exif->geo_pretty_fracs2dec($longitude) . $lng_ref . '</li>';
		}
	}
	
	return $content;
}
add_filter('exifography_display_exif','change_location',11,3);

Some brief notes on what some of that code does:

  • $exif = new exifography(); sets a new variable to access functions within the plugin’s class. Without it you won’t be able to use the geo formatting functions that I have used here (and your location info will just be a big number).
  • $imgmeta = wp_get_attachment_metadata($imgID); gets all the metadata for the image, including EXIF and IPTC data.
  • The middle bunch of code is fetching all the different location related fields from the image meta so that we can use them in the content we wish to display.
  • $content['location'] = defines how the location data should display, and I’ve set it to show two list items, one with latitude and one with longitude both in the degree format.

As you can see there is a lot that can be done to customise your EXIF output. I hope these examples get you well on your way.

Comments

  1. Hi Kristen,
    great work !!!!
    Found your plugin while redesigning my page.
    I have a two questions ?
    1. how to add additional exif/iptc fields make them markable and bring them on.
    i.e Lens and Whitebalance
    2. how to format the output in an Subform.
    ie in an table with border?

  2. Holger — Cheers.

    The second part is easy: put your HTML in the options page, like:
    options page HTML settings

    The first part is more complicated. Neither of those things are imported by WordPress so you need to filter the WordPress image processor to import those things. I wrote a post about how you import geo data; it would be similar for the ones you’re talking about. Then you need to figure out what the official tags for those exif items are in the EXIF specs. The one for white balance is WhiteBalance, but I can’t find the official spec for the lens type in EXIF or IPTC. There’s the focal length the photo was taken at, and there’s the lens’ maximum aperture, which is useful if you’re using a prime lens, but otherwise not as useful. As far as I can see in discussions on the net the lens might be LensID, but then that is only stored as a number and you need a table like this one for Nikon lenses to figure out what the numbers mean.

    The function to allow importing that info into the database is:

    function add_my_exif($meta,$file,$sourceImageType) {
    		$exif = @exif_read_data( $file );
    			if (!empty($exif['WhiteBalance']))
    				$meta['white_balance'] = $exif['WhiteBalance'] ;
    			if (!empty($exif['LensID']))
    				$meta['lens'] = trim( $exif['LensID'] );
    	
    	return $meta;
    }
    add_filter('wp_read_image_metadata', 'add_my_exif','',3);

    The function in the post that shows redefining how the location shows should give some hints as to how you fetch the info from the database in order to show it. You would create new array entries for your new data.

    I will think about adding these to future versions of the plugin, but the lens one might take a bit of work to find or build a little database of lens numbers & readable formats.

  3. Hi Kristarella,

    impressive fast and good respond ;-) thx!!!!
    Ok, the first Part is sucsessfully implemented in my TestEnviroment.

    The second Part requires a little more work 2do….
    Meanwhile I have edited your exifography.php tohopefully i can figure out how to add and display the WhiteBal field in your exifography.php, because this great plugin is exactly that waht I need on my page !!
    For the start I added the checkboxes for WB on the backend and can now display the linked maps in an seperate Tab but the best is my changes are working so far ;-)

    CU

  4. Hi,
    Sorry for the Post before my Line was laggy ;-) Here waht I want to write…

    Hi Kristarella,

    impressive fast and good respond ;-) thx!!!!
    Ok, the first Part is sucsessfully implemented in my TestEnviroment.

    The second Part requires a little more work 2do….

    For the start I edited your exifography.php to add the checkboxes forthe WhiteBalance on the backend and changed the geodata to display the linked maps in an seperate Tab. But the best thing for me as an noob is that my changes are working so far ;-)

    CU

  5. Holger — I would generally recommend not editing the main plugin file because any changes will be overwritten when there’s an update. The idea of the filter is that you shouldn’t need to edit the plugin itself. Adding White Balance as a checkbox won’t actually add the EXIF to the plugin output unless the relevant EXIF is first imported from the image into the database (which is where the filter for ‘wp_read_image_metadata’ came in)… if that’s done adding it to the checklist might be sufficient, but I’d need to test it.

    If you need more code-based help it is probably better to do that in the WordPress forum because posting code in WordPress comments can be problematic.

  6. Emmanuel Rondeau

    Hello Kristarella,

    I’ve tried many times (with many different kind of images) to get this lensID but with no result.

    However, when I open the file with Mac Preview, I can see the information on lenses in the Inspector tab.

    Any idea?

    Thanks!
    Emmanuel.

    • Emmanuel — lens id is not currently imported into the WordPress database and so not able to be displayed by exifography. I may enable lens id in the future, but I haven’t had time yet: it’s actually a lot of work because the lens is only stored as a number in the exif and so I need to have my own database to check that number against to show the human-readable version of the lens. So far I’ve found a few tables of different brand lenses. When I get the chance I will either compile them or find a more comprehensive list.

  7. Emmanuel Rondeau

    Thanks Kristarella. I was currently also looking into this [http://www.ozhiker.com/electronics/pjmt/] that seem to work for getting the ID…I’m just starting to dive into this, so I will know more in about an hour or so.

    For the db, I got the Canon and Nikon ones.

  8. Emmanuel Rondeau

    Back to you. Using the library below and using this code :

    $image_header = get_jpeg_header_data(“00001.jpg”);
    $XMP_text = get_XMP_text($image_header);
    print( “VALUE:” . $XMP_text . “”);

    I’m getting the following output (I’ve put ‘etc’ at the end because the output is pretty long’) :
    VALUE: 489 70/1 300/1 0/0 0/0 0 EF70-300mm f/4-5.6L IS USM 0/1 2.0.7 420202419 Emmanuel Rondeau etc….

    So there is the lensID (489) but ALSO the lens name (EF70-300mm f/4-5.6L IS USM), I’m surprised about this.

  9. Emmanuel Rondeau

    Sorry for spamming like this :)

    Besides the code&library I shown above, the still I’m still not getting is how $exif['LensID'] cam be empty when on Mac Preview/Inspector I’m having the right value. I’m actually fine with the database option, but I still need to get a way to get this ID.

  10. Emmanuel — I’m not sure if I can explain it more than my previous comment, but I’ll try again… WordPress and Exifography use EXIF data that is imported into the WordPress database upon upload. Not all EXIF is imported; only the specified fields. At the moment all of those fields are available in Exifography (see the shortcode terms list to see all the fields). And Exifography has actually enabled the import of exposure bias and geo data; those two aren’t in the WordPress core.
    So to use any WordPress or Exifography functions to display the lens ID, the lens info first has to be imported into the WordPress database.

    I’ve had a brief look at the software you mentioned, but I can’t immediately see anything helpful regarding the lens ID; I won’t get a chance to properly look for a few days. If you want to look into enabling the import of the lens ID into WordPress you can look at the Exifography source, or see this blog post. That is probably the least of it though; making a comprehensive list to compare the IDs to their proper names is the main part.