前端JS实现GIF动图分解为多帧PNG并上传

作者:工具松鼠时间:2026-10-23 12:18:15浏览:83

本文介绍如何在Web项目中利用libgif-js库将GIF动图分解为多帧PNG图片。通过创建img元素并实例化SuperGif类获取每一帧的Canvas数据,再将其转换为File对象,最终实现单张图片的多帧拆分与批量上传功能,适用于头像裁剪或素材库管理等场景。

GIF分解与上传实现概述

在项目开发中,有时需要支持用户上传GIF格式的图片,并将其分解后的每一帧图片一次性展示给用户。下面直接展示相关实现代码。

要实现GIF图片的分解功能,需要依赖libgif-js这个第三方库。

第一步是引入该Git库。

引入依赖库


import SuperGif from './libgif.js'

第二步是将GIF分解为PNG图片。

GIF分解为PNG图片


const GifDecomposer = {
  structureGifObject (gifFiles, cb) { // gifFiles 获取的文件对象 e.target.files[0]
    const gifImg = document.createElement('img');
    gifImg.setAttribute('rel:animated_src', URL.createObjectURL(gifFiles));
    gifImg.setAttribute('rel:auto_play', '0');
    // Modified pictures must be added to the body
    document.body.appendChild(gifImg);
    // Construction example
    var rub = new SuperGif({ gif: gifImg });
    rub.load(() => {
      var img_list = [];
      for (let i=1; i <= rub.get_length(); i++) {
        // Traversing through each frame of a GIF instance
        rub.move_to(i);
        // Converting each frame of canvas into a file object
        let cur_file = this.convertCanvasToImage(rub.get_canvas(), gifFiles.name.replace('.gif', '') + `-${i}`)
        img_list.push({
          file_name: cur_file.name,
          url: URL.createObjectURL(cur_file),
          file: cur_file,
        })
      }
      cb(img_list)
    });
  },
  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});
  },
  convertCanvasToImage (canvas, filename) {
    return this.dataURLtoFile(canvas.toDataURL('image/png'), filename);
  }
}

第三步是上传分解后的每一张图片。

上传图片处理


/**
 * costume upload GIF decomposer
 */
 const filesImg = function (list, storage, costumeFormat, assetType, handleCostume) {
  let proDataList = list.map((item, index) => {
      return new Promise(function(resolve, reject) {
        let reader = new FileReader();
        reader.readAsArrayBuffer(item.file);
        reader.onload = () => {
          let data = {result: reader.result, type: item.file.type, name: item.file.name}
          resolve(data);
        };
        reader.onerror = (error) => {reject(error)};
      })
    })
  Promise.all(proDataList).then(res => {
    res.forEach(item => {
    // 上传
    })
  }).catch(data => {console.log(data)})
 }

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持本站。

作者最新文章