2

How to extract frames from a gif using GifImage 2.X which does not have TGifRenderer?

This is how I try but the frames are incomplete (half empty):

 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 Bmp.Assign(Gif.Images.SubImages[i].Bitmap); Bmp.SaveToFile('out/' + IntToStr(i) + '.bmp'); end; 
12
  • Delphi's native TGIFImage does not have an Images.SubImages[] property, it should be Images.Frames[] instead, eg: Gif.Images.Frames[i].Bitmap Commented Apr 27, 2020 at 23:50
  • @Remy Version 3.X is native to new Delphis. For older Delphis there is 2.X here tolderlund.eu/delphi Commented Apr 27, 2020 at 23:52
  • You are positive that what you call half empty is not the differential image from the previous frame? Commented Apr 28, 2020 at 0:50
  • @SertacAkyuz Most likely it is a differential image but how to get a full image? Commented Apr 28, 2020 at 0:55
  • 1
    You might want to add your specific Delphi version tag to the question. Commented Apr 28, 2020 at 1:13

2 Answers 2

0

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; 
Sign up to request clarification or add additional context in comments.

Comments

0

Take a look at the LightVcl.Graph.Gif.pas in my Delphi LightSaber library (open source). It is probably what you need. Use Open, then ExtractFrame. That's pretty much it.

TYPE TGifLoader = class(TObject) private FileName: string; GIFImg : TGIFImage; Renderer: TGIFRenderer; public { Output } FrameDelay: Integer; FrameCount: Cardinal; constructor Create; destructor Destroy; override; { Utils } function Open(aFileName: string): Boolean; function SaveFrames(OutputFolder: string): Boolean; procedure SaveFrame (Frame: TBitmap; FrameNo: Integer; OutputFolder: string); function ExtractFrame(FrameNo: Cardinal): TBitmap; end; 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.