一些GIF查看器的Delphi TGIFImage动画问题

时间:2014-08-24 20:48:42

标签: delphi animation gif animated-gif tgifimage

我发现使用Delphi 2009 TGIFImage创建的动画GIF有时在某些 GIF查看器中无法正常播放。问题是动画过早重启。

考虑以下示例:

program GIFAnomaly;

{$APPTYPE CONSOLE}

uses
  Windows, Types, Classes, SysUtils, Graphics, GIFImg;

var
  g: TGIFImage;
  bm: TBitmap;

procedure MakeFrame(n: integer);
var
  x: Integer;
  y: Integer;
begin
  for x := 0 to 256 - 1 do
    for y := 0 to 256 - 1 do
      bm.Canvas.Pixels[x, y] := RGB((x + n) mod 255,
        (x + y - 2*n) mod 255, (x*y*n div 500) mod 255);
end;

var
  i: integer;

begin

  bm := TBitmap.Create;
  bm.SetSize(256, 256);

  g := TGIFImage.Create;
  g.Animate := true;
  for i := 0 to 499 do
  begin
    MakeFrame(i);
    TGIFGraphicControlExtension.Create(g.Add(bm)).Delay := 3;
    Writeln('Creating frame ', i+1, ' of 500.');
  end;
  TGIFAppExtNSLoop.Create(g.Images.Frames[0]).Loops := 0;

  g.SaveToFile('C:\Users\Andreas Rejbrand\Desktop\test.gif');


end.

(这是我能找到的解决问题的最简单的例子。)

输出是一个相当大的动画GIF。在Internet Explorer 11中,整个15秒的电影'播放正常,但在谷歌浏览器中的电影'只需大约四秒钟就会过早重启。

为什么会这样?

  1. 输出GIF文件有问题吗?
  2. 如果是,我上面的代码是否有问题,或GIFImg是否有问题?
  3. 如果没有,观众中问题的本质是什么?有多少可用的观众有这个问题?有没有办法避免'在创建GIF期间出现此问题?
  4. 为了SO用户的利益,上面的代码是一个最小的工作示例。当然,当我发现这个问题时,我并没有创造出这些迷幻图案。相反,我正在研究一个Lorenz系统模拟器,并制作了这个GIF动画,它可以在IE中播放但不在Chrome中播放:

    Sample GIF animation displaying the issue http://privat.rejbrand.se/lorenz50.gif

    在Internet Explorer 11中,模型在重新启动动画之前旋转360度。在谷歌浏览器中,动画仅在大约20度后过早重启。

    • Lorenz图像工作在Internet Explorer 11.0.9600.17239,GIMP 2.8.0,Opera 12.16中
    • Lorenz图片在Google Chrome 36.0.1985.143 m,Firefox 26.0,27.0.1,31.0中无效

    如果我打开一个有问题的' GIMP中的GIF让GIMP(重新)将其保存为动画GIF,结果适用于每个观众。以下是Lorenz动画的GIMPed版本:

    Sample GIF animation that has been GIMPed http://privat.rejbrand.se/lorenz50_GIMPed.gif

    使用十六进制编辑器比较两个文件,并使用the Wikipedia article作为参考,例如,似乎' NETSCAPE' string在原始(unGIMPed)版本中的位置错误。有点奇怪,即使我设置了GIF图像的widthheight,逻辑屏幕描述符中的相应值也不存在。

2 个答案:

答案 0 :(得分:6)

这是TGIFImage的LZW编码器中的一个错误。

在极少数情况下,LZW编码器会在LZW蒸汽结束时输出一个额外的零字节。由于LZW结束块标记也是零字节,严格的GIF阅读器可能会对此进行阻塞或将其解释为GIF的结尾(尽管文件结束标记为$ 3B)。

一些GIF读者能够解决这个问题的原因可能是多年前有这个问题的GIF很常见。显然,TGIFImage不是唯一能够犯这个错误的库。

要解决此问题,请对gifimg.pas进行以下修改(更改标有 * ):

procedure TGIFWriter.FlushBuffer;
begin
  if (FNeedsFlush) then
  begin
    FBuffer[0] := Byte(FBufferCount-1); // Block size excluding the count
    Stream.WriteBuffer(FBuffer, FBufferCount);
    FBufferCount := 1; // Reserve first byte of buffer for length
    FNeedsFlush := False; // *** Add this ***
  end;
end;

答案 1 :(得分:1)

编辑:事实证明这不是答案,但我保留了它,因为关于循环扩展的规则仍然适用。


NETSCAPE循环扩展必须是第一个扩展名:

var
  Frame: TGIFFrame;
...
for i := 0 to 499 do
begin
  MakeFrame(i);
  Frame := g.Add(bm);
  if (i = 0) then
    TGIFAppExtNSLoop.Create(Frame).Loops := 0;
  TGIFGraphicControlExtension.Create(Frame).Delay := 3;
  Writeln('Creating frame ', i+1, ' of 500.');
end;

请参阅:The TGIFImage FAQ

除此之外,我认为您的GIF没有任何问题,但您可以使用全局颜色表稍微减小尺寸。