前言
在这次寒假比赛中遇到了许多坑,有些坑堪称奇葩,比如说下面这个比较神奇的坑:HTML5中类型为file的input元素在上传图片,展示出来后,某些手机竖拍的照片会逆时针旋转90度的问题。
概述
发现这个bug大概在一周前,因为我们这个比赛项目需要用户上传图片,并能在发布之前预览。在预览的时候发现竖着拍的照片居然都旋转了90度!于是Google之,发现基本上所有机型手机的相机都存在这个问题(我当时用于测试的手机是小米Note3 MIUI 9,期间也尝试过iPhone、iPad等机型,均发现此问题)。导致旋转90度的原因大概是HTML自动将旋转角减去了90度。
解决问题
用到的工具/库
要解决这个问题,首先需要读取照片的旋转角度(Orientation),而EXIF.JS可以读出照片的旋转角度:

我拿了一张用小米Note3的相机拍摄的照片测试,根据EXIF.JS读出的信息得出这张图片的方向角度是90度。
思路
其实用EXIF.JS读出来是一堆tags,从tags中找到Orientation的值,如果图片的方向是90度,那么Orientation的值就为6。
所以,我们只需要在拿到图片之后放进EXIF.JS里判断一下Orientation的值是否为6,如果为6,那么就将图片绘制到一个隐藏的Canvas里,再使用Canvas的rotate API进行旋转,最后再将修改好的图片输出。
步骤
- 在Webpack项目中安装EXIF.JS:
npm install exif-js --save
- 在项目中引入EXIF.JS:
import EXIF from 'exif-js'
- 读出图片旋转角:
const _this = this
EXIF.getData($IMG_SRC, () => {
if (EXIF.getAllTags($IMG_SRC).Orientation == 6) {
Utils.rotateImg($IMG_SRC, _this) //如果Orientation为6,就交给Utils中的rotateImg方法
} else {
_this.imgList.push($IMG_SRC) //如果假,就不做处理
}
})
- Utils中的图片处理方法
rotateImg: (imgSrc, vue) => {
function getObjectURL (object) {
return (window.URL) ? window.URL.createObjectURL(object) : window.webkitURL.createObjectURL(object)
}
function dataURLtoBlob (dataurl) {
var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],
bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);
while (n--) {
u8arr[n] = bstr.charCodeAt(n);
}
return new Blob([u8arr], { type: mime });
}
var canvas = document.createElement('canvas') //新建一个Canvas元素,隐藏起来,不appendChild
var context = canvas.getContext('2d')
var image = new Image() //新建一个Image对象,拿到IMG_SRC,绘制到Canvas中
var testSrc
image.src = imgSrc
image.onload = () => {
var imgRealWidth = image.width
var imgRealHeight = image.height
canvas.width = imgRealHeight
canvas.height = imgRealWidth
context.rotate(90 * Math.PI / 180) //顺时针旋转90度
context.drawImage(image, 0, -imgRealHeight)
var result = canvas.toDataURL('image/png')
var blobObj = dataURLtoBlob(result)
var file = new File([blobObj], `${Date.now()}.png`, {type: 'image/png'}) //输出修改好的图片
var pushSrc = getObjectURL(file)
testSrc = getObjectURL(file) //拿到图片的Blob URL,推到数组中
vue.imgList.push(pushSrc)
}
}
结果
经过好几天的折腾,这个问题终于被解决了,只不过处理的过程有点缓慢,容易影响用户体验。
总结
这个Bug也不知道是手机设备厂商的锅还是HTML5的锅,感觉问题比较棘手,虽然最后解决了,但是还是觉得毒性很强。🌚