29 January 2009

Scripting iPhoto 09 with Ruby

I upgraded to Apple iLife 09. My main motivation was to get the new version of iPhoto, which adds support for face recognition and GPS integration.

When I fired up the new iPhoto, I discovered that the GPS data for my images in JPEG format had been read in correctly; but that all of my Canon raw CR2 files had been ignored, even though the photos of Hamburg mostly had GPS data.

I investigated whether iPhoto was scriptable. If I could add the GPS coordinates to the existing photos via AppleScript, I could take the GPS track logs and build an importer. Unfortunately, though, there’s no AppleScript interface to the GPS metadata, according to iPhoto’s AppleScript dictionary.

Experimenting further, I discovered that if I rooted around inside the iPhoto library (using right click and “Show contents”), copied the CR2 files out, and imported them into iPhoto again, that the GPS data would be processed correctly.

There was a snag, though. If I did that, I would lose all the names and descriptions I had entered in iPhoto. This was a solvable problem, though: iPhoto remembers the original filename, and has AppleScript properties that let you read and write the description/comment and name/title of any image.

The next small snag was that I don’t know AppleScript. I’ve tried to learn it, but I find it very annoying and syntaxy. I considered giving it another go, but I did a few quick Google searches and determined that AppleScript lacks hashes, arrays, and most other useful data structures that you might use to store and retrieve a set of captions for a large number of photographs indexed by filename.

Ruby to the rescue. When Apple created AppleScript, they did it by layering it on top of a lower level system called OSA or Open Scripting Architecture. This is a language-independent API, which means that you can glue any scripting language to it, and instantly be able to do anything in that language that you can do in AppleScript. There are a couple of projects which link OSA to Ruby; I picked RubyOSA , though a brief exploration of rb-appscript (a port of a Python bridge, spit ) suggests that it would have done the job too.

A quick sudo su and gem install ruby-osa , and I was ready to script iPhoto using Ruby. I built two scripts. The first, iphotodump.rb , dumps out all the titles and comments for the selected photos, storing them in data files using Ruby’s standard marshalling (persistence) mechanism. The second script, iphotorestore.rb , reverses the process: it reads in the data files, then scans through the selected images and restores the appropriate metadata by matching up the filenames of the original image files.

I ran iphotodump to dump out all the metadata for my Hamburg photos, deleted them from iPhoto, re-imported the CR2 files, then ran iphotorestore to restore the metadata. Problem solved.

I imagine there are other people out there with similar iPhoto-related metadata problems, so hopefully my scripts can point the way at solutions. With iPhoto glued to Ruby, there are all kinds of possibilities–for example, you have the power to do a full regular expression search and replace, with Perl-like regular expression power. I think I’m also going to write something to append the photo’s keywords to the description, so I can then go on a keyword deleting spree but still be able to find photos using search.

© mathew 2016