前言
最近在做一個內嵌App的vueH5應用,項目中需要進行拍照上傳人臉識別,然而App不提供原生拍照插件,故想使用H5的拍照。
首先調用H5拍照有兩種方案:
1.使用H5Api:navigator.getUserMedia(constraints, successCallback, errorCallback);
2.使用input type=file 。
這里我們采用第二種方案,第一種兼容性不太好,并且沒有第二種體驗效果好。
代碼實現(xiàn)
拿上input標簽:
<input type="file" name="photo" accept=".jpg,.png" multiple>
默認樣式比較丑,我們需要美化樣式:
HTML:
<div class="face">
<input type="file" name="file" class="upload" @change="uploadImg">
<span class="span-txt">開始認證</span>
</div>
CSS:
.face{
margin-top: 20px;
position: relative;
.upload{
width: calc(100% - 40px);
height: 43px;
line-height: 43px;
opacity: 0;
position: absolute;
z-index: 22;
left: 0;
margin: auto;
right: 0;
}
.span-txt{
font-family: PingFangSC-Medium;
font-size: 16px;
color: #FFFFFF;
position: absolute;
left: 0;
margin: auto;
right: 0;
background: #CDAB6A;
width: calc(100% - 40px);
height: 43px;
line-height: 43px;
border-radius: 4px;
text-align: center;
}
}
美化后效果:

如同button一般,點擊即可調用攝像頭拍照,或者使用相冊。
接下來就是使用處理圖片進行上傳
在uploadImg方法中處理系統(tǒng)拿到的圖片,整體的思路就是:先把拿到的file文件去獲取當前文件的角度方向,接著將文件轉為reader對象,在reader的onload函數(shù)中將文件轉為base64,然后把base64傳入resetOrientation 方法中(矯正壓縮圖片),最后再將base64轉為接口所需的blob對象傳給后臺。以下為拍照上傳代碼:
uploadImg(e) {
const vm = this;
let file = e.target.files[0]
let param = new FormData() // 創(chuàng)建form對象
let config = {
headers: {'Content-Type': 'multipart/form-data'}
}
//解決ios拍照照片自動旋轉問題
getOrientation(file, function (orientation) {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(evt){
const base64 = evt.target.result;
// 將圖片旋轉到正確的角度 并壓縮
resetOrientation(base64, orientation, function (resultBase64) {
b64toBlob(resultBase64, function (blob) {
param.append('file', blob); // 通過append向form對象添加數(shù)據
//調用接口上傳圖片
return registerFace(param, config).then((res) => {
// 上傳成功邏輯
})
});
});
}
});
}
拍照時圖片矯正的問題
由于我的項目中設計到上傳人臉,所以上傳的照片必須是正的,然而在實測中發(fā)現(xiàn),在ios中拍照上傳后會傳一個90° 反轉的照片上去,導致后端無法識別這種照片,在安卓機上則不會。那么,如何解決呢?
思路很簡單,我們在上傳照片前先做判斷:如果是反轉了的照片,我們調整過來,如果不是,不做調整。
1.使用EXIF.js對圖片進行角度判斷;定義一個函數(shù):
// 獲取圖片的角度
function getOrientation(file, callback) {
EXIF.getData(file, function () {
var orientation = EXIF.getTag(this, 'Orientation');
return callback(orientation);
});
}
2.使用canvas drawImage方法將圖片調整正確角度,在回調函數(shù)中使用toDataURL導出調整后的圖片base64對象。
關鍵代碼 base64toBlob函數(shù):
function b64toBlob(b64, onsuccess, onerror) {
let img = new Image();
img.onerror = onerror;
img.onload = function onload() {
const canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
let width = img.width;
let height = img.height;
let ctx = canvas.getContext('2d');
let rate = 1;
ctx.drawImage(img, 0, 0, width, height, 0, 0, width * rate, height * rate);
canvas.toBlob(onsuccess);
};
img.src = b64;
}
關鍵代碼 resetOrientation函數(shù):
function resetOrientation(srcBase64, srcOrientation, callback) {
const img = new Image();
img.onload = function () {
const width = img.width,
height = img.height,
canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
// 判斷圖片尺寸壓縮一定比率
const big = (img.width > img.height) ? img.width : img.height;
let rate = 1;
if (big > 840) {
rate = 840 / big;
}
canvas.width = width * rate;
canvas.height = height * rate;
// 安卓機不需要矯正圖片
if(srcOrientation && srcOrientation !== 1){
// 判斷圖片方向,壓縮并矯正
switch (srcOrientation) {
// 當圖片旋轉180°時
case 3:
ctx.rotate(Math.PI);
ctx.drawImage(this, -this.width * rate, -this.height * rate, this.width * rate, this.height * rate);
break;
// 當圖片旋轉90°時
case 6:
canvas.width = this.height * rate;
canvas.height = this.width * rate;
ctx.rotate(Math.PI / 2);
// (0,-imgHeight) 從旋轉原理圖那里獲得的起始點
ctx.drawImage(this, 0, -this.height * rate, this.width * rate, this.height * rate);
break;
// 當圖片旋轉270°時
case 8:
canvas.width = this.height * rate;
canvas.height = this.width * rate;
ctx.rotate(3 * Math.PI / 2);
ctx.drawImage(this, -this.width * rate, 0, this.width * rate, this.height * rate);
break;
default:
ctx.drawImage(img, 0, 0, width, height, 0, 0, width * rate, height * rate);
}
}else {
ctx.drawImage(img, 0, 0, width, height, 0, 0, width * rate, height * rate);
}
// 返回 base64
callback(canvas.toDataURL('image/jpeg'));
};
img.src = srcBase64;
};
至此,可解決圖片反轉的問題。