I just said what I said and it was wrong
Or was taken wrong

I wrote a little utility called snapftp a few years ago to streamline my writing of posts about software. These posts typically include a snapshot or two of the software, and the purpose of snapftp was to take the multistep process of

taking the screenshot,

resizing it to fit in the blog, if necessary,

uploading it to the server, and

putting the URL of the uploaded image onto the clipboard for linking

and make it about as simple as the built-in screenshot utility bound to ⇧⌘4.1

Snapftp still works fine, but I’ve been thinking recently that most of the images I use here should be served from Flickr rather than the blog’s shared hosting server—this should help stave off any future Fireballings. I do, after all, have a Flickr Pro account and might as well take advantage of it.

So I wrote a new script, called snapflickr, which I use more or less the same way I used snapftp: I launch it via FastScripts through the ⌃⌥⌘4 key combination, and it puts up this dialog box:

I fill in the file name and, optionally, a description. If I don’t want the image uploaded to Flickr, I click the “Local file only” checkbox (this is typically for images I want to edit or annotate before uploading). When I click the Snap button, the dialog disappears and the cursor turns into a camera. I put it over the window I want a snapshot of and click. The image is saved to my Desktop and uploaded to Flickr. A URL for the uploaded image (about which more later) is put in the clipboard, and the Flickr page for the image appears in my default browser.2

As with the built-in ⇧⌘4 screenshot utility, I can switch between taking snapshots of windows and snapshots of rectangular areas by pressing the spacebar after clicking the Snap button.

Here’s the source code for snapflickr. It uses two third-party libraries: Carsten Blum’s Pashua, which is both an application and a library, and Sybren Stüvel’s FlickrAPI. The other libraries snapflickr uses are included in the standard Python distribution.

Flickr requires programmers to register their applications before using its API. It’s a simple process, and at the end you’re given a key and a secret that are parts of the authentication process. Snapflickr stores my key and secret on Lines 15 and 16. The last part of the authentication process, the token, is stored on Line 17. Getting the token is an interactive bit of business that we’ll look at later.

The biggest section of the script, Lines 19-64, is the definition of the dialog box and the call to Pashua to display it and get the input. As I’ve discussed this in a previous post, I won’t repeat the description here. Suffice it to say that if I had to write this kind of fiddly UI code often, I’d be looking for a way to use Interface Builder instead.

The snapshot itself is taken in Line 73 by calling the screencapture utility. The -i option makes it work interactively; the -W option puts it in “window selection” mode initially (which, as I said, can be changed to “mouse selection” mode by pressing the spacebar); and the -t jpg option does exactly what you think: it saves the screenshot as a JPEG.

I used to save my screenshots as PNGs to get pixel-perfect representations, but I’ve learned that Flickr is better suited to JPEGs. The problem is the transparency in the window shadow. Flickr handles that well in the Original version of an uploaded PNG, but in all the other sizes, the transparency is lost and the shadow turns into an ugly black frame around the image. That doesn’t happen with JPEGs.3

Lines 79-107 handle the interaction with Flickr.

Lines 80-81 establish the connection with the API using the credentials given near the top of the script.

Lines 82-84 do the uploading and get back the Flickr ID of the uploaded image.

Lines 87 and 88 use the ID to construct the URL to the Flickr page for the image.

Lines 89-94 grab the information about the Original and Medium sizes of the image, and Lines 98-101 determine which image URL will be put on the clipboard. If the Original image is wider than 500 pixels, I use the Medium size because that fits well in the content area of the blog.

Line 104 calls the pbcopy utility to put the image URL on the clipboard.

Line 107 calls the ever-useful open utility to open the image’s Flickr page in my default browser. Currently, this is Safari, but if I ever change to Chrome, open is smart enough know that and use Chrome instead.

The hardest part was the stuff in Lines 86-101, mainly because it involved the confluence of three libraries I’d never used before: the Python FlickrAPI library, the Flickr API itself, and the Python ElementTree library, which FlickrAPI uses to return results. I often found myself searching for help only to realize that I was looking in the wrong documentation.

Let’s talk about the authentication token. Flickr requires the user of a program to give permission for that program to access the account. When the user gives permission, Flickr provides a token that the program must then include to authenticate subsequent calls to the API. Fortunately, I don’t have to go through this permission dance every time I want to use snapflickr. I only had to get the token once—using a completely different script—and save it on Line 17.

The script I used to get the token is the Authentication script found in the documentation of Maël Clérambault’s Ruby flickraw library. Why did I use a Ruby script when I don’t really know Ruby? Well, the documentation for the Python FlickrAPI library didn’t have very many code examples, and before I did any coding I wondered if maybe Python wasn’t the right tool for this job. The Ruby library seemed much more inviting, so I began playing around with it. One of the scripts I tried was this Authentication example:

I put in my key and secret in Lines 3 and 4 and got a token when I ran it. When I eventually decided to use Python anyway,4 there seemed no good reason to let that token go to waste, so I copied it from the Terminal into snapflickr. You may call this lazy; I prefer to think of it as supremely efficient.

Now that I have a little experience with the FlickrAPI library, I’ll probably rewrite my Flickr URL TextExpander snippet to use it instead of the convoluted (and fragile) screenscraping logic it currently uses.

If the “Local file only” box is checked, none of the Flickr-related actions are performed. ↩

You may be wondering why I don’t use the -o option to screencapture to eliminate the shadow. The problem is that -o also eliminates the thin black line around the window border, which makes the screenshots look wrong. Try it and see. ↩

There are two parts to the snapflickr: the user-facing Pashua interface and the backend Flickr interface. Ruby seemed easier for the backend work, but that was going to be the distinctly smaller part of the script. Because I’d already used the Python interface to Pashua on snapftp and had a few dozen lines of code that just needed a little editing, Python won. ↩