视频转GIF动图实践, 支持长视频转GIF

背景

找了很多GIF动图制作的工具,比如将视频转成GIF, 或者将一系列图片转成GIF, 增加背景文案等等功能。很多收费或者用的一些三方库有点点卡顿,或者需要安装一个软件,所以就自己做一款纯前端页面级别的 视频转 GIF 动图工具。

最开始找到一款可使用的库 gifshot, 该库最后一个版本在 2017 年(这篇文档记录截止查看的时间)。该包提供了示例, 其实支持的功能还挺多的,如下:

  1. 可以指定图片链接生成 GIF
  2. 可以上传视频生成 GIF
  3. 一边录制视频生成 GIF

不过也有一些缺点,查看源码可知,内部实现的时候,是在 omggif 库的基础上, 使用 canvas 对视频流进行截取, 然后通过 getImageData 获取图片资源, 再次进行视图转化后 交给 omggif 一张张图片追加上去 (当然源码中将 omggif 库部分代码直接拷贝下来的), 最终通过生成 base64格式的 GIF 资源。

gifshot 使用过程中遇到的自己感觉体验不好的点

  1. 该包可能很多年没有更新维护了, 内部做了很多兼容性处理, 最后一步生成的 base64 如果 GIF 图片较大这个还是挺大的, 可以使用别的方法可能更佳, 不需要各种数据格式转化
  2. 有点点卡顿, 该库的生成流程是,根据视频流或者给出的图片列表, 首先使用 canvas 绘制得到图片数据, 然后开启多个 worker 线程 将图片数据转成 omggif 支持的视图数据格式。到这一步可能不会卡, 且有进度提示。不过从源码中能看到, AnimatedGIF 构造函数中 generateGIF 方法使用 omggif 写入每一张图片数据时, 没有做任务调度, 一次性全部写入, 如果稍微长点的视频, 有个三五百张图片, 这一步会导致页面短暂卡顿无法交互
  3. 假如想自己根据 canvas 截取的图片资源来生成 GIF, 只能调用canvas的toDataURL生成图片资源列表传进去, 内部还会走一遍 canvas 截取过程, 这样自定义的情况稍微较慢了
  4. 功能揉合在一个包中, 其实很强大。 不过如果想要分开使用某些功能, 比如想自定义截取(包括从视频流, 图片集), 然后只提供处理 canvas 生成的 Uint8ClampedArray 图片数据的功能, 这样就是一个纯 js 功能, 不包括 window, canvas等元素的引用, 能全部在 worker 中使用处理了

鉴于上述的一些情况, 所以就基于 omggif 库, 参考 gifshot 库(其中多线程生成图片特征很不错), 在项目中做一款纯 js 的专门处理 canvas 调用 getImageData 方法得到的数据的工具类了, 其他的功能比如 截取视频流, 截取图片列表等等, 来源根据各自的使用场景自定义。该工具类只处理 ImageData 资源。

自定义GIF图片生成

鉴于上述, 基于omggif自定义一个生成GIF的功能模块,实际上,将该库部分功能截取下来了。自定义GIF生成主要分如下两个部分功能

  1. 纯 js 处理 ImageData 图片资源工具, 比如定义名称 gif-tool(仅在该文中称呼), 只提供底层功能, 处理数据
  2. 基于该 js 工具做的跟 DOM 相关的组件功能,可以定义一系列参数。根据各种来源生成待处理的特征

gif-tool 可以完全在 woker 中运行, 这样就能将整个 图片资源转化和图片生成 GIF 放在独立线程处理了。不过此处图片特征处理比较耗时, 且可以不按顺序处理, 将这个流程交与子线程处理就好了, 其他的进行任务调度。

图片资源特征抽取比较耗时间, 并且与顺序无关, 参考 gifshot 的方式, 开多个线程处理。生成的图片特征生成GIF, 不能遍历直接生成, 通过任务调度的方式来生成, 以免造成页面卡顿, 且每完成一张就可以将进度显示在页面, 优化体验效果。

方案选取,主要有两种方式

  1. 一次截取全部图片数量, 然后全部处理完交给下一个步骤,问题是占用内存大, 但图片数量有个总览, 且图片不是太多时也不会出现大问题。
  2. 批量处理, 生成一批, 处理一批, 处理完后回删,这样就不用一次性处理很多图片, 内存占用上会好很多。

因为生成的GIF也不宜过大,且可以支持截取对应的视频区间以及长视频模式处理,所以直接一次性生成,没有分批处理。不过实际工作项目中肯定需要做demo进行对比。

所以选取的整体流程是 截取屏幕瞬间 -> 生成图片数据列表 -> 处理图片特征 -> 增加每一张图片为 GIF 播放瞬间以及停留时间设置 -> 生成供下载的GIF链接

页面信息显示大概如下, 截取图片的数量, 通过帧率来设置截取频率, 展示频率默认一帧等等。支持大时长视频生成GIF预览, 也就是长视频模式。

交互体验

生成的时候可以明确的看到各个阶段的进度,以及每次设置之后预估的截取数量,如果想截取视频中某一段或者某个范围,可以对时间和区域进行裁剪,效果如下:

其他优化: 目前只做简单的提示,比如多少张可能会卡,实际上可以做更详细的优化,比如预计截取多少张图片会导致卡顿, 预计会截取多少资源到内存等等,从而提示截取帧数是否需要修改。

其他一些小功能点设想

因为可以完全自定义绘制部分, 所以想要追加啥东西都可以, 最终给 gif-tool 工具处理图片资源即可。

  • 各种文字特效, 比如出现时机和消失的时机
  • 插入小图标且做播放动效
  • 播放/停止视频, 快进到某个节点等各种方式的生成
  • 在某个时间段展示一些自定义的内容
  • ...... 等等一系列的小功能点, 比较简单只不过要花时间测试和调试

因为暂时没有用到, 所以就没做了,方案详细记录

最后在线免费体验地址www.nqone.com/gif,如果想要将某些录取的视频操作生成GIF可以试试哦,大致效果如下:

相关推荐
FØund404几秒前
antd form.setFieldsValue问题总结
前端·react.js·typescript·html
Backstroke fish1 分钟前
Token刷新机制
前端·javascript·vue.js·typescript·vue
zwjapple1 分钟前
typescript里面正则的使用
开发语言·javascript·正则表达式
小五Five2 分钟前
TypeScript项目中Axios的封装
开发语言·前端·javascript
小曲程序2 分钟前
vue3 封装request请求
java·前端·typescript·vue
临枫5413 分钟前
Nuxt3封装网络请求 useFetch & $fetch
前端·javascript·vue.js·typescript
酷酷的威朗普4 分钟前
医院绩效考核系统
javascript·css·vue.js·typescript·node.js·echarts·html5
前端每日三省4 分钟前
面试题-TS(八):什么是装饰器(decorators)?如何在 TypeScript 中使用它们?
开发语言·前端·javascript
小刺猬_9854 分钟前
(超详细)数组方法 ——— splice( )
前端·javascript·typescript
契机再现5 分钟前
babel与AST
javascript·webpack·typescript