Sorting images by EXIF date

Introduction

At least once a year we go for holiday together with some friends. No question, they all bring their digital cameras and take a load of pictures.

Right after we get back home they send me their images to upload them to our gallery.

The Problem

Then i usually end up with a directory structure looking smthg like:

.
├── philipp
│   └── S8000
│       ├── DSC_0700.JPG
│       ├── DSC_0701.JPG
│       └── DSC_0709.JPG
├── iris
│   ├── C5600
│   │   ├── DSCN4664.JPG
│   │   ├── DSCN4666.JPG
│   │   └── DSCN4667.JPG
│   └── D80
│       ├── DSC_0830.JPG
│       ├── DSC_0837.JPG
│       ├── DSC_0838.JPG
│       └── DSC_0839.JPG
├── nina
│   └── S3000
│       ├── DSCN4610.JPG
│       ├── DSCN4616.JPG
│       └── DSCN4617.JPG
└── tom
    ├── D70
    │   ├── DSC_4040.JPG
    │   ├── DSC_4048.JPG
    │   └── DSC_4049.JPG
    └── iphone
        ├── IMG_0104.JPG
        └── IMG_0105.JPG

First of all, there might be duplicate filenames as in the example above. But the major problem is that these photos are not sorted by the date they’d been taken which makes it hard to just browse them all and sort out the ones we dislike.

The Script

This is far from being perfect. Actually it’s just a quick hack, but it does the job for me.
It sorts all images given according to its EXIF CreateDate, copies/moves the files and prefixes them with an incrementing number.

Prerequisites:
  • Image::Exiftool
#!/usr/bin/perl -w
##################################################
#Move or copy images and rename them to be sorted by EXIF-CreateDate
#cmdline options:
#./cmd -move <list of images>
#./cmd -copy -dest <destination directory>  <list of images>
##################################################
 
use strict;
use Image::ExifTool;
use Time::Local;
use Getopt::Long;
use File::Basename;
use File::Copy;
 
our $dest;
our $copy;
our $move;
my %Info;
 
GetOptions ('dest=s' => \$dest,
            'copy' => \$copy,
            'move' => \$move           
);
 
 
foreach (@ARGV) {
  GetDateAndTime($_, \%Info);
}
SortAndMove(\%Info);
 
 
sub GetDateAndTime {
  my ($srcfile, $Info_ref) = @_;
  my $srcfileExif = new Image::ExifTool;
  my $info = $srcfileExif->ImageInfo($srcfile,"CreateDate");
  $$info{'CreateDate'} =~ s/\s+/:/g;
  my ($year,$mon,$mday,$hour,$min,$sec) = split(/:/, $$info{'CreateDate'}); 
  $mon = $mon-1;
  $$Info_ref{$srcfile} = timelocal($sec,$min,$hour,$mday,$mon,$year);
}
 
sub SortAndMove {
  my ($Info_ref) = @_;
  my $count = sprintf("%0".length(keys %$Info_ref)."d",0);
  foreach (sort {$$Info_ref{$a} cmp $$Info_ref{$b}} keys %$Info_ref) {
    move("$_",dirname($_) . "/" . $count . "_" . basename($_)) if $move;
    copy("$_",$dest . "/" . $count . "_" . basename($_)) if $copy;
    $count++;
  }
}
Tested on:
  • ArchLinux
  • Debian GNU/Linux Squeeze
Cameras tested with:
  • Nikon D70s
  • Nikon D80
  • Nikon Coolpix 5600
  • Apple Iphone 3GS

Example 1: Sort on Copy

Input Filenames: $ find a/ -xdev -iname "*.jpg*"

a/iris/D80/DSC_0838.JPG
a/iris/C5600/DSCN4665.JPG
a/philipp/S8000/DSC_0700.JPG
a/philipp/S8000/DSC_0705.JPG
a/nina/S3000/DSCN4613.JPG
a/nina/S3000/DSCN4614.JPG
a/tom/iphone/IMG_0102.JPG
a/tom/D70/DSC_4043.JPG
a/tom/D70/DSC_4048.JPG

Copy and sort:
$ NameByExifDate.pl -c -d b/ `find a/ -xdev -iname "*jpg*"`

Resulting Filenames: $ find b/ -xdev -iname "*.jpg*"

b/0_DSC_0700.JPG
b/1_DSCN4613.JPG
b/2_DSCN4614.JPG
b/3_DSC_0705.JPG
b/4_IMG_0102.JPG
b/5_DSCN4665.JPG
b/6_DSC_0838.JPG
b/7_DSC_4043.JPG
b/8_DSC_4048.JPG

Example 2: Sort on Move

Input Filenames: $ find a/ -xdev -iname "*.jpg*"

a/iris/D80/DSC_0838.JPG
a/iris/C5600/DSCN4665.JPG
a/philipp/S8000/DSC_0700.JPG
a/philipp/S8000/DSC_0705.JPG
a/nina/S3000/DSCN4613.JPG
a/nina/S3000/DSCN4614.JPG
a/tom/iphone/IMG_0102.JPG
a/tom/D70/DSC_4043.JPG
a/tom/D70/DSC_4048.JPG

Move and sort:
$ NameByExifDate.pl -m `find a/ -xdev -iname "*jpg*"`

Resulting Filenames: $ find a/ -xdev -iname "*.jpg*"

a/iris/D80/6_DSC_0838.JPG
a/iris/C5600/5_DSCN4665.JPG
a/philipp/S8000/0_DSC_0700.JPG
a/philipp/S8000/3_DSC_0705.JPG
a/nina/S3000/1_DSCN4613.JPG
a/nina/S3000/2_DSCN4614.JPG
a/tom/iphone/4_IMG_0102.JPG
a/tom/D70/7_DSC_4043.JPG
a/tom/D70/8_DSC_4048.JPG

The sort on move routine preserves the original directory structure while the sort on copy routine flattens the hierarchy to a single destination directory.

I highly appreciate feedback of any kind.


Comments

  1. exiv2 rename * is doing the same!!!

    • ohhh….damn. knowing this would have saved me 30min of work.
      thank you for the information, andi.

Leave a Reply

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

This site uses Akismet to reduce spam. Learn how your comment data is processed.