如何从此 GIF 图像中提取帧? (TGIFRenderer.Draw 中的访问冲突)
How to extract frames from this GIF image? (Access violation in TGIFRenderer.Draw)
我有这个功能可以从动画 GIF 中提取帧。它适用于除此之外的所有 GIF:
{ 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
Debugger Exception Notification Project Tester.exe raised exception
class $C0000005 with message 'access violation at 0x005d3924: read of
address 0x0000002c'.
堆栈跟踪是:
GetGifFrames('C:\Test gif\err.gif')
GIFImg.TGIFRenderer.Draw(EFA9070,(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!!!!
如何解决这个问题?
GIF 文件中帧的属性之一是 DisposalMethod
,它定义了在准备下一帧时应如何处理帧中的图像。在原始文件中(post 顶部的 "Sansanimated.gif" link),所有 13 帧都设置为 dmNoDisposal
。这在您的代码中没有问题。在文件 "err.gif" 中,两个帧都有 dmPrevious
,这需要额外的内部位图。如果 GIFRenderer
未初始化为动画,则不会分配此位图。
要使用 dmPrevious
处理方法设置为帧正确初始化 GIFRenderer 添加一行
GR.Animate := True; // <---- add this line
在创建后 GR
。
我有这个功能可以从动画 GIF 中提取帧。它适用于除此之外的所有 GIF:
{ 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
Debugger Exception Notification Project Tester.exe raised exception class $C0000005 with message 'access violation at 0x005d3924: read of address 0x0000002c'.
堆栈跟踪是:
GetGifFrames('C:\Test gif\err.gif')
GIFImg.TGIFRenderer.Draw(EFA9070,(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!!!!
如何解决这个问题?
GIF 文件中帧的属性之一是 DisposalMethod
,它定义了在准备下一帧时应如何处理帧中的图像。在原始文件中(post 顶部的 "Sansanimated.gif" link),所有 13 帧都设置为 dmNoDisposal
。这在您的代码中没有问题。在文件 "err.gif" 中,两个帧都有 dmPrevious
,这需要额外的内部位图。如果 GIFRenderer
未初始化为动画,则不会分配此位图。
要使用 dmPrevious
处理方法设置为帧正确初始化 GIFRenderer 添加一行
GR.Animate := True; // <---- add this line
在创建后 GR
。