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

Hi again!

Yesterday I got familiar with the GD module (Quite a nice one). I have recently wrote a Photo Album with Perl and decided to write a little subroutine using GD to create thumbnails to every picture added to the photo album whose dimensions are heigher than the minimum (Let's say 250x250). I wrote this little program as a test:

#!/usr/bin/perl -w use GD; my @dirs; $directory = "D:/Temp"; getdirs($directory); for $dir (@dirs) { update($dir); } print "DONE\n"; sub getdirs { my $directory = shift; opendir (DIR, $directory); @files = readdir DIR; closedir DIR; push (@dirs, $directory); for $file (@files) { if (-d "$directory/$file") { push (@dirs, "$directory/$file") unless ($file eq "." || $file eq +".."); getdirs("$directory/$file"); } } } sub update { my $directory = shift; for $file (@files) { $full = "$directory/$file"; if (-f $full && $full =~ m/\.png/i) { open (PNG, "$full") || die; $image = newFromPng GD::Image(\*PNG) || die; close PNG; ($width,$height) = $image->getBounds(); if ($width <= 250 && $height <= 250) { # DO NOTHING } else { if ($width <= 250 && $height > 250) { $percent = (250*100)/$height; $newidth = ($width*$percent)/100; $desimage = new GD::Image($newidth, 250); $desimage->copyResized($image, 0, 0, 0, 0, $newidth, 250, $w +idth, $height); } elsif ($width > 250 && $height <= 250) { $percent = (250*100)/$width; $newheight = ($height*$percent)/100; $desimage = new GD::Image(250, $newheight); $desimage->copyResized($image, 0, 0, 0, 0, 250, $newheight, +$width, $height); } else { if ($width > $height) { $percent = (250*100)/$width; $newheight = ($height*$percent)/100; $desimage = new GD::Image(250, $newheight); $desimage->copyResized($image, 0, 0, 0, 0, 250, $newheight +, $width, $height); } else { $percent = (250*100)/$height; $newidth = ($width*$percent)/100; $desimage = new GD::Image($newidth, 250); $desimage->copyResized($image, 0, 0, 0, 0, $newidth, 250, +$width, $height); } } open (FILE, "+>$directory/less$file") or die "Can't open file: + $!"; binmode FILE; print FILE $desimage->png; close FILE; } } } }
As you can see the program get's the main picture directory (This is how the photo album works). All the pictures in the photo album must be under this directory (If specifically in it, or in subdirectories). The program should go through all those subdirectories and update every file who's above the minimal dimensions (update = create a thumbnail). The implementation is definitely not the most efficient one. It's just I've tried several ways and still get (Pretty much) the same result. I just left the last one I tried.

My pic folder - D:/Temp, has something like 80 .tmp files, 1 .png file and a folder, which holds one .png file and one folder, which holds one .png file.
On my first implementations, Perl gave me a deep recursion message and printed like a million "DONE"s (The print "DONE\n" statement was in the update sub), although (As I recall) nothing got updated. This was very weird cause the recursion should occur only 2 times (According to the contents of D:/Temp). On this implementation, I still get a Deep recursion message and only the files in the first 2 folders are updated. No thumbnail is created to the one in the third folder.

Anyone's got an idea why this happens?!
Thanks again.

Replies are listed 'Best First'.
Re: A very deep recursion and the GD module (problem)
by slayven (Pilgrim) on Jul 31, 2003 at 08:49 UTC
    You are nesting your global variables. use strict; and declare them correctly. You're unnecessarily pushing your directories twice into @dir, so skip that line. Also grep only the desired files from the directory listing, adding a  grep { !/^\.\.?$/ }, which ignores "./" and "../".
    This should work:
    use strict; my @dirs; my $directory = "D:/Temp"; getdirs($directory); for my $dir (@dirs) { update($dir); } print "DONE\n"; sub getdirs { my $directory = shift; opendir (DIR, $directory); my @files = grep { !/^\.\.?$/ } readdir DIR; closedir DIR; push (@dirs, $directory); for my $file (@files) { if (-d "$directory/$file") { getdirs("$directory/$file"); } } }

    Finally, as simon.proctor mentioned, I'd really recommend using File::Find for this kind of job.


    --
    trust in bash
    but tie your camel
Re: A very deep recursion and the GD module (problem)
by simon.proctor (Vicar) on Jul 31, 2003 at 08:34 UTC
    Apart from using strict I would recommend using File::Find to do any and all of your directory recursion. Its a great module and I would use it anywhere you need to do directory traversals of this type.
Re: A very deep recursion and the GD module (problem)
by sgifford (Prior) on Jul 31, 2003 at 08:20 UTC
    I don't know about Windows, but in UNIX your list of files in:
    opendir (DIR, $directory); @files = readdir DIR; closedir DIR;
    will include both ".", the current directory, and "..", the parent directory. These will cause your program to look at your entire hard drive over and over again.

    The normal way to deal with that is, in your for $file loop, to add a line like next if ($file =~ /^\./);.

Re: A very deep recursion and the GD module (problem)
by chunlou (Curate) on Jul 31, 2003 at 08:14 UTC
    Your @files in your update sub looks ambiguous. Try to add use strict; to see if you get additional error messages.
Re: A very deep recursion and the GD module (problem)
by ido50 (Scribe) on Jul 31, 2003 at 09:21 UTC
    Great. Thanks everyone.
    I love this place.