#!/usr/bin/perl -w # # image_info_modtime # # AUTHOR: # Dan Harkless # # COPYRIGHT: # This file is Copyright (C) 2010 by Dan Harkless, and is released under the # GNU General Public License . # # USAGE: # % image_info_modtime [-f ] [-u] [-v] [...] # # DESCRIPTION: # For each file specified on the commandline, uses the CPAN module # Image::ExifTool to look in the file for an embedded timestamp (the EXIF # "DateTimeOriginal" field by default). If one is there, that date/time will # be set as the modification time of the file. # # If -f is specified, will be used rather than # "DateTimeOriginal". Examples would be the EXIF "DateTime" and # "DateTimeDigitized", or the cross-format "LastModificationTime". Note that # the specified date/time field must be formatted as "YYYY.MM.DD HH:MM:SS" # (where "." means any non-digit character). # # If -u is specified, the embedded timestamp will be interpreted as UTC rather # than a time in the local zone. # # If -v is specified, the date/time and integer timestamp each file is being # set to will be printed. # # Note that any specified options must appear earlier on the commandline than # the files. image_info_modtime will exit with non-zero status if any errors # occur. # # DATE MODIFICATION # ========== ================================================================== # 2010-08-13 As with image_info before it, found a photo (a different one) that # caused Image::TIFF to output an error. Again, as with image_info, # modified image_info_modtime to use Image::ExifTool instead. I'll # archive the old Image::Info version as . # 2008-09-02 "use English qw(-no_match_vars)": avoid regex performance penalty. # 2002-11-27 With current version of Perl, was outputting warnings if no args. # 2002-03-23 Original. ## Modules used ################################################################ use English qw(-no_match_vars); # allow use of names like @ARG rather than @_ use File::Basename; # for basename() use Image::ExifTool qw(:Public); use Time::Local; # for timegm() and timelocal() ## Main ######################################################################## $field = "DateTimeOriginal"; if (scalar(@ARGV) and $ARGV[0] eq "-f") { shift; $field = shift; } if (scalar(@ARGV) and $ARGV[0] eq "-u") { shift; $UTC_mode = 1; } if (scalar(@ARGV) and $ARGV[0] eq "-v") { shift; $verbose_mode = 1; } $number_of_files = scalar @ARGV; if ($number_of_files < 1) { $progname = basename($PROGRAM_NAME); # strip off the path print STDERR "Usage: $progname [-f ] [-u] [-v] " . " [...]\n"; exit 1; } $exit_status = 0; foreach $file (@ARGV) { # TBD: The below is probably no longer necessary now that we're using # Image::ExifTool, but leaving it this way is fine too. # # Image::Info (up to 1.09, at least) doesn't do proper error handling -- # errors are not catchable by an eval and are printed (in a goofy format) on # STDOUT rather than STDERR. Therefore, we need to try to open the file # ourself, then do proper error reporting or pass the filehandle to # ImageInfo(), as appropriate. if (not open(FILE, $file)) { print STDERR "$file: $OS_ERROR.\n"; $exit_status = 1; } else { $hash_ref = ImageInfo(\*FILE); close FILE; $embedded_time = $hash_ref->{$field}; if (not $embedded_time) { print STDERR "$file: No $field field found.\n"; $exit_status = 1; } elsif ($embedded_time !~ /(\d\d\d\d).(\d\d).(\d\d) (\d\d):(\d\d):(\d\d)/) { print STDERR "$file: $field \"$embedded_time\" not in" . " \"YYYY.MM.DD HH:MM:SS\" format.\n"; $exit_status = 1; } else { $actime = time(); # TBD: preserve the pre-open() access time? if ($UTC_mode) { $modtime = timegm($6, $5, $4, $3, $2 - 1, $1 - 1900); $zone = "UTC"; } else { $modtime = timelocal($6, $5, $4, $3, $2 - 1, $1 - 1900); $zone = "local"; } if ($verbose_mode) { print "$file: Setting modtime to $1-$2-$3 $4:$5:$6 $zone" . " ($modtime).\n"; } if (not utime($actime, $modtime, $file)) { print STDERR "$file: utime(): $OS_ERROR.\n"; $exit_status = 1; } } } } exit $exit_status;