November 10, 2008

Automated processing tools for better digital pictures

Author: Ben Martin

When you return from a trip and copy your digital pictures over to your file server, you might like to rename the image files or (losslessly) rotate them to their correct orientation to make finding and viewing them simpler. You might even want to embed comments right into the image files in such a way that all image viewing tools should be able to harvest and share this metadata. In this article we'll take a look at some command-line tools to help you with these tasks.

Although JPEG image compression is a "lossy" format, meaning that some information is thrown away at compression time, these tools will allow you to rotate an image multiples of 90 degrees without having to recompress the JPEG image data. The upshot is that you do not needlessly throw away more information from the image due to decompressing the data, rotating it, and then using a lossy compression to save the rotated image data. Many JPEG images created by digital cameras also include an embedded thumbnail image, and the tools normally rotate both the image and its thumbnail.

Note that the rotation offered by these tools relies on the orientation information being correctly set in an image's metadata. Many digital cameras can write the orientation to EXIF tags as you take photos. You will have to verify that your cameras have this ability and they are correctly configured to set this metadata. I used a Canon G7 for testing and had to set "Auto Rotate" to on in order for orientation information to be written.


exiftool, which is included with the Image::ExifTool Perl library for reading and writing metadata information from images and audio and video files, is extremely handy for manipulating image metadata from the command line.

The exiftool manual page lists a vast number of file formats and metadata standards that the Image::ExifTool Perl library and thus exiftool support, including EXIF, GPS, and XMP, and image formats like JPEG and RAW.

exiftool gives you great flexibility in how you invoke it. Depending on which options you are using, exiftool either updates the supplied image files or works more as a filter: reading images from your nominated locations and writing them to standard output or a target directory. When exiftool is operating in filter mode, you supply the file or directory name you would like to use as the source as the final argument. You can also use a hyphen to have exiftool read its data from standard input. In filter mode the results are written to standard output, or you can use the -w option to write output images to files instead.

A typical invocation of exiftool takes an input image, performs some metadata operations on it, and writes the output to standard output (filter mode) or back to the original file name, keeping a backup of the original content as file.jpg_original (update mode). If you have good backups and you are confident that exiftool works as expected, you can also update an image without creating backup files by using the -overwrite_original option.

The first example below extracts the embedded thumbnail from the image.jpg file. The second example sets the Comment tag for the image.jpg file. Note that after the second command the original image will still exist in image.jpg_original. After deleting the original uncommented file, the final command changes the comment, but due to the -overwrite_original flag there will be no image.jpg_original created.

$ exiftool -b -ThumbnailImage image.jpg > thumbnail.jpg
$ exiftool -Comment='This is a new comment' image.jpg
$ rm -f image.jpg_original
$ exiftool -Comment='This is a second comment' -overwrite_original image.jpg


The renrot project takes its name from the first three letters of "rename" and "rotate," which are the project's two main goals. Rotation is only available on JPEG images. Other features of renrot include the ability to separate your images into different directories based on when the photos were taken and the ability to change the embedded comments.

There are renrot packages in the Fedora 9 and Ubuntu Intrepid repositories but not for openSUSE 11. You should be able to create RPM files for the latter with the command rpmbuild -tb renrot-1.1.tar.gz. I built the utility from source using version 1.1 of renrot on a 64-bit Fedora 9 machine. renrot requires Perl 5.6.0 or later, as well as the Perl modules Image::ExifTool, Getopt::Long, and jpegtran, with an optional dependency on Image::Magick.

If you run renrot without arguments it will exit telling you that you must at least specify the extension of the image files you wish to operate on. The file name extension is case-sensitive, so if you have mixed JPG and jpg extensions you must either invoke renrot twice or rename the files to all have a uniform case for their extension. Given that the --extension parameter is used to specify the file extension, and that renrot will rename the image files, it would be nice to be able to use an --iextension argument to specify that renrot should treat the extension as case-insensitive, but no such argument exists.

Shown below is an example invocation of renrot. The first attempt fails, but the second will rename and rotate all image files with a .jpg extension in the current directory. When renrot rotates an image it keeps the old one around, renamed with _orig appended to its original filename. There is no option to have renrot remove the original_orig files automatically after processing.

$ renrot -v
FATAL: Extension of files is required!
$ renrot --extension jpg -v
DEBUG[1]: main::renRotProcess(): Trim string: '-trim'
DEBUG[1]: main::renRotProcess(): Initializing tags...
Processing file: (1 of 19) 00001.jpg...
Renamed: 00001.jpg -> 20080921171446.jpg

Processing file: (2 of 19) 00002.jpg...
Renamed: 00002.jpg -> 20080921171452.jpg
$ ls -lh
-rw-r----- 1 ben ben 4.0M 2008-09-21 17:14 20080921171446.jpg
-rw-r----- 1 ben ben 4.4M 2008-09-21 17:14 20080921171452.jpg

The --work-directory parameter lets you specify where to look for images instead of the current directory. You can't tell renrot to recurse into the work-directory looking for images, but it is easy to get around this with the --sub-fileset parameter, which lets you tell renrot to operate on an explicit collection of files. The --sub-fileset parameter is used to specify a file name from which renrot reads image filenames, one per line. The below use of the find command together with telling renrot to use stdin as the file from which to read image file names gives you recursive renrot. You can use more specific find parameters to gain great control over which images should be operated on.

$ find . -mindepth 1 | renrot --sub-fileset -

By default renrot renames files based on the time a photo was taken: year, month, day, hour, minute, and second, followed by the old extension. The --name-template parameter lets you change how files are renamed. You can use the time the photo was taken in various formats as well as information from the EXIF tags such as exposure time and white balance. You use percent-character placeholders to specify the information -- for example, %E for the exposure time. If you only want to rotate the images you can use --no-rename.

You can tell renrot to place photos into different directories based on when the photos were taken. The default directory names created are year, month, day without any separators with a directory prefix "Images." You can change the prefix with the --aggr-directory parameter. The same flags that are used for renaming files are used for the --aggr-template parameter.

You can also include tags and user comments into the EXIF data of images as you process them with renrot. This is one area where --no-rename comes in handy, when you just want to use renrot to set some tags on a collection of photos, as shown below.

$ echo 20081102170950.JPG | \
renrot --no-rename \
--tag 'UserComment: foobar' \
--sub-fileset -

Most of the renrot options that you can specify with command-line parameters can also be set in the global configuration file /etc/renrot/renrot.conf, or a per-user configuration file in ~/.renrot.

You can also generate new embedded thumbnails with renrot, though you'll have to use another tool to remove any embedded thumbnail first. The commands shown below create a copy of a digital picture that renrot has already operated on once. I first remove the thumbnail image with exiftool and move the original file out of the way. I then invoke renrot to rename the image and use --generate-thumb to have a new thumbnail added to the image. The original thumbnail size was 3,548 bytes, and the newly generated one was 8,081 bytes -- more than twice the size of the original thumbnail, but also a nicer image. Given that the digital pictures themselves were 4MB in size, a few extra kilobytes for better thumbnails is likely to be acceptable. I found an option to set the dimensions of the generated thumbnail in the renrot.conf file, but nothing to set the JPEG compression level in order to make smaller lower-quality thumbnails should you wish to.

$ cp -a 20081102170950.JPG 20081102170950-nothumb.JPG
$ exiftool -tagsFromFile 20081102170950-nothumb.JPG -ThumbnailImage= -m 20081102170950-nothumb.JPG
$ mv 20081102170950.JPG 20081102170950-original.JPG

$ renrot --no-rotate --generate-thumb 20081102170950-nothumb.JPG
Processing file: (1 of 1) 20081102170950-nothumb.JPG...
Renamed: 20081102170950-nothumb.JPG -> 20081102170950.JPG


DigicaMerge has a primary focus on renaming digital pictures. It lets you merge multiple directories of images, taken with different cameras, into a single tree without losing any images that might have had the same file name.

DigicaMerge is not packaged for openSUSE, Fedora, or Ubuntu. I'll build version 2.00 of DigicaMerge from source on a 64-bit Fedora 9 machine. You need pyexif installed to use DigicaMerge. I couldn't find packages for pyexif in distribution repositories, and there is no for pyexif. Hand installation of pyexif is shown first, followed by DigicaMerge itself.

$ cd /tmp
$ tar xzvf /.../pyexif-0.9.tar.gz
# su -l
# cd /tmp/pyexif/lib
# cp /usr/lib64/python2.5/
# chmod 444 /usr/lib64/python2.5/

$ tar xzvf /.../digicamerge-2.00.tar.gz
$ cd ./digicamerge-*/
$ sudo python install

You invoke DigicaMerge with a collection of source directory names and a final target directory where you would like to have the results placed. Normally images are moved into the target directory, but you can specify --copy to have the originals left intact. The --nodupes option removes any duplicate files from the target directory. The files to merge into the target directory are specified with the --pattern parameter. The default --pattern is *.jpg.

You can use --touch to have DigicaMerge set the modification time of the images in the target directory to match the EXIF metadata for the date a picture was taken.

The photos are renamed according to the --scheme parameter. You can use the photo creation time in many convenient variables as well as information from other EXIF tags in your scheme. After selecting a variable, you need to tell DigicaMerge how to format its value. The formatting strings follow the Python language string formatting conventions. All variables are strings except count0 and count1, which give a unique integer every time they are used. The only difference between count0 and count1 is that count0 starts at zero and count1 starts from one.

The command below moves all the images from the src1, foo, and bar directories into the myPictures directory and renames them all to have the camera model first, a hyphen, the resolution in WxH, a hyphen, and a unique number before the jpg extension.

$ digicamerge --touch \
--scheme "%(Model)s-%(ExifImageWidth)sx%(ExifImageHeight)s-%(count1)04i.jpg" \
src1 foo bar myPictures

The below example uses the time each photo was taken to form part of its new file name. Note that the date portion is separated with backslash to avoid issues with the filesystem path separator.

$ digicamerge --pattern "*JPG" --touch \
--scheme "%(Model)s-%(year)s\\%(month)s\\%(day)s--%(hour)s:%(minute)s:%(second)s-%(count1)04i.jpg" \
samples-with-auto-rotate output

samples-with-auto-rotate/IMG_9815.JPG moved to output/Canon PowerShot G7-2008\11\02--17:12:07-0001.jpg
samples-with-auto-rotate/IMG_9816.JPG moved to output/Canon PowerShot G7-2008\11\02--17:12:11-0002.jpg

After your images have been moved or copied to the target directory, you can have DigicaMerge execute a command on each image. All the information that is available to the --scheme option is available in environment variables when DigicaMerge executes your command, so you can do things like rotate your image if the orientation is set to specific values.

Final words

I chose to focus on renrot and DigicaMerge because they are targetted toward renaming and rotating images to clean up filesystem layout. In addition to these tools, there are many other projects that help with renaming and automated processing of digital photos. For other command-line tools, look at renamepics and PECoMaTo. Tools with graphical interfaces include MediaSort and fotoalbum.

Embedded thumbnails that are generated by a digital camera may be large and of poor quality. A camera has to compress the image and thumbnail in as small an amount of time as possible. Your desktop machine has much more processing power available, and you don't mind if it takes a while to rethumbnail the images from your last trip. Deleting the embedded thumbnails and regenerating them may result in much better quality thumbnails with perhaps a slight increase in file size.

The renrot tool has support for lossless image rotation built in, so if you use some image viewers that do not respect the EXIF orientation tag, renrot will save you some grief. You could also rotate your images using DigicaMerge and its ability to execute external commands, but you'd have to work out those commands yourself. If you want to rename and rotate your images, renrot will likely provide a quicker solution.


  • Graphics & Multimedia
  • Tools & Utilities
Click Here!