一、H5场景介绍
需求:APP里面内嵌H5页面,页面需要调用webview原生的拍照和上传图片功能,最后拿到照片渲染到H5页面上。
二、遇到的问题
1、部分Android手机拍照后渲染的照片会自动顺时针旋转90度,例如:小米MIX 2(Android 9.0)
2、iphone手机有些ios系统拍照后渲染的照片会自动顺时针旋转90度,例如:ios13.4之前的系统
三、解决方案
1、借助 EXIF.js
插件读取图像的元数据,获取图像的拍摄方向 Orientation
的值,根据相应的方向修正图像的位置。
EXIF.getData(imgObj, callback) //获取图像的圆数据
EXIF.getTag(imgObj, "Orientation") //获取图像的拍摄方向,1:正常,6:图片顺时针旋转90度,8:图片逆时针旋转90度,3:图片旋转180度,倒置
2、目前只发现部分手机出现 Orientation
为 6
的情况,图片被顺时针旋转90度,处理方案如下
//获取修正过的图片
function getCorrectImg(file) {
let Orientation = 0; //图片方向默认为0,代表正常方向
let reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = (e) => {
let image = new Image();
image.src = e.target.result;
//获取照片方向角属性,旋转控制图片
image.onload = function () {
EXIF.getData(image, function () {
Orientation = EXIF.getTag(this, "Orientation"); // 获取图像的拍摄方向
let rotateCanvas = document.createElement("canvas");
let rotateCtx = rotateCanvas.getContext("2d");
let rotateDegs = 0; //旋转角度
//根据不同方向控制旋转角度
switch (Orientation) {
//正常角度,图片绘制
case 1:
rotateCanvas.width = image.width;
rotateCanvas.height = image.height;
rotateCtx.drawImage(image, 0, 0, image.width, image.height);
break;
//顺时针旋转90度,手动对图片校正处理
case 6:
let sy = 0; //canvas左上角Y轴坐标
//ios 13.4以上版本竖屏拍照会自动校正,所以需要兼容高版本ios
//其他设备方向为6的全部需要顺时针旋转90度
if((isIOS() && compareVersion(getIosVer(), "13.4") < 0) || !isIOS()) {
rotateCanvas.width = image.height;
rotateCanvas.height = image.width;
rotateCtx.translate(0, 0);
rotateDegs = (90 * Math.PI) / 180;
sy = -image.height;
} else {
rotateCanvas.width = image.width;
rotateCanvas.height = image.height;
rotateCtx.rotate(rotateDegs);
rotateCtx.drawImage(image, 0, sy, image.width, image.height);
}
break;
//逆时针旋转90度,手动对图片校正处理
case 8:
rotateCanvas.width = image.height;
rotateCanvas.height = image.width;
rotateCtx.translate(0, 0);
rotateCtx.rotate((-90 * Math.PI) / 180);
rotateCtx.drawImage(image, -image.width, 0 , image.width , image.height);
break;
//旋转180度,手动对图片校正处理
case 3:
rotateCanvas.width = image.width;
rotateCanvas.height = image.height;
rotateCtx.translate(0, 0);
rotateCtx.rotate(Math.PI);
rotateCtx.drawImage(image, -image.width, -image.width , image.width , image.height);
break;
default:
rotateCanvas.width = image.width;
rotateCanvas.height = image.height;
rotateCtx.drawImage(image, 0, 0, image.width, image.height);
}
return rotateCanvas.toDataURL("image/jpeg", 0.8); //修正过的图片地址
})
}
}
3、上面用到的一些函数,获取ios版本、比较系统版本号等
/*
* 获取ios系统版本
*/
const getIosVer = () => {
let userAgent = navigator.userAgent;
let reg = /CPU iPhone OS (.*?) like Mac OS/i;
let verStr = userAgent.match(reg)[1];
return verStr.replace(/_/g, ".");
};
/**
* 判断软件/系统的版本是否低于设定的版本值,返回1表示当前版本大于设定的版本,返回0表示两个版本相等,返回-1表示当前版本小于设定的版本
* @param {string} ver 软件/系统版本
* @param {string} compareVer 设定的版本值
*/
const compareVersion = (ver, compareVer) => {
ver = ver.split(".");
compareVer = compareVer.split(".");
const len = Math.max(ver.length, compareVer.length);
while (ver.length < len) {
ver.push("0");
}
while (compareVer.length < len) {
compareVer.push("0");
}
for (let i = 0; i < len; i++) {
const num1 = parseInt(ver[i]);
const num2 = parseInt(compareVer[i]);
if (num1 > num2) {
return 1;
} else if (num1 < num2) {
return -1;
}
}
return 0;
};