wxml
<view>
<view class="flex white">
<!-- 镜头翻转 -->
<view bindtap="reverse">镜头翻转</view>
<view bindtap="clickScanCode">扫二维码</view>
</view>
<view class="head-image-box w-100 text-center position-relative">
<!-- resolution:获取人脸图片后的清晰度 low:低 -->
<camera device-position="{{devicePosition ?'back': 'front'}}" class="camera" flash="off" resolution='low' />
<view class="title">{{ tipsText }}1</view>
<image src="{{faceImage}}" mode="" />
<cover-view class="cover-box" wx:if="{{isShow}}">
<!-- <cover-image class="image-box" src="@/static/images/camera_verify.png"></cover-image> -->
<!-- cover-view 不支持动画所以只能变通的形式实现 -->
<!-- <cover-image :style="'transform: translateY('+translateY+'rpx);'" class="line" src="@/static/images/bg_line.png"></cover-image> -->
<!-- <cover-view class="line"></cover-view> -->
</cover-view>
<canvas id="myCanvas" canvas-id="myCanvas" :style="'width:'+screenWidth+'px;'+'height:'+screenHeight+'px'"></canvas>
</view>
</view>
js
Page({
data() {
return {
isShow: false,
tipsText: '',
tempImg: '',
cameraEngine: null,
devicePosition: false,
isAuthCamera: true,
isVerify: false,
translateY: -24,
timer: null,
isFlag: true,
origin: null,
base64: "",
personId: "",
isFlag2: true,
screenWidth: 375,
screenHeight: 640,
faceImage: '',
}
},
onShow: function () {
this.setData({
isVerify: false,
tipsText: "",
isFlag: true,
})
this.lineAnimation();
},
onLoad(options) {
this.initData();
},
onUnload() {
this.clearTimer();
},
onHide() {
this.clearTimer();
},
clearTimer() {
if (this.data.timer) {
clearInterval(this.data.timer);
this.setData({
timer: null,
})
}
this.setData({
isFlag: false,
})
},
initData() {
wx.initFaceDetect();
this.setData({
cameraEngine: wx.createCameraContext(),
isShow: true,
})
const listener = this.data.cameraEngine.onCameraFrame((frame) => {
console.log(888888888, frame.data, frame.width, frame.height)
if (this.data.isVerify) return
if (this.data.isFlag2) {
this.setData({
isFlag2: false,
screenWidth: frame.width,
screenHeight: frame.height,
})
}
wx.faceDetect({
frameBuffer: frame.data,
width: frame.width,
height: frame.height,
enablePoint: true,
enableConf: true,
enableAngle: true,
enableMultiFace: true,
success: async (faceData) => {
console.log(1111, faceData)
let face = faceData.faceInfo[0]
if (face.x == -1 || face.y == -1) {
this.setData({
tipsText: '检测不到人'
})
}
if (faceData.faceInfo.length > 1) {
this.setData({
tipsText: '请保证只有一个人'
})
} else {
const {
pitch,
roll,
yaw
} = face.angleArray;
const standard = 0.5
if (Math.abs(pitch) >= standard || Math.abs(roll) >= standard ||
Math.abs(yaw) >= standard) {
this.setData({
tipsText: '请平视摄像头'
})
} else if (face.confArray.global <= 0.8 || face.confArray.leftEye <=
0.8 || face.confArray.mouth <= 0.8 || face.confArray.nose <= 0.8 ||
face.confArray.rightEye <= 0.8) {
this.setData({
tipsText: '请勿遮挡五官'
})
} else {
if (this.isVerify) return
var centerWidth = 250;
var centerHeight = 250;
if (face.x > (frame.width - centerWidth) / 2 && face.x < (frame
.width - centerWidth) / 2 + centerWidth && face.y > (frame
.height - centerHeight) / 2 && face.y < (frame.height -
centerHeight) / 2 + centerHeight) {
this.setData({
tipsText: '校验中...',
isVerify: true
})
setTimeout(async () => {
let img = await this.changeDataToBase64(
frame);
this.setData({
base64: img
})
this.searchUserFace();
}, 300)
} else {
this.setData({
tipsText: '请将人脸对准中心位置'
})
}
}
}
},
fail: (err) => {
console.log(2222, err)
if (this.isVerify) return
if (err.x == -1 || err.y == -1) {
this.setData({
tipsText: '检测不到人'
})
} else {
this.setData({
tipsText: err.errMsg || '网络错误,请退出页面重试'
})
}
},
})
})
listener.start()
this.setData({
listener: listener
})
},
reverse() {
let a = this.data.devicePosition
this.setData({
devicePosition: !a
})
},
clickScanCode() {
wx.scanCode({
onlyFromCamera: true,
success: (res) => {
var data = JSON.parse(res.result.replace(/\ufeff/g, ""));
}
});
},
changeDataToBase64(frame) {
console.log(4444, frame)
return new Promise((resolve, reject) => {
var data = new Uint8Array(frame.data);
var clamped = new Uint8ClampedArray(data);
let that = this;
var width = this.data.screenWidth;
var height = frame.height * this.data.screenWidth / frame.width;
wx.canvasPutImageData({
canvasId: 'myCanvas',
x: 0,
y: 0,
width: frame.width,
height: frame.height,
data: clamped,
success(res) {
console.log(5555, res)
wx.canvasToTempFilePath({
x: 0,
y: 0,
width: width,
height: height,
canvasId: 'myCanvas',
fileType: 'jpg',
destWidth: width,
destHeight: height,
quality: 0.5,
success(res) {
console.log(666, res)
wx.getFileSystemManager().readFile({
filePath: res.tempFilePath,
encoding: 'base64',
success: res => {
console.log(7777, res)
resolve(res.data);
}
})
},
fail(res) {
console.log(8888, res)
reject(false);
}
});
},
fail(error) {
console.log(error);
}
})
})
},
searchUserFace() {
console.log(333, this.data.base64)
this.setData({
faceImage: 'data:image/jpeg;base64,' + this.data.base64,
tipsText: '校验成功'
})
wx.stopFaceDetect();
this.data.listener.stop();
return
var params = {
faceImage: this.data.base64,
}
searchFaces(params).then(res => {
console.log(444, res)
if (res.code == 200) {
wx.stopFaceDetect();
this.data.listener.stop();
this.clickPushDetail(res.data.personCode);
this.setData({
tipsText: '校验成功'
})
}
}).catch(error => {
setTimeout(() => {
this.setData({
isVerify: 'false'
})
}, 500)
this.setData({
tipsText: '暂未查找到相关人员'
})
})
},
clickPushDetail() {
},
lineAnimation() {
if (this.timer) return
this.setData({
timer: setInterval(() => {
this.setData({
translateY: this.data.translateY + 8
})
if (this.data.translateY >= 460) {
this.setData({
translateY: 10
})
}
}, 40)
})
},
onPullDownRefresh() {
},
onReachBottom() {
},
onShareAppMessage() {
}
})
css
page {
background-color: #000000;
}
.camera-change-image {
width: 52rpx;
margin-left: 40rpx;
}
.scan-image {
width: 48rpx;
}
.update-box {
color: #ffffff;
}
.operation-box {
position: fixed;
width: 100%;
bottom: calc(120rpx + env(safe-area-inset-bottom));
}
.icon-box {
width: 76rpx;
height: 76rpx;
}
first {
width: 72rpx;
height: 72rpx;
}
.head-image-box {
position: absolute;
top: 10vh;
color: white;
}
.camera {
width: 750rpx;
height: 872rpx;
position: relative;
z-index: 10;
}
#myCanvas {
position: absolute;
z-index: 1;
top: -10000px;
}
.title {
font-size: 40rpx;
margin-top: 60rpx;
}
.cover-box {
position: absolute;
top: 40%;
left: 50%;
transform: translate(-50%, -50%);
width: 500rpx;
height: 500rpx;
}
.image-box {
width: 100%;
height: 100%;
}
.line {
position: absolute;
top: 0rpx;
left: 8rpx;
right: 8rpx;
width: auto;
height: 30rpx;
z-index: 2;
}