木匣子

Web/Game/Programming/Life etc.

检测 GIF 版本的方法

之前在 角色动作练习:jumping/crouch 一文中录制的第一个跳跃 GIF 动画不知为何在浏览器中播放一次就停了下来,而其它的动画却可以正常循环。

jump.gif

GIF Versions

为此对 GIF 的历史进行了一番考查,发现 GIF 有两个版本,分区是 GIF87a 和 GIF89a 。其中 87a 是第一个 GIF 版本,于 1987 年制定。而后 89年又发布了 89a 版:

在这个版本中,为图像互换格式文档扩充了图形控制区块、备注、说明、应用程序接口等四个区块,并提供了对透明色和多帧动画的支持。
via wikipedia

也就是说由于 87a 缺少图形控制区块,可能导致动画无法正常播放。那么如何知道 GIF 图像是哪个版本的呢?

方法1: hexdump

通过 hexdump 输出 gif 文件,观察前6个字节的信息即可判断 GIF 的版本:

$ hexdump 87a.gif
0000000 47 49 46 38 37 61 5c 01 20 01 f7 00 00 00 00 00

$ hexdump 89a.gif
0000000 47 49 46 38 39 61 5c 01 20 01 77 00 00 21 ff 0b

十六进制的 47 49 46 38 37 61 转换成 ASCII 码即是 GIF87a

方法2: file

如果觉得 16 进制太酷炫,可以用 file 命令获得可读性更高的信息:

$ file 87a.gif 
87a.gif: GIF image data, version 87a, 348 x 288

$ file 89a.gif 
89a.gif: GIF image data, version 89a, 348 x 288

真是个方便的工具,还可以用它来检查未知扩展名的文件。

Convert GIF87a to GIF89a

经过鉴定,文章最开始的图像果真是个 GIF87a 。那么问题来了,挖掘机哪家强,如何才能把 GIF87a 转换成 GIF89a 呢?

这时候就要祭出神器 ImageMagick 了:

ImageMagick® is a software suite to create, edit, compose, or convert bitmap images. It can read and write images in a variety of formats (over 200) including DPX, EXR, GIF, JPEG, JPEG-2000, PDF, PNG, Postscript, SVG, and TIFF. Use ImageMagick to resize, flip, mirror, rotate, distort, shear and transform images, adjust image colors, apply various special effects, or draw text, lines, polygons, ellipses and Bézier curves.

Install ImageMagick

MAC OSX 直接通过 brew 就可以安装:

$ brew install ImageMagick

$ convert --version
Version: ImageMagick 6.8.9-5 Q16 x86_64 2014-07-25 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2014 ImageMagick Studio LLC
Features: DPC Modules
Delegates: bzlib freetype jng jpeg ltdl lzma png xml zlib

ImageMagick 提供非常强大的 CLI 命令直接编辑图片。

Convert Animation to Frames

第一步,把 gif87a 打散成序列帧:

$ convert -coalesce animation.gif frame.png

可以得到 frame-1.png frame-2.png … frame-n.png 。其中 -coalesce 参数是为了保证序列帧保持原有图像大小:

Fully define the look of each frame of an GIF animation sequence, to form a ‘film strip’ animation.

Convert Frames to Animation

第二步,重新把这些序列帧组装回 GIF:

$ convert -layers optimize -delay 6.25 frame-*.png animation.gif

-layers optimize 可以极大地优化 gif 文件的体积,每一帧只保留差异的部分,而不是整个帧;

Optimize a coalesced animation, into GIF animation using a number of general techniques. This currently a short cut to apply both the ‘optimize-frame’, and ‘optimize-transparency’ methods but may be expanded to include other optimization methods as they are developed.

-delay 6.25 指定了每帧之间间隔 62.5 毫秒;

更多关于 ImageMagick 参数的定义可以参考这里

Verify the GIF version

最后我们验证一下生成的动画是不是变成 GIF89a 了:

$ file animation.gif 
animation.gif: GIF image data, version 89a, 348 x 288

Good! 大功告成,走起!

jump_89a.gif