结合 element -Plus组件库,压缩图片大小,限制图片格式

业务背景:业务上需求满足上传的图片不能太大,但是有时候上传的图片确实超过了限制大小,所以前端这边可以将图片压缩再上传,
亦或者是上传给后端接口的图片只能是指定格式,我们前端需要将图片后缀转化,也可以处理!封装的使用方法如下:

使用 canvas 对图片进行压缩处理:

复制代码
/*

* 压缩图片

* param file: 接受的文件对象

* param option: 图片压缩的参数 具体可以看一下 canvas的官网介绍 :https://www.canvasapi.cn/HTMLCanvasElement/toDataURL

*/

复制代码
export function compressPic(
  file: any,
  option?: {
    maxWidth?: number;
    maxHeight?: number;
    minSize?: number;
    mimeType?: string;
    quality?: number;
  }
): any {
  const maxWidth = option?.maxWidth || 750; // 最大宽度
  const maxHeight = option?.maxHeight || 750; // 最大高度
  const minSize = option?.minSize ?? 300 * 1024; // 最小压缩文件大小 300kb
  const mimeType = option?.mimeType || "image/jpeg"; // 默认图片类型
  let qualitys: number = option?.quality || 0.8; // 默认压缩阙值0.75
  // 根据文件大小设置不同的默认压缩质量
  if (parseInt((file.size / 1024).toFixed(2)) < 1024) {
    qualitys = 0.85;
  }
  if (5 * 1024 < parseInt((file.size / 1024).toFixed(2))) {
    qualitys = 0.92;
  }

  // 如果上传的是多个文件,递归处理每个文件
  if (file[0]) {
    return Promise.all(
      Array.from(file).map((e: any) => compressPic(e, option))
    );
  } else {
    return new Promise((resolve) => {
    // 这里我注释了是因为我们没有这个需求,如果有这个需求的可以将这个注释放开就可以了
      // // 如果图片大小小于300KB,直接返回原始图片数据
      // if (file.size < minSize) {
      //   resolve({
      //     file: file,
      //   });
      // } else {
      // 创建FileReader对象,异步读取存储在客户端上的文件内容
      const reader: FileReader = new FileReader();
      // 读取操作完成时触发该事件,使用格式(必须将接收到的数据从onload发送到其他函数):reader.onload = e => {}
      reader.onload = ({ target }: ProgressEvent<FileReader>) => {
        // console.log("target----", target);

        //创建img元素
        const image = new Image() as any;
        // 图片加载完成后异步执行,当image的src发生改变,浏览器就会跑去加载这个src里的资源,这个操作是异步的。
        image.onload = async () => {
          // 创建一个新的画布元素和上下文,用于绘制压缩后的图片
          const canvas = document.createElement("canvas");
          const context = canvas.getContext("2d") as any;
          // 计算目标图片的宽度和高度,以适应最大宽度和高度的要求
          let targetWidth = image.width;
          let targetHeight = image.height;

          // 缩放图片尺寸以适应最大宽度和高度
          if (targetWidth > maxWidth || targetHeight > maxHeight) {
            const scaleFactor = Math.min(
              maxWidth / targetWidth,
              maxHeight / targetHeight
            );
            targetWidth *= scaleFactor;
            targetHeight *= scaleFactor;
          }
          // 设置画布的尺寸
          canvas.width = targetWidth;
          canvas.height = targetHeight;
          // 清空画布并在画布上绘制压缩后的图片
          context.clearRect(0, 0, targetWidth, targetHeight);
          context.drawImage(image, 0, 0, targetWidth, targetHeight);
          // 将压缩后的图片数据转换为 data URI。可以使用 type 参数其类型,默认为 PNG 格式。qualitys越小,文件体积越小
          const canvasURL = canvas.toDataURL(mimeType, qualitys);
          // 解码 data URI,获取图片的二进制数据。atob:是ascii to binary,用于将ascii码解析成binary数据,即Base64的解码过程。
          const buffer = atob(canvasURL.split(",")[1]);
          let length = buffer.length;
          //创建一个 Uint8Array 类型的向量,用于存储图片的二进制数据
          const bufferArray = new Uint8Array(new ArrayBuffer(length));
          while (length--) {
            bufferArray[length] = buffer.charCodeAt(length);
          }
          // 创建一个压缩后的文件对象
          const miniFile = new File([bufferArray], file.name, {
            type: mimeType,
          });

          // 解析压缩后的文件对象
          resolve({
            uid: file.uid,
            raw: miniFile,
            origin: file,
            beforeSrc: target?.result,
            afterSrc: canvasURL,
            beforeKB: Number((file.size / 1024).toFixed(2)),
            afterKB: Number((miniFile.size / 1024).toFixed(2)),
          });
        };
        // 设置图片的 src,触发图片加载
        image.src = target?.result;
      };
      // 读取文件内容,并在读取完成后触发 onload 事件
      reader.readAsDataURL(file);
      // }
    });
  }
}

页面使用:

1、组件中引入封装的方法

2、在页面中直接使用方法就 OK,传入一个文件对象,不传第二个值就是默认值