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

Hello, I am very new to perl so hopefully this is something simple. I have a script that reads a data file and creates a png image based on the data for each record in the file. The first pass through the loop the image created in 56kb, all the rest of the images are 145kb. In the while loop, I am creating a new image object for each pass. I am guessing I need to destroy the image object before creating the new one but I am not sure how.

When I first built this, every image after the first one had a black background and I had to place a white rectangle on the image first to make the background white. I think the black background is where the extra size is coming from.

Any suggestions would be appreciated.

Thanks

George

Code snippet is below:

#!/usr/bin/perl use GD; # size of image $maxx = 600; $maxy = 500; $numGrids = 33; # A background inmage to add open (PNG,"gradient/river.png") || die; $mapImage = newFromPng GD::Image(\*PNG) || die; close PNG; open(FILENAME,"gradient/current_r") || die "open failed"; { my @tmp; my @data; my $line1 = <FILENAME>; $count=0; while ($line2 = <FILENAME>) { @tmp = split(' ', $line2); @PRESOBS = @tmp; # create a new image $im = new GD::Image($maxx+50,$maxy); # enough for y axis label +s $im->trueColor(1); # allocate some colors $white = $im->colorAllocate(255,255,255); $black = $im->colorAllocate(0,0,0); #$red = $im->colorAllocate(255,0,0); #$blue = $im->colorAllocate(0,0,255); $grey = $im->colorAllocate(128, 128, 128); #$green= $im->colorAllocate(0, 255, 0); # make the background transparent and interlaced $im->transparent($white); $im->interlaced('true'); # hack added to images after the first one do not have a black backgro +und $im->filledRectangle(0,0,$maxx+50, $maxy, $white); .... Code here to draw the image elements #Load map image $im->copy($mapImage, 0, $maxy/2+1, 0,0,600,250); # Put a black frame around the picture $im->rectangle(0,0,$maxx-1,$maxy-1,$black); $im->line(0, $maxy/2, $maxx, $maxy/2, $black); $png_data = $im->png; $hour = sprintf("%02d", $PRESOBS[0]); $xnum = sprintf("%d", $count); my $file = "EtaGradient". $xnum.".png"; open(DISPLAY,">$file") || die "open failed"; binmode DISPLAY; print DISPLAY $png_data; close DISPLAY; print "Output file = ".$file."\n"; $count++; } close (FILENAME); }

Replies are listed 'Best First'.
Re: Images created in a loop grow
by zentara (Cardinal) on Apr 16, 2006 at 16:19 UTC
    I am guessing I need to destroy the image object before creating the new one but I am not sure how.

    With GD, you just "undef $im". I'm not sure in your loop where it needs to be done, because it's not a working snippet, but try putting it right before you create the GD object, it may complain on the first run, but it will clear it out for subsequent runs.


    I'm not really a human, but I play one on earth. flash japh
      Thanks for the suggestions. I tried using undef $im but I still seem to have the problem. The following code builds 10 images. The first one has a white background and the rest all have black backgrounds. I am not sure why. I would expect them to all be the same. Any suggestions? Thanks again.

      Here is the code

      #!/usr/bin/perl use GD; $maxx = 600; $maxy = 500; for ($x = 0; $x < 10; $x++) { # create a new image undef $im; $im = new GD::Image($maxx+50,$maxy); $im->trueColor(1); # allocate some colors $white = $im->colorAllocate(255,255,255); $black = $im->colorAllocate(0,0,0); # make the background transparent and interlaced $im->transparent($white); $im->interlaced('true'); # Put a black frame around the picture $im->rectangle(0,0,$maxx-1,$maxy-1,$black); $im->line(0, $maxy/2, $maxx, $maxy/2, $black); $png_data = $im->png; my $file = "TestImage". $x.".png"; open(DISPLAY,">$file") || die "open failed"; binmode DISPLAY; print DISPLAY $png_data; close DISPLAY; print "Output file = ".$file."\n"; undef $png_data; undef $im; }
        Your example was a little tricky, because of the white transparency, and black rectangles, it all showed up as black on my screen....BUT I did find your problem. What I noticed was the first file was one third the file size of the subsequent files.

        Your problem is the truecolor setting. This isn't obvious, it's just that I've seen the question asked before, and had the answer handy. Just look at it as a recipe.

        The truecolor spec is a global in the c library, and should be set the way I've shown below. What was happening in your script, (I think :-) )was the truecolor was only being set after the first run through, thus the first file was different. I said GD can be tricky sometimes. :-) Try this

        #!/usr/bin/perl use GD; GD::Image->trueColor(1); $maxx = 600; $maxy = 500; for ($x = 0; $x < 10; $x++) { # create a new image undef $im; $im = new GD::Image($maxx+50,$maxy); # not $im->trueColor(1); # allocate some colors $white = $im->colorAllocate(255,255,255); $black = $im->colorAllocate(0,0,0); # make the background transparent and interlaced $im->transparent($white); $im->interlaced('true'); # Put a black frame around the picture $im->rectangle(0,0,$maxx-1,$maxy-1,$black); $im->line(0, $maxy/2, $maxx, $maxy/2, $black); $png_data = $im->png; my $file = "TestImage". $x.".png"; open(DISPLAY,">$file") || die "open failed"; binmode DISPLAY; print DISPLAY $png_data; close DISPLAY; print "Output file = ".$file."\n"; undef $png_data; undef $im; }

        I'm not really a human, but I play one on earth. flash japh

      I haven't used GD in years; is that better than declaring $im as lexical within the loop?

        It would seem so. I can't say for sure, because I usually use Imager, or ImageMagick, but GD does act slightly different from most Perl objects because of it's c base. It actually runs well in a loop, and will not gain "program memory" if you undef it in the loop. I havn't tested it, but I would suspect that if you just rely on the lexical scoping, some of the previous GD object will get left for the the next run.

        Those Image modules are tricky. ImageMagick has a recipe too, it's

        undef @$image;
        which allows you to reuse the IM object, but flushes out all the old data.

        I'm not really a human, but I play one on earth. flash japh