解决 input 标签在IOS上传图片翻转问题

1,193 阅读2分钟

一、问题描述

在 h5 页面中使用 <input /> 标签在 ios 端进行拍照上传图片时,图片会发生旋转。

二、原因

ios 设备拍摄的照片中包含一个方向(Orientation)信息,但在有些情况下,上传时候可能导致图像方向不正确。

Orientation 有几个值:

Orientation 值旋转角度
10
2左右翻转
3顺时针180度
4上下翻转
5顺时针翻转90度后,左右翻转
6顺时针90度
7逆时针翻转90度后,左右翻转
8逆时针90度

三、解决步骤

首先,我们先将 input 标签设置为type='file',允许用户选择照片,并获取图片的大小信息。

<input
  type="file"
  accept="image/*"
  onChange={e => this.fileUpLoad(e)}
/>
function loadImageSize(url) {
  return new Promise(resolve => {
    const img = new Image();
    img.src = url;
    img.onload = () => {
      const width = img.width;
      const height = img.height;
      const size = { width, height };
      resolve(size);
    };
  });
}

然后,我们添加旋转按钮,由用户操作决定使用哪种角度的图片(每次操作旋转90度)

起始图是这样的:

翻转的过程

  1. 修改canvas的宽高

canvas.width = height;
canvas.height = width;
  1. 将canvas旋转90度

    ⚠️ 旋转过程中canvas的坐标轴也会跟着旋转

ctx.rotate(angle);
  1. 将canvas移动到可视区

ctx.drawImage(img, 0, -height);

此外,我们还可以自动根据图像EXIF信息中的相机拍摄角度(Orientation),再旋转回来

使用 exif-js 库来获取Orientation信息,再根据 Orientation 的值处理旋转图片的角度。

  • 优点:无需用户操作,一气呵成,无论是什么角度的照片,都能给旋转回来

  • 缺点:开发人员需要获取图像的EXIF信息

四、扩展

旋转180度

canvas.width = width;
canvas.height = height;
ctx.rotate(angle);
ctx.drawImage(img, -width, -height);

旋转270度

canvas.width = height;
canvas.height = width;
ctx.rotate(angle);
ctx.drawImage(img, -width, 0);

旋转90度以内的(以30度为例)

const x = height * Math.sin(angle) * Math.cos(angle);
const y = height * Math.sin(angle) * Math.sin(angle);
canvas.width = height * Math.sin(angle) + width * Math.cos(angle);
canvas.height = height * Math.cos(angle) + width * Math.sin(angle);
ctx.rotate(angle);
ctx.drawImage(img, x, -y);

代码请看这里👉