Bootstrap

前端项目上传图片,压缩,拍照图片旋转解决方案

1.使用input标签上传
capture = 'user' 调用前置摄像头, 'environment' 调用后置摄像头
2.获取上传的数据

$refs!: {
  imgFile: any;
};

const file = e.target.files[0];
const rFilter = /\.(png|jpg|gif|jpeg|webp)$/; // 检查图片格式

if (!rFilter.test(file.type)) {
  alert('请上传图片');
  this.$refs.imgFile.value = '';
  return false
}
3.使用FileReader 对象读取文件类型
/**
 * 获取文件数据
 */
enum Type {
    readAsArrayBuffer = 'readAsArrayBuffer',
    readAsDataURL = 'readAsDataURL',
}
const getFileData = (file: Blob | object, type?: string): Promise => {
    return new Promise((resolve, reject) => {
        const fileReader: any = new FileReader();
        switch (type) {
            case Type.readAsArrayBuffer:
                fileReader.readAsArrayBuffer(file);
                break;
            case Type.readAsDataURL:
                fileReader.readAsDataURL(file);
                break;
            default:
                fileReader.readAsArrayBuffer(file);
                break;
        }

        return fileReader.addEventListener('load', () => {
            return resolve(fileReader.result);
        });
    });
};
4.使用FormData 对象上传文件
const formDate = new FormData()
formDate.append(name, value, filename)
5.上传文件
 // 设置上传内容格式
 headers: {
    'Content-Type': 'multipart/form-data'
  }
// axios 使用onUploadProgress监听上传进度
6.移动端拍照旋转的问题(几年没更新,用苹果7测试没发现任何问题,返回6图片显示也是正常的,上传到服务器也是正常的,本地node测试)
// 返回方向
EXIF.getData(file, function() {
  EXIF.getAllTags(this)
  return EXIF.getTag(this, 'Orientation')
})

2.使用本地代码解决

const getOrientation = (buffer) => {
    const view = new DataView(buffer);
    if (view.getUint16(0, false) !== 0xFFD8) { return -2; }
    const length = view.byteLength;
    let offset = 2;
    while (offset < length) {
        const marker = view.getUint16(offset, false);
        offset += 2;
        if (marker === 0xFFE1) {
            if (view.getUint32(offset += 2, false) !== 0x45786966) { return -1; }
            const little = view.getUint16(offset += 6, false) === 0x4949;
            offset += view.getUint32(offset + 4, little);
            const tags = view.getUint16(offset, little);
            offset += 2;
            for (let i = 0; i < tags; i++) {
                if (view.getUint16(offset + i * 12, little) === 0x0112) {
                    return view.getUint16(offset + i * 12 + 8, little);
                }
            }
            // tslint:disable-next-line: no-bitwise
        } else if ((marker & 0xFF00) !== 0xFF00) { break; } else { offset += view.getUint16(offset, false); }
    }
    return -1;
};

// 转换成Buffer
const dataURItoBuffer = (dataURI) => {
    const byteString = atob(dataURI.split(',')[1]);
    const buffer = new ArrayBuffer(byteString.length);
    const view = new Uint8Array(buffer);
    for (let i = 0; i < byteString.length; i++) {
        view[i] = byteString.charCodeAt(i);
    }
    return buffer;
};
7.初始化画布大小
  initCanvas(Mw: number, Mh: number, img: any) {
    const canvas = document.createElement("canvas");
    const ctx = canvas.getContext("2d");
    document.body.append(canvas);
    // 配置画布最大大小
    const maxW: number = Mw;
    const maxH: number = Mh;
    let w: number = img.width;
    let h: number = img.height;

    if (w < h && h > maxH) {
      w = parseInt((maxH * img.width) / img.height);
      h = maxH;
    } else if (w >= h && w > maxW) {
      h = parseInt((maxW * img.height) / img.width);
      w = maxW;
    }

    canvas.width = w;
    canvas.height = h;
    console.log(canvas, w, h, img.width, img.height);
  }

8.使用canvas处理方向
// http://stackoverflow.com/questions/19463126/how-to-draw-photo-with-correct-orientation-in-canvas-after-capture-photo-by-usin
function orientationHelper(canvas, ctx, orientation) {
  const w = canvas.width,
        h = canvas.height;
  if (orientation > 4) {
    canvas.width = h;
    canvas.height = w;
  }
  switch (orientation) {
    case 3:
      ctx.translate(w, h);
      ctx.rotate(Math.PI);
      break;
    case 6:
      ctx.rotate(0.5 * Math.PI);
      ctx.translate(0, -h);
      break;
    case 8:
      ctx.rotate(-0.5 * Math.PI);
      ctx.translate(-w, 0);
      break;
  }
}
9.导出画布
// canvas的toDataURL是只能压缩jpg,png图片的透明性质在canvas中是无效的,(win10有透明元素,苹果7,默认就没有)
ctx.drawImage(img, 0, 0, w, h);
const dataURL = canvas.toDataURL('image/jpeg', quality);
10.图片压缩处理完成后转为blob格式
const convertBase64UrlToBlob = (a) => {
    const arr = a.split(',');
    const mime = arr[0].match(/:(.*?);/)[1];
    const bstr = atob(arr[1]);
    let n = bstr.length;
    const u8arr = new Uint8Array(n);
    while (n--) {
        u8arr[n] = bstr.charCodeAt(n);
    }
    return new Blob([u8arr], { type: mime });
};
11.配置axios,上传文件防止序列化
    transformRequest: [function (data, headers) {
        if (headers['Content-Type'] === 'multipart/form-data;charset=UTF-8') {
            return data;
        }
        // 对 data 进行任意转换处理
        return Qs.stringify(data);
    }],
12.触发事件
  async changeFile(e: any) {
    const file = e.target.files[0];
    const rFilter = /(png|jpg|gif|jpeg|webp)$/; // 检查图片格式

    if (!rFilter.test(file.type)) {
      alert('请上传图片');
      this.$refs.imgFile.value = '';
    } else {
      const url = await getFileData(file);
      this.imgSrc = url;
      const Orientation = getOrientation(dataURItoBuffer(url));
      console.log(Orientation, '方向00');

      const img = new Image();
      img.src = url;
      img.onload = () => {
        this.initCanvas(1000, 1000, img, Orientation);
      };
    }
  }