#!/usr/bin/perl # Filename: fix_img, normalize, geometry, etc.. # Author: David Ljung Madison # See License: http://MarginalHacks.com/License/ # Description: Run ImageMagick 'convert' on a photo, optionally saving a backup # By itself (as "fix_img") can sometimes repair broken images # # Name the executable either "fix_img" or one of converts options # (such as geometry for -geometry, normalize for -normalize, etc..) # # You can also use links to a main executable, for example (on unix): # % ln -s fix_img normalize # % ln -s fix_img geometry # etc.. # # The program will need extra arguments if the convert option requires them. # See examples in usage. use strict; ################################################## # Setup the variables ################################################## my $PROGNAME = $0; $PROGNAME =~ s|.*/||; my ($BASENAME,$PROGNAME) = ($0 =~ m|(.*)/(.+)|) ? ($1?$1:'/',$2) : ('.',$0); my @DEFAULT_BAK = qw(normalize); # I like to do backups by default when norm.. my $CONVERT = "convert"; # Use full path for windows systems my $VIEWER = "xv"; # Default graphics viewer (with args) ################################################## # Usage ################################################## sub fatal { foreach my $msg (@_) { print STDERR "[$PROGNAME] ERROR: $msg\n"; } exit(-1); } sub usage { my ($opt) = shift @_; foreach my $msg (@_) { print STDERR "ERROR: $msg\n"; } my $bak = $opt->{bak} ? "ON" : "OFF"; my $arg = $PROGNAME eq "fix_img" ? "" : " with '-$PROGNAME'"; print STDERR < Run ImageMagick 'convert'$arg on a bunch of images. -d Set debug mode -q Run quiet (no "Done: .." messages) -bak Save backups [default $bak] -nobak Don't save backups -view Run image viewer when done -viewer Image viewer [default $opt->{viewer}] --opts .. -- Options to add to convert Name the executable either "fix_img" or one of convert's options. Example runs: % fix_img *.jpg % normalize *.jpg % geometry 50% *.jpg % geometry 50% -bak -view *.jpg USAGE exit -1; } sub convert_usage { my ($arg) = @_; open(CONV,"$CONVERT -h|") || die("Couldn't read convert usage output\n"); while () { if (/^\s+-($arg.*)/) { # Heuristic for determining if convert usage shows an arg. # Chop off after 20 characters (that's the usage sentence) # And split to see how many args might be mentioned. my @usage = split(/\s+/,substr($1,0,20)); return @usage ? $#usage : 0; # Number of args needed. (Likely 0, 1 or 2) } } close CONV; die("Unknown convert option [-$arg]\n"); } sub parse_prog { my $opt = {}; $opt->{args} = []; $opt->{viewer} = $VIEWER; my $arg = $PROGNAME; return $opt if $arg eq "fix_img"; push(@{$opt->{args}}, "-$arg"); my $needs_args = convert_usage($arg); foreach ( 1..$needs_args ) { push(@{$opt->{args}}, shift @ARGV); } $opt->{bak} = 1 if grep($arg eq $_, @DEFAULT_BAK); $opt; } sub get_dashdash { my @dash; while ($#ARGV>=0) { my $arg=shift(@ARGV); last if $arg eq "--"; push(@dash,$arg); } @dash; } sub parse_args { my $opt = parse_prog(); while (my $arg=shift(@ARGV)) { if ($arg =~ /^-h$/) { usage($opt); } if ($arg =~ /^-d$/) { $MAIN::DEBUG=1; next; } if ($arg =~ /^-q$/) { $opt->{q}=1; next; } if ($arg =~ /^-bak$/) { $opt->{bak}=1; next; } if ($arg =~ /^-nobak$/) { $opt->{bak}=0; next; } if ($arg =~ /^-view$/) { $opt->{view}=1; next; } if ($arg =~ /^-viewer$/) { $opt->{viewer}=shift(@ARGV); next; } if ($arg =~ /^--(convert_)?opts$/) { push(@{$opt->{args}},get_dashdash()); next; } if ($arg =~ /^-/) { usage($opt,"Unknown option: $arg"); } push(@{$opt->{files}},$arg); } usage($opt,"No files defined") unless $opt->{files}; $opt; } sub debug { return unless $MAIN::DEBUG; foreach my $msg (@_) { print STDERR "[$PROGNAME] $msg\n"; } } ################################################## # Main code ################################################## sub main { my $opt = parse_args(); my @view; foreach my $file ( @{$opt->{files}} ) { my $orig = $file; push(@view,$file); if ($opt->{bak}) { $orig =~ s/(\.(gif|jpg|jpeg))?$/.orig$1/i; if (-f $orig) { print "Already has original: $orig\n"; next; } rename($file,$orig); push(@view,$orig); } system($CONVERT,@{$opt->{args}},$orig,$file); print STDERR "ERROR: $file: $?\n" if $?; print "Done: $file\n" unless $opt->{q}; } exec($opt->{viewer},@view) if $opt->{view}; } main();