How to extract frames of an animated GIF with PHP
I spent my day creating a class based on this one to achieve what I wanted using only PHP!
You can find it here: https://github.com/Sybio/GifFrameExtractor
Thanks for your answers!
Exploding Animated GIF and Manipulating Frames (GD Library)
A GIF does not contain just separate images appended after each other. A frame in a GIF may change just a part of the image - it does not have to cover the whole frame. It can also contain a local palette, but otherwise it relies on the global palette of the image - which is stored for the file itself and not just the frame.
I.e. - you can't just explode the file and decode each segment separately and except to get useful images from GD.
You'll at least have to add the gif header to each set of image data, but I strongly recommend using the PHP ImageMagick interface instead if possible - it has far better support for iterating through frames in an image.
Another option is using a pure PHP implementation that does what you want, such as GifFrameExtractor.
The relevant code is located at line 137 of the source file:
$img = imagecreatefromstring(
$this->fileHeader["gifheader"] .
$this->frameSources[$i]["graphicsextension"] .
$this->frameSources[$i]["imagedata"] .
chr(0x3b)
);
As you can see, there is far more data necessary (the header, the extension (87a vs 89) and a terminating character) to make it valid GIF data. Output each individual animated GIF frame as visually intended
I found out on my own how to do it with Imagick:
$frameIndex = 0;
$img = $img->coalesceImages();
foreach( $img as $frame )
{
$frameName = ++$frameIndex . '.gif';
$frame->writeImage( $frameName );
}
In other words, Imagick::coalesceImages()
did the trick. How to extract frames from a GIF file preserving frame dimensions
Use the -coalesce
option:
convert -coalesce brocoli.gif out%05d.pgm
Reading animated GIF in PHP
Yup. I think the ImageMagick extension should work nicely in your case. I've used it in my PHP codes before, and while I've not used GD before, ImageMagick has been sufficient for my minor image manipulation needs. =)
$agif = new Imagick("animated.gif");
// Loop over all individual frames
foreach ($agif as $frame) {
// Do whatever you need to do here
}
// Save the modified gif
$agif->writeImages("new_animated.gif", true);
The full set of functions available through the ImageMagick PHP extension can be found at http://php.net/manual/en/book.imagick.php Extract a frame from a gif using GifImage
This is a solution for version 2.X available for download from http://www.tolderlund.eu/delphi/
Gir frames can have various disposal methods set. The approach below doesn't support this but it works fine for most GIFS.
Gif := TGifImage.Create;
Gif.LoadFromFile('test.gif');
Bmp := TBitmap.Create;
Bmp.PixelFormat := pf24bit;
Bmp.Width := Gif.Width;
Bmp.Height := Gif.Height;
for i:=0 to Gif.Images.Count-1 do begin
if GIF.Images[i].Empty then Continue; //skip empty
Gif.Images[i].Bitmap.TransparentColor := Gif.Images[i].GraphicControlExtension.TransparentColor;
if i <> 0 then Gif.Images[i].Bitmap.Transparent := True;
//you should also take care of various disposal methods:
//Gif.Images[i].GraphicControlExtension.Disposal
Bmp.Canvas.Draw(0,0, Gif.Images[i].Bitmap);
Bmp.SaveToFile('out/' + IntToStr(i) + '.bmp');
end;
A different solution is to use TGIFPainter but then it won't work in a loop.Bmp: TBitmap; //global
...
Gif := TGifImage.Create;
Gif.LoadFromFile('test.gif');
Gif.DrawOptions := GIF.DrawOptions - [goLoop, goLoopContinously, goAsync];
Gif.OnAfterPaint := AfterPaintGIF;
Gif.Paint(Bmp.Canvas, Bmp.Canvas.ClipRect, GIF.DrawOptions);
...
procedure TForm1.AfterPaintGIF(Sender: TObject);
begin
if not (Sender is TGIFPainter) then Exit;
if not Assigned(Bmp) then Exit;
Bmp.Canvas.Lock;
try
Bmp.SaveToFile('out/' + IntToStr(TGIFPainter(Sender).ActiveImage) + '.bmp');
finally
Bmp.Canvas.Unlock;
end;
end;
And the solution for version 3.X is super easy: Gif := TGifImage.Create;
Gif.LoadFromFile('test.gif');
Bmp := TBitmap.Create;
Bmp.PixelFormat := pf24bit;
Bmp.Width := Gif.Width;
Bmp.Height := Gif.Height;
GR := TGIFRenderer.Create(GIF);
GR.Animate := True;
for i:=0 to Gif.Images.Count-1 do begin
if GIF.Images[i].Empty then Continue; //skip empty
GR.Draw(Bmp.Canvas, Bmp.Canvas.ClipRect);
GR.NextFrame;
Bmp.SaveToFile('out/' + IntToStr(i) + '.bmp');
end;
Related Topics
PHP Exec() Command: How to Specify Working Directory
Send Zip File to Browser/Force Direct Download
Setting Up PHPmailer with Office365 Smtp
Denormalize Nested Structure in Objects with Symfony 2 Serializer
Png Transparency Resize with Simpleimage.PHP Class
How to Split a String into an Array of Unicode Characters in PHP
How to Implement Ws-Security 1.1 in PHP5
.Htaccess Deny Access to Specific Files? More Than One
Use MySQL_Fetch_Array() with Foreach() Instead of While()
Share Variables/Memory Between All PHP Processes
How to Sort Null Values Last Using Eloquent in Laravel
MySQL Insert ....On Duplicate Update - Adds One to the Autoincrement
Regular Expression for French Characters
Are There Any PHP Docblock Parser Tools Available
PHP - Regex - How to Extract a Number with Decimal (Dot and Comma) from a String (E.G. 1,120.01)
PHP Splitting an Array into Two Arrays - Keys Array and Values Array