问题背景:
在移动端使用html5 + canvas进行图片上传时,ios手机竖拍照片时会发生旋转,横拍无此问题,android无此类问题,所以我们希望获取到照片拍摄的方向角,进行旋转修复。
EXIF(Exchangeable Image File)是“可交换图像文件”的缩写,Exif.js 提供了 JavaScript 读取图像的原始数据的功能扩展,例如:拍照方向、相机设备型号、拍摄时间、ISO 感光度、GPS 地理位置等数据。Exif信息是镶嵌在 JPEG/TIFF 图像文件格式内的一组拍摄参数,需要注意的是EXIF信息是不支持png,webp等图片格式的。
各种相关信息以及EXIF的其他API,详见 http://code.ciaoca.com/javascript/exif-js/
安装
- 通过NPM包安装
npm install exif-js --save
- 在HTML中使用script添加js文件
<script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
该包添加了一个全局EXIF变量;因为EXIF.js是异步的,在调用getData或任何其他功能之前,您必须等待图像完全加载,在下面我传入的url是一张base64格式的图片,在新创建Image对象的onload方法中调用EXIF的方法。
// 获取图像的数据
```javascript
getOrientation (url) {
// url base64格式
return new Promise(resolve => {
const img = new Image()
img.src = url
img.onload = function () {
let orientation
// 获取图像的旋转方向
EXIF.getData(img, function () {
EXIF.getAllTags(this)
orientation = EXIF.getTag(this, 'Orientation')
resolve(orientation)
})
}
})
}
EXIF提供的API方法
下面附完整的代码 包括Canvas压缩图片大小、获取图像的旋转方向、修复旋转的图像
<template>
<div>
<div style="height: 50px; line-height: 50px;text-align: center;border-bottom: 1px solid #171E28;">
上传图片:
<input type="file" accept="image/*" id="uploadImage" @change="selectFileImage"/>
<!--调取手机摄像头的属性-->
</div>
<div style="margin-top: 10px;">
<img alt="preview" :src="myImage" style="width: 300px"/>
</div>
</div>
</template>
<script type="text/ecmascript-6">
import EXIF from 'exif-js'
export default {
data () {
return {
myImage: ''
}
},
methods: {
selectFileImage (fileObj) {
// 获取到上传的图片文件
const file = fileObj.target.files[0]
const reader = new FileReader()
reader.onload = (evt) => {
this.getOrientation(evt.target.result).then(res => {
this.drawCanvas(evt.target.result, file.type, res)
})
}
reader.readAsDataURL(file)
},
// 获取图像的数据
getOrientation (url) {
// url base64格式
return new Promise(resolve => {
const img = new Image()
img.src = url
img.onload = function () {
let orientation
// 获取图像的旋转方向
EXIF.getData(img, function () {
EXIF.getAllTags(this)
orientation = EXIF.getTag(this, 'Orientation')
resolve(orientation)
})
}
})
},
drawCanvas (result, type, orientation) {
const img = new Image()
img.src = result
img.onload = () => {
// 绘制canvas 压缩图片
let expectWidth = img.width
let expectHeight = img.height
let dataURL
// 这里的800、1200、0.8可自定义
if (img.width > img.height && img.width > 800) {
expectWidth = 800
expectHeight = expectWidth * img.height / img.width
} else if (img.height > img.width && img.height > 1200) {
expectHeight = 1200
expectWidth = expectHeight * img.width / img.height
}
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d')
canvas.width = expectWidth
canvas.height = expectHeight
// 旋转修复
if (orientation > 1) {
this.modifyOrientation(canvas, ctx, orientation)
}
ctx.drawImage(img, 0, 0, expectWidth, expectHeight)
if (/image\/jpeg/.test(type) || /image\/jpg/.test(type)) {
dataURL = canvas.toDataURL('image/jpeg', 0.8)
} else {
dataURL = canvas.toDataURL(type)
}
// 把旋转后的dataURL转换为需要上传的格式传出
this.myImage = dataURL
}
},
// 修正ios拍照时旋转问题
modifyOrientation (canvas, ctx, orientation) {
const w = canvas.width
const h = canvas.height
switch (orientation) {
case 6: // 需要顺时针(向左)90度旋转
ctx.rotate(0.5 * Math.PI)
ctx.translate(0, -h)
break
case 8: // 需要逆时针(向右)90度旋转
ctx.rotate(-0.5 * Math.PI)
ctx.translate(-w, 0)
break
case 3: // 需要180度旋转
ctx.translate(w, h)
ctx.rotate(Math.PI)
break
}
}
}
}
</script>
<style lang="stylus" rel="stylesheet/stylus" scoped>
</style>