qa-prevention-wlaq-vue/static/face/face_camera.html

253 lines
8.1 KiB
HTML
Raw Normal View History

2024-11-19 14:13:47 +08:00
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<title>人脸识别</title>
<script src="./js/vue.js"></script>
<script type="text/javascript" src="./js/jquery-3.3.1.min.js"></script>
<script src="../config.js"></script>
<script src="build/tracking-min.js"></script>
<script src="build/data/face-min.js"></script>
<style>
#video {
transform: rotateY(180deg);
}
.face-capture {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.face-capture video, .face-capture canvas {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 2;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.face-capture canvas {
z-index: 2;
}
.face-capture .img-cover {
position: fixed;
top: 0;
bottom: 0;
left: 0;
right: 0;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 2;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.face-capture .rect {
border: 2px solid #0aeb08;
position: fixed;
z-index: 3;
}
.face-capture .control-container {
margin-top: 10rem;
position: relative;
width: 100%;
height: 100%;
object-fit: cover;
z-index: 4;
background-repeat: no-repeat;
background-size: 100% 100%;
}
.face-capture .title {
text-align: center;
color: white;
margin: 1.6rem auto;
font-size: 28px;
}
.face-capture .close {
width: 0.8rem;
height: 0.8rem;
}
</style>
</head>
<body>
<div id="app">
<div v-show="showContainer" class="face-capture" id="face-capture">
<video ref="refVideo" id="video" autoplay></video>
<!-- <img src="./../images/video-cover.png" alt="cover" class="img-cover"/> -->
<div class="control-container face-capture">
<h2 class="title">{{scanTip}}</h2>
<h2 class="title">{{msg}}</h2>
<!-- <img class="close" src="./../images/address_edit_clear.png" alt=""/> -->
<canvas ref="refCanvas" :width="screenSize.width" :height="screenSize.height" :style="{opacity: 0}"></canvas>
</div>
<div class="rect" v-for="item in profile"
:style="{ width: item.width + 'px', height: item.height + 'px', left: item.left + 'px', top: item.top + 'px'}"></div>
</div>
<div v-show="!showContainer">验证成功</div>
</div>
</body>
</html>
<script type="text/javascript">
var vm = new Vue({
el: '#app',
data: {
USER_ID: null,
screenSize: { width: window.screen.width, height: window.screen.height },
URL: null,
streamIns: null, // 视频流
showContainer: true, // 显示
tracker: null,
tipFlag: false, // 提示用户已经检测到
flag: false, // 判断是否已经拍照
context: null, // canvas上下文
profile: [], // 轮廓
removePhotoID: null, // 停止转换图片
scanTip: '人脸识别中...请将人脸置于镜头内', // 提示文字
imgUrl: '', // base64格式图片
weburl: config.weburl,
msg: '',
countdown: 0,
timer: null
},
beforeDestroy() {
if (this.timer) {
clearInterval(this.timer)
this.timer = null
}
},
mounted() {
this.USER_ID = this.getUrlKey('USER_ID')
// 这段代 主要是获取摄像头的视频流并显示在Video 签中
window.addEventListener('DOMContentLoaded', function() {
// 拍照按钮
// $("#snap").click(function () {
// context.drawImage(video, 0, 0, 330, 250);
// })
// 拍照每秒一次
// setInterval(function(){
// context.drawImage(video, 0, 0, 330, 250)
// },1000);
var constraints = { 'audio': false, 'video': { 'facingMode': 'user' }}
// 老的浏览器可能根本没有实现 mediaDevices所以我们可以先设置一个空的对象
if (navigator.mediaDevices === undefined) {
navigator.mediaDevices = {}
}
// 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
// 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
if (navigator.mediaDevices.getUserMedia === undefined) {
navigator.mediaDevices.getUserMedia = function(constraints) {
// 首先如果有getUserMedia的话就获得它
var getUserMedia = navigator.webkitGetUserMedia || navigator.mozGetUserMedia
// 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
if (!getUserMedia) {
return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
}
// 否则为老的navigator.getUserMedia方法包裹一个Promise
return new Promise(function(resolve, reject) {
getUserMedia.call(navigator, constraints, resolve, reject)
})
}
}
if (window.stream) {
window.stream.getTracks().forEach(track => {
track.stop()
})
}
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
var video = document.querySelector('video')
video.setAttribute('playsinline', true)
// 旧的浏览器可能没有srcObject
window.stream = stream
if ('srcObject' in video) {
video.srcObject = stream
} else {
// 防止在新的浏览器里使用它,应为它已经不再支持了
video.src = window.URL.createObjectURL(stream)
}
video.play()
})
.catch(function(err) {
alert(err.name + ': ' + err.message)
}) // 总是在最后检查错误
}, false)
this.tackPhoto()
},
methods: {
// 拍照
tackPhoto() {
this.context = this.$refs.refCanvas.getContext('2d') // 画布
this.timer = setInterval(() => {
this.countdown += 1
if (this.countdown > 30) {
clearInterval(this.timer)
this.timer = null
this.msg = '验证失败,请重新打开此页面'
}
this.context.drawImage(this.$refs.refVideo, 0, 0, this.screenSize.width, this.screenSize.height)
// // 保存为base64格式
this.imgUrl = this.saveAsPNG(this.$refs.refCanvas)
// /** 拿到base64格式图片之后就可以在this.compare方法中去调用后端接口比较了也可以调用getBlobBydataURI方法转化成文件再去比较
// * 我们项目里有一个设置个人头像的地方,先保存一下用户的图片,然后去拿这个图片的地址和当前拍照图片给后端接口去比较。
// * */
var _this = this
var USERAVATARURL = this.imgUrl.substring(this.imgUrl.indexOf('base64,') + 7)
$.ajax({
xhrFields: {
withCredentials: true
},
type: 'POST',
url: config.httpurl + '/app/user/compareFaceForH5',
data: {
USERAVATARURL: USERAVATARURL,
USER_ID: this.USER_ID
},
dataType: 'json',
success: function(data) {
var result = data.result
if (result == 'success') {
clearInterval(_this.timer)
_this.timer = null
_this.msg = '验证成功'
_this.showContainer = false
} else if (result == 'error') {
_this.msg = data.msg
}
},
fail: function(data) {
_this.msg = '验证失败'
}
})
// this.msg = USERAVATARURL
}, 2000)
},
// 保存为png,base64格式图片
saveAsPNG(c) {
return c.toDataURL('image/png', 0.3)
},
// 根据url参数名称获取参数值
getUrlKey: function(name) {
return decodeURIComponent(
(new RegExp('[?|&]' + name + '=' + '([^&;]+?)(&|#|;|$)').exec(location.href) || [, ''])[1].replace(/\+/g, '%20')) || null
}
}
})
</script>