美文网首页
javascript将用户上传gif动图分解成多张帧图片

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

作者: Yomldj | 来源:发表于2018-08-27 17:16 被阅读0次

    写在前面

    工作中遇到一个这么一个需求:这是一个多图上传的场景,如果用户上传选择多张图片,则上传后直接展示多张图片,如果上传的图片是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函数即可得知所有图片上传完毕的回调。

    相关文章

      网友评论

          本文标题:javascript将用户上传gif动图分解成多张帧图片

          本文链接:https://www.haomeiwen.com/subject/mastwftx.html