#! /usr/bin/perl # This program is used to rename pictures in a directory. First it # displays the picture, then it lists a reasonable default name which # can be edited. # # The image is then renamed if there doesn't exist an image with the # same name already in the directory. # Sorting now is fixed. Images are sorted by shot order, rather than # directory transversal. # BUGS: # # Renaming should be done in a loop rather than going through once # only. [Eg, repeat the file on a renaming error.] # TODO: # # number of leading zeros adjustable... [or automatic?] # use warnings; use strict; use IO::Dir; use Term::ReadLine; use Image::Info qw(image_info); use Getopt::Long; use Date::Calc qw(Date_to_Time); my $config = {counter_start => 1, renumber_only => 0, }; ($config->{program_name}) = $0 =~/([^\/]+)\s*$/; GetOptions($config,'counter_start|c=i','renumber_only|renumber-only|r!'); if ($#ARGV < 0) { print STDERR "No Directory Specified\nUsage: $config->{program_name} \n"; exit 1; } $config->{dir} ||= $ARGV[0]; # The counter is used to keep the images in the order in which they # were shot. It assumes that the order they are listed in the # directory is the same as the order in which they were shot. May not # always be true, but it's a decent guess. my $file_counter = $config->{counter_start}; my $current_directory = new IO::Dir $config->{dir} or die "Unable to read directory $config->{dir}"; # We use readline to handle prompting for a new name for the picture my $readline = new Term::ReadLine 'RenamePicture'; my @pictures = (); while (defined($_ = $current_directory->read)) { #skip non images next unless /(jpg|gif|jpeg|png|pict|bmp)$/i; # Change the extension to lower case. my %picture = (); $picture{extension} = lc $1; # ignore directories [directories named .bmp? strange.] next unless -f $_; # Read image info, and ignore images for which there is no # info. [probably not really an image.] $picture{image_info} = image_info($_); next if not defined $picture{image_info}; $picture{old_name} = $_; # Default name is ${file_counter}__${picture_time}.${extension} ($picture{clean_old_name}) = $picture{old_name} =~ /\d+\_(.*?)\_?\d+\.(?:jpg|gif|jpeg|png|pict|bmp)/i; $picture{clean_old_name} ||= ''; # Pull out the date and time when the image was shot $picture{date_ymdhms} = [split(/[\s\:]+/,$picture{image_info}{DateTime})]; $picture{picture_time} = join('',@{$picture{date_ymdhms}}[0..2]); $picture{default_name} = qq(_$picture{clean_old_name}_$picture{picture_time}.$picture{extension}); push @pictures, \%picture; } # Sort @pictures = sort {Date_to_Time(@{$$a{date_ymdhms}})<=> Date_to_Time(@{$$b{date_ymdhms}})} @pictures; # Rename foreach my $picture (@pictures) { # view the image `feh -FZ $$picture{old_name} > /dev/null` unless $$config{renumber_only}; #prompt to rename the picture print "Rename $$picture{old_name}\n"; # sprintf('%03s',$file_counter); $$picture{clean_old_name} = $readline->readline('new name:',$$picture{clean_old_name}) unless $$config{renumber_only}; my $line = sprintf('%03s',$file_counter).qq(_$$picture{clean_old_name}_$$picture{picture_time}.$$picture{extension}); # Remove leading and trailing spaces, replace all remaining # spaces with _, and remove ugly characters. lowercase everything # while we're at it. $line =~ s/^\s*//; $line =~ s/\s*$//; $line =~ s/\s+/\_/g; $line =~ tr/A-Z/a-z/; $line =~ s/[^\w\_\-\d\.]//g; # Make sure we're not saving over an existing file. if (not -e $line) { rename $$picture{old_name}, $line; print "Renamed $$picture{old_name} to $line\n"; } else { print STDERR "$line already exists, cowardly doing nothing to $$picture{old_name}.\n"; } $file_counter++; }