vue3 vant4 h5图片上传时压缩

代码如下

upload组件的 afterRead 方法:

const afterRead = async file => {
  file.status = "uploading";
  file.message = "上传中...";
  const { data } = await upLoaderImg(file.file); //使用上传的方法。file.file
  if (data) {
    file.status = "done";
    // fileList.value.push(data);
  } else {
    file.status = "failed";
    file.message = "上传失败";
  }
};

共用文件中的方法如下:

方法一 使用compressorjs

compressorjs

import Compressor from "compressorjs";

export const upLoaderImg = async (file) => {
  let _file = file;
  const maxSize = 200;
  // 先压缩 再上传
  if (file.size / 1024 > maxSize) {
    const imgFile = await compress(file);
    _file = imgFile;
  }

  // file为 你读取成功的回调文件信息
  // new 一个FormData格式的参数
  let params = new FormData();
  params.append("file", _file);

  const config = {
    headers: {
      token: getToken()
    }
  };

  return new Promise((resolve, reject) => {
    axios
      .post(`${baseURL}/upload`, params, config)
      .then(res => {
        if (res && res.data && res.status === 200) {
          //如果为真 resolve出去
          if (res.data.data) {
            resolve(res.data);
          } else {
            showFailToast(res.data.message);
            resolve(res.data);
          }
        } else {
          //否则 showFailToast 提示
          showFailToast("请求失败");
          resolve({});
        }
      })
      .catch(err => {
        console.log("err", err);
        showFailToast("请求失败");
        resolve({});
      });
  });
};

const compress = file => {
  return new Promise(resolve => {
    // compressorjs 默认开启 checkOrientation 选项
    // 会将图片修正为正确方向
    new Compressor(file, {
      quality: 0.1,
      success: resolve,
      error(err) {
        console.log(err.message);
      }
    });
  });
};

方法二

export const upLoaderImg = async (file) => {
  let _file = file;
  const maxSize = 200;
  // 先压缩 再上传
  if (file.size / 1024 > maxSize) {
    const img = await readImg(file);
    const base64Data = compress(img);
    _file = dataURLtoFile(base64Data, file.name);
  }

  // file为 你读取成功的回调文件信息
  // new 一个FormData格式的参数
  let params = new FormData();
  params.append("file", _file);

  const config = {
    headers: {
      token: getToken()
    }
  };

  return new Promise((resolve, reject) => {
    axios
      .post(`${baseURL}/upload`, params, config)
      .then(res => {
        if (res && res.data && res.status === 200) {
          //如果为真 resolve出去
          if (res.data.data) {
            resolve(res.data);
          } else {
            showFailToast(res.data.message);
            resolve(res.data);
          }
        } else {
          //否则 showFailToast 提示
          showFailToast("请求失败");
          resolve({});
        }
      })
      .catch(err => {
        console.log("err", err);
        showFailToast("请求失败");
        resolve({});
      });
  });
};

const compress = img => {
  let initSize = img.src.length;
  let width = img.width;
  let height = img.height;

  //如果图片大于四百万像素,计算压缩比并将大小压至400万以下
  let ratio;
  if ((ratio = (width * height) / 4000000) > 1) {
    ratio = Math.sqrt(ratio);
    width /= ratio;
    height /= ratio;
  } else {
    ratio = 1;
  }

  let canvas = document.createElement("canvas"),
    ctx = canvas.getContext("2d");

  let tCanvas = document.createElement("canvas"),
    tctx = tCanvas.getContext("2d");

  canvas.width = width;
  canvas.height = height;

  //  铺底色
  ctx.fillStyle = "#fff";
  ctx.fillRect(0, 0, canvas.width, canvas.height);

  //如果图片像素大于100万则使用瓦片绘制
  let count;
  if ((count = (width * height) / 1000000) > 1) {
    count = ~~(Math.sqrt(count) + 1); //计算要分成多少块瓦片

    //   计算每块瓦片的宽和高
    let nw = ~~(width / count);
    let nh = ~~(height / count);

    tCanvas.width = nw;
    tCanvas.height = nh;

    for (let i = 0; i < count; i++) {
      for (let j = 0; j < count; j++) {
        tctx.drawImage(
          img,
          i * nw * ratio,
          j * nh * ratio,
          nw * ratio,
          nh * ratio,
          0,
          0,
          nw,
          nh
        );

        ctx.drawImage(tCanvas, i * nw, j * nh, nw, nh);
      }
    }
  } else {
    ctx.drawImage(img, 0, 0, width, height);
  }

  //进行最小压缩
  let ndata = canvas.toDataURL("image/jpeg", 0.1);

  console.log("压缩前:" + initSize);
  console.log("压缩后:" + ndata.length);
  // console.log(
  //   "压缩率:" + ~~((100 * (initSize - ndata.length)) / initSize) + "%"
  // );

  tCanvas.width = tCanvas.height = canvas.width = canvas.height = 0;

  return ndata;
};

// File文件转为base64
const readImg = file => {
  return new Promise((resolve, reject) => {
    const reader = new FileReader();

    reader.onload = e => {
      // 创建一个Image对象
      const img = new Image();
      img.src = e.target.result;
      img.onload = () => {
        // 获取图片宽度和高度
        console.log(`图片宽度: ${img.width}, 图片高度: ${img.height}`);
        // return img;
        resolve(img);
      };
    };

    // 以DataURL的形式读取文件内容
    reader.readAsDataURL(file);
  });
};

//将base64转换为文件
const dataURLtoFile = (dataurl, filename) => {
  var arr = dataurl.split(","),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]),
    n = bstr.length,
    u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
};

文件转换时如果ios有兼容问题,可参考 https://www.cnblogs.com/ZerlinM/p/18168055

posted @ 2024-04-30 14:04  ZerlinM  阅读(108)  评论(0编辑  收藏  举报