8

使用ImageDecoder API让GIF图片暂停播放

 1 year ago
source link: https://www.zhangxinxu.com/wordpress/2023/05/js-imagedecoder-api-gif/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

by zhangxinxu from https://www.zhangxinxu.com/wordpress/?p=10830 鑫空间-鑫生活
本文欢迎分享与聚合,全文转载就不必了,尊重版权,圈子就这么大,若急用可以联系授权。

占位图,头图,封面图

一、回顾历史

2015年的时候,我曾研究并撰写过一篇文章,“CSS或JS实现gif动态图片的停止与播放”,其中展示了各种技术实现 GIF 动图的播放控制。

并在20年和21年陆续更新了使用libgif.js暂停gif,和使用 apng-js 暂停APNG。

规范迭代,技术发展。

时间来到了2023年,对于GIF动态的播放与暂停,又有了新的技术实现,就是借助浏览器原生的API。

由于原生API,所以实现要更加简单。

铺垫了那么多,该主角出场了。

这个API就是ImageDecoder,属于 WebCodecs API中的一个细分API,提供了对GIF图片的每一帧进行处理的能力。

下面就简单介绍下如何使用这个API解析GIF,并控制其暂停。

二、解析GIF并暂停播放

GIF本质上和视频一样,都是一帧一帧的图片拼合而成,所以,暂停GIF功能实现的要点,就是获取具体某一帧的资源。

所以,事情其实很简单。

  1. 使用ImageDecoder API解析GIF每一帧的图像资源;
  2. 将该图像资源绘制在canvas画布上。

1. 资源获取

使用fetch方法即可。

fetch("by-zhangxinxu.gif").then((response) => {
    // response.body 就是图像资源数据
});

这里,如果GIF图像跨域,则有可能会获取失败。

下面轮到ImageDecoder出马了,我们可以利用上面返回的图像资源数据构造一个 imageDecoder 对象,例如:

const imageDecoder = new ImageDecoder({ 
    data: response.body, 
    type: "image/gif" 
});

此时,imageDecoder对象就包含了一系列的属性和方法,用来对解析好的图像数据进行各种各样的处理。

例如,我们希望获取GIF第一帧的图形数据,则可以:

imageDecoder.decode({ 
    frameIndex: 1
}).then((result) => {
    // result 对象就是解析后的结果
});

这里的 result 对象包括下面这些属性:

{
    // 解码的图像
    image: VideoFrame,
    // 如果为true,则表示该图像包含最终的完整细节输出。
    complete: boolean
}

在本场景中,我们需要的是 result.image,此值可以作为 ImageSource 绘制在 canvas 画布上。

创建一个 canvas,尺寸设置为和原始的GIF图像一致,然后就可以绘制了。

const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");

context.drawImage(result.image, 0, 0);

此时,画布上就有第一帧的GIF图像了。

接下来的事情就很简单了,根据每一帧的时间间隔,绘制下一帧即可。

result.image 的返回值是一个 VideoFrame 对象,包含很多属性和方法,例如,帧图像的编码尺寸,显示尺寸,时间戳,时间间隔等,具体见文档

其中,result.image.duration 就是每一帧的时间间隔,单位是毫秒,我们就可以基于此值,外加 setTimeout 定时器,在canvas上模拟出完整的GIF绘制啦。

setTimeout(() => {
    // 绘制下一帧的 result.image
}, result.image.duration / 1000.0);

极简demo示意

为了方便大家的理解和学习,我做了个非常简易的演示页面。

您可以狠狠地点击这里:GIF解析并点击暂停/播放demo

源代码直接右键查看即可。

在Chrome浏览器下,点击“苏檀儿”,就可以看到其动作暂停了。

如下图示意:

demo演示示意

三、封装与开源

为了便于大家控制GIf的播放与暂停,我将上面的那套实现封装成了更加方便调用的小组件,并且在gitee上开源了。

访问访问项目点击这里:https://gitee.com/zhangxinxu/gif-pause

PS:欢迎关注我的gitee账号,不定期更新一些小玩具。

对应的JS资源在src目录中。

截图示意
  1. 引入对应的 JS 文件,例如:
<script src="./src/renderGif.js"></script>
  1. 对应的GIF图像元素进行调用:
renderGif(eleImage);

就可以实现点击GIF暂停播放的效果了。

当然,也支持在外部手动触发GIF的播放与暂停。使用示意:

const player = renderGif(eleImage, {
  bindEvent: false
});

// 点击按钮,GIF暂停播放
button.onclick = function () {
  player.pause();
}

眼见为实,您可以用力戳这里访问:https://zhangxinxu.gitee.io/gif-pause/

例如,点击“暂停”按钮,康娜的高能炮就停止发射了。

GIf外部暂停示意

语法和参数

const player = renderGif(data, options);

data

data 参数可缺省,如果不设置,表示获取当前页面中所有以 ‘.gif’ 为后缀的 IMG 元素并进行处理。

data 参数可以是字符串,表示对应元素选择器;可以是DOM对象;也可以是 NodeList 对象,或者 HTMLCollection、HTMLAllCollection 对象。

options

options 是可选参数,目前仅支持一个属性值。

{
    bindEvent: true
}

表示是否给GIF图片绑定点击暂停行为,如果设置 bindEvent 为 false,可以使用返回值 player 对GIF的播放和暂停进行手动控制。

player 返回值包含了以下属性和方法:

{   
    // 当前 GIF 图像元素对象
    element: null,
    // GIF 是否暂停中,只读
    paused: false,
    // 继续播放
    play: function () {},
    // 暂停播放
    pause: function () {},
    // 当前帧,只读
    frameIndex: -1
}

四、ImageDecoder API简介

顺便简单介绍下ImageDecoder的各个属性和方法。

ImageDecoder() 创建一个新的ImageDecoder对象。 ImageDecoder.complete 返回一个布尔值,表示编码的数据是否已经完全缓冲。 ImageDecoder.completed 返回一个Promise,当complete为true的时候,会立即触发resolves。 ImageDecoder.tracks 返回一个ImageTrackList对象,该对象列出了可用轨道,并提供了可以解码轨道数据的方法。 ImageDecoder.type 返回一个字符串,表示在使用new构造时候配置的MIME类型。 ImageDecoder.isTypeSupported() 指示是否支持提供的MIME类型进行编解码。 ImageDecoder.close() 结束所有挂起的工作并释放系统资源。 ImageDecoder.decode() 对图像的帧进行解码。 ImageDecoder.reset() 中止所有进行中的的decode()操作。

各个属性或方法更深入的使用,可以访问MDN文档进行了解。

目前ImageDecoder仅Chrome浏览器支持,因此,本文出现的几个demo页面也只有在Chrome浏览器下访问才有效果。

ImageDecoder的兼容性表

五、总结及新书抽奖

除了GIF解析,Web现在还可以解析视频和音频,甚至合成音频。

下一个分享,我就会尝试利用Web已有API,让图片序列合成为视频。

OK,说点其他的。

《CSS选择器世界 第2版》已经京东上架了,购买链接点击这里

CSS选择器世界 第2版

另外,现在再B站有个抽奖活动,只要在下面的视频(点击图片即可访问)下方评论,就有就会获得《CSS选择器世界 第2版》签字版。

B站视频截图

祝大家好运!

😋😋😋

(本篇完)1f44d.svg 是不是学到了很多?可以分享到微信
1f44a.svg 有话要说?点击这里


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK