Archive for the ‘photos’ Category
Selecting nonRAW photos in iPhoto via AppleScript
July 7th, 2009 at 4:14 pm
I’ve started using the RAW format on my Canon G10 and have run into a small annoyance when importing into iPhoto. Both the RAW image and an accompanying JPEG of the same photo are imported, giving me two images for every photo.

The JPEGs seem unnecessary; they contain less information than the RAWs and new JPEGs can always be generated from the RAWs. Selecting the JPEGs and deleting them is easy when I’m importing only a few images, but it’s tedious when importing dozens. Here’s a semi-automated to do it.
- Have the Event you’ve just imported showing in iPhoto, as in the screenshot.
- Run the “Select non-RAWs” script described below (I use FastScripts, but there are other ways).
- Deselect any JPEGs that don’t have an associated RAW, because we don’t want to delete those.
- Delete the selection.
Here’s the AppleScript that does the selecting:
1: tell application "iPhoto"
2: set rawKW to item 1 of (every keyword whose name is "Raw")
3:
4: select (every photo in current album whose keywords does not contain rawKW)
5:
6: end tell
The script takes advantage of the fact that iPhoto automatically gives every RAW image the “Raw” tag. As usual, a seemingly simple AppleScript actually involved much trial and error to make sure the distinctions between strings, lists, and the ever-mysterious “references” are honored. Also note the “English-like” construction in Line 4:
whose keywords does not contain
Lovely.
The script would be much better if I had been able to write it like this:
tell application "iPhoto"
set rawKW to item 1 of (every keyword whose name is "Raw")
set rawNames to name of every photo in current album whose keywords contains rawKW
select (every photo in current album whose keywords does not contain rawKW and name is in rawNames)
end tell
This would select only those JPEGs that have a corresponding RAW, and Step 3 of the procedure wouldn’t be needed. Unfortunately, trying to run this script leads to an error:
iPhoto got an error: Can’t make {"IMG_1050", …} into type reference.
This is, apparently, a known problem for which I couldn’t find a straightforward workaround. If you know of one, email or Twitter me.
Update (7/10/09) After reading this post at maccreate.com, I went looking for a setting to prevent my camera from automatically creating a JPEG along with the RAW. This morning I finally found it. Not making or importing the JPEG in the first place is a much better solution than what I’ve described in this post.
Poor man’s cable release
July 6th, 2009 at 4:30 pm
I was going to take fireworks photos on Saturday with my Canon G10, which has a fireworks mode (focus at infinity, 2-second exposure, f8.0, ISO 80), but decided that I was already carrying more to the park—chairs, blanket, bug spray, etc.—than I wanted to. Maybe I’ll take photos next year, when my boys are older and can share more of the burden. In preparation for the photos I never took, I “made” a cable release for the camera, the highly intricate plans for which are detailed below.
A cable release is way of remotely operating the shutter of your camera. Its used mainly to take long-exposure photos without touching— and thereby shaking—the camera. Canon makes a cable release for the G10, but it’s only two feet long and pretty expensive for an item that I don’t expect to use very often.

You can also use the G10’s self-timer as a sort of cable release. Set up the camera to use the timer, press the shutter button, and pull your hands back so the camera’s vibration damps out before the timer opens the shutter. I’ve used this method many times with several camera models; it works fine, but it is a bit slow and awkward compared to a real cable release.
The key to making your own cable release lies in recognizing that the official Canon product has a 2.5 mm (or 3/32″) TRS connector—i.e., mini stereo plug—that fits into a jack on the side of the G10’s body. This is just a smaller version of the standard 3.5 mm (1/8″) stereo plug you’ll find at the end of your iPod earbuds.

(Image taken from the G10 manual.)
Cables with 2.5 mm jacks are relatively rare, but cables with 3.5 mm jacks are as common as dirt. I had a couple of them in my electronic junk box, including a 10-footer that had the TRS jack at one end and a 9-pin serial connector at the other1. This cable, combined with a 3.5-to-2.5 mm adapter—which are fairly cheap—were all I needed.
Cutting off the serial connector and stripping back the insulation, I exposed the three wires inside the cable. One wire is connected to the sleeve (1) of the jack, one is connected to the ring (2), and one is connected to the tip (3). The TRS connector gets its name from these three parts: Tip, Ring, Sleeve.

The image above shows the stripped wires in the cable, the 3.5 mm jack at the other end of the cable, and a Radio Shack adapter. The numbering of the tip, ring, and sleeve were taken from an image on the TRS Wikipedia page.
After plugging the cable’s jack into the adapter and the adapter into the port on the camera, it took less than a minute of experimenting to learn that touching the ring wire to the sleeve wire caused the camera to focus (like pushing the shutter button halfway down) and touching the tip wire to the sleeve wire caused the shutter to trip (like pushing the shutter button all the way down). There’s no need for power or any other wiring; just touch the wires to operate your camera remotely. Now you see why I said in the first paragraph that I “made” this release—there’s really nothing to it.
Eventually I’ll buy a cheap momentary switch and connect the raw end to it to give me something a little easier to use and less likely to unravel. But even without that, I have a working 10-foot cable release.
-
I don’t know what it was for, but I do know that none of my computers have serial ports anymore. I’ll never need that connector again. ↩
FMiL
June 16th, 2009 at 7:52 pm
Today I got my copy of iLife ’09 and installed it. I’ll start playing around with iMovie and iDVD eventually, I’m sure my older son will get interested in those programs and in GarageBand and iWeb, but my immediate interest was in iPhoto. So far it’s been a series of disappointments.
I’ve never been a big fan of iPhoto and still won’t use it with the photos I take for work—they need a specific type of project-based organization and separation that iPhoto will never provide—but I have started using it for my personal photos. I’ve been using whatever version came with my Intel iMac a couple of years ago, and wanted to upgrade to iPhoto ’09 for four reasons:
- Geotagging my photos with Places. I don’t have a GPS-equipped camera, but I like the idea of having the location of the photo attached to it, even if I have to do it “by hand.”
- Handling RAW images. My camera does have the ability to shoot RAW, and there are times when I’d like to make use of that.
- Uploading directly from iPhoto to Flickr. The uploader program from Flickr is kind of clunky.
- Straightening photos without using an external editor. I have a tendency to tilt the camera a bit when composing a shot, and I’d like to correct for that within iPhoto itself. My older version couldn’t do that.
I haven’t tried anything with RAW images yet. The straightening function seems to work very smoothly. As for geotagging and Flickr uploading, they’ve been a real disappointment. Geotagging by hand simply doesn’t work, and Flickr support is sort of half-assed by design.
Let’s start with Flickr, because it’s easier to explain. When you choose some photos and click on the Flickr button, this sheet pops out of the titlebar:

The first problem is that the name of the photo I’m uploading isn’t “Dec 23, 2008”—that’s the date on which it was taken. So the heading at the top of the sheet is misleading. More important, though, is that iPhoto is going to create a new Flickr set to put the uploaded photo into. There’s no opportunity for me to select an existing set. If I want the picture in an existing set—or a new set with a name other than “Dec 23, 2008”—I’ll have to go to my Flickr Organizr and do all that manually. Same for adding photos to groups. This is really annoying, as it makes it seem like you’re doing everything twice.
iPhoto does upload its metadata—title, keywords (tags), description—to Flickr, but there are some downsides to that. You can’t, for example, use different tags for iPhoto than you use for Flickr, because iPhoto establishes a permanent two-way connection between the two. This automatic syncing may be just what you want, but there are situations where you’d probably want different tags. Pictures of your kids, for example, would probably be tagged with their names in your personal iPhoto library, but you may prefer a more generic “kids” tag on a public site.
Frazier Spears discussed these shortcomings and others in a blog post written shortly after iPhoto ’09 came out. I saw links to the post back then but didn’t think to check it out when I was making the decision to buy iLife ’09. Spears is the developer of FlickrExport, an iPhoto plugin that does exactly what you’d think. It’s true that he’s hardly a disinterested party, but it’s also true that he’s spent a lot of time thinking about how Flickr exporting should be done. His appraisal of iPhoto’s Flickr uploader seems pretty fair to me.
The problem with geotagging is worse, but it seems to be due to a bug, not a design decision. When you try to set the location of an image through the Add New Place map, you cannot scroll the map to the right spot by dragging it around.

Instead of scrolling, the tiles of the map turn to ghost images as you click and drag them. It’s reminiscent of the way images on a web page become ghost-like as you drag them out of Safari and onto the Desktop.
Apparently that resemblance is not a coincidence. In this thread on Apple’s discussion site, several people have mentioned this problem and said it only arose after they upgraded to Safari 4—before that, the maps could be dragged just they can in Google Maps. At first, you may think that a web browser upgrade would have nothing to do with iPhoto, but I think the connection is reasonable. Much of the Safari upgrade consists of changes to the underlying WebKit infrastructure, an infrastructure that many applications use. OmniFocus had some problems during the Safari 4 beta phase. It only makes sense that iPhoto would be using WebKit to access and display data from Google Maps.
The most important thing I got from the Apple discussion thread is that I wasn’t nuts. The map is supposed to be draggable and in fact was draggable until recently for all those people.
Almost everyone on the thread has filed a bug report. I filed one myself this evening. It would be nice if Apple came out and told us if this really is related to Safari and when we can expect—ah hahahahahahahahahaha heeheeeheeheeee hohohohohoho haaaaa hahahahahahaha, oh man, I kill me sometimes. Anyway, maybe we’ll get one of those “assorted bug fixes and feature enhancements” updates and the problem will go away.
Update 6/17/09
Apparently I have more influence at Apple than I thought. Just one day later, Apple has issued Safari update 4.0.1, which “addresses incompatibilities between Safari 4.0 and certain features in iPhoto ’09, including Places and Facebook publishing.”1 I don’t know anything about the Facebook publishing part, but the Places problem is gone. The map can now be scrolled by clicking and dragging and you can set a photo’s location to wherever you want.
I must learn to harness this newfound power and ensure that it is used for good rather than evil.
-
I even shamed them into giving a proper description of the fix instead of the usual mumblemumble. ↩
Snappy
June 9th, 2009 at 11:30 am
On my way into work yesterday, I pedaled past this guy resting alongside the Waubonsie Creek Trail.

The path runs between a creek and a pond, and I’m not sure if he was going from one to the other or was just out to stretch his legs. I stopped and pulled out my camera for a few pictures, which I put up on Flickr.
The nice thing about shooting a turtle instead of a bird is that you don’t have be stealthy or quick about it. I did make sure to take one photo from a distance so I could capture him before he pulled his head in, but otherwise it was like shooting an interesting rock.
He was pretty big: his shell was about 10 inches across from side to side, and 12 inches long from front to back. I don’t carry a tape measure with me on my bike, but I can use my hand to give a sense of scale.

I wanted a clear view of his eyes for this portrait, and briefly considered clearing away some of the grass in front of him. But I decided my fingers were more important than an unobstructed photo.

Derotating JPEGs with exiftool
April 20th, 2009 at 4:30 pm
After importing photos from my digital camera, I often find that pictures I took in landscape mode are rotated to portrait mode. Rotating photos is no big deal—I can’t imagine any image editor that won’t let you do it—but I want the rotation to be done losslessly and I want to know it’s being done losslessly. Enter exiftool, an extremely full-featured program and Perl library for editing the EXIF metadata in image files. With exiftool, I can remove the spurious rotation that sometimes appears, and I know that it’s a lossless operation because exiftool doesn’t touch the image itself, only the metadata.
For a few years now, digital cameras have included a device that tracks the orientation of the camera and puts that information into the image file’s metadata. Applications that display images read that information and present the image rotated accordingly. The orientation information is expressed as an integer and written to a specific field in the EXIF metadata for the image.
If the camera is in landscape orientation with the bottom of the camera down, the orientation value is 1:

We can use exiftool to tell us this by executing
exiftool -Orientation -n <imagename>
and out will pop
Orientation : 1
If we leave out the -n option, exiftool will tell us the orientation in English:
exiftool -Orientation <imagename>
gives
Orientation : Horizontal (normal)
If the camera is rotated so the top is pointing to the photographer’s left, the image will look like this on our computer

and exiftool will tell us the orientation as
Orientation : 8
or
Orientation : Rotate 270 CW
which tells the software on the computer to rotate the image data 270° clockwise before displaying it.
Finally, if the camera is rotated so its top is pointed to the photographer’s right, the image will look like this on our computer

and exiftool will tell us the orientation as
Orientation : 6
or
Orientation : Rotate 90 CW
So far, so good. The photos of Dr. Doom appeared on my computer with the correct orientation because my computer looked at the Orientation field of the EXIF data and rotated the image accordingly.
Unfortunately, I happen to take a lot of photographs looking down, with the camera’s image sensor in a nearly horizontal plane. In this position, the orientation device—which presumably uses gravity to figure out which way is up—doesn’t have much to go on, and the value of the Orientation field is kind of a crapshoot. I think it reports the orientation the camera was in just before I pointed it down to take the picture. And that could be any orientation, because I never think about how I’m holding the camera before I’m ready to shoot.
When this inadvertent rotation occurs, I typically want to get rid of the rotation and put the photo in landscape orientation. Exiftool has a way of doing that. Instead of having it report the value of the Orientation field, I can have it write the value1:
exiftool -Orientation=1 -n <imagename>
will get stick the value of 1 into the Orientation field, and my computer will now display the images as if the camera had been held in the normal orientation. Doing this to the two portrait images of Dr. Doom yields

and

respectively.
I found myself doing this enough that I wrote a one-line shell script to save myself from typing “Orientation” over and over. I call it derotate:
#!/bin/bash
exiftool -Orientation=1 -n "$@"
One nice thing about derotate (which it inherits from exiftool) is that I can invoke it with as many arguments as I want:
derotate <imagename1> <imagename2> <imagename3> ...
and all of the images will be derotated.
There’s more to the Orientation field than 1, 6, and 8. A value of 3 represents an image rotated upside down (which my current camera, a Canon G10, doesn’t seem to generate), and values of 2, 4, 5, and 7 represent combinations of rotation and mirroring. You can see a full discussion here.
There’s more to exiftool, too. Read the fine manual.
-
By default, exiftool keeps a copy of the unaltered file in
<imagename_original>, so goof-ups can be recovered from. ↩
Fixing photo dates
February 4th, 2009 at 1:39 pm
Let’s say, just for argument’s sake, that when you got that new camera shortly after the first of the year, you mistakenly set its clock to the year 2008 instead of 2009. So now you have a bunch of photos with screwed-up metadata. What to do?
The first thing to do is download and install Phil Harvey’s extensive ExifTool system. ExifTool is a Perl library with a command-line application that can do all kinds of reporting and surgery on the metadata in your image files. Mac users can install ExifTool using either the Mac instructions (which install from a package) or the Unix instructions (which install through a Makefile). I chose1 the Unix installation so I’d have standard access to the libraries if I wanted to write my own programs. One thing I didn’t like about the installation was that it put the exiftool command-line program in /usr/bin, which I think should be reserved for Apple-supplied programs. After following Harvey’s instructions, I also did
sudo mv /usr/bin/exiftool /usr/local/bin/
which moved exiftool to a more suitable directory. There’s probably nothing wrong with the standard installation; this is just my preference.
With exiftool installed, navigate to the directory where your mistakenly-dated photos are and execute
exiftool '-AllDates+=1:0:0 0:0:0' *.JPG
This adds (+=) one year to all the date values (-AllDates) in the metadata for every .JPG file in the directory. The time shift is in the format
years:months:days hours:minutes:seconds
There are some shortcuts you can use if you just need to adjust the hour value—after a vacation in a different time zone, for example, or a shift to/from Daylight Saving Time.
Considering how little it seems to be doing, ExifTool runs rather slowly. That’s because it makes a backup copy of every file before changing the metadata. You’ll find the backups in the same directory as the originals, with an _original extension. If the metadata editing goes wrong, you can restore from these backups. This is a nice feature, but I still prefer to make backups before editing my photos.
ExifTool changes the metadata in the JPEG file itself. I’m not a big user of iPhoto, but it’s my understanding that it reads file’s metadata when the photo is imported, then uses its own copy of that data when displaying dates. So if you’ve already put the mistakenly-dated photos into iPhoto, you may need to move them out of iPhoto, change their dates, and then reimport them. Whatever you do, make sure you have backups before doing anything that might affect your precious photographs.
-
Oh, wait! This was supposed to be a hypothetical discussion, wasn’t it? ↩
TrueType fonts for the Python Imaging Library
November 12th, 2008 at 9:28 am
I’m gearing up to rewrite my photo indexing program again, and I’ve run across a problem in using TrueType fonts on the Macintosh with the Python Imaging Library. Fortunately, there’s a simply remedy.
In the beginning…
Back in 2000 or so, I wrote a Python program that took a bunch of JPEGs and created a new set of JPEG files (index pages) with reduced-size versions of the originals laid out in a matrix and labeled with their file names.
![]()
I called the program “photopage” and wrote about it here.
Over the years, I’ve rewritten the program several times. I’ve
- changed the language from Python to Perl to Ruby;
- changed the underlying library from the Python Imaging Library (PIL) to ImageMagick;
- changed the output from JPEG to PDF and back; and
- changed the output paper size from 8½×11 to 8×10.
Most of these rewrites were done to support different ways of printing the index pages, but sometimes I was trying to get the program to run faster and sometimes I was trying to learn a new language and/or library. The last rewrite was called “photosheets” and I described it here. That was two years ago, so I’m antsy to do another rewrite.
Fonts in PIL
I’ve decided to go back to Python and PIL. Overall, I liked PIL more than ImageMagick but didn’t like PIL’s need for specially-formatted bitmap fonts for every size and resolution. Now that PIL can use TrueType fonts, I’m eager to go back to it as I’ll have more freedom in laying out the image labels and captions.
PIL’s function for loading a TrueType font is in the ImageFont module:
ImageFont.truetype(file, size)
where file is path to the .ttf file and size is the font size in points. Unfortunately, many of the system fonts on the Macintosh don’t have a .ttf file. If you look in /System/Library/Fonts/, for example, you’ll find a Helvetica.dfont, but no Helvetica.ttf. The .dfont format is a Mac-specific thing that, among other things, binds together the .ttfs for all the variants of the font.1 The TrueType information for each variant is inside Helvetica.dfont, but PIL isn’t smart enough to know how to extract it.
Fondu to the rescue
Luckily, a smart programmer named George Williams wrote a neat little command-line utility that creates .ttfs from .dfontss. It’s called “fondu”, and you can download it here. Williams provides Mac, Linux, and source versions of the program; the Mac version is a package that installs itself in /usr/local/bin/. Don’t be worried that the last update was three years ago—the program works fine on Leopard.
Because fondu creates several files, I recommend you create a new folder before running it. Then open Terminal, cd your way into that new folder in the Terminal, and run something like
fondu /System/Library/Fonts/Helvetica.dfont
using the full path to whatever font you’re interested in as the program’s argument. For the command above, I got 20 new files:
Helvetica-10.bdf HelveticaCE-12.bdf
Helvetica-12.bdf HelveticaCE-14.bdf
Helvetica-14.bdf HelveticaCE-18.bdf
Helvetica-18.bdf HelveticaCE-24.bdf
Helvetica-24.bdf HelveticaCE-9.bdf
Helvetica-9.bdf HelveticaOblique.ttf
Helvetica.ttf Untitled1-13.bdf
HelveticaBold.ttf Untitled2-13.bdf
HelveticaBoldOblique.ttf Untitled3-11.bdf
HelveticaCE-10.bdf Untitled4-11.bdf
The .bdf files are text files that contain bitmap versions of the font at various sizes. BDF is a Unix standard for X Windows. The four .ttf files are what we’re after. PIL works happily with them.
Looking ahead
I’m not sure of the best place to save the .ttfs. I’m certain I don’t want them in /System/Library/Fonts/ or anywhere the Mac normally looks for fonts, because I don’t want duplicates. I’ll probably end up saving them with the PIL library in /Library/Python/2.5/site-packages/.
-
For Helvetica, the variants are Regular, Bold, Oblique, and BoldOblique. ↩
Annotating photos with OmniGraffle
October 2nd, 2008 at 4:26 pm
The reports I write for work usually include photographs. Most of the photos are straightforward and need nothing more than a simple caption to explain. But some are of unusual items or are taken at unusual angles or magnifications; these are best served by annotations directly on the photo. Almost any graphics application can be used to add text and arrows to a photo, but OmniGraffle has become my favorite. It’s toolset makes the trial and error process of annotation very smooth.
OmniGraffle’s main purpose is to create diagrams—organization charts, flow charts, family trees, that sort of thing. It’s the Visio of the Macintosh world. What makes it different from other Mac drawing programs is how it keeps track of the structure of a drawing. Items that are connected by a line or an arrow stay connected as you move one or the other around. And it’s that feature that makes is so good for marking up a photo.
Start by creating a new, blank OmniGraffle document for importing the photo. Since OmniGraffle is a vector graphics program and photos are bitmapped images, there’s something of a mismatch between the two when it comes to sizes. OmniGraffle uses the Resolution setting in the JPEG to figure out big it should make the photo. For example, an 800x600 photo with a 150 dpi (dots per inch) resolution will be imported as a 5⅓″ by 4″ object in OmniGraffle.
To get a photo that fits nicely on a one-page OmniGraffle document, open the photo in Preview first, and use the Adjust Size command from the Tools menu to change the Resolution. If you change the units of Width and Height to inches, you’ll see immediately what size the photo will be in OmniGraffle. I like to adjust the Resolution to get the photo’s long dimension in the 5″ to 6″ range. Make note of the Resolution; you’ll need it when the time comes to export the annotated photo.

You may think that changing the resolution in Preview is an unnecessary step. After all, you can just grab one of the corner handles on the imported photo and resize it directly in OmniGraffle. That’s true, and if you plan to export the annotated photo as a PDF, resizing it directly in OmniGraffle is fine. But if you want to export it as a JPEG, TIFF, or PNG, you’ll need to know the resolution to get the best quality output. The only way I know to be sure of the resolution is to set it before you import the photo.
Once you’ve saved your photo with the new Resolution setting, you can import it into OmniGraffle either by using the Place Image command from the File menu or by simply dragging the photo from the Finder into OmniGraffle. Select the photo and lock it so you can add text to the document over the photo without attaching the text to the photo object itself. Now it’s time to start annotating.
I like to start by creating text objects with all the words I’m going to use. Helvetica Bold is my usual font and a 14-point size works well for 5″–6″ photos. I fiddle with the text colors to get decent contrast with the background colors. Here’s an example using a photo from my Flickr stream:

Now I select all the text objects and give them magnets on their left and right—or east and west, as OmniGraffle would have it—sides. This is done through the Connections tab of the Properties Inspector. Now the ends of the arrows I attach to these text objects will stay attached.

The next step is to create invisible rectangles to place over all the things I want to point to. I start out creating visible rectangles, then uncheck the Stroke, Fill, and Shadow properties in the Style Inspector.

Now that I have the invisible rectangles, I set the magnets on them according to how I want the lines to attach. North and south magnets on the objects that will have the lines coming in from the top or the bottom; east and west magnets on the objects that will have the lines coming in from the sides.

Now it’s time to draw the lines from the text objects to the invisible rectangles. Change the color and thickness of the lines to suit your purposes. Add arrowheads to the ends if that helps.

It’s at this point that OmniGraffle’s understanding of structure makes things nice. If you decide to move the text or the other end of the leader line, you just grab the object and drag it where you think it will look better. The lines will readjust on their own. For someone like me, who can’t stop fiddling with the layout, this saves a tremendous amount of time.

Also very helpful are OmniGraffle’s auto-arrangement features. When you need all your annotation text to be lined up and equally spaced, OmniGraffle pops up little hints that let you snap things into place as you drag them around. Very neat.
I’m not suggesting you go out and buy OmniGraffle just for annotating photos. But if you happen to have a copy, this is a use you might not have thought of.
Photos, CoverFlow, QuickLook, and Spotlight
February 9th, 2008 at 11:22 pm
I take a lot of photos for work. I organize the photo files according to project and the date on which they were taken. For example, the photos I take on April 23, 2007 on the Smith Industries project will be kept in the folder /Users/drang/projects/smith.industries/Photos/20070423.1 I don’t use iPhoto, because:
- I don’t like having all my photos lumped together, which is iPhoto’s default behavior.
- Setting up an iPhoto library for each project is a hassle, as is telling iPhoto which library to use.
- I often need to burn all the photos for a particular project onto a CD or DVD and send them to a client. This is much more convenient when all the photos are in a single directory.
I used to use a combination of the Finder and Xee to review photos, and I outlined my system here and here. Basically, I’d use the Finder’s Icon View with 128 pixel icons to quickly scroll through a folder of photos (I wrote an AppleScript to toggle between the large icon size and the 48 pixel size I usually use), and I’d use Xee for more detailed viewing. This worked well, but with Leopard there’s a better way.
First, I can use CoverFlow in the Finder to scroll through a folder of photos, and I get to see them at a much larger size than in Icon View.
Often, this view is good enough for my purposes. If I need to see a picture at a larger size, a quick press of the spacebar brings it up at a larger size in QuickLook. Option-clicking in the QuickLook window will zoom in further, if necessary. Although it’s a fine program that’s served me well, Xee now seems unnecessary.
I’m trying to make better use of Spotlight with my photos, too. You’ll notice in the screenshot above that the file list below the CoverFlow area has a Comments field just after the Name field. I’m using this as a way of captioning the photos. The captions are easy to read as I flip through the photos, and I can use Spotlight to show just those photos that have a keyword in their comment. Comments aren’t visible by default; you have to select Show View Options from the View menu at click the Comments checkbox.

Once the Comments are visible, you can reorder and resize the columns.
The normal way of adding Spotlight comments to a file is to open the file’s Info window and typing in the little Spotlight Comments box. This is a lot of busywork if you have dozens or hundreds of photos to caption. So I wrote an AppleScript that looks for a file called “captions.txt” in the same folder as the photos and sets the comments according to the contents of that file. You can write “captions.txt” in your favorite text editor, making use of whatever shortcuts and timesavers it provides.
The “captions.txt” file is a plain text file with the following format:
20080127-073.jpg|passenger area
20080127-074.jpg|LF hub linkage
20080127-075.jpg|RF hub linkage
20080127-076.jpg|LF hub linkage
20080127-077.jpg|LR hub linkage
20080127-078.jpg|RR hub linkage
20080127-079.jpg|sight glass after filling
20080127-080.jpg|front of crane; fluid pools
20080127-081.jpg|front of crane; fluid pools
Each line represents a single file. The name of the photo file and its caption are separated by the vertical pipe character (which I chose because I don’t expect it to ever show up in my file names or captions).
Here’s a hint for automatically generating all the photo file names: open Terminal, cd to the photo folder, and run this command:
ls *.jpg | pbcopy
The ls lists all the files that end with “.jpg”, and the pbcopy puts that list onto the Clipboard. Now you can Paste in your text editor, and the files will appear, one per line. You may need to change the *.jpg to *.JPG if that’s how your files are named.
The AppleScript that processes the captions, cleverly entitled “Caption photos,” looks like this:
1: tell application "Finder"
2: set photoFolder to target of front Finder window as alias
3: set cFiles to files of photoFolder whose name is "captions.txt"
4: if (count of cFiles) = 0 then
5: return -- stop if there's no captions file
6: end if
7:
8: display dialog "Do you want to append or replace existing comments?" buttons ["Append", "Replace"] default button 2
9: set dialogResult to result
10: set cFile to item 1 of cFiles as alias
11: set capLines to read cFile as text using delimiter "
12: "
13: set savedTextItemDelimiters to AppleScript's text item delimiters
14: set AppleScript's text item delimiters to {"|"}
15: repeat with theLine in capLines
16: set fileName to text item 1 of theLine
17: set fileComment to text item 2 of theLine
18: if button returned of dialogResult is "Append" then
19: set oldComment to comment of file fileName in folder photoFolder
20: set comment of file fileName in folder photoFolder to (oldComment & return & fileComment)
21: else
22: set comment of file fileName in folder photoFolder to fileComment
23: end if
24: end repeat
25: set AppleScript's text item delimiters to savedTextItemDelimiters
26:
27: end tell
It’s meant to be run when the folder of photos is open and is the frontmost Finder window. If there’s no “captions.txt” file in the folder, nothing happens. If there is a “captions.txt” file, the script asks (in Line 8) if you want the captions in the file to be appended to or replace any existing comments. Replace is the default. The append or replace question is not asked for each individual file, because I can’t imagine the need for that.
I just started using Spotlight comments for photo captions. There may be some downside to it that I haven’t discovered yet, but so far it seems very useful.
-
I got into the habit of capitalizing the
Photosfolder back in my Linux days. The Linux file managers I used sorted contents in ASCII order, so items with initial capital letters always came first. MyPhotosfolder was therefore always near the top of the project folder’s contents list—easy to find and open. The Mac’s “Arrange by Name” scheme is not case sensitive, so there’s no point in capitalizing anymore. I just haven’t dropped the habit yet. ↩
Digital photos and me, Part V
October 19th, 2006 at 11:14 pm
In this fifth and—I think—last post in the series, I’m going to describe the program I use to prepare sheets of photos for printing at my local Costco. You could use the same procedure for printing at, say, Wal-Mart or any of the various online photo printing shops.
It’s not really necessary for you to read the first four posts in the series (one, two, three, and four), but since the program uses the RMagick library for Ruby, reading the fourth post would probably be a good idea if you’re using a Macintosh, as it explains a fairly simple way to get RMagick installed. The program I’ll describe isn’t Mac-specific, so if you can get RMagick installed on your Windows or Linux machine, it should work fine. (The should in that last sentence is the tipoff that I haven’t tested it on Windows or Linux. If you do, let me know how it works.)
The idea behind the program is to create a JPEG file that:
- contains several photographs, each labeled with its file name;
- has an optional title and a pair of subtitles;
- it formatted to print out nicely on an 8×10, with room for binding or punched holes along one of the long edges.
An example would be something like this, which you can click on to see a larger version.
Back in 2000, I wrote a similar program in Python. I used it first to organize family photos, but then adapted it to handle the digital photos I was taking at work. I chose Python because of Tkinter, Python’s built-in interface to the Tk library of user interface widgets. I wanted the program to have a GUI that worked in Windows so my wife and coworkers could use it. The program worked pretty well, and I wrote a post about it some time ago. But I began to dislike it because:
- it was written with an 8½×11 sheet in mind, and when I switched from inkjet printing my own sheets on 8½×11 paper to sending the files off to Costco for photographic printing on 8×10 paper, the difference in aspect ratio changed the placement of the images and messed up the binding margin;
- it used the Python Imaging Library (PIL) and a set of high-resolution bitmap font files, and I wanted the flexibility to change fonts and the resolution of the output file;
- I’d rather just use a command-line program; and
- my fling with Python was over, and I didn’t want to be maintaining a Python program anymore.
The result is the following Ruby program. I’m not really a Ruby programmer—not yet, anyway—and it shows. The program is very much a procedural program, not object-oriented in any way, so I’m sure it would be considered poor Ruby style. No matter. For now, the important thing is that it works; the logic and data contained in it can be rewritten into a more Rubyish form as I learn the language and its styles and idioms.
I call the program photosheets because that’s what it makes. Here’s the listing.
#!/usr/bin/env ruby
require 'optparse'
require 'RMagick'
include Magick
Geometry = {
4 => {
'name' => 'Quad',
'rows' => 2,
'cols' => 2,
'image_size' => [1280, 960],
'dpi' => 300,
'height' => 2400,
'width' => 3000,
'left_margin' => 145,
'right_margin' => 2855,
'top_margin' => 180,
'title_size' => 16*4,
'subtitle_size' => 10*4,
'title_clearance' => 45,
'label_size' => 9*4,
'label_clearance' => 4,
'horizontal_clearance' => 150,
'vertical_clearance' => 100,
'bfont' => 'Helvetica-Bold',
'font' => 'Helvetica'
},
9 => {
'name' => 'Nine',
'rows' => 3,
'cols' => 3,
'image_size' => [800, 600],
'dpi' => 300,
'height' => 2400,
'width' => 3000,
'left_margin' => 150,
'right_margin' => 2850,
'top_margin' => 180,
'title_size' => 16*4,
'subtitle_size' => 10*4,
'title_clearance' => 45,
'label_size' => 9*4,
'label_clearance' => 4,
'horizontal_clearance' => 150,
'vertical_clearance' => 100,
'bfont' => 'Helvetica-Bold',
'font' => 'Helvetica'
}
}
def place_photo(photo, pos, per_page, lo)
pos = (pos - 1) % per_page
$img.read(photo)
# Strip out the photo's directory path and extension.
base = File::basename(photo, ".*")
# Rotate if necesary and scale
if ($img.rows > $img.columns)
$img.rotate!(270)
end
scale_x = lo['image_size'][0]*1.0/$img.columns
scale_y = lo['image_size'][1]*1.0/$img.rows
scale = [scale_x, scale_y].min
h = (scale*$img.columns).round
v = (scale*$img.rows).round
$img.resize!(h,v, HammingFilter)
# Determine placement on page.
row = pos/lo['cols'] # zero-indexed
col = pos - row*lo['cols'] # zero-indexed
x = lo['left_margin'] +
col * (lo['image_size'][0] + lo['horizontal_clearance']) +
lo['image_size'][0] - h
y = lo['top_margin'] + lo['title_size'] + lo['title_clearance'] +
row * (lo['image_size'][1] + lo['vertical_clearance']) +
lo['image_size'][1] - v
lx = x + h
ly = y + v + lo['label_clearance'] + lo['label_size']
# Place the photo.
# $sheet.composite!($thumb, x, y, OverCompositeOp)
$sheet.composite!($img, x, y, OverCompositeOp)
# Place the label.
label = Draw.new
label.font(lo['font'])
label.pointsize(lo['label_size'])
label.text_align(RightAlign)
label.text(lx, ly, base)
label.draw($sheet)
$img.clear
STDERR.print "#{pos+1}..." if $verbose
end
def make_sheet(sheet_count, photo_list, per_page, lo)
# Determine the range of photos for this sheet.
first_photo = (sheet_count - 1) * per_page
last_photo = first_photo + per_page - 1
if (last_photo >= photo_list.size)
last_photo = photo_list.size - 1
end
sublist = photo_list[first_photo..last_photo]
# Initialize the sheet.
# sheet = Image.new(lo['width'], lo['height'])
$sheet.erase!
# $sheet = $sheet.texture_floodfill(100,100, $granite)
# Draw the title block.
tx = lo['width']/2
ty = lo['top_margin'] + lo['title_size']
title = Draw.new
title.font(lo['bfont'])
title.pointsize(lo['title_size'])
title.text_align(CenterAlign)
title.text(tx, ty, $ctitle) unless $ctitle == ''
title.pointsize(lo['subtitle_size'])
title.font(lo['font'])
title.font_weight(NormalWeight)
tx = lo['left_margin']
title.text_align(LeftAlign)
title.text(tx, ty, $ltitle) unless $ltitle == ''
tx = lo['right_margin']
title.text_align(RightAlign)
title.text(tx, ty, $rtitle) unless $rtitle == ''
title.draw($sheet)
# Place the photos.
pos = 0
sublist.each do |photo|
pos += 1
place_photo(photo, pos, per_page, lo)
end
# Save the sheet.
name = "Sheet-%02d.jpg" % sheet_count
$sheet.write(name)
STDERR.puts "#{name} done!" if $verbose
end
# Start of main program.
# Defaults.
per_page = 9
$ctitle = ''
$ltitle = ''
$rtitle = ''
$verbose = FALSE
# Process the options.
opts = OptionParser.new
opts.banner = "Usage: photosheets [options] files"
opts.separator("Create one or more 8x10 sheets of photos.\nOptions:")
opts.on("-n N", Integer, "photos per page (4 or 9; default: 9)") {
|num| per_page = num }
opts.on("-t TITLE", String, "main title (centered)") {
|str| $ctitle = str }
opts.on("-l SUBTITLE", String, "left subtitle (project)") {
|str| $ltitle = str }
opts.on("-r SUBTITLE", String, "right subtitle (date)") {
|str| $rtitle = str }
opts.on("-v", "verbose output (default: off)") {
|str| $verbose = TRUE }
opts.on("-h", "--help", "print this message") {
|str| puts opts.help; exit }
photo_list = opts.parse(ARGV) #everything after the options
photo_list = photo_list.delete_if { |f| f =~ /^Sheet-/ }
layout = Geometry[per_page]
# Get the title and subtitles interactively if no main title is given.
if ($ctitle == '')
STDERR.print "Main title: "
$ctitle = STDIN.gets
STDERR.print "Left subtitle (project): "
$ltitle = STDIN.gets
STDERR.print "Right subtitle (date): "
$rtitle = STDIN.gets
end
# Initialize the counts and the images.
num_photos = photo_list.size;
num_sheets = num_photos/per_page
num_sheets =num_sheets + 1 if (num_photos % per_page > 0)
$granite = Magick::Image.read('granite:').first
# $granite = $granite.level(0, 1.50)
$sheet = Image.new(layout['width'], layout['height'])#{
# self.background_color = '#DDD'
# }
$img = ImageList.new
# Make the sheets.
1.upto(num_sheets) do |i|
make_sheet(i, photo_list, per_page, layout)
end
As you can see, it’s about 200 lines long, with the first 50 or so lines taken up with defining the geometry of the layout.
Thanks to the optparse library, you can get a good idea of how the program works by typing photosheets --help at the command line. The response will be
Usage: photosheets [options] files
Create one or more 8x10 sheets of photos.
Options:
-n N photos per page (4 or 9; default: 9)
-t TITLE main title (centered)
-l SUBTITLE left subtitle (project)
-r SUBTITLE right subtitle (date)
-v verbose output (default: off)
-h, --help print this message
which tells you that you can use the -n option to specify either 4 or 9 photos per sheet and you can give the main title with the -t option and the two subtitles with the -l and -r options. Since at work I usually use the left subtitle for the project name and the right subtitle for the date or date range of the photos, those conventions are mentioned parenthetically in the help. Nine photos per sheet is the default because that’s what I use the most. You can change any of this stuff by fiddling with the parts of the program labeled # Defaults and # Process the options.
The program creates a series of JPEG files in the directory you are in when you call it. The files are named Sheet-01.jpg, Sheet-02.jpg`, etc. If you already have files with those names in the current directory, they’ll be overwritten (a ruthlessness that is a legacy of my Linux days).
Normally, the program doesn’t give any feedback as it runs—you just wait until the output files are created. But if you call the program with the -v option, it will give you a running account of its progress, like this
1...2...3...4...5...6...7...8...9...Sheet-01.jpg done!
1...2...3...4...5...6...7...8...9...Sheet-02.jpg done!
1...2...3...4...5...6...7...8...9...Sheet-03.jpg done!
1...2...3...4...5...6...7...8...9...Sheet-04.jpg done!
1...2...3...Sheet-05.jpg done!
An important feature not mentioned in the help is interactive input. If you call the program without the -t option, it assumes you want to provide the title and subtitles interactively and begins prompting you for them. Here’s an example of the prompts and the answers I gave to produce the sheet shown above.
Main title: Main Title
Left subtitle (project): Project Name
Right subtitle (date): October 8, 2006
This behavior is set up to make my life easier and require the least amount of typing and thinking. My most common use of the program is to open the Terminal, change to a directory of photos, and call photosheets *.jpg. I then type in the titles (any of which can be blank) when prompted and wait for the multi-photo sheets to be created. These get uploaded to Costco and printed on 8×10 paper.
If you’re wondering why I bother printing out my photos when I can just view them on my computer, you need to get more experience with that big analog thing we older folks call the “real world.” Riffling through sheets of photos, or laying them all out on a big table, is much more efficient than looking at just a few at a time on your screen. No matter how big your screen is, I’ll be able to find a table that’s bigger.
So that’s it. These five posts, taken together, explain how I deal with digital photos on screen and off. No iPhoto necessary, and in fact, no iPhoto wanted because iPhoto’s method of organizing photos isn’t convenient for the way I work. Perhaps I should say “iPhoto’s old method of organizing photos,” as this way of working was developed when iPhoto ’05 was the current thing. I’ve read somewhere that the current iPhoto doesn’t force you to organize your photos its way. If that’s the case, I might be willing to revisit it. But right now I don’t feel any compelling need to.












