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. 取消Gridvie中button的焦点

    Gridview中添加button,onclick方法使得 GridView的setOnItemClickListener方法无效. 解决方法: 设置Button的XML布局文件,也就是自定义的Ada ...

  2. POJ 3068 "Shortest" pair of paths(费用流)

    [题目链接] http://poj.org/problem?id=3068 [题目大意] 给出一张图,要把两个物品从起点运到终点,他们不能运同一条路过 每条路都有一定的费用,求最小费用 [题解] 题目 ...

  3. [CF418E]Tricky Password

    题意:有一个无限行$n$列的数表$a_{i,j}$,对于第$i\geq2$行,$a_{i,j}$为$a_{i-1,j}$在$a_{i-1,1\cdots j}$中出现的次数,要维护这个数表,支持修改第 ...

  4. 【spfa】bzoj1295 [SCOI2009]最长距离

    题意:给你一个n*m的点阵.有些点是障碍,求一个欧几里得距离最大的点对(A,B),使得在移走的障碍≤T的情况下,可以从A走到B. 建图,跑n*m次spfa,求出从 每个点 出发到 其他所有点 的 经过 ...

  5. 125.乘积最大(划分性DP)

    1017 乘积最大 2000年NOIP全国联赛普及组NOIP全国联赛提高组  时间限制: 1 s  空间限制: 128000 KB  题目等级 : 黄金 Gold 题解 题目描述 Descriptio ...

  6. linux+iptables搭建网关服务器

    公司购买的一批云服务器只带内网,配置了一个负载均衡器(lb),这批服务器通过lb可以对外提供服务,但是这批服务器不能主动连接外网,例如使用wget下载文件,或者curl访问ttlsa.com站点. 额 ...

  7. WPF附加属性的Set函数不调用的问题

    今天写程序的时候用到了附加属性,我是用VS内置的propa的代码段来实现的,代码如下: class Attach    {        public static bool GetIsEnabled ...

  8. TDiocpCoderTcpServer返回数据记录有条数限制的问题

    TDiocpCoderTcpServer返回数据记录有条数限制的问题 在使用TDiocpCoderTcpServer控件返回查询数据的时候,发现当记录条数超过一定数量的时候(比方有人反试图返回30万条 ...

  9. ztree jquery 树 控件

    插件地址:http://www.ztree.me 数据:[{"id":1,"pId":-1,"name":"根目录"}, ...

  10. 通过python脚本查看端口

    [root@zabbix-server alertscripts]# cat check_port1.py #!/usr/bin/env python #coding:utf-8 import os, ...