“
上传时,图片发生了自动旋转/翻转,与本地显示的图片方向不一致。实际上,部分 jpg 图片属于 EXIF (可交换的图像文件格式)。EXIF 中包含一个 Orientation 参数,用来记录拍摄照片时的方向。在使用PS或者其他软件旋转图片时,图片旋转了,但 Orientation 不会改变,由于我们使用的图片预览器能够预处理图片,使其看起来与旋转后一致,但上传图片时,浏览器并不会预处理,所以导致图片旋转/翻转。这样的图片在经过 微信、QQ 等软件发送后,图像的 EXIF 信息消失,再次上传时,也不会发生旋转/翻转。
”
01
—
EXIF 介绍
1、获取 EXIF 中 Orientation 参数
* 手写算法获取 Orientation
* 引入 exif-js 插件获取 Orientation
2、Orientation 参数说明
Orientation | 说明 |
1 | 正常 |
2 | 正常镜像 |
3 | 顺时针旋转180° |
4 | 顺时针旋转180°镜像 |
5 | 顺时针旋转270°镜像 |
6 | 顺时针旋转270° |
7 | 顺时针旋转90°镜像 |
8 | 顺时针旋转90° |
3、以下说明采用方式
为了方便,采用了第三方插件的形式,移入 [exif-js](https://github.com/exif-js/exif-js) 来获取 Orientation 参数。
* 安装 exif-js
yarn add exif-js
* 引入并获取 Orientation
import EXIF from 'exif-js';let reader = new FileReader();let img = new Image();reader.readAsDataURL(file);reader.onload = function(e) { img.src = e.target.result;};img.onload = function() { let orientation; EXIF.getData(img, function() { orientation = EXIF.getTag(this, 'Orientation'); }); console.log('orientation:', orientation);}
* 判断并做矫正
Orientation 有 8 个值,分别代表不同含义,对应需要矫正的方式也不同:1 6 3 8 对应镜像 2 5 4 7
Orientation | 说明 | 矫正方式 |
1 | 正常 | 不做操作 |
2 | 正常镜像 | 水平翻转 |
3 | 顺时针旋转180° | 逆时针旋转 180、向上、右移动复原位置 |
4 | 顺时针旋转180°镜像 | 水平翻转、逆时针旋转 90、向上、右移动复原位置 |
5 | 顺时针旋转270°镜像 | 垂直翻转、顺时针旋转 90、向上平移复原位置 |
6 | 顺时针旋转270° | 顺时针旋转 90、向上平移复原位置 |
7 | 顺时针旋转90°镜像 | 垂直翻转、逆时针旋转 90、向右平移复原位置 |
8 | 顺时针旋转90° | 逆时针旋转 90、向右平移复原位置 |
* 主要代码展示
canvas.width = targetWidth;canvas.height = targetHeight;context.clearRect(0, 0, targetWidth, targetHeight); // 清除画布// 1 6 3 8 对应镜像 2 5 4 7if (orientation === 3) { context.rotate(Math.PI); // 逆时针旋转 180 context.translate(-canvas.width, -canvas.height); // 向上、右移动} else if (orientation === 4) { context.translate(canvas.width / 2, canvas.height / 2); context.scale(-1, 1); // 水平翻转 context.translate(-canvas.width / 2, -canvas.height / 2); context.rotate(Math.PI); // 逆时针旋转 180 context.translate(-canvas.width, -canvas.height); // 向上、右移动} else if (orientation === 5) { canvas.width = targetHeight; canvas.height = targetWidth; context.translate(canvas.width / 2, canvas.height / 2); context.scale(1, -1); // 垂直翻转 context.translate(-canvas.width / 2, -canvas.height / 2); context.rotate(-Math.PI / 2); // 顺时针旋转 90 context.translate(-canvas.height, 0); // 向上平移} else if (orientation === 6) { canvas.width = targetHeight; canvas.height = targetWidth; context.rotate(-Math.PI / 2); // 顺时针旋转 90 context.translate(-canvas.height, 0); // 向上平移} else if (orientation === 7) { canvas.width = targetHeight; canvas.height = targetWidth; context.translate(canvas.width / 2, canvas.height / 2); context.scale(1, -1); // 垂直翻转 context.translate(-canvas.width / 2, -canvas.height / 2); context.rotate(Math.PI / 2); // 逆时针旋转 90 context.translate(0, -canvas.width); // 向右平移} else if (orientation === 8) { canvas.width = targetHeight; canvas.height = targetWidth; context.rotate(Math.PI / 2); // 逆时针旋转 90 context.translate(0, -canvas.width); // 向右平移} else if (orientation === 2) { context.translate(canvas.width / 2, canvas.height / 2); context.scale(-1, 1); // 水平翻转 context.translate(-canvas.width / 2, -canvas.height / 2);} else {return resolve(file);}context.drawImage(img, 0, 0, targetWidth, targetHeight);
4、工具尝试
* [在线查看图片信息](http://code.ciaoca.com/javascript/exif-js/demo/upfile)* [在线编辑](https://codepen.io/movii/pen/MJzRYr/)* [图片取材](http://www.peichenhu.cn/%E5%BC%80%E6%BA%90%E9%A1%B9%E7%9B%AE/fix-image-orientation.html#%E4%BB%80%E4%B9%88%E6%98%AF%E6%95%B0%E7%A0%81%E7%85%A7%E7%89%87%E6%96%B9%E5%90%91%E9%94%99%E8%AF%AF)
02
—
巨坑
1、坑
整个过程耗费了我很长时间(晚上 + 早上),一直在纠结方向旋转、翻转、平移的问题,当我把眼前的 11 个特殊的图片试完之后,我以为成功了,准备交给测试去测一下。结果...
这种根据参数做自动旋转的方式看是否合理,但实际问题很多:操作系统、浏览器型号、浏览器版本...
不同操作系统上展示的图片方向不同,如:windows 10/mac 上展示的是旋转之后的图片,而 windows 7 上部分图片展示的是原始图像(未找到规律)
2、以 6 为例
* windows 7 Chrome 65
* windows 7 Chrome 83
* windows 7 Firefox 77
* windows 10 Chrome 65
* windows 10 Chrome 81 -> 部分图片上传与桌面展示一致,但实际url图片不会正的
* windows 10 Firefox 75
* Mac Chrome 83
* windows Chrome 80
以上内容均为个人总结,如有不对的地方欢迎指正