punkish has asked for the wisdom of the Perl Monks concerning the following question:
I am trying to create the simplest possible animated gif using GD, but I am failing. What am I doing wrong? Needless to say, making a static gif image works just fine. The animated gif just comes out black.
Update: I have successfully made an animated gif with Imager, but am still curious as to why GD doesn't work for me. On an additional note, there are several modules for working with images -- GD, Imager, PerlMagick, probably many more. Is there some comprehensive-ish comparison of the offerings out there?
use GD;
my $img_width = 400; my $img_height = 300;
my $cell_width = 100; my $cell_height = 100;
my $num_of_years = 3;
# Create a new, empty image
my $img = GD::Image->new($img_width, $img_height);
# Allocate some colors
my $colors = colors($img);
# Mark start of a new animation
my $gifdata = $img->gifanimbegin;
for (1 .. $num_of_years) {
# Make a frame of right size
my $frame = GD::Image->new($img->getBounds);
image($frame, $img_width, $img_height, $cell_width, $cell_height,
+$colors);
# Add frame
$gifdata .= $frame->gifanimadd;
}
# Finish the animated GIF
$gifdata .= $img->gifanimend;
open F, ">image.gif" or die $!;
print F $img->gif();
close F;
sub colors {
my ($img) = @_;
my @colors = ();
for my $r (0 .. 7) {
for my $g (0 .. 7) {
for my $b (0 .. 7) {
push @colors, $img->colorAllocate($r*32, $g*32, $b*32)
+;
}
}
}
return \@colors;
}
sub image {
my ($img, $img_width, $img_height, $cell_width, $cell_height, $col
+ors) = @_;
my $num_of_cells_in_x = ($img_width / $cell_width) - 1;
my $num_of_cells_in_y = ($img_height / $cell_height) - 1;
for my $y1 (0 .. $num_of_cells_in_y ) {
my $ymin = $y1 * $cell_height;
my $ymax = ($y1 * $cell_height) + $cell_height;
for my $x1 (0 .. $num_of_cells_in_x ) {
my $xmin = $x1 * $cell_width;
my $xmax = ($x1 * $cell_width) + $cell_width;
# Draw a filled rect of specified color
my $color = $colors->[ int(rand( @$colors )) ];
$img->filledRectangle($xmin, $ymin, $xmax, $ymax, $color);
}
}
return $img;
}
--
when small people start casting long shadows, it is time to go to bed
Re: Creating an animated gif with GD
by BrowserUk (Patriarch) on Aug 22, 2010 at 02:39 UTC
|
but am still curious as to why GD doesn't work for me.
Because you're using it wrong :).
First, you are accumulating the frames in $gifdata .= $frame->gifanimadd;, but then you print just the header info from the image into the file: print F $img->gif();.
You should be printing the accumulated headers and frame data to the file: print F $gifdata;
That doesn't affect a complete fix though because you're also confusing what constitutes a frame and what a complete animation. That is, you appear to be drawing a complete set of moving rectangles into each frame, rather than one rectangle at a different position in each frame.
You should also check that each frame, when viewed as a discrete image, actually displays what you think you are drawing in that frame..
And finally, you need to ensure that all the colors you use in the frames, are added to the palette of the base image, before you capture the header with gifanimbegin()
Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
"Science is about questioning the status quo. Questioning authority".
In the absence of evidence, opinion is indistinguishable from prejudice.
| [reply] [d/l] [select] |
|
First, you are accumulating the frames in $gifdata .= $frame->gifanimadd;, but then you print just the header info from the image into the file: print F $img->gif();.
You should be printing the accumulated headers and frame data to the file: print F $gifdata;
Silly me, of course, I was doing it wrong. It is all working now, many thanks. Oh, and GD is about an order of magnitude faster than Imager. This would make a significant difference when I work with real data... 100 years worth (iow, 100 frames) of a few hundred thousand to a couple of million cells.
That doesn't affect a complete fix though because you're also confusing what constitutes a frame and what a complete animation. That is, you appear to be drawing a complete set of moving rectangles into each frame, rather than one rectangle at a different position in each frame.
No, thankfully, I got that part right.
Now I have to figure out whether an animated gif is appropriate for me (pretty universal readability... all browsers can), or if I should go the route of HTML5 video. What I would really like is a user-controllable scrub/scroll bar so the time-lapse can be changed to any time period. But, that is not a perl problem...
Many thanks again.
--
when small people start casting long shadows, it is time to go to bed
| [reply] |
|
| [reply] |
Re: Creating an animated gif with GD
by zentara (Archbishop) on Aug 22, 2010 at 11:51 UTC
|
there are several modules for working with images -- GD, Imager, PerlMagick, probably many more. Is there some comprehensive-ish comparison of the offerings out there?
I usually use gifsicle for animated gifs. It works well. Then you can use any of GD, Imager or ImageMagick to make your frames, and feed them to gifsicle like
system("gifsicle -lforever $my_stuffl*.gif > $my_stuff.anim.gif") ;
for GD, try Text to animated pseudo-braille GIF and see Image::Magick GIF Animation Speed for ImageMagick usage.
| [reply] [d/l] |
Re: Creating an animated gif with GD
by Khen1950fx (Canon) on Aug 22, 2010 at 07:23 UTC
|
I tried a mix of GD and
GD::Image::AnimatedGif.
I used the sample from GD, but I kept it very simple. I just wanted the blue border of the red oval to expand and contract when I passed over it with my mouse. It's almost imperceptible, but it works.
#!/usr/bin/perl
use strict;
use warnings;
use GD;
use GD::Image::AnimatedGif;
my $im_width = 100;
my $im_height = 100;
my $im = new GD::Image($im_width, $im_height);
my $white = $im->colorAllocate(255,255,255);
my $black = $im->colorAllocate(0,0,255);
my $red = $im->colorAllocate(255,0,0);
my $blue = $im->colorAllocate(0,0,255);
$im->rectangle(0,0,99,99,$black);
$im->arc(50,50,95,75,0,360,$blue);
$im->fill(50,50,$red);
my $gifdata = $im->gifanimbegin;
my $frame = GD::Image->new($im->getBounds);
$gifdata = $frame->gifanimadd;
my $loop = 0;
my $speed = 82;
$gifdata .= $im->gifanimend;
print "Content-type: image/gif\n\n";
print $im->animated_gif($loop, $speed);
| [reply] [d/l] |
|
|