More photo stuff

To continue on from my last post, the other program in my photo organization scheme is a program that takes the photo files, which have names like DSCnnnn.JPG, and gives them new names based on the day they were taken. The format for the names is yymmddnn.jpg, where

I kept the name to the old DOS “8.3” format because I read somewhere that the ISO 9660 standard for CDROMs requires it. And although there are (obviously) extensions to that standard that allow longer names, the short naming system didn’t seem like too much of a burden.

The name of the program is canonize, a mild pun: the file name is being put in canonical form, and our camera is made by Canon.

Here’s the program.

#!/usr/bin/perl

use Image::Info qw(image_info);
use Getopt::Std;

$help = <<HELP;
canonize: rename photos to reflect the date on which they were taken.
          Use the date embedded in the EXIF file. The format for the
          file name is yymmddnn.jpg, where yy is the year, mm is
          the month, dd is the day, and nnn is the photo number for
          that day. This is specialized for the EXIF format of our
          Canon PowerShot S30.
usage:
  canonize [options] file-list

option:
  -s num:   the starting number for the photos (default: 1)

  -p:       print the new photo names, but don't rename the files

  -h:       display this help message

HELP

getopts('hps:');
$number = $opt_s || 1;          # default starting number is 1

if ($opt_h || !@ARGV) { die $usage; }

#initialize count and date string
$i = 1;
$olddatestring = "1989:03:25";  # can be any date that will certainly
                                # be before the date the photo was taken

while ($oldname = shift) {
  my $info = image_info($oldname);
  $datestring = $info->{DateTimeOriginal}; 
  if ($datestring =~ /^\d\d(\d\d):(\d\d):(\d\d)/) {
    $datestring = substr($datestring,0,10);
    if ($datestring ne $olddatestring) {
      $olddatestring = $datestring;
      $i = $number;
    } else {
      $i++;
    }
    $newname = sprintf("%02d%02d%02d%02d.jpg", $1,$2,$3,$i);
  }
  if ($opt_p) {
    print "$oldname -> $newname\n";
  } else {
    rename ($oldname, $newname) or print "Couldn't change $oldname to $newname\n";
  }
}

The program uses the Image::Info module from CPAN to extract the date and time of the photo from the file. (Although we call our photo files “JPEGs,” JPEG is actually a compression method, not a file format. Digital cameras save their images in EXIF files which use JPEG compression for the image data and also holds a bunch of other info, like the aperture setting, shutter speed, focal length. And date and time.)

As I’m trying to do in all my utility programs, canonize has a usage string near the top that I can print as a help message from the command line and which I see immediately upon opening the file for editing or study.

The -s option lets you start your photo numbering at something other than 01. This may seem weird, but I thought it might be needed in case I downloaded part of a day’s photos and renamed them before downloading the rest. So far, I haven’t used that option. I used the -p option (which prints out the old and new file names, but doesn’t actually change the name) a lot during debugging and decided to leave it in the final code (is any program really final?). It turns out I have used it a few times to make sure things were going to go the way I thought they should.

The program doesn’t actually sort the files in date order. The intention is to invoke the program as canonize *.JPG, so it receives the file names in alphabetical order from the shell. Because of the way the camera names the files, alphabetical order is also chronological order. This is potential flaw, and I suppose I should suck in all the file names and sort them by date before assigning new names to them. But it works with my personal camera (the Canon) and with the cameras I use a work (three different models of Nikon), so I’m not inclined to dig in and change it.

You’ll notice a date of 1989:03:25 embedded in the code. The logic of the program needed a date that was always going to be earlier than the earliest photo being renamed. Any date before I bought the camera would have been fine; March 25, 1989 is my daughter’s birth date.