如何从这个GIF图像中提取帧? (TGIFRenderer.Draw中的访问冲突)

时间:2016-04-06 07:15:48

标签: delphi graphics gif delphi-xe7

我有这个功能,可以从动画GIF中提取帧。它适用于除此之外的所有GIF:enter image description here

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

我在上面指定的行上有一个AV

  

调试器异常通知项目Tester.exe引发异常   类$ C0000005,消息'访问冲突在0x005d3924:读取   地址0x0000002c'。

更新:    可编译的测试人员herehere

堆栈跟踪是:

   GetGifFrames('C:\Test gif\err.gif')
   GIFImg.TGIFRenderer.Draw($7EFA9070,(0, 0, 108, 146, (0, 0), (108, 146)))
   GIFImg.TGIFRenderer.GetBitmap
   GIFImg.TGIFRenderer.RenderFrame

此处在渲染帧中,它在此行崩溃:

PreviousBuffer.Canvas.CopyRect(PreviousBuffer.Canvas.ClipRect, Buffer.Canvas, Buffer.Canvas.ClipRect);

这是因为 PreviousBuffer为NIL !!!!

如何解决这个问题?

1 个答案:

答案 0 :(得分:2)

GIF文件中帧的一个属性是DisposalMethod,它定义了如何处理帧中的图像以准备下一帧。在原始文件中(&#34; Sansanimated.gif&#34;帖子顶部的链接),对于所有13个帧,这被设置为dmNoDisposal。这在您的代码中可以正常工作而没有问题。在文件&#34; err.gif&#34;这两个帧都有dmPrevious,需要额外的内部位图。如果GIFRenderer未初始化为动画,则不会分配此位图。

为具有dmPrevious处置方法设置的帧正确初始化GIFRenderer添加一行

GR.Animate := True;  // <---- add this line
创建GR后立即