Search code examples
delphidelphi-7gifdelphi-2010delphi-6

Extract a frame from a gif using GifImage


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;

Solution

  • 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;