浏览器调起摄像头,base64转文件,base64转blob

浏览器调起摄像头

<template>
  <div class="body">
    这里什么都没有
    <video ref="videoRef" id="videoCamera" class="video"></video>
    <button @click="getCompetence" class="btn" :disabled="!videoState">
      打开摄像头
    </button>
    <button @click="stopNavigator" class="btn" :disabled="videoState">
      关闭摄像头
    </button>
    <button @click="captureScreenshot" class="btn">点击截图</button>
    {{ imgSrc }}
    <canvas ref="canvasRef" class="canvas"></canvas>
  </div>
</template>

<script>
export default {
  data() {
    return {
      videoWidth: 500,
      videoHeight: 300,
      number: 0,
      hours: 0,
      minutes: 0,
      seconds: 0,
      run: false,
      imgSrc: "",
      flag: true,
      thisCancas: null,
      thisContext: null,
      thisVideo: null,
      userInfo: {
        imgStr: "",
      },
      videoState: true,
    };
  },
  methods: {
    // 调用摄像头
    getCompetence() {
      this.videoState = false;
      var _this = this;
      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;
          // 有些浏览器不支持,会返回错误信息
          // 保持接口一致
          console.log("viedo", 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);
          });
        };
      }
      //使用此方式获取本地音频视频输入输出设备,找到要使用的设备id,方式见下图
      var enumeratorPromise = navigator.mediaDevices.enumerateDevices();
      // console.log(enumeratorPromise);
      let videoDeviceId = "";
      enumeratorPromise.then((results) => {
        results.forEach((result) => {
          if (result.kind == "videoinput") {
            videoDeviceId = result.deviceId;
            console.log(result.deviceId);
          }
        });
      });
      //把上面获取到的设备deviceId填入下面video的deviceId中,就可以选择要调用的摄像头了
      var constraints = {
        audio: false,
        video: {
          deviceId: videoDeviceId,
          width: this.videoWidth,
          height: this.videoHeight,
        },
      };
      navigator.mediaDevices
        .getUserMedia(constraints)
        .then(function (stream) {
          // 旧的浏览器可能没有srcObject
          if ("srcObject" in _this.thisVideo) {
            _this.thisVideo.srcObject = stream;
          } else {
            // 避免在新的浏览器中使用它,因为它正在被弃用。
            _this.thisVideo.src = window.URL.createObjectURL(stream);
          }
          _this.thisVideo.onloadedmetadata = function (e) {
            if (_this.flag == true) {
              _this.thisVideo.play();
              _this.flag = false;
            } else {
              _this.thisVideo.pause();
              _this.flag = true;
            }
          };
        })
        .catch((err) => {
          console.log(err);
        });
    },
    // 关闭摄像头
    stopNavigator() {
      this.videoState = true;
      this.thisVideo.srcObject.getTracks()[0].stop();
      this.flag = true;
    },
    // 截图
    // captureScreenshot() {
    //   this.imgSrc = ""
    //   const video = this.$refs.videoRef;
    //   const canvas = this.$refs.canvasRef;
    //   const context = canvas.getContext('2d');
      
    //   // 将canvas的尺寸设置为视频的尺寸
    //   canvas.width = video.videoWidth;
    //   canvas.height = video.videoHeight;
      
    //   // 在canvas上绘制视频画面
    //   context.drawImage(video, 0, 0, canvas.width, canvas.height);
      
    //   // 将canvas内容转换为图片
    //   this.imgSrc = canvas.toDataURL();
      
    //   // 打印图片的DataURL
    //   console.log(this.imgSrc); //base64
    //   console.log("转换", this.dataURLtoFile(this.imgSrc, "file")); //二进制文件
    //   // 可以将这个image上传到服务器,保存为图片文件等等
    // },
    //处理一下canvas的scale和dpi,截图有点模糊,让图片变清晰些,但好像也一般
    captureScreenshot() {
      const video = this.$refs.videoRef;
      const canvas = this.$refs.canvasRef;
      const context = canvas.getContext('2d');
      
      const scale = window.devicePixelRatio || 1;
      
      // 将canvas的尺寸设置为视频的尺寸,并考虑DPI缩放
      canvas.width = video.videoWidth * scale;
      canvas.height = video.videoHeight * scale;
      
      // 缩放canvas
      context.scale(scale, scale);
      
      // 绘制视频画面
      context.drawImage(video, 0, 0, canvas.width, canvas.height);
      
      // 将canvas内容转换为图片,指定输出的图像质量
      this.imgSrc = canvas.toDataURL('image/jpeg', 1.0);

      // 将canvas内容转换为图片
      this.imgSrc = canvas.toDataURL();
      
      // 打印图片的DataURL
      console.log(this.imgSrc); //base64
      console.log("转换", this.dataURLtoFile(this.imgSrc, "file")); //二进制文件
      // 可以将这个image上传到服务器,保存为图片文件等等
    },

    clearImgSrc() {
      this.imgSrc = "";
    },

    //base64转文件
    dataURLtoFile(urlData, fileName) {
      let arr = urlData.split(",");
      let mime = arr[0].match(/:(.*?);/)[1];
      let bytes = atob(arr[1]); // 解码base64
      let n = bytes.length;
      let ia = new Uint8Array(n);
      while (n--) {
        ia[n] = bytes.charCodeAt(n);
      }
      console.log("转换成功");
      return new File([ia], fileName, { type: mime });
    },
    base64ToBlob(base64) {
      const byteCharacters = atob(base64);
      const byteArrays = [];

      for (let offset = 0; offset < byteCharacters.length; offset += 512) {
        const slice = byteCharacters.slice(offset, offset + 512);

        const byteNumbers = new Array(slice.length);
        for (let i = 0; i < slice.length; i++) {
          byteNumbers[i] = slice.charCodeAt(i);
        }

        const byteArray = new Uint8Array(byteNumbers);
        byteArrays.push(byteArray);
      }

      const blob = new Blob(byteArrays, { type: "image/jpeg" }); // 根据实际的 Base64 字符串类型设置对应的 MIME 类型
      return blob;
    },

    blobToUrl(blob) {
      const url = URL.createObjectURL(blob);
      return url;
    },
  },
};
</script>

<style lang="less">
.body {
  display: flex;
  flex-direction: column;
  justify-content: center;
  // align-items: center;
  width: 100%;
  height: 100%;
}

.video {
  width: 500px;
  height: 300px;
}

.canvas {
  width: 500px;
  height: 100%;
}

.btn {
  width: 100px;
  height: 20px;
}
</style>

参考:
【前端vue——系列6】vue连接摄像头并实现摄像头暂停,计时,截图到本地等功能

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值