图片转换base64(压缩、方向旋转)

526 阅读1分钟

背景:

最近项目需求需要使用到base64的图片格式,需要用户手机端上传压缩处理,所以打算写一个图片选择、压缩、转换的方法(需要压缩到指定大小)。

思路:

1) 调用 FileReaderreader.readAsDataURL(img)方法, reader.readAsDataURL(file);读取图片信息。 

2) 在reader.onload的事件中,新建Image对象,并将reader.result的值赋给img.src,在img.onload中判断尺寸大小,并且根据 [ exif-js ](https://github.com/exif-js/exif-js) 判断图片角度是否需要校正

实现代码


    /**
     * 图片转换base64(压缩、方向旋转)
     * @param {blob} file文件对象
     * @param {func} callBack 成功回调函数,参数为压缩后的二进制文件流
     * @param {object} params 压缩文件参数 {可以根据 isBase64 == true 返回 base64格式, 否则返回 blob 格式内容
     */

    function imageCompression(
      file,
      callBack = () => {},
      params = {
        width: 500,
        LIMIT_SIZE: 4 * 1024 * 2014,
        isBase64: true,
      }
    ) {
      let compressCount = 0;
      const { width, LIMIT_SIZE, isBase64 } = params;
      const orientation = EXIF.getTag(file, "Orientation") || 1;
      // 图片压缩出错函数
      const errorFn = (e) => {
        console.error("图片压缩出问题了", e);
        callBack(file);
      };
      if (!window.FileReader) {
        console.error("浏览器不支持 window.FileReader 方法哦");
        callBack(file);
      } else {
        try {
          let reader = new FileReader();
          reader.readAsDataURL(file);
          reader.onload = function () {
            let img = new Image();
            img.src = reader.result;
            img.onload = function () {
              try {
                const canvas = document.createElement("canvas");
                const context = canvas.getContext("2d");
                const canvasWidth = width;
                const canvasHeight = canvasWidth / (img.width / img.height);
                canvas.width = canvasWidth;
                canvas.height = canvasHeight;
                let angle = 0;
                switch (orientation) {
                  case 1:
                    break;
                  case 6:
                    angle = (90 * Math.PI) / 180;
                    canvas.width = canvasHeight;
                    canvas.height = canvasWidth;
                    context.rotate(angle);
                    context.translate(0, -canvas.width);
                    break;
                  case 8:
                    angle = (270 * Math.PI) / 180;
                    canvas.width = canvasHeight;
                    canvas.height = canvasWidth;
                    context.rotate(angle);
                    context.translate(-canvas.height, 0);
                    break;
                  case 3:
                    angle = (180 * Math.PI) / 180;
                    canvas.width = canvasWidth;
                    canvas.height = canvasHeight;
                    context.rotate(angle);
                    context.translate(-canvas.width, -canvas.height);
                    break;
                  default:
                    break;
                }

                context.drawImage(img, 0, 0, canvasWidth, canvasHeight);
                context.setTransform(1, 0, 0, 1, 0, 0);
                canvas.toBlob(
                  (blob) => {
                    if (blob.size > LIMIT_SIZE) {
                      compressCount += 1;
                      imageCompression(blob, callBack);
                    } else {
                      compressCount = 0;
                      if (isBase64) {
                        conversion(blob, callBack);
                      } else {
                        callBack(blob);
                      }
                    }
                  },
                  "image/jpeg",
                  0.9 - compressCount * 0.1
                );
              } catch (error) {
                errorFn(error);
              }
            };
          };
          reader.onerror = (error) => {
            errorFn(error);
          };
        } catch (error) {
          errorFn(error);
        }
        // 转为base64
        function conversion(blob, callback) {
          let reader = new FileReader();
          reader.onload = function (e) {
            callback(e.target.result);
          };
          reader.readAsDataURL(blob);
        }
      }
    }

效果图

image.png

代码地址