0%

uniapp实现调起手机相机增加人脸框

应用场景

在web页面上调起手机摄像头,并增加人脸框进行拍照,然后把图片上传到服务器。

实现原理

1、基本原理

使用getUserMedia()方法获取视频流,通过video标签在页面上播放,通过canvas画布截取图片。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<!--video用于显示媒体设备的视频流,自动播放-->
<div class="camera-wrapper">
<!-- 人脸框照片 -->
<image class="face-icon" src="@/static/images/home/collecte/face.png"</image>
<video class="video"
id="video"
autoplay
height="100%"
width="100%"
:controls="false"
:show-play-btn="false"
:show-center-play-btn="false"
:show-mute-btn="false"
:muted="true"></video>
</div>
<!--拍照按钮-->
<div class="bottom-btn">
<button class="btn-cell bottom-btn-left" @click="stopMedia">取消</button>
<button class="btn-cell bottom-btn-middle" @click="captureImg">
<image class="capture-icon" src="@/static/images/home/collecte/capture.png"></image>
</button>
<button class="btn-cell bottom-btn-right" @click="clipMedia">
<image src="@/static/images/home/collecte/flip.png" class="flip-icon"></image>
</button>
<!--拍照图片-->
<canvas id="canvas"></canvas>
</div>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
// getUserMedia()获取视频流
getUserMedia(){
const constraints = window.constraints = {
// 关闭视频声音
audio: false,
// 摄像头参数 user 前置摄像头 environment 后置摄像头
// 默认前置 通过变量isFront控制展示前置还是后置
video: {facingMode: this.isFront ? "user" : "environment"}
};
if(navigator.mediaDevices.getUserMedia){
//最新标准API navigator.mediaDevices.getUserMedia(constraints).then(this.success).catch(this.error);
} else if (navigator.webkitGetUserMedia){
//webkit内核浏览器
navigator.webkitGetUserMedia(constraints,this.success, this.error)
} else if (navigator.mozGetUserMedia){
//Firefox浏览器
navigator.mozGetUserMedia(constraints, this.success, this.error);
} else if (navigator.getUserMedia){
//旧版API
navigator.getUserMedia(constraints, this.success, this.error);
}
},
init()
{
if ((navigator.mediaDevices && navigator.mediaDevices.getUserMedia) || navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia){
this.getUserMedia();
} else {
console.log("你的浏览器不支持访问用户媒体设备");
}
},
error(error){
uni.showToast({
title: error.message,
icon: 'none'
});
console.log(error.name+error.message);
},
success(stream){
const video = document.getelementIdBy('video');
const videoTracks = stream.getVideoTracks();
console.log('Got stream with constraints:', constraints);
this.mediaStreamTrack = stream;
video.srcObject = stream;
video.play();
},
//关闭视频流
stopMedia()
{
this.mediaStreamTrack.getTracks().forEach( (track) =>
{
track.stop();
});
},
// 拍照片
captureImg()
{
var videoHtml = document.getElementById("video");
var canvasHtml = document.getelementById("canvas");
var context = canvasHtml.getContext("2d");
context.drawImage(videoHtml, 0, 0, 100, 100);
},
// 翻转摄像头
clipMedia()
{
this.isFront = !this.isFront;
this.getUserMedia();
},
2、坑1:getContext is not undefined

uniapp里面获取的canvas画布没法转getContext,官方给的是用uni.createCanvasContext获取,但是用这个截取不了视频流,就是没法获取照片。

解决办法:利用原生的方法创建一个canvas画布,利用这个canvas画布截取视频流,再转成图片路径展示。拍照函数做下改动。

1
2
3
4
5
var videoHtml = document.getElementById("video");
var canvasHtml = document.createElement("canvas");
var context = canvasHtml.getContext("2d");
context.drawImage(videoHtml, 0, 0, 100, 100);
let img = canvasHtml.toDataURL("image/png", 1); // 获取的图片路径,可直接在页面显示
3、坑2:截取视频流时报错,数据不是视频流

与上一个坑一个意思,利用id去获取的vedio标签其实是uniapp包装以后的div盒子,所以直接获取是不行的,还是要用原生的方法获取vedio标签。

解决办法:改动代码如下。

1
2
3
4
5
var videoHtml = document.getElementById("video").querySelector("video");
var canvasHtml = document.createElement("canvas");
var context = canvasHtml.getContext("2d");
context.drawImage(videoHtml, 0, 0, width, height);
let img = canvasHtml.toDataURL("image/png", 1); // 获取的图片路径,可直接在页面显示
4、坑三:画出的图片不完整

图片不完整是因为图片的宽高设置有问题,drawImage需要传入起点终点及宽高数据,直接写的话会有适配问题。

解决办法:获取视频vedio标签的宽高,作为截取的宽高赋值,别忘了也给canvas赋值。

1
2
3
4
5
6
7
8
9
var videoHtml = document.getElementById("video").querySelector("video");
var width = document.getElementById("video").clientWidth;
var height = document.getElementById("video").clientHeight;
var canvasHtml = document.createElement("canvas");
canvasHtml.width = width;
canvasHtml.height = height;
var context = canvasHtml.getContext("2d");
context.drawImage(videoHtml, 0, 0, width, height);
let img = canvasHtml.toDataURL("image/png", 1);
5、补充

getUserMedia()方法需要在https协议或者localhost才能调用,如果电脑开发,需要手机上看效果的话,可以在manifest.json中设置”https” : true,就可以在手机上运行测试了。

配置代码如下:

1
2
3
4
5
"h5" : {
"devServer":{
"https" : true
}
}
-------------The End-------------
坚持原创技术分享,您的支持将鼓励我继续创作!