Tag, You're It

One of the most frequent complaints I get about my photo album is that it's too linear - i.e., with over two thousand photos in there, some people would rather browse by topic/keyword than follow a time line or click around randomly.

But to do so requires proper handling of metadata, and we all know how utterly useless iPhoto is at storing and manipulating the metadata in the files themselves - not only does it not handle all EXIF/IPTC fields I need, but it insists on storing the metadata separately and is inconsistent as hell on what it imports and exports.

This is something I've been complaining about for years (just check out my EXIF node or search for "metadata"), and I've been coding my own web-based EXIF tagger for months now.

The trouble is that there have been two things putting me off time and again:

  1. the lack of a decent Python library to write EXIF data
  2. my utter lack of time to code (which includes being able to do a decent UI with Prototype)

My current Snakelets prototype works for reading, adding comments and using a sort of "poor man's EXIF tagging". This consists of adding keywords to the Comments field (like my very first approach to filing and tagging), and works fine as a general technique.

The real trouble is that the time and energy required to polish the application to a level where I could actually use it on a daily basis was too much. Maybe going all Web 2.0 on it wasn't a good idea, since making sure thumbnails were cached and generated properly, doing the "automagic" completion UI, getting drag and drop to work, etc., etc. turned out to be a major drag (pun intended).

I'm finicky to the point of spending hours getting the interaction model down to something I can use without thinking and re-painting pixels to line up just right, and dealing with JavaScript and several browser quirks was getting on my nerves - which meant less and less time (or will power) to make any significant progress.

Scripting Judo

So I decided to turn the problem around - instead of rolling my own, I am now going back to where I was a year ago, trying to make the best out of what Apple (and quite a few other folk out there) already built. Which, since it means using iPhoto as the main UI, involves lots and lots of AppleScript.

The only catch is that it all has to comply with my Data For The Ages approach - i.e., the end result must allow me to export a set of photos with proper IPTC/EXIF tagging, even if the tools themselves are fairly proprietary.

As a starting point, I activated the Script Menu on my iMac and grabbed Andrew Turner's set of AppleScripts. He uses ExifTool (yes, yes, I know, it's a Perl-based utility - pfig will harp on about this for weeks), and the download archive includes three basic scripts:

  • One to set copyright and ownership information
  • One to set GPS EXIF tags (through a series of dialogues)
  • And another to set EXIF data (titles, comments, keywords, etc.) based on iPhoto metadata.

The thing is, these are only one-way (iPhoto to EXIF). I already had some EXIF metadata (like photo titles) that I wanted to migrate into iPhoto, so I tackled that problem first.


Before I started doing my own tagger, I decided to store basic metadata on a text file with the same base name as my photos. Since all my photos are batch renamed into a YYYYMMDDHHMMSS.jpg pattern, it was fairly simple to maintain and update as necessary (even if a bit wasteful of disk space).

To import them into the right EXIF fields, I set up a local replica of my online photo album and ran the following script to merge the titles (which I had stored in .txt files alongside the photos) into the EXIF Title tag and remove some of the comments I already had:


for FILE in *.txt
  echo $IMAGE
  TITLE=`cat $FILE | head -1`
  exiftool -overwrite_original_in_place -title="$TITLE" -comment="" $IMAGE

Then I held Option (Alt for those of you who only know modern-era Apple keyboards) down as I launched iPhoto to create a brand new photo library for my tagging endeavors, and started playing around with AppleScript.

EXIF to iPhoto

Since Andrew's scripts only add EXIF tags based on metadata, I had to reverse the process and set iPhoto metadata based on the EXIF info.

Once I figured out how to output EXIF data as a tab-separated list of names and values, it was fairly easy to do:

copy (my selected_images()) to these_images
if these_images is false or (the count of these_images) is 0 then ¬
  error "Please select at least one image."

repeat with i from 1 to the count of these_images
  set the keywordslist to ""
  set this_photo to item i of these_images
  -- Grab the image file name
  tell this_photo
    set the image_file to the image path
  end tell
  -- Ask exiftool for tab-separated fields
  set output to do shell script ¬
    "exiftool -t '" & image_file & "'"
  -- Split output into a list of lines
  set output to the paragraphs of output
  -- Prepare to split lines by tabs
  set AppleScript's text item delimiters to {ASCII character 9}
  repeat with fields in output
    set fields to fields's text items
    if item 1 of fields is "Title" then
      tell this_photo
        set title to the item 2 of fields
      end tell
    else if item 1 of fields is "Comment" then
      tell this_photo
        set comment to the item 2 of fields
      end tell
    end if
  end repeat
end repeat

display dialog "Exif reading complete."

This needs some clean-up and optimization (invoking exiftool for each file sucks, and I'll have to add keyword parsing later as well), but did the trick for the initial import of 2100 photos into a new iPhoto library - I just selected them all and ran the script, which took a while.

Paging AppleScript Gurus

So far so good. But my goal is to have fully symmetrical import/export of all the metadata I need, and so far I've come across two major problems:

  • There seems to be no way in the iPhoto dictionary to programmatically set GPS attributes via AppleScript.
  • If I set them manually via the filesystem, iPhoto refuses to load them from the updated files.

Rebuilding the library doesn't seem to work, either.

Any input on this is welcome, since there seems to be no documentation on the right technique to use, and AppleScript oral tradition (i.e., Google) has led me nowhere.

Other stuff I intend to do is:

  • Find a way to preserve rankings (maybe using keywords, but I'd rather use a standard EXIF/IPTC field).
  • Get GPS tagging to work by invoking Google/Maps via Safari and parsing the location URL (which is pretty easy to do).
  • Adding Growl notifications and some sort of a decent progress bar.
  • Building an "export" script to archive my photos on a network drive and update a list of MD5 checksums.

...which probably means I will be playing around with AppleScript Studio and build some sort of UI instead of relying on the Scripts menu.

Update: dth pointed me to Sven-S. Porst's approach to Geotagging, which includes a Google/Earth-aware script but which does not solve one of the fundamental issues - to get iPhoto to refresh its own metadata and display the new GPS tags.

Keywords Galore

Now that I have a fancy UI to do all sorts of group tagging, titling, commenting and whatnot, all that's left is to use it, right?

Well, as it turns out, iPhoto's tagging UI sucks. I would even go as far as to consider it utterly useless, since it seems to have been designed for people who will seldom tag photos (if at all), and requires you to do two things I find positively stupid:

  • You have to invoke the Info panel and use the mouse to hit a checkbox per keyword (which means lots of scrolling around and clicking if you have more than a dozen keywords)
  • You can't define new keywords on the fly - You have to go back to Preferences to add them.

As it turns out, there is a ready fix for that - Ken Ferry's Keyword Assistant makes it relatively painless to do mass tagging and lets you define keywords on the fly.

Plus, with a bit of practice, you can use it almost exclusively via the keyboard.

Update: James Webster pointed out in the comments that there is now a Universal version of Keyword Assistant released the very day I posted this, so I revised the text below.

The first version I got had two catches, though: It wasn't a Universal binary (something that isn't important for me yet, but which bears noting) and it was written for iPhoto 6.0.2, which means that it couldn't automatically add keywords to iPhoto 6.0.4 unless you fired up your favorite hex editor and applied this fix.

I'm using the freshly updated Universal version now, and it is full of neat tricks (such as holding down modifier keys to remove tags). It has certainly saved me a lot of time, although my back-up plan was to add scripting actions to Quicksilver, which is something I will explore later (since it seems feasible to invoke Quicksilver, type in a bunch of keywords and have them applied to the current selection via AppleScript).

Now, Where Did I Shoot That?

I'm now going through the 2100 photos in this site's photo album, and to further ease the process I've created a set of smart folders to save me a lot of time:

  • A few smart folders for specific keywords that I know will be associated with many photos (Lisbon, Flowers, etc.)
  • A smart folder for photos with invalid titles (all untitled photos have their title set to their filename)
  • A smart folder for untagged photos (which is where I spend most of my time)

And yeah, it takes some doing. Fortunately, I can still remember where I shot most of my photos and in which context, but I've come across one or two fun puzzles already. It's odd to think that it all comes back to me when I browse the album at random, but that it sneaks around the corner of my mind when I'm actually trying to remember.

I can't wait to figure out how to set GPS tags properly - clicking around on a map is going to add an entire new dimension to this sort of mind game...

See Also: