Webcodecs解析GIF图
Webcodecs解析GIF图
什么是GIF
GIF格式的名称是Graphics Interchange Format的缩写,是在1987年由Compu Serve公司为了填补跨平台图像格式的空白而发展起来的。GIF可以被PC和Mactiontosh等多种平台上被支持。
GIF是一种位图。位图的大致原理是:图片由许多的像素组成,每一个像素都被指定了一种颜色,这些像素综合起来就构成了图片。GIF采用的是Lempel-Zev-Welch(LZW)压缩算法,最高支持256种颜色。由于这种特性,GIF比较适用于色彩较少的图片,比如卡通造型、公司标志等等。如果碰到需要用真彩色的场合,那么GIF的表现力就有限了。GIF通常会自带一个调色板,里面存放需要用到的各种颜色。在Web运用中,图像的文件量的大小将会明显地影响到下载的速度,因此我们可以根据GIF带调色板的特性来优化调色板,减少图像使用的颜色数(有些图像用不到的颜色可以舍去),而不影响到图片的质量。
GIF格式和其他图像格式的最大区别在于,它完全是作为一种公用标准而设计的,由于Compu Serve网络的流行,许多平台都支持GIF格式。Compu Serve通过免费发行格式说明书推广GIF,但要求使用GIF文件格式的软件要包含其版权信息的说明。
在平时的开发中经常会遇到需要控制gif图暂停播放、或者控制播放次数的需求,这个看起来很正常的需求在前端实现其实不太简单,因为浏览器提供的能力只有通过 标签循环播放GIF图,如果要控制的话往往需要引入gif-decoder的库去解析gif图,在将其作为帧动画进行播放控制。
不过现在已经是2022年了,chrome在94开始提供了Webcodecs的ImageDecoder
解析GIF图,不需要借助外力了,我们可以提前熟悉起来了
什么是Webcodecs
WebCodecs API为 Web 开发人员提供了对视频流的各个帧和音频块的低级访问。它对于需要完全控制媒体处理方式的 Web 应用程序很有用。例如,视频或音频编辑器以及视频会议
许多 Web API 在内部使用媒体编解码器。例如
Web Audio API
, 和WebRTC API
。然而,这些 API 不允许开发人员处理视频流的单个帧和未混合的编码音频或视频块。Web 开发人员通常使用 WebAssembly 来绕过这个限制,并在浏览器中使用媒体编解码器。但是,这需要额外的带宽来下载浏览器中已经存在的编解码器,从而降低性能和电源效率,并增加额外的开发开销。
WebCodecs API 提供对浏览器中已有编解码器的访问。它可以访问原始视频帧、音频数据块、图像解码器、音频和视频编码器和解码器。
从上面描述可以了解到Webcodecs是提供给开发者处理音视频和图片的,可以让开发者可以直接通过浏览器api解析音视频抽出视频帧直接在canvas上显示出来。不过目前支持的音视频编码格式很有限,可以说是在实际开发场景中几乎无法使用,单单音频编码不支持AAC基本已经把大部分的主流web视频给嘎了。
不过Webcodecs提供了一个ImageDecoder
倒是很实用的,它可以解析GIF图,得到gif图的所有帧图片。
ImageDecoder
ImageDecoder接口是Webcodecs提供了一种解包和解码编码图像数据的方法
构造函数
-
创建一个新
ImageDecoder
对象。
特性
-
返回一个
boolean
指示数据是否完全缓冲的值。 -
返回一次
Promise
解析complete
为真的 a。 -
返回一个
ImageTrackList
列出可用轨道并提供选择要解码的轨道的方法的对象。
方法
-
结束所有待处理的工作并释放系统资源。
-
将控制消息排入队列以解码图像的帧。
-
重置所有状态,包括配置、控制消息队列中的控制消息以及所有挂起的回调。
使用步骤
1.获取GIF图的buffer和宽高(用设置canvas宽高)
// 获取图片宽高
const getDimensions = async blob => {
return new Promise(resolve => {
const img = document.createElement("img");
img.addEventListener("load", e => {
return resolve({ width: img.naturalWidth, height: img.naturalHeight });
});
img.src = URL.createObjectURL(blob);
});
};
// 获取gif buffer
const getGifBuffer = async (url) => {
const response = await fetch(url);
const clone = response.clone();
const blob = await response.blob();
const { width, height } = await getDimensions(blob);
canvas.width = width;
canvas.height = height;
return clone.body
}
2.实例化ImageDecoder和获取当前选中的轨道
const imageDecoder = new ImageDecoder({
data: imageByteStream,
type: 'image/gif',
});
// imageDecoder.tracks为轨道集,selectedTrack为选中轨道,可以通过track.frameCount获取GIF图总共有多少帧
const track = imageDecoder.tracks.selectedTrack;
3.获取某一帧图片并绘制
const renderImage = async (frameIndex) => {
const imageFrame = await imageDecoder.decode({frameIndex: imageIndex});
ctx.drawImage(imageFrame.image, 0, 0);
}
4.循环渲染所有帧图
const run = async (imageIndex) => {
if (imageIndex + 1 >= track.frameCount) {
imageIndex = 0;
}
await renderImage(imageIndex);
window.setTimeout(() => {
run(imageIndex + 1);
}, 50);
}
run(0)
上面是分步骤的一个实现主要是,完整的代码例子可以参考下面的地址,效果如下,我们可以做到控制gif播放速度,增加滤镜等能力