本文引用开源 gif.js 库介绍使用 Javascript 在 WEB 前端实现合成 GIF 图片的示例。
原库网址:https://jnordberg.github.io/gif.js/
根据指引下载库文件后,我们得到有用的两个 js 文件,gif.js 和 gif.worker.js;准备几张材料图片用于合成测试:
gradient_1.jpg 640 * 134 px
gradient_2.jpg 640 * 311 px
gradient_3.jpg 640 * 606 px
gradient_4.jpg 640 * 905 px显然,前几张图片分别是最后一张图片的不同区域的裁切,这样我们就能测试处理不同尺寸图片的情况。
编码阶段,假设页面存在一个用于显示合成结果的 img 元素,我们需要在页面中先引用的是 gif.js,实例化语句中的 workerScript
参数指向下载的 gif.worker.js 文件,示例代码如下:
<img id="img_result_preview" />
<script src="gif.js"></script>
<script>
var gif = new GIF({
workers: 2,
quality: 1,
repeat: 0,
//width: null,
height: 905,
//background: "#00f",
//transparent: "#00f",
//dither: "Stucki-serpentine",
workerScript: "gif.worker.js"
})
gif.on('finished', gifRendered)
function gifRendered(blob) {
document.getElementById("img_result_preview").src = URL.createObjectURL(blob)
}
var img1 = new Image()
img1.src = "gradient_1.jpg"
img1.onload = imageLoaded
var img2 = new Image()
img2.src = "gradient_2.jpg"
img2.onload = imageLoaded
var img3 = new Image()
img3.src = "gradient_3.jpg"
img3.onload = imageLoaded
var img4 = new Image()
img4.src = "gradient_4.jpg"
img4.onload = imageLoaded
var counts = 0
function imageLoaded() {
counts += 1
if (counts == 4) {
gif.addFrame(img1)
gif.addFrame(img2, { delay: 1500 })
gif.addFrame(img3, { delay: 1000 })
gif.addFrame(img4, { delay: 2000 })
gif.render()
}
}
</script>
实例化 GIF 对象那块语句的其它参数请参见原库网址中的说明,这里重点介绍有点意外影响的几个属性。
quality
值越小表示输出图片的质量越高,同时处理的速度也越慢,这是影响合成速度的关键因素。
width
与 height
如果不明确指定,那么会自动取第一张添加图片帧的宽高为值,这里为高度指定了最后一张图片的高度值就是避免生成的图片只有第一张那么小。
background
参数在此例中似乎没有什么用,好像在原本就具有透明像素的材料图片中能够指定透明部分的背景颜色。
transparent
如果有值则会使图像尺寸大小不一的空白处变得透明,如果缺省,空白处将变成黑色;具体设置成什么颜色值意义不明确,好像在原本就具有透明像素的材料图片中可以设置透明部分的取样颜色值。
另外 background 和 transparent 这两个属性在添加的图片帧是画布类的数据时会有显而易见的作用,在图片帧是 Image 对象时似乎都没有什么大用。
dither
据翻译似乎指颜色抖动、混色模式之类的,此参数的值如果加上 -serpentine 后缀那么就共有 8 个可能的值,看最终的表现效果像是多了一些杂质点。
workerScript
指向 WEB worker 类型的文件对象,这是 HTML5 规范的一部分,因为这个原因可能会使你不能直接在本地通过文件访问的形式测试这个示例,现在的浏览器默认会出现跨域类型的错误,所以测试时可能需要至少在本地环回环境访问。
gif 对象的 addFrame 方法就是添加一张图片帧,delay 参数以毫秒为单位指定这一帧的持续时间,如果缺省则默认为 500 毫秒,也就是半秒钟;此方法不仅支持添加一个 Image 对象,还支持 img 元素节点,甚至是画布,具体的请参见原库网址。
最后的 render 方法就是开始处理的意思,处理完成后会进入到上面指定的回调方法中并传递 blob 类型的图片数据。
示例代码运行后最终产出的 GIF 图片是这样的:

注意事项:此文的示例中对图片的引用有些不一样,使用回调方法监测图片是否加载完成这个步骤是有很大意义的,因为 gif.js 组件不会等待图片是否已经加载完就开始处理,这样的话如果遇到引用的是网络图片且网速比较慢的情况下会造成丢帧或其它意料之外的错误。
笔者总结:即使是 quality 值已经是 1 了,最终的动图效果依然不太理想,颜色过渡并不太平滑,毕竟这其实也是 GIF 图像格式自身的短板,256 色确实比不上现代 24 位真彩色;结果图的最后一帧明显要优于另外的帧,这最后一帧才是应该达到的效果才对,但是中间两帧表现得非常差,不清楚具体原因,可能这就是这个库的不足之处;黑色部分可以通过修改 transparent 参数值使其变得透明,支持透明像素是这个库的优点之一,因为我对比了另外的好多都不支持透明;这个库的使用方法、逻辑较为直观明了,这也是优点之一;原素材 4 张图片共 125 KB 左右,合成结果图大小 67 KB 左右,虽然单帧质量有所降低,不过也同样减少了其体积。