../sorting-images-by-exif-date

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
{{- $pages = where site.RegularPages "Type" "in" site.Params.mainSections }}
│       └── 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:
#!/usr/bin/perl -w
##################################################
#Move or copy images and rename them to be sorted by EXIF-CreateDate
#cmdline options:
#./cmd -move
#./cmd -copy -dest
##################################################

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:
Cameras tested with:

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.