Mass Image Renaming based on EXIF

By Ziddykins on Apr 08, 2015

A friend came to me asking if I could help him making crawling through his thousands of camera images a little easier. His camera named his pictures in a confusing manner I guess so I came up with this. This uses the EXIF data of the images to rename your images in a date/time format. It also supports sequences, which are pictures taken in rapid succession. This only does png/jpg's and the extension part is a bit sloppy (is jpeg a thing still?).

As I know images are important to people, if you find any bugs, please immediately report them to me.


use Image::ExifTool qw(:Public);
use File::Copy qw(move);
use warnings; use strict;

## This will rename all your jpg/png files in a folder
## in a YYYY-MM-DD_HH-MM-SS_SEQ# format based off of EXIF data
## The folder used is specified on the command line; if a location
## is not specified, it will default to your home directory

## Examples:
## perl /home/dan/pictures/2005
## perl
## perl /usr/share/pictures/

## The renamed files are placed in a folder called OUTPUT
## which will be located inside the folder specified, or home default.

my $d = shift || $ENV{"HOME"};
if ($d =~ /\/$/) { chop $d; }

#Read directory files into an array
opendir D, "$d" || die "Can't open directory $d: $!\n";
    my @list = readdir(D);

#Store image files in an array; skip other files and hidden files
my @files;
foreach my $file (@list) {
    next if $file =~ /^\./;
    next if $file !~ /[jpg|png]$/gi;
    print "Adding $file\n";
    push @files, $file;

#If we didn't find any images, die
if (scalar @files < 1) { die "No suitable images found!\n"; }

#If we can't make the output folder, die
#Skip check if output exists already
if (! -e "$d/OUTPUT/") {
    unless (mkdir "$d/OUTPUT") {
        die "Unable to create output directory, make sure you have

#For each image, we grab the date/time and sequence number
#as well as the extension. If no time can be grabbed, it is
#assumed no EXIF is present and we will skip that file.
my $count = 0;
foreach my $file (@files) {
    my $exifTool = new Image::ExifTool;
    my $filename;

    my $time = $exifTool->GetValue('DateTimeOriginal');
    my $seq  = $exifTool->GetValue('SequenceNumber');
    my $ext = substr $file, -3;

    next if !$time;

    if ($time =~ /(\d+):(\d+):(\d+)\s(\d+):(\d+):(\d+)/) {
        my ($year, $month, $day, $hour, $minute, $second)
        =  ($1, $2, $3, $4, $5, $6);

        $filename = "$year-$month-$day\_$hour-$minute-$second";

        if ($seq) {
            $filename .= "_$seq.$ext";
        } else {
            $filename .= ".$ext";

        print "$d/OUTPUT/$filename\n";

        if (-e "$d/OUTPUT/$filename") {
            my $choice = 0;
            print "A file with this name exists already. Proceeding will" .
                  " overwrite the existing file.\n";

            while ($choice !~ /[a|s|o]/) {
                print "[a]bort, [s]kip, [o]verwrite: ";
                $choice = <STDIN>;
                chomp $choice;

            if ($choice eq "a") {
                die "Aborted by user\n";
            } elsif ($choice eq "s") {
                print "Skipped $file\n";
            } else {
                print "Overwriting $file\n";

        move "$d/$file", "$d/OUTPUT/$filename";


print "Finished: $count images stored\n";


Sign in to comment.
Are you sure you want to unfollow this person?
Are you sure you want to delete this?
Click "Unsubscribe" to stop receiving notices pertaining to this post.
Click "Subscribe" to resume notices pertaining to this post.