H5手机人脸拍照,带遮罩

3,121 阅读2分钟

故事是这样的,我上一篇文章做了个uniapp的人脸遮罩,主要是针对微信小程序上的人脸

拍照获取,但是呢~微信那边对于人脸等信息必须进行申请,然后调用他们的接口,才能在小程序上使用人脸拍照功能。

so sad~,然后公司又让我弄一个H5带人脸遮罩的拍照工具。我之前的文章是通过input标签来调取摄像头:

juejin.cn/post/696093…

然后经过我疯狂的搜索,后来发现可以通过使用video标签调取视频流,因为是吧画面写在页面,所以是可以添加遮罩的,然后拍照的时候通过canvas截取拍照时画面,这样就可以实现拍照了 

点击查看效果:

管理 (myqcloud.com)

注意:只能在https和本地环境下才能调取到摄像头,所以自己开发测试的时候可以使用网上的代码工具做一个网站托管来看效果,我这边使用的是coding的网站托管(码云维护了不能使用)

话不多说!直接上代码!

<template>  
<div class="camera_outer">   
     <p class="square"></p>   
     <!--        playsinline webkit-playsinline="true"-->   
     <video       
         ref="photo"        
         webkit-playsinline="true"       
         x-webkit-airplay="true"       
         x5-playsinline="true"       
         playsinline="true"        
         id="videoCamera"          
         :width="videoWidth"          
         :height="videoHeight"        
         autoplay      
      >     
      </video>    
      <div class="board">      
          <div class="border-wrap">        
          <p class="tip">请按图示将人脸放入取景框中</p>        
          <div class="circle-wrap">          
              <div class="circle" @click="setImage()"></div>        
          </div>     
      </div>   
 </div>    
 <canvas      
    style="display: none"          
    :width="canvasWidth"          
    :height="canvasHeight"      
    id="canvasCamera">
 </canvas>    
 <div class="shade">      
    <img :src="scan" alt="">    
 </div>    
  <div v-if="imgSrc" class="img_bg_camera">      
    <img :src="imgSrc" alt="" class="tx_img" />   
  </div>    
 <loading v-model="showLoading" ></loading>    
 <x-icon class="close" type="ios-close-empty" size="40" @click="close"></x-icon> 
 </div>
</template>
<script>  
    import {Loading} from "vux";  
    import scan from "../style/img/scan-img.png";//遮罩图片  
    import { setStore, removeStore, getStore } from "../config/mUtils";  
    export default {    
        data() {      
            return {        
                showLoading:false,        
                scan:scan,        
                canvasWidth:600,        
                canvasHeight:600,        
                videoWidth: 600,        
                videoHeight: 600,       
                imgSrc: "",        
                thisCancas: null,        
                thisContext: null,        
                thisVideo: null,      
            };    
        },    
        components: {      
            Loading,    
        },    
        mounted() {      
            this.getCompetence();    
        },   
        methods: {      
            close(){        
                this.$router.go(-1);        
                // this.$emit('addImg',"");      
            },      // 调用权限(打开摄像头功能)      
            getCompetence() {        
                var _this = this;        
                this.videoWidth =  this.$refs.photo.clientWidth  //宽度        
                this.videoHeight = this.videoWidth;        
                this.thisCancas = document.getElementById("canvasCamera");        
                this.thisContext = this.thisCancas.getContext("2d");        
                this.thisVideo = document.getElementById("videoCamera");        
                // 旧版本浏览器可能根本不支持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 ||              
                    navigator.getUserMedia;            
                    // 有些浏览器不支持,会返回错误信息           
                     // 保持接口一致            
                    if (!getUserMedia) {              
                        return Promise.reject(                
                            new Error("getUserMedia is not implemented in this browser")              
                        );            
                    }           
                    // 否则,使用Promise将调用包装到旧的navigator.getUserMedia            
                        return new Promise(function (resolve, reject) {              
                            getUserMedia.call(navigator, constraints, resolve, reject); 
                        });          
                    };        
                 }        
                if (window.stream) {//一进来的时候判断是否开着摄像头         
                     window.stream.getTracks().forEach(track => {            
                        track.stop();          
                     });        
                }        
                var constraints = {//配置默认前置摄像头,以及手机上摄像头取到的画面宽高          
                audio: false,          
                video: {            
                    width: this.videoWidth,            
                    height: this.videoHeight,            
                    transform: "scaleX(-1)",            
                    sourceId: 'default',            
                    // facingMode:  { exact: "user" }            
                    facingMode: "user"         
                },        
            };        
            navigator.mediaDevices          
            .getUserMedia(constraints)          
            .then(function (stream) {            
                // 旧的浏览器可能没有srcObject            
                if ("srcObject" in _this.thisVideo) {                        
                    _this.$nextTick(() => {               
                    _this.thisVideo.srcObject = stream;//that.video是video标签节点,请自行获取节点,updated周期里可以拿到!                
                    _this.thisVideo.play();              
              });            
            } else {              
                // 避免在新的浏览器中使用它,因为它正在被弃用。             
                 _this.thisVideo.src = window.URL.createObjectURL(stream);            
            }           
             // _this.thisVideo.onloadedmetadata = function (e) {            
                  //   _this.thisVideo.play();            
             // };          
        })          
        .catch((err) => {            
            console.log("错误");            
            console.log(err);          
         });      
       },      
       //  绘制图片(拍照功能)      
       setImage() {        
            var _this = this;        
                // 点击,canvas画图       
                _this.thisContext.scale(-1,1)//如果你上传图片是镜像的加上这段,我这边图片上传后会镜像
                _this.thisContext.drawImage(  
                _this.thisVideo,  
                -parseInt(_this.canvasWidth),  //镜像翻转要往负方向移动图片的距离
                0,  _this.canvasWidth,  
                _this.canvasHeight);
            );        
            // 获取图片base64链接        
            var image = this.thisCancas.toDataURL("image/jpeg",0.5);        
            _this.imgSrc = image;        
            let file = _this.dataURLtoFile(image,'pic')        
            // _this.upload(file);        
            // 停止摄像机        
            _this.thisVideo.pause();        
            this.stopNavigator();       
        },      
        // base64转文件      
        dataURLtoFile(dataurl, filename) {        
            var arr = dataurl.split(",");        
            var mime = arr[0].match(/:(.*?);/)[1];        
            var bstr = atob(arr[1]);        
            var n = bstr.length;        
            var u8arr = new Uint8Array(n);        
            while (n--) {          
                u8arr[n] = bstr.charCodeAt(n);        
            }        
            return new File([u8arr], filename, { 
                type: mime 
            });      
         },      // 上传图片      
         upload(file){        
            this.showLoading = true        
            var formdata = new FormData();        
            formdata.append("file",file,file.name)        
            let _this = this;        
            _this.axios.post("https://xxxxxxx/upload", formdata).then(res => {          
                if (res.data.code == "200") {            
                    this.showLoading = false;            
                    let _this = this;            
                    // _this.$emit('addImg',res.data.data);            
                    // setTimeout(function(){            
                    //   _this.$router.go(-1);            
                    // },300)          
                }else{            
                    this.showLoading = false;            
                    alert(res.msg);          
                }        
             });      
         },      
        // 关闭摄像头      
        stopNavigator() {        
            this.thisVideo.srcObject.getTracks()[0].stop();      
        },    
     },  
};
</script>
<style lang="scss" scoped>  #videoCamera{    width:100%;  }  .close{    position:absolute;    top:0.3rem;    right:0.3rem;  }  .vux-x-icon {    fill: #000;  }  /*遮罩*/  .shade{    width:100%;    position:absolute;    top:15vh;  }  .square{    margin:0;    height:15vh;    background:#fff;  }  .shade img{    width:100%;  }  .board{    background:#4b4956;    height:40vh;    width:100%;    margin-top:-5px;    .border-wrap{      width:100%;      position:absolute;      bottom:0;      display: flex;      flex-wrap: wrap;      justify-content: center;      align-items: center;    }    .tip{      width:100%;      height:1em;      text-align: center;      font-size:18px;      color:#fff;    }    .circle-wrap{      width:100%;      height:120px;      display: flex;      flex-wrap: wrap;      justify-content: center;      align-items: center;      .circle{        bottom:1rem;        width:1.5rem;        height:1.5rem;        background:#fff;        border:5px solid #ccc;        border-radius: 50%;        /*transform: all 1s ;*/      }      .circle:active{        width:1rem;        height:1rem;      }    }  }  .camera_outer {    height:100vh;    position: relative;    overflow: hidden;    background-size: 100%;    video,    canvas,    .tx_img {      -moz-transform: scaleX(-1);      -webkit-transform: scaleX(-1);      -o-transform: scaleX(-1);      transform: scaleX(-1);    }    .btn_camera {      position: absolute;      bottom: 4px;      left: 0;      right: 0;      height: 50px;      background-color: rgba(0, 0, 0, 0.3);      line-height: 50px;      text-align: center;      color: #ffffff;    }    .bg_r_img {      position: absolute;      bottom: 0;      left: 0;      right: 0;      top: 0;    }    .img_bg_camera {      position: absolute;      top:0;      left:0;      width:300px;      height:300px;      z-index:9999;      img {        width: 300px;        height: 300px;      }    }  }