移动端手机h5上传图片会旋转90度的问题
h5页面调用相机正常情况下都是正常的,但是有些手机横着照相的时候就会正常的,iphone正确的拍照方式是横屏的,而用户往往是竖屏拍照上传的,就相当于照相机反转了90度,当你横屏拍照上传,图片就是正确的,一张生成的图片是无法辨别方向的,就只有在上传之前反转了.
首先我们借助exif-js可以实现相机镜头的读取,不支持IE10以下,也可以直接引用的js文件,我使用npm安装依赖里面没有看到相关的js文件,就使用此办法.exif
的部分文档API
//index.html引入js
<script src="https://cdn.jsdelivr.net/npm/exif-js"></script>
这个js文件暴露了一个EXIF
的全局变量,我们可以把它挂在window
对象上,使他变为一个全局变量
<script type="text/javascript">
window.onload = function () {
window.EXIF = EXIF
}
</script>
然后在上传的file文件中获取相机方向,然后使用convas
重绘图片并旋转角度就可以了,我再项目里面使用的是vant-ui
//html
<van-uploader
:after-read="onRead"
:before-read="beforeRead"
v-model="fileList"
accept='image/*'
:max-count="2"/>
//js
methods: {
dataURLtoFile (dataurl, filename) { // 将base64转换为文件
let arr = dataurl.split(',')
let mime = arr[0].match(/:(.*?);/)[1]
let bstr = atob(arr[1])
let n = bstr.length
let u8arr = new Uint8Array(n)
while (n--) {
u8arr[n] = bstr.charCodeAt(n)
}
return new File([u8arr], filename, {type: mime})
},
uploadImg (file) {
let _this = this
let index = this.fileList.length - 1
/* eslint-disable */
EXIF.getData(file, () => {
let orientation = null // 相机方向
let imgWidth = null // 图片宽度
let imgHeight = null // 图片高度
EXIF.getAllTags(file)
orientation = EXIF.getTag(file, 'Orientation')
imgWidth = EXIF.getTag(file, 'ImageWidth')
imgHeight = EXIF.getTag(file, 'ImageHeight')
if (orientation === 6) { // 等于6顺时针旋转90度,等于8需要逆时针旋转90度,等于3需要旋转180度
let canvas = document.createElement('canvas')
let context = canvas.getContext('2d')
let img = new Image()
let reader = new FileReader()
reader.readAsDataURL(file)
reader.onload = (e) => {
img.src = e.target.result
img.onload = () => {
canvas.width = imgWidth
canvas.height = imgHeight
context.save() // 保存状态
context.translate(canvas.width / 2, canvas.height / 2)
context.rotate(90 * Math.PI / 180) // 旋转角度
context.drawImage(img, -(canvas.height / 2), -(canvas.width / 2), canvas.height, canvas.width)
context.restore() // 恢复状态
let newImg = canvas.toDataURL('image/jpeg', 1)
let files = _this.dataURLtoFile(newImg, file.name) // 将base64转为files文件
let urlImg = window.URL.createObjectURL(files) // 将file转为临时url给组件回显
this.$set(this.fileList, index, {url: urlImg, isImage: true})
this.uploadImgAPI(files)
}
}
} else { // 不需要旋转的直接上传
this.uploadImgAPI(file)
}
})
},
uploadImgAPI (file) { // 上传图片接口
const data = new FormData()
data.append('file', file)
data.append('code', this.applyNo)
data.append('type', 'chat')
apiUpload(data).then(res => {
if (res.status === 200) {
this.imagePath.push(res.data.reqUrl)
Toast('上传成功')
}
}).catch(() => {
this.fileList.pop()
})
}
}
将重绘的图片转为file文件传给后台,就OK了,其实在这之前还有一步压缩和检验格式的过程,在其他文章里面也写过
//js
method: {
beforeRead (file) { // 检测文件大小
let regex = /(.jpg|.jpeg|.png|.bmp)$/
if (!regex.test(file.type)) {
Toast('图片格式不支持上传')
return false
} else {
return true
}
},
onRead (file) { // 上传图片
// 大于10MB的图片都缩小像素上传
if (file.file.size > 10485760) {
let canvas = document.createElement('canvas')
let context = canvas.getContext('2d')
let img = new Image()
img.src = file.content // 指定图片的DataURL(图片的base64编码数据)
img.onload = () => {
canvas.width = 400 // 指定canvas画布大小,该大小为最后生成图片的大小
canvas.height = 300
context.drawImage(img, 0, 0, 400, 300)
file.content = canvas.toDataURL(file.file.type, 0.92)
let files = this.dataURLtoFile(file.content, file.file.name)
this.uploadImg(files)
}
} else {
this.uploadImg(file.file)
}
}
}
最终这样就好了.但是这样还有一个小问题需要优化的就是经过压缩之后的图片没有相机方向,需要在压缩的同时就需要旋转过来,大家可以尝试一下.