之前的H5拍照在最新ios手机上拍照会出现旋转90°的现象,
然后问题排查后发现其中一个原因
是因为ios13.4版本以上的苹果手机,拍照的话会自动校准旋转,
但是我这边还是会根据EXIF获取到旋转值,然后把图片再旋转了一次。
找到问题就对版本做一个判断,
在安卓和13.4ios之前的手机,我们做旋转处理,
其他则不处理,顺便把旋转和压缩的代码整理了下首先还是通过input标签调取摄像头:<input ref="file" type="file" accept="image/*" @change="h5CompressImage" capture="user">
<button style="margin-top:10px;" class="search-btn">点击拍摄</button>隐藏input,放在button上做一个假的button点击
拍照后照片传入这个方法处理:
async h5CompressImage (event) {
let _this = this
let file = event.target.files[0]
let fileReader = new FileReader()
let img = new Image() let imgWidth = ''
let imgHeight = '' // 旋转角度
let Orientation = null // 缩放图片需要的canvas
let canvas = document.createElement('canvas')
let ctx = canvas.getContext('2d') // 图片大小 大于500KB 则压缩
const isLt2MB = file.size < 512000 // 通过 EXIF 获取旋转角度 1 为正常 3 为 180° 6 顺时针90° 9 为 逆时针90°
const getOrientation = () => new Promise((resolve) => {
EXIF.getData(file, function () {
EXIF.getAllTags(this)
Orientation = EXIF.getTag(this, 'Orientation')
resolve()
})
})
await getOrientation()//确保获取到旋转值
const fileReaderOnload = () => new Promise(resolve => { // 文件读取 成功执行
fileReader.onload = function (ev) { // 文件base64化,以便获知图片原始尺寸
resolve(ev.target.result)
} // 读取文件
fileReader.readAsDataURL(file)
})
const src = await fileReaderOnload()
img.src = src // base64地址图片加载完毕后
img.onload = async function () {
imgWidth = img.width
imgHeight = img.height
canvas.width = img.width
canvas.height = img.height // 目标尺寸
let targetWidth = imgWidth
let targetHeight = imgHeight // 满足条件不需要压缩
if (isLt2MB && imgWidth < 960 && imgHeight < 960) {
return _this.upload(_this.base64toFile(src))//把上传的图片base64转化jpg格式为文件流
} // 大于2MB 、img宽高 > 960 则进行压缩
if (!isLt2MB || imgWidth >= 960 || imgHeight >= 960) { // 最大尺寸
let maxWidth = 960
let maxHeight = 960 // 图片尺寸超过 960 X 960 的限制
if (imgWidth > maxWidth || imgHeight > maxHeight) {
if (imgWidth / imgHeight > maxWidth / maxHeight) {
// 更宽,按照宽度限定尺寸
targetWidth = maxWidth
targetHeight = Math.round(maxWidth * (imgHeight / imgWidth))
} else {
targetHeight = maxHeight
targetWidth = Math.round(maxHeight * (imgWidth / imgHeight))
if(targetWidth <500){
targetWidth = 500;
}
}
} // canvas对图片进行缩放
canvas.width = targetWidth
canvas.height = targetHeight
ctx.drawImage(img, 0, 0, targetWidth, targetHeight)
}
var u = navigator.userAgent;
var versions = u.toLowerCase();
const isAndroid = u.indexOf('Android') > -1 || u.indexOf('Adr') > -1//判断是否是安卓
let isOldiOSVersion = false if(!isAndroid){
var ver=versions.match(/cpu iphone os (.*?) like mac os/);
isOldiOSVersion = ver[1].replace(/_/g,".")<'13.4'//判断ios是否大于13.4
} // android
let imgSrc = canvas.toDataURL('image/jpeg', 0.5)
if (isAndroid || isOldiOSVersion){ // 拍照旋转 需矫正图片
if (Orientation && +Orientation !== 1) {//根据获取到的值旋转
if(+Orientation == 6){ // 旋转90度
imgSrc = await _this.rotateBase64Img(imgSrc, 90)
}else if(+Orientation == 3){ // 旋转180度
imgSrc = await _this.rotateBase64Img(imgSrc, 180)
}else if(+Orientation == 8){ // 旋转270度
imgSrc = await _this.rotateBase64Img(imgSrc, 270)
}
}
}
_this.upload(_this.base64toFile(imgSrc))
}
}
图片旋转方法:
rotateBase64Img(src, edg) {
return new Promise(resolve => {
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d"); var imgW;//图片宽度
var imgH;//图片高度 var size;//canvas初始大小
if (edg % 90 != 0) {
console.error("旋转角度必须是90的倍数!");
throw '旋转角度必须是90的倍数!';
}
if(edg < 0){
edg = (edg % 360) + 360
}
const quadrant = (edg / 90) % 4; //旋转象限
const cutCoor = {sx: 0, sy: 0, ex: 0, ey: 0}; //裁剪坐标
var image = new Image();
image.crossOrigin = "anonymous"
image.src = src;
image.onload = function() {
imgW = image.width;
imgH = image.height;
size = imgW > imgH ? imgW : imgH;
canvas.width = size * 2;
canvas.height = size * 2;
switch (quadrant) {
case 0:
cutCoor.sx = size;
cutCoor.sy = size;
cutCoor.ex = size + imgW;
cutCoor.ey = size + imgH;
break;
case 1:
cutCoor.sx = size - imgH;
cutCoor.sy = size;
cutCoor.ex = size;
cutCoor.ey = size + imgW;
break;
case 2:
cutCoor.sx = size - imgW;
cutCoor.sy = size - imgH;
cutCoor.ex = size;
cutCoor.ey = size;
break;
case 3:
cutCoor.sx = size;
cutCoor.sy = size - imgW;
cutCoor.ex = size + imgH;
cutCoor.ey = size + imgW;
break;
}
ctx.translate(size, size);
ctx.rotate(edg * Math.PI / 180);
ctx.drawImage(image, 0, 0);
var imgData = ctx.getImageData(cutCoor.sx, cutCoor.sy, cutCoor.ex, cutCoor.ey);
if (quadrant % 2 == 0) {
canvas.width = imgW;
canvas.height = imgH;
} else {
canvas.width = imgH;
canvas.height = imgW;
}
ctx.putImageData(imgData, 0, 0);
resolve(canvas.toDataURL("iamge/jpeg"))
};
})
}
base64转文件流方法:
base64toFile (dataurl, filename = 'picture') {
let arr = dataurl.split(',')
let mime = 'image/jpg' // 转为jpg格式
let suffix = mime.split('/')[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}.${suffix}`, {
type: mime
})
},
上传图片方法:
upload(file){
this.showLoading = true
var formdata = new FormData();
formdata.append("file",file)
let config = {
headers: {
'Content-Type': 'multipart/form-data ',
}
}
let _this = this;
_this.axios.post("https:xxxxxxx", formdata, config).then(res => {
if (res.data.code == "200" || res.data.code == "0") {
console.log("上传成功")
}
});
},