How to Extract Frames of an Animated Gif with PHP

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



Leave a reply



Submit