前端图片压缩与 zip 压缩

  在项目中,为了节约网络消耗,需要将文件进行压缩后上传服务端。

  最开始考虑的是将文件压缩为 zip ,由服务端返回后前端 zip 再进行解压。但 zip 对小文件、图片、视频的压缩效果很差。所以需要多种压缩方式配合使用。

  图像采用 canvas 有损压缩:

 utils.dealImage = (base64, rate) => {
    return new Promise((resolve, reject) => {
      try {
        let newImage = new Image();
        let quality = rate || rate > 1 || rate <= 0 ? rate : 0.6; //压缩系数0-1之间
        // newImage.setAttribute("crossOrigin", 'Anonymous'); //url为外域时需要
        let imgWidth, imgHeight;
        newImage.onload = function () {
          imgWidth = this.width;
          imgHeight = this.height;
          let canvas = document.createElement("canvas");
          let ctx = canvas.getContext("2d");
          canvas.width = imgWidth;
          canvas.height = imgHeight;
          ctx.clearRect(0, 0, canvas.width, canvas.height);
          ctx.drawImage(this, 0, 0, canvas.width, canvas.height);
          let base64 = canvas.toDataURL("image/jpeg", quality); //压缩语句
          resolve(base64);
        }
        newImage.src = base64;
      } catch (err) {
        reject(err);
      }
    })
  }

  其余文件采用 zip 方式无损压缩,这里使用的是 jszip :

// 文件 base64 压缩为 zip
utils.zip = (base64, fileName) => {
    let inputBlob = utils.dataURItoBlob(base64);
    let JSZip = require("jszip");
    let zip = new JSZip();
    zip.file(fileName, inputBlob, {
      type: "blob"
    });
    // return a promise
    return zip.generateAsync({
      type: "blob",
      compression: "DEFLATE", // force a compression for this file
      compressionOptions: {
        level: 9,
      },
    });
  }

  //blob to base64
  utils.blobToDataURI = (blob) => {
    return new Promise((resolve, reject) => {
      try {
        var reader = new FileReader();
        reader.readAsDataURL(blob);
        reader.onload = function (e) {
          resolve(e.target.result);
        };
      } catch (err) {
        reject(err);
      }
    });
  }

  // base64 to blob
  utils.dataURItoBlob = (dataURI) => {
    let mimeString = dataURI.split(",")[0].split(":")[1].split(";")[0]; // mime类型
    let byteString = atob(dataURI.split(",")[1]); //base64 解码
    let arrayBuffer = new ArrayBuffer(byteString.length); //创建缓冲数组
    let intArray = new Uint8Array(arrayBuffer); //创建视图
    for (let i = 0; i < byteString.length; i++) {
      intArray[i] = byteString.charCodeAt(i);
    }
    return new Blob([intArray], {
      type: mimeString,
    });
  }

  对于视频和小文件,暂时没有找到合适的压缩方式。且因为 zip 的压缩率不稳定,对于压缩后文件还需要进行二次判断大小才可上传服务端,目前测试综合压缩率在 60% 左右。

  另,因项目中,源文件也可能被客户下载,因此采用了 zip 的压缩方式方便用户解压。仅就压缩率看,snappy 与 7z 也是很好的选择。

posted @ 2021-10-22 15:54  牛有肉  阅读(707)  评论(0编辑  收藏  举报