js将用户上传gif动图分解成多张帧图片

写在前面

工作中遇到一个这么一个需求:这是一个多图上传的场景,如果用户上传选择多张图片,则上传后直接展示多张图片,如果上传的图片是gif动图,则需要分解这张动图拆分成一帧一帧的单张图片,再按顺序展示出来。

实现思路

这里主要针对gif分解多图的实现

  1. 首先对用户上传的文件格式进行判断;
  2. 将gif动图经过gif库解析成gif实例
  3. 遍历获取gif实例的每一帧的canvas,转换成baseURL,再转一份file对象存放起来。
  4. 通过转换后的baseURL展示到界面,用户点上传就把对应的file对象上传服务器。

这里最核心的就是2,3步,非常庆幸有https://github.com/buzzfeed/libgif-js 这个库,才得以实现后面的步骤;

代码部分

由于是公司项目就不展示界面和完整代码,只放关键代码:

0. 引入gif库

import { SuperGif } from  './libgif.js'

1. 对用户上传的文件格式进行判断

// 判断文件格式并展示的函数
pre_upload() {
// 点击上传按钮触发弹出文件选择框
const input = document.createElement('input');
input.setAttribute('type', 'file');
// 注意要设置多选属性
input.setAttribute('multiple', 'true');
input.addEventListener('change', (e) => {
this.img_list = [];
this.can_upload = true;
this.qiniu_url_list = [];
// 判断是gif格式则交给this.pre_load_gif函数处理
if (/(image\/gif)/.test(e.path[0].files[0].type)) {
this.pre_load_gif(e.path[0].files[0])
return;
} // 如果是上传多张静态的png、jpg图片则直接转换成baseURL
var img_list = [];
for(let i=0,item; item = e.path[0].files[i]; i++) {
if (!/(image\/png)|(image\/jp(e?)g)/.test(item.type)) {
alert('请上传jpg、png格式的图片')
return;
}
img_list.push({
file_name: item.name,
url: URL.createObjectURL(item),
file: item,
})
}
this.img_list = img_list
});
input.click();
},

2. 分解gif图片

dataURLtoFile(dataurl, filename) {
const arr = dataurl.split(',');
const mime = arr[0].match(/:(.*?);/)[1];
const bstr = atob(arr[1]);
var n = bstr.length;
const u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new File([u8arr], filename, {type:mime});
},
// 将canvas转换成file对象
convertCanvasToImage(canvas, filename) {
return this.dataURLtoFile(canvas.toDataURL('image/png'), filename);
},
pre_load_gif(gif_source) {
var img_list = [];
const gifImg = document.createElement('img');
// gif库需要img标签配置下面两个属性
gifImg.setAttribute('rel:animated_src', URL.createObjectURL(gif_source))
gifImg.setAttribute('rel:auto_play', '0')
// 新建gif实例
var rub = new SuperGif({ gif: gifImg } );
rub.load(() => {
var img_list = [];
for (let i=1; i <= rub.get_length(); i++) {
// 遍历gif实例的每一帧
rub.move_to(i);
// 将每一帧的canvas转换成file对象
let cur_file = this.convertCanvasToImage(rub.get_canvas(), gif_source.name.replace('.gif', '') + `-${i}`)
img_list.push({
file_name: cur_file.name,
url: URL.createObjectURL(cur_file),
file: cur_file,
})
}
this.img_list = img_list
});
},

至此,核心功能基本实现,上面的函数已经将gif分解成多张图片存放在this.img_list 这个数组里面。

接下来只要拿img_list数组里的file对象上传到服务器即可。

上传方式各不相同,这里就不放具体代码了,需要注意的是,图片上传是异步操作,多图上传需要得知所有的图片全部上传成功才能确定上传完成,所以如果上传的函数返回的是promise对象,则可以直接用Promise.all函数即可得知所有图片上传完毕的回调。

js将用户上传gif动图分解成多张帧图片的更多相关文章

  1. 用户上传gif动图分解成多张帧图片,并合并生成新gif图片

    背景 为什么要制作这么一款工具 首先公司最近在做一款表情包的产品,需要将文字生成到gif图片中,并可以控制文字显示的位置,并将不同的文字显示在不同的图片上 制作成网页端工具,随时随地,方便使用 探索 ...

  2. Django项目实战之用户上传与访问

    1 将文件保存到服务器本地 upload.html <!DOCTYPE html> <html lang="en"> <head> <me ...

  3. js实现分段上传文件

    使用js实现分段上传文件,本文使用了FileReader对象,可参考:https://developer.mozilla.org/zh-CN/docs/Web/API/FileReader 1)获取文 ...

  4. ubuntu server vsftpd 匿名用户上传下载及目录设置

    ubuntu server vsftpd 匿名用户上传下载及目录设置 1:vsftpd服务器安装: sudo apt-get install vsftpd #安装 cd /srv/ #切换到默认匿名用 ...

  5. springboot配置虚拟路径访问用户上传的附件及图片资源

    在springmvc项目中,我们通常把图片及附件存放到WEB-INF/upload类似的路径. springboot项目是通过jar包方式运行的. 笔者曾尝试以下代码,把图片转成base64格式的图片 ...

  6. JS大文件上传断点续传解决方案

    1 背景 用户本地有一份txt或者csv文件,无论是从业务数据库导出.还是其他途径获取,当需要使用蚂蚁的大数据分析工具进行数据加工.挖掘和共创应用的时候,首先要将本地文件上传至ODPS,普通的小文件通 ...

  7. js文件夹上传

    文件夹上传:从前端到后端 文件上传是 Web 开发肯定会碰到的问题,而文件夹上传则更加难缠.网上关于文件夹上传的资料多集中在前端,缺少对于后端的关注,然后讲某个后端框架文件上传的文章又不会涉及文件夹. ...

  8. JS大文件上传解决方案

    1 背景 用户本地有一份txt或者csv文件,无论是从业务数据库导出.还是其他途径获取,当需要使用蚂蚁的大数据分析工具进行数据加工.挖掘和共创应用的时候,首先要将本地文件上传至ODPS,普通的小文件通 ...

  9. vue : 检测用户上传的图片的宽高

    需求: 用户可上传3-6张图片(第 1 2 3 张必须传),上传的图片必须是540 * 330 像素. 第一步,获取上传的图片的宽高. 初始化一个对象数组,宽高均设为0. 如果用户上传的图片没有上限, ...

随机推荐

  1. sed 很棒的介绍

    选项与参数:-n :使用安静(silent)模式.在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上.但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作) ...

  2. java客户端编辑为win中可执行文件(exe4j)

    exe4j 网址: http://www.ej-technologies.com/products/exe4j/overview.html

  3. [ARC100]E:Or Plus Max(FZT)

    https://arc100.contest.atcoder.jp/tasks/arc100_c 一个很自然的想法是,对于每个K求出i or j=k的所有a[i]+a[j]的最大值ans[k],答案就 ...

  4. 【主席树】bzoj2588 Spoj 10628. Count on a tree

    每个点的主席树的root是从其父转移来的.询问的时候用U+V-LCA-FA(LCA)即可. #include<cstdio> #include<algorithm> using ...

  5. 【KM】POJ2195/HDU1533-Going home

    //最近没什么时间quq据说长得帅的人都在切八中,然而长得丑的人只能水水裸题 [题目大意] 给出一张地图及人和房屋的位置,求出每个人回到不同房屋所具有的最小代价和. [思路] 最小权匹配,先O(n^2 ...

  6. 微服务之SpringCloud实战(五):SpringCloud Eureka详解

    Eureka详解 在第三节高可用中,实际已经讲解了服务的注册,只不过注册的是Eureka本身,原理相同,通过这几篇文章我相信大家对Eureka有了一定的了解,三个核心角色:服务注册中心.服务提供者和服 ...

  7. Java高级架构师(一)第04节:Git基本原理和安装配置使用

    关于Git的常规操作---没有什么特别难点,只做截图记录.

  8. 命令行下的C++程序转换成VC的MFC程序需要注意的问题

    在将命令行下的C++程序转换成MFC窗口程序时一般会提示下面这种错误: fatal error C1010: unexpected end of file while looking for prec ...

  9. iOS 国际化最新最全教程+如何快速国际化一个现成APP

    同学面试时遇到一个问题,面试官问他,有一个现成的APP马上要上线了,怎么在不改原来代码,也不改xib.storyboard里的文字的情况下快速实现国际化.这里应同学请求写下此教程.反正国际化的步骤都要 ...

  10. oracle表空间操作语句

    1.查看所有表空间及表空间大小: select tablespace_name ,sum(bytes) / 1024 / 1024 as MB from dba_data_files group by ...