应用场景
在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
| <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(){ const constraints = window.constraints = { audio: false, video: {facingMode: this.isFront ? "user" : "environment"} }; if(navigator.mediaDevices.getUserMedia){ } else if (navigator.webkitGetUserMedia){ navigator.webkitGetUserMedia(constraints,this.success, this.error) } else if (navigator.mozGetUserMedia){ navigator.mozGetUserMedia(constraints, this.success, this.error); } else if (navigator.getUserMedia){ 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 } }
|