I have this functions that extracts frames from animated GIFs. It works with all GIFs except this one:
{ Loads a GIF. Returns a list of BMP frames }
function GetGifFrames(GifFile: string): TObjectList;
var
GIF: TGIFImage;
TempFrame: TBitmap;
Frame: TBitmap;
Counter: Integer;
GR: TGIFRenderer;
begin
{ Load GIF }
GIF := TGIFImage.Create;
TRY
TRY
Gif.Animate := FALSE;
GIF.LoadFromFile(GifFile);
EXCEPT
MesajError('Cannot load '+ GifFile);
EXIT(NIL);
END;
if Gif.Images.Count= 1 then
begin
MsgError('This is not an animated GIF'+ CRLF+ GifFile);
EXIT(NIL);
end;
Result:= TObjectList.Create;
Result.OwnsObjects:= TRUE; { Array of images }
{ GIF render }
TempFrame:= TBitmap.Create;
GR:= TGIFRenderer.Create(GIF); { GIF render }
TRY
TempFrame.SetSize(GIF.Width, GIF.Height);
for Counter:= 0 to GIF.Images.Count-1 DO
begin
{ Skip bad frames }
if GIF.Images[Counter].Empty
then Continue;
{ Create new frame }
Frame:= TBitmap.Create;
Frame.SetSize(GIF.Width, GIF.Height);
GR.Draw(TempFrame.Canvas, TempFrame.Canvas.ClipRect); <---------- AV here { Transfer image from GIF to BMP }
Frame.Assign(TempFrame);
Result.Add(Frame); { Add to list of bitmap frames }
GR.NextFrame; { Advance }
end;
FINALLY
FreeAndNil(GR);
FreeAndNil(TempFrame);
END;
FINALLY
FreeAndNil(GIF);
END;
end;
I have an AV on the line indicated above
Debugger Exception Notification Project Tester.exe raised exception class $C0000005 with message 'access violation at 0x005d3924: read of address 0x0000002c'.
Update: Compilable tester here or here.
The stack trace is:
GetGifFrames('C:\Test gif\err.gif')
GIFImg.TGIFRenderer.Draw($7EFA9070,(0, 0, 108, 146, (0, 0), (108, 146)))
GIFImg.TGIFRenderer.GetBitmap
GIFImg.TGIFRenderer.RenderFrame
Here in Render frame it crashes on this line:
PreviousBuffer.Canvas.CopyRect(PreviousBuffer.Canvas.ClipRect, Buffer.Canvas, Buffer.Canvas.ClipRect);
This is because PreviousBuffer is NIL!!!!
How to fix this?
One of the properties of a frame in a GIF file is the DisposalMethod
which defines how the image in the frame should be disposed of in preparation of the next frame. In the original file ("Sansanimated.gif" link at the top of the post) this is set to dmNoDisposal
for all 13 frames. This works as such in your code without problems. In the file "err.gif" the two frames both have dmPrevious
which require an extra internal bitmap. This bitmap is not allocated if the GIFRenderer
is not initialized as being animating.
To have the GIFRenderer properly initialized for frames with dmPrevious
disposal method setting add one line
GR.Animate := True; // <---- add this line
right after creating GR
.
User contributions licensed under CC BY-SA 3.0