Recently, I have been undertaking the enormous task of scanning my father’s extensive collection of photographic negatives. The idea is to ensure their longterm survival, with the bonus of (re-)discovering gems among them. But archival quality TIFF files do not make for an easy browsing experience, so I was looking for a way of creating low quality “contact sheets.” This proved a lot harder than I thought, but I found a fantastic solution.

I looked through my existing stable of graphics applications and searched the Mac App Store but none had the simplicity I was looking for. I had — so far — 127 folders with over 4,000 images between them. I just wanted to choose some basic parameters and then no more than a few clicks at most for each folder. I asked around my online communities and found some more apps, and it was while responding to one suggestion that I opined “I’m starting to think now whether there are any command line options to roll my own.” Twenty minutes later I had a working solution.

The core of the solution is an open source graphics tool called ImageMagick. It’s a solution which does require a certain amount of geekery, but it’s worth it for the simplicity and flexibility. I long ago installed HomeBrew, which made the installation a cinch with simply “brew install ImageMagick”. I’ll not give detailed instructions here as many have already documented that process.

With ImageMagick installed, I searched for examples and eventually stumbled across this comprehensive page on their own site. With that page handy, and a few dozen searches on the peculiarities of bash scripting, I was finally able to put together an incredibly easy-to-use tool that does exactly what I want. I used Automator to set up a new Quick Action for Finder (new to Mojave, but you can also use Services in prior OS versions).

Screen capture of Automator action
My Automator Quick Action for “Make Contact Sheet”

Everything you need should be visible in that screen capture, but I’ll explain a few key pieces and also how you might customise the script for your own purposes.

I’ve set the Quick Action to accept only folders from Finder. You could expand on that a bit if you use other applications to view your folders. The script is not set up to receive files, but could be adapted to do so. It is critical that the Run Shell Script action have “Pass input:” set to “as arguments” in the top right corner of the action, which is not the default.

for f in "$@"
   pics=$( /bin/ls -1U "$f"/* | wc -l )
   n=$( echo "scale=4; $pics/144" | bc )
   cols=$( echo "scale=0; sqrt($n) * 16" | bc )
   thedir="$(basename "$f")"
   /usr/local/bin/magick montage "$f/*.*" -tile "$cols"x -geometry 240x240+4+4 -set label "%t" "$f/../!contact_$thedir.jpg"
   /usr/local/bin/terminal-notifier -title 'Contact Sheet' -sound default -subtitle 'Completed' -message "$thedir"

The first three lines after the do are a bit of cleverness to make the final output very roughly conform to a 16:9 aspect ratio. This generally makes the resulting contact sheet more viewable on a standard screen than if it were taller or wider. For the math geeks — the number of columns is the square root of (the number of pictures divided by (16 x 9)) multiplied by 16. For the bash geeks — how do you ever learn that esoteric syntax??

The magick command has a whole ton of parameters. “$cols”x uses the previous cleverness to set the number of columns and allowing the rows to go as far as needed. The numbers after -geometry specify each image tile to be 240 pixels square and 4 pixels apart in each dimension. The -set label “%t” puts a label/caption under each image with the filename (not including the extension). The final parameter is the output filename. I’ve set it to generate the contact sheet in the parent directory as this made the most sense to me — you’ll end up with a folder containing both the contact sheets and the folders they represent. You may also want to change the naming of the contact sheet file — use $thedir in the name to reflect the folder it was generated from. Finally, if you want a PNG instead of a JPG, just change the extension on the file name.

The next line is optional and uses another tool I installed via HomeBrew, called terminal-notifier. It allows the script to send a standard macOS notification as it completes generation of each contact sheet. You could also add a native Automator action below the Run Shell Script action to send a final notification once all contact sheets have been generated, or add another command in the script below the done.

Hopefully this proves as useful to others as it has to me. There are a heap of other abilities to the montage sub-command of ImageMagick you might like to explore, plus a huge amount of further capabilities with other sub-commands.

Oh, a final point — how to actually generate a contact sheet? Easy. Select one or more folders in Finder, right click, and select Quick Actions > Make Contact Sheet (or whatever you called yours). Just be warned it can take a while to create each contact sheet depending on the number and size of the images involved. While executing, there will be a rotating cog in your menu bar.

Example contact sheet image


Steven B. · 7 August 2019 at 15:36

Are you sure your shell script is correct? Mine runs and I see the message from terminal-notifier, but no jpg file is created. I’ll try to troubleshoot it tomorrow but first wanted to know if there is some error that you are aware of. Thanks.

Steven Bennett · 8 August 2019 at 14:59

I found one error and one typo in your code. In the line that calls magicking, the first argument should be “$f/*” instead of “$f/.” so that all of the files in the $f directory are passed in. And in that same line, the name of the contact sheet should be “$f/../contact_$thedir.jpg” . Currently you include a “!” as the first character of the file name.

Allister · 29 September 2019 at 17:31

Sorry, Steven, I have barely looked at the site in the last few months. You were correct about the wildcard error in the script as shown. I just checked my (slightly different now) real script and I have $f/*.* to pick up all files. I have corrected it in the post.

The “!” is deliberate, to ensure the contact sheet sorts first in the directory.

Leave a Reply

Your email address will not be published. Required fields are marked *