公司项目需求,播放gif动图,并且要能控制播放速度,在网上搜索了一下gif相关的库,首先搜到了libgif,这个库基于jQuery,使用起来比较麻烦,而且主要的功能是控制gif图的播放和暂停,没有逐帧播放的功能。
于是选择从文件本身入手,尝试自己解析gif图,前端可以获取gif文件的ArrayBuffer信息,然后对其进行分析,gif图的编码遵循的原则可以参考网站:What's In A GIF
解析了半天,发现太麻烦了,又去找有没有已经实现的库,找到了gifuct-js,主要功能是获取gif图的ArrayBuffer,解析出颜色、大小、图片等信息并返回一个对象。
对象结构如下(摘自官网)
{
// The color table lookup index for each pixel
pixels: [...],
// the dimensions of the gif frame (see disposal method)
dims: {
top: 0,
left: 10,
width: 100,
height: 50
},
// the time in milliseconds that this frame should be shown
delay: 50,
// the disposal method (see below)
disposalType: 1,
// an array of colors that the pixel data points to
colorTable: [...],
// An optional color index that represents transparency (see below)
transparentIndex: 33,
// Uint8ClampedArray color converted patch information for drawing
patch: [...]
}
github项目链接:GitHub - matt-way/gifuct-js: Fastest javascript .GIF decoder/parser
在项目的demo.js里面给出了一些案例,gifuct-js解析完色卡和图片之后,将图片逐帧绘制到canvas上,从而实现对gif图片的灵活操控。
代码
<template>
<div>
<canvas ref="gifNode"></canvas>
</div>
</template>
<script>
import { parseGIF, decompressFrames } from 'gifuct-js';
export default {
name: 'MyGif',
created: function () {
},
data: function () {
return {
width: 300, // 画板宽度
height: 300, // 画板高度
// 页面上的canvas的上下文
gifCanvasCtx: null,
// 用于绘制gif单张图片的画板及上下文
tempCanvas: null,
tempCanvasCtx: null,
// 用于存放正在播放的gif信息
currentGifFrames: null,
// 记录gif图播放速度
speed: 5,
// 记录正在播放的gif图的序号
count: 0,
// 用来存放图片数据信息
frameImageData: null,
// 绘制图像用的定时器
gifPlayTimer: null
};
},
mounted() {
this.init();
},
methods: {
async init() {
// 设置画板
let canvas = this.$refs.gifNode;
canvas.width = this.width;
canvas.height = this.height;
this.gifCanvasCtx = canvas.getContext('2d');
// 初始化
this.tempCanvas = document.createElement('canvas');
this.tempCanvasCtx = this.tempCanvas.getContext('2d');
// getFile用来向服务器请求文件并返回ArrayBuffer
gifFrames = await getFile('test.gif');
this.resetGifPlayer();
},
// 当修改速度的时候,重置gif播放器
resetGifPlayer(speed) {
clearInterval(this.gifPlayTimer);
this.gifPlayTimer = null;
this.gifPlayTimer = setInterval(() => {
this.drawGif(this.currentGifFrames[this.count]);
this.count++;
}, this.speed);
},
// 利用gifuct.js库逐帧绘制gif图像
drawGif(frame) {
if (!frame) {
this.count = 0;
return;
}
if (frame.disposalType === 2) {
this.gifCanvasCtx.clearRect(0, 0, this.width, this.height);
}
let dims = frame.dims;
if (!this.frameImageData || dims.width != this.frameImageData.width || dims.height != this.frameImageData.height) {
this.tempCanvas.width = dims.width
this.tempCanvas.height = dims.height
this.frameImageData = this.tempCanvasCtx.createImageData(dims.width, dims.height)
}
this.frameImageData.data.set(frame.patch)
this.tempCanvasCtx.putImageData(this.frameImageData, 0, 0)
this.gifCanvasCtx.drawImage(this.tempCanvas, dims.left, dims.top, this.width, this.height)
},
}
};
</script>
<style scoped>
</style>