1.安装依赖

npm install tracking

2.封装组件

<template>
  <div class="camera_outer">
    <!--
      此处代码请勿随意删除:
      input兼容ios无法调用摄像头的问题
      accept属性兼容某些华为手机调用摄像头,打开的是文件管理器的问题
    -->
    <input
      type="file"
      id="file"
      accept="image/*"
      capture="camera"
      style="display:none"
      @change="changePic"
    />
    <video
      id="videoCamera"
      :width="videoWidth"
      :height="videoHeight"
      autoplay
      class="img_bg_camera"
    />
    <canvas
      style="display:none"
      id="canvasCamera"
      :width="videoWidth"
      :height="videoHeight"
      class="img_bg_camera"
    />
    <div v-if="imgSrc" class="img_bg_camera" :class="[isDisplay?'displayBlock':'displayNone']">
      <img :src="imgSrc" alt class="tx_img" />
    </div>
    <div class="bottomButton">
      <van-button color="#aaaaaa" @click="goBack()" class="marginRight10">返回</van-button>
      <van-button type="warning" @click="getCamers()" class="marginRight10">打开摄像机</van-button>
      <van-button type="warning" @click="setImage()">拍照</van-button>
    </div>
  </div>
</template>

<script lang="ts">
import { Component, Vue, Emit } from "vue-property-decorator";
import { Toast } from "vant";
require("../common/js/tracking-min");
require("../common/js/face-min");
require("../common/js/mouth-min");
require("../common/js/stats.min.js");

@Component
export default class faceRecognition extends Vue {
  private videoWidth: number = 300; //摄像机宽度
  private videoHeight: number = 300; //摄像机高度
  private imgSrc: string = ""; //生成图片链接
  private thisCanvas: any = null; //canvas
  private thisContext: any = null; //context
  private thisVideo: any = null; //video
  private isFlag: boolean = false; //非正常拍照
  private isDisplay: boolean = false; //生成的照片是否显示

  //调用权限(打开摄像头功能)
  getCompetence() {
    var _this = this;
    //得到canvasCamera的元素
    this.thisCanvas = document.getElementById("canvasCamera");
    this.thisContext = this.thisCanvas.getContext("2d");
    this.thisVideo = document.getElementById("videoCamera") as
      | HTMLImageElement
      | SVGImageElement
      | HTMLVideoElement
      | HTMLCanvasElement
      | ImageBitmap
      | OffscreenCanvas;
    // 旧版本浏览器可能根本不支持mediaDevices,我们首先设置一个空对象
    if (navigator.mediaDevices === undefined) {
      Object.defineProperty(navigator, "mediaDevices", {
        value: {},
        writable: true,
        configurable: true,
        enumerable: true,
      });
    }
    // 一些浏览器实现了部分mediaDevices,我们不能只分配一个对象,如果使用getUserMedia,因为它会覆盖现有的属性。如果缺少getUserMedia属性,就添加它。
    if (navigator.mediaDevices.getUserMedia === undefined) {
      navigator.mediaDevices.getUserMedia = function (constraints) {
        // 首先获取现存的getUserMedia(如果存在)
        var getUserMedia =
          navigator.getUserMedia || navigator.mediaDevices.getUserMedia;
        // 有些浏览器不支持,会返回错误信息
        if (!getUserMedia) {
          Toast("getUserMedia is not implemented in this browser");
          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 as any, resolve, reject);
        });
      };
    }
    var constraints = {
      audio: false,
      video: {
        width: this.videoWidth,
        height: this.videoHeight,
        transform: "scaleX(-1)",
      },
    };
    //使苹果手机和苹果ipad支持打开摄像机
    if (
      (navigator.userAgent.toLowerCase().indexOf("iphone") != -1 ||
        navigator.userAgent.toLowerCase().indexOf("ipad") != -1)
    ) {
      //使得file一定可以获取到
      document.getElementById("file")!.click();
    } else {
      //在用户允许的情况下,打开相机,得到相关的流
      navigator.mediaDevices
        .getUserMedia(constraints)
        .then(function (stream) {
          // 旧的浏览器可能没有srcObject
          if (!_this.thisVideo) {
            _this.thisVideo = {};
          }
          try {
            _this.thisVideo.srcObject = stream;
          } catch (err) {
            _this.thisVideo.src = window.URL.createObjectURL(stream);
          }
          _this.isFlag = true;
          _this.thisVideo.onloadedmetadata = () => _this.thisVideo.play();
        })
        .catch((err) => {
          Toast(err);
          console.log(err);
        });
    }
  }
  //苹果手机获取图片并且保存图片
  changePic() {
    var reader = new FileReader();
    var f = (document.getElementById("file") as HTMLInputElement)
      .files as FileList;
    reader.readAsDataURL(f[0]);
    reader.onload = () => {
      var re = reader.result as string;
      this.canvasDataURL(re, { quality: 0.3 }, (base64Codes: string) => {
        if (base64Codes) {
          this.imgSrc = base64Codes;
          this.isDisplay = true;
          this.submitCollectInfo();
        } else {
          Toast("拍照失败");
        }
      });
    };
  }
  //压缩图片
  canvasDataURL(path: string, obj: any, callback: any) {
    let img = new Image();
    img.src = path;
    img.onload = () => {
      let that: any = this;
      // 默认按比例压缩
      var w: any = that.videoWidth,
        h: any = that.videoHeight,
        scale = w / h;
      w = obj.width || w;
      h = obj.height || w / scale;
      var quality = 0.5; // 默认图片质量为0.5
      //生成canvas
      var canvas = document.createElement("canvas");
      var ctx = canvas.getContext("2d");
      // 创建属性节点
      ctx!.drawImage(image, 0, 0, w, h);
      // 图像质量
      if (obj.quality && obj.quality <= 1 && obj.quality > 0) {
        quality = obj.quality;
      }
      // quality值越小,所绘制出的图像越模糊
      var base64 = canvas.toDataURL("image/jpeg", quality);
      // 回调函数返回base64的值
      callback(base64);
    };
  }
  //绘制图片(拍照功能)
  setImage() {
    this.thisContext.drawImage(
      this.thisVideo as
        | HTMLImageElement
        | SVGImageElement
        | HTMLVideoElement
        | HTMLCanvasElement
        | ImageBitmap
        | OffscreenCanvas,
      0,
      0,
      this.videoWidth,
      this.videoHeight
    );
    // 获取图片base64链接
    var image = this.thisCanvas.toDataURL("image/png", 0.5);
    if (this.isFlag) {
      if (image) {
        this.imgSrc = image;
        this.isDisplay = true;
        this.submitCollectInfo();
      } else {
        Toast("拍照失败");
      }
    } else {
      Toast("拍照失败");
    }
  }
  //保存图片
  async submitCollectInfo() {
    //其中可以和后端做一些交互
  }
  // 关闭摄像头
  stopNavigator() {
    if (this.thisVideo.srcObject) {
      this.thisVideo.srcObject.getTracks()[0].stop();
    }
  }
  //打开摄像机
  getCamers() {
    this.isDisplay = false;
  }
  //返回
  goBack() {
    this.stopNavigator();
     //可以写相应的返回的一些操作,携带一些需要携带的参数
  }
  mounted() {
    this.getCompetence();
  }
  destory() {
    this.stopNavigator();
  }
}
</script>

<style lang="scss" scoped>
.camera_outer {
  position: relative;
  overflow: hidden;
  background-size: cover;
  background: white;
  width: 100%;
  height: 100%;
}
video,
canvas,
.tx_img {
  -moz-transform: scaleX(-1);
  -webkit-transform: scaleX(-1);
  -ms-transform: scaleX(-1);
  -o-transform: scaleX(-1);
  transform: scaleX(-1);
}
.img_bg_camera {
  position: absolute;
  bottom: 25%;
  top: 25%;
  left: 50%;
  margin-left: -150px;
  border-radius: 50%;
  -webkit-border-radius: 50%;
  -moz-border-radius: 50%;
  -ms-border-radius: 50%;
  -o-border-radius: 50%;
}
.img_bg_camera img {
  width: 300px;
  height: 300px;
  border-radius: 50%;
  -webkit-border-radius: 50%;
  -moz-border-radius: 50%;
  -ms-border-radius: 50%;
  -o-border-radius: 50%;
}

.displayNone {
  display: none;
}

.displayBlock {
  display: block;
}

.marginRight10 {
  margin-right: 20px;
}

.bottomButton {
  position: fixed;
  bottom: 20px;
  width: 100%;
  text-align: center;
}
</style>
Logo

前往低代码交流专区

更多推荐