【发布时间】:2015-08-15 16:40:07
【问题描述】:
我想提取 GIF 图像的帧。下面的代码有效,但这不是我需要的。我需要将提取的帧保存在一系列位图中。
procedure TForm1.Button2Click(Sender: TObject);
var
GIF: TGIFImage;
Bitmap: TBitmap;
I: Integer;
GR: TGIFRenderer;
R: TRect;
begin
GIF := TGIFImage.Create;
TRY
GIF.LoadFromFile('c:\1.gif');
Bitmap := TBitmap.Create; <------------ one single object, reused
Bitmap.SetSize(GIF.Width, GIF.Height);
GR := TGIFRenderer.Create(GIF);
try
for I := 0 to GIF.Images.Count - 1 do
begin
GR.Draw(Bitmap.Canvas, Bitmap.Canvas.ClipRect);
Self.Canvas.Draw(0, 0, Bitmap);
GR.NextFrame;
end;
finally
GR.Free;
end;
finally
GIF.Free;
//Bitmap.Free;
end;
end;
所以我为每一帧动态地创建一个位图。但这行不通。它只会在所有位图中显示相同/第一帧!
procedure TForm1.Button2Click(Sender: TObject);
var
GIF: TGIFImage;
Bitmap: TBitmap;
I: Integer;
GR: TGIFRenderer;
R: TRect;
begin
GIF := TGIFImage.Create;
TRY
GIF.LoadFromFile('c:\1.gif');
GR := TGIFRenderer.Create(GIF);
try
for I := 0 to GIF.Images.Count - 1 do
begin
Bitmap := TBitmap.Create; <----- multiple bitmaps, one for each frame
Bitmap.SetSize(GIF.Width, GIF.Height);
GR.Draw(Bitmap.Canvas, Bitmap.Canvas.ClipRect);
Self.Canvas.Draw(0, 0, Bitmap);
GR.NextFrame;
end;
finally
GR.Free;
end;
{TODO: store bitmaps in a TObjectList for later use
List.Add(Bitmap); }
finally
GIF.Free;
end;
end;
上面的代码有什么问题?也许 TGIFRenderer 只绘制帧之间的差异?
TLama/jachguate 的更新:
TLama 说代码不起作用,因为我没有释放位图。我不想释放位图。我以后需要它们。这是一些(演示级)代码。
VAR List: TObjectList; {used and freed somwhere else}
procedure TForm1.Button2Click(Sender: TObject);
var
GIF: TGIFImage;
UniqueBMP: TBitmap;
I: Integer;
GR: TGIFRenderer;
R: TRect;
begin
List:= TObjectList.Create;
GIF := TGIFImage.Create;
TRY
GIF.LoadFromFile('c:\1.gif');
GR := TGIFRenderer.Create(GIF);
try
for I := 0 to GIF.Images.Count - 1 do
begin
UniqueBMP := TBitmap.Create;
UniqueBMP.SetSize(GIF.Width, GIF.Height);
if GIF.Images[I].Empty then Break;
GR.Draw(UniqueBMP.Canvas, UniqueBMP.Canvas.ClipRect);
Self.Canvas.Draw(0, 0, UniqueBMP);
Sleep(50);
List.Add(UniqueBMP);
GR.NextFrame;
end;
finally
GR.Free;
end;
finally
GIF.Free;
end;
end;
procedure TForm1.btnFreeClick(Sender: TObject);
begin
FreeAndNil(List);
end;
【问题讨论】:
-
我知道!请忽略它!这只是一个演示。这与我们当前的问题无关:)
-
不起作用说明什么,但我怀疑帧交错。我的猜测是渲染器完全按原样绘制帧(为什么不会,无论如何),并且由于您始终为每个帧使用一个新位图,您可以获得(视觉上)几乎空的位图,因为(视觉上)其余部分必须被渲染由底层框架。换句话说,您需要使用一个位图并让渲染器为您绘制图层。但是,这只是我的猜测。
-
@TLama - 我也这么认为,但我使用的 GIF 图像非常动画。帧之间有很多差异。我应该能够在接下来的帧中看到一些东西......
-
你能把那张图片上传到某个地方(例如 imgur.com)并附上你的问题的链接吗?除了渲染隔行扫描的帧,我找不到任何其他合理的原因,为什么这两个代码示例的结果可能不同。
-
这对我来说似乎是一个错误:TGIFRenderer 在
FCanvas严格的私有字段中缓存了对 Canvas 的引用。然后,TCustomGIFRenderer.Draw方法以:if (FCanvas <> ACanvas)开头,但是碰巧当 Bitmap 被释放时,新的 Bitmap 在相同的地址创建,然后,渲染器Reset和Initialize方法没有被调用,所以动画工作,多亏了这个错误。
标签: delphi