理论原因就是,苹果手机拍摄的图片,会把旋转信息存在 EXIF 里,读取这里的信息就可以旋转图片。

直接上代码

export function chooseFile(type) {
  return new Promise(function (ok) {
    const form = document.createElement('form');
    // tslint:disable-next-line
    form.innerHTML = `<input name=file type=file multiple accept="${type}" />`;
    const input: any = form.querySelector('input');
    input.onchange = function () {
      if (!input.files) { return; }
      foreachlistasync(input.files).then(
        (files) => {
          ok(files);
        }
      );
    };
    input.click();
  });
}


function foreachlistasync(filelist: FileList) {
  const Promises = Array.from(filelist).map((filepromise) => {
    return rotateImage(filepromise);
  });
  return Promise.all(Promises);
}

function rotateImage(file: File): Promise<File> {
  return new Promise((resolve, reject) => {
    // 过滤掉非 jpg的
    if (file.type === 'image/jpeg') {
      EXIF.getData(file, () => {
        const orientation = EXIF.getTag(file, 'Orientation');
        // console.log('orientation', orientation);
        changepic(file, orientation).then(
          (result: File) => {
            resolve(result);
          }
        );
      });
    } else {
      resolve(file);
    }
  });
}

function changepic(file: File, orientation: number) {
  return new Promise((resolve, reject) => {
    switch (orientation) {
      case 1:
        resolve(file);
        break;
      case undefined:
        resolve(file);
        break;
    }
    // 读取图片为 base64
    readFile(file).then(
      (base64) => {
        const form = document.createElement('form');
        form.innerHTML = `<img src="${base64}" />`;
        const img: any = form.querySelector('img');
        img.onload = () => {
          const width = img.width;
          const height = img.height;
          const canvas = document.createElement('canvas');
          canvas.height = width;
          canvas.width = height;
          const ctx = canvas.getContext('2d');
          switch (orientation) {
            case 6:
              ctx.rotate(Math.PI / 2);
              ctx.translate(0, -height);
              ctx.drawImage(img, 0, 0);
              const imageData6 = canvas.toDataURL('Image/jpeg', 0.9);
              const result6 = dataURLtoFile(imageData6, file.name);
              resolve(result6);
              break;
            case 3:
              ctx.rotate(Math.PI);
              ctx.translate(-width, -height);
              ctx.drawImage(img, 0, 0);
              const imageData3 = canvas.toDataURL('Image/jpeg', 0.9);
              const result3 = dataURLtoFile(imageData3, file.name);
              resolve(result3);
              break;
            case 8:
              ctx.rotate(-Math.PI / 2);
              ctx.translate(-height, 0);
              ctx.drawImage(img, 0, 0);
              const imageData8 = canvas.toDataURL('Image/jpeg', 0.9);
              const result8 = dataURLtoFile(imageData8, file.name);
              resolve(result8);
              break;
          }
        };
      }
    );
  });
}
function dataURLtoFile(imageData, filename) {
  // tslint:disable-next-line: one-variable-per-declaration
  const arr = imageData.split(','),
    mime = arr[0].match(/:(.*?);/)[1],
    bstr = atob(arr[1]);
  let n = bstr.length;
  const u8arr = new Uint8Array(n);
  while (n--) {
    u8arr[n] = bstr.charCodeAt(n);
  }
  return new File([u8arr], filename, { type: mime });
}

function readFile(file) {
  return new Promise((resolve, reject) => {
    const fr = new FileReader();
    fr.onload = () => {
      resolve(fr.result);
    };
    fr.readAsDataURL(file);
  });
}

发表评论