sdyates has asked for the wisdom of the Perl Monks concerning the following question:

This one is a little tricky. I created a script that uses ImageMagick's identify command to verify the validity of fpx image files. It does a good job most of the time and reports most bad images to a flat file. The problem occurs with a few files that are bad and bring down the programme.

When identify crashes, it generates a windows program error dialogue box. The problemis that the next time the script tries to analyse an image, it fails to start identify again. Included is a copy of my entire script.


Should I be launching identify differently?
Shold I be handling error control better?
How do I get the script to launch identify again?

Please advise,
Simon
############################################################# # This script checks the validity of image files using # # Image Magick's Identify command. This script works with # # various file formats. Several variables can be changed to # # altering logging and analysis. # # # # Simon D. Yates 30may02. # # Simon D. Yates Version 2.00.0168 18jun02. # ############################################################# # Allow this for emailing on errors. Will also require the email metho +d # Email me at sdyates2001@yahoo.com for the method. # use LWP::UserAgent use File::Find; #>---------------[ Customisable variables ]----------------- my $SummaryHTML = ">c:\\summary.html"; # Location of Summary.html. Report summary in html format. my $SummaryCSV = ">c:\\summary.csv"; # Location of Summary.csv. Report summary in csv format. my $SummaryCSVread = "<c:\\summary.csv"; # Location of dump.txt. Contains granular data on each image tested. my $dump = "c:\\dump.txt"; # Location of error.txt. Contains a list of potentially corrupt images +. my $error = ">>c:\\error.txt"; # Specify "yes" to allow good images to be copied to $CopyDestination my $CopyGoodImages = "yes"; # by-passes prompting sections when set to other than no my $AutoScript = "yes"; # Specify the root directory where the images will be analysed and cop +ied from my $CopySource = "c:\\fpx"; # Specify the directory where the good images will be copied to my $CopyDestination= "c:\\temp"; #>----------------------[ variables ]------------------------ @Structure=('\#\#','Format','Geometry','Class','Type','Depth', 'Colors','Filesize','Compression','Tainted'); #>---------------------[ Main logic ]------------------------ # Generates time stamp for log files Date(); # prompts for Source directory. RetrieveValues(); # Analyse each image and dump raw data and log errors CheckImageArchieve(); # Create summary file of images processed GrepImageDetails(); print OUTPUT "\n"; # Creates HTML file from CSV file PrintHTML(); #>----------------[ Subroutine Section ] -------------------- sub RetrieveValues { if ($AutoScript eq "no") { print "\n\nSpecify the Directory path to image folder:\n"; $directory = (<STDIN>); chomp $directory; } } sub CheckImageArchieve { my $a = 0; if ($AutoScript = "yes") { $directory=$CopySource } opendir(DIR, $directory) or die "Cannot open directory $directory"; find (\&RetrieveAll, $directory); system ("cls"); while ($DIR[$a]) { open (STDERR, "$error") or die "$!"; # verbose option is critical for creating summary file $file="$DIR[$a]"; if (-d $file) { system("echo ##: $DIR[$a](SUB DIRECTORY) >> $dump"); print "DIR: $file" . "\n" } elsif (-f $file) { system("echo ##: $DIR[$a] >> $dump"); print "$DIR[$a]\n"; system("identify -verbose $DIR[$a] >> $dump") and print STDERR "##: $DIR[$a] likely corrupt!\n------------------ +--------------------------------\n" and $img="bad"; CopyGoodImage() } $a=$a+1; close STDERR; } } sub GrepImageDetails { open (INFILE, "<$dump") or die "Cannot open $dump file"; open (OUTPUT, $SummaryCSV) or die "Cannot open Summary CSVfile"; print OUTPUT "\n$Date\n"; print OUTPUT "File,Format,Geometry,Class,Type,Depth,Colors,Filesize,C +ompression,Tainted"; while (<INFILE>) { $SFS = $_; $z=0; foreach $Structure(@Structure) { if ($SFS =~ m/$Structure[$z]/) { if ($Structure[1] =~ m/Format/) { if ($SFS =~ m/\#\#/) { print OUTPUT "\n"; } } $SFS =~ s/$Structure[$z]: //; $SFS =~ s/ //g; $SFS =~ s/\r//g; chomp $SFS; if ($z ne 9) { print OUTPUT $SFS . ","; } else { print OUTPUT $SFS; } print $SFS . "\n"; } $z=$z+1; } } $z=$z+1; close INFILE; close OUTPUT; } sub Date { ($sec,$min,$hou,$day,$mon,$yer,$wek,$dy,$DST)=localtime(time); my $rlm=$mon+1; my $yer=$yer+1900; if ($rlm == 1) {$rlm = "Jan"} elsif ($rlm == 2) {$rlm = "Feb"} elsif ($rlm == 3) {$rlm = "Mar"} elsif ($rlm == 4) {$rlm = "Apr"} elsif ($rlm == 5) {$rlm = "May"} elsif ($rlm == 6) {$rlm = "Jun"} elsif ($rlm == 7) {$rlm = "Jul"} elsif ($rlm == 8) {$rlm = "Aug"} elsif ($rlm == 9) {$rlm = "Sep"} elsif ($rlm == 10) {$rlm = "Oct"} elsif ($rlm == 11) {$rlm = "Nov"} elsif ($rlm == 12) {$rlm = "Dec"}; $Date="$hou"."h"."$min:$sec $rlm-$day-$yer"; } sub RetrieveAll { $File::Find::dir =~ s/\//\\/g; $_ =~ s/\//\\/g; push (@DIR,$File::Find::dir."\\".$_); } sub SummaryHTML { print OUTPUTHTML "</tr></table></p></BODY></HTML>"; } sub PrintHTML { open (OUTPUTHTML, $SummaryHTML) or die "Cannot open Summary HTML file +"; open (SUMMARY, "$SummaryCSVread") or die "Cannot open $dump file"; print OUTPUTHTML "<HTML><HEAD> <META NAME='GENERATOR' Content='Zoom Image Server Library'> <TITLE></TITLE> </HEAD> <TABLE BORDER=0 width=1000 cellpadding=2 align=left bordercolor='#FF +9933' body bgcolor=steelblue> <TR><TH><font face=arial size=2>File name</TH> <TH><font face=arial size=2>Format</TH> <TH><font face=arial size=2>Pixel size</TH> <TH><font face=arial size=2>Class</TH> <TH><font face=arial size=2>Depth</TH> <TH><font face=arial size=2>Colour Depth</TH> <TH><font face=arial size=2>Colours</TH> <TH><font face=arial size=2>File size</TH> <TH><font face=arial size=2>Compression</TH> <TH><font face=arial size=2>Tainted</TH></TR> <font face='Courier'><TR><TH>"; $directory=~ s/\\/\\\\/g; while (<SUMMARY>) { $line=$_; $line =~ s/,/\<\/td\>\n\<td width='100' height='20' font face=arial +size='1' bordercolor='#FFFFCC' bgcolor='#FFFFCC' align=left\>/g; # replace with scalar representing the path if ($line =~ m/$directory/) { print OUTPUTHTML "<tr><td width='150' height='20' font face=arial s +ize=1 border='1' bordercolor='#FFFFCC' bgcolor='#FFFFCC' align='left' +>$line</td></tr>"; print OUTPUTHTML "\n"; } } close SUMMARY; close OUTPUTHTML; } sub CopyGoodImage { if ($img eq "bad") { print "$file is potentially damaged, recompress.\nFile not coppied!\ +n\n"; $img=(); } else { print "$file is fine\n"; if ($CopyGoodImages eq "no") { print "File copy is turned off\n\n" } else { print "Copying $file ...\n"; system ("copy $file $CopyDestination\n"); } print "\n"; $img=(); } }

edited: Fri Jun 21 15:12:29 2002 by jeffa - added readmore tag

Replies are listed 'Best First'.
Re: Error Handling
by joealba (Hermit) on Jun 21, 2002 at 15:02 UTC
    You might want to look into PerlMagick - the Object Oriented interface to the ImageMagick goodness.

    Here's the PerlMagick way to do what you're doing. It will also give you some better error handling.
    use Image::Magick; my $photo = Image::Magick->new(); my $x = $photo->ReadImage($input); if ($x) { warn $x; # This will catch any bad files or serious errors in reading the ima +ge } my ($height, $width) = $photo->Get('height','width');
    You can find your other attributes here on the PerlMagick page.
Re: Error Handling
by vladb (Vicar) on Jun 21, 2002 at 14:53 UTC
    Although, as much as I hate to remind it, my first suggestion would be to 'use strict' in your code. I've tried running your script with 'use strict' and it brought up a hoard of errors and warnings. I'm not, however, implying that this may be the cause of your troubles, but there's still a lot of 'unknowns' and blind spots left if you don't use the strict pragma in your code.

    Update:

    From the system manpage, you may try retrieve a little bit more info on the specific error of the ImageMagic script like so:
    my $sys_res = system("identify -verbose $DIR[$a] >> $dump"); if ($sys_res) { # an error occurred! my $exit_value = $? >> 8; my $signal_num = $? & 127; my $dumped_core = $? & 128; die "system failed: $exit_value, $signal_num, $dumped_core!" }
    You also say,

    The problem occurs with a few files that are bad and bring down the programme.

    Do you mean the system() call causes your actual script to terminate, not only the ImageMagic script? Please verify. Frankly, I never came across a problem where a call to the system() function would kill the parent process. Maybe that it is implemented differently on the Win 32 platform as it doesn't do 'forking' quite well or differently.

    _____________________ <code> # Under Construction </c ode>
Re: Error Handling
by bronto (Priest) on Jun 21, 2002 at 15:03 UTC

    You say that identify crashes, but it generates a window... is it still running or not? I suppose it is running, since I would find strange that it spawns another process just to tell you it is crashing. So, with this in mind...

    Instead of using system you could fork a child process that launches identify, and use alarm in the parent.

    If the child process doesn't return in a fixed amount of seconds (as far as I can understand, 10 is far more than enough), its parent could kill it and go on with next image.

    Have you any experience on that?

      Well, this is windows which makes things a little different. The identify will go away but requires the clicking of an ok or cancel button. I need to redirect the program error so that window's dialogue does not appear waiting for an ok or cancel button to appear.

      This would be much easier if it was run in linux. Windows always has to make things difficult!