一、问题描述
在 h5 页面中使用 <input />
标签在 ios 端进行拍照上传图片时,图片会发生旋转。
二、原因
ios 设备拍摄的照片中包含一个方向(Orientation)信息,但在有些情况下,上传时候可能导致图像方向不正确。
Orientation 有几个值:
Orientation 值 | 旋转角度 |
---|---|
1 | 0 |
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度)
起始图是这样的:
翻转的过程
- 修改canvas的宽高
canvas.width = height;
canvas.height = width;
-
将canvas旋转90度
⚠️ 旋转过程中canvas的坐标轴也会跟着旋转
ctx.rotate(angle);
- 将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);