h5+js 拍照取景框

实现思路

1、 使用MediaDevices.getUserMedia() 方法获取摄像头媒体流,传给标签渲染

2、用标签截取当前摄像头画面,用canvas.getContext(‘2d’).drawImage()方法来绘制

3、canvas.toDataURL() 方法将图像转换为 base64 格式

代码实现

1、<video playsinline webkit-playsinline="true" ref="refVideo" id="video"
  preload="auto" muted loop autoplay x5-video-player-type="h5" x5-video-player-fullscreen x5-video-orientation="portraint" x-webkit-airplay x5-playsinline></video>
2、取景框:
<img :src="./frameImg.png" v-if="frame_type" width="100%" height="100%">
3、<canvas id="mycanvas" "></canvas>

使用 MediaDevices.getUserMedia() 方法获取摄像头媒体流,并将其传递给 标签进行渲染。


    openCamera() {
      // 1. 先展示,因为要从这里获取video标签
      this.cameraShow = true

      // 2. constraints:指定请求的媒体类型和相对应的参数
      // facingMode值:user:前置。environment:后置
      var constraints = {
        audio: false,
        video: {
          facingMode: 'environment'
        }
      }

      // 3. 兼容部分:
      // 老的浏览器可能根本没有实现 mediaDevices,所以我们可以先设置一个空的对象
      if (navigator.mediaDevices === undefined) {
        navigator.mediaDevices = {}
      }
      // 一些浏览器部分支持 mediaDevices。我们不能直接给对象设置 getUserMedia
      // 因为这样可能会覆盖已有的属性。这里我们只会在没有getUserMedia属性的时候添加它。
      if (navigator.mediaDevices.getUserMedia === undefined) {
        navigator.mediaDevices.getUserMedia = function (constraints) {
          // 首先,如果有getUserMedia的话,就获得它
          var getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia
          // 一些浏览器根本没实现它 - 那么就返回一个error到promise的reject来保持一个统一的接口
          if (!getUserMedia) {
            return Promise.reject(new Error('getUserMedia is not implemented in this browser'))
          }
          // 否则,为老的navigator.getUserMedia方法包裹一个Promise
          return new Promise(function (resolve, reject) {
            getUserMedia.call(navigator, constraints, resolve, reject)
          })
        }
      }

      // 4. 获取视频流
      let that = this
      navigator.mediaDevices.getUserMedia(constraints)
        .then(function (stream) {
          that.videostream = stream
          // 进来这里表示能够兼容
          let video = document.querySelector('video')
          video.setAttribute('playsinline', true)
          if ('srcObject' in that.$refs.refVideo) {
            that.$refs.refVideo.srcObject = stream
          } else {
            that.$refs.refVideo.src = this.URL.createObjectURL(stream)
          }

          video.srcObject = stream
          video.onloadedmetadata = function (e) {
            video.play()
            that.$refs.refVideo.play()
          }
          // 进入自定义拍摄模式
          that.status = 1
        })
        .catch(function (err) {
          that.cameraShow = false
          // 进来这里表示不能兼容
          console.log('nonono', err)
        })
    },

拍照

    // 拍照
    snapPhoto() {
      var canvas = document.querySelector('#mycanvas')
      var video = document.querySelector('video')
      // 如果有取景框,拍摄的图片需要摆正
      if (this.frame_type) {
        canvas.width = video.clientHeight
        canvas.height = video.clientWidth
        this.canvasWidth = video.clientHeight
        this.canvasHeight = video.clientWidth
        // 图像翻转
        let ctx = canvas.getContext('2d')
        var xpos = video.clientWidth / 2
        var ypos = video.clientHeight / 2
        ctx.translate(xpos, ypos)
        ctx.rotate((-90 * Math.PI) / 180)
        ctx.drawImage(video, -(video.clientWidth - video.clientHeight / 2), -video.clientWidth / 2, video.clientWidth, video.clientHeight)
      } else {
        canvas.width = video.clientWidth
        canvas.height = video.clientHeight
        this.canvasWidth = video.clientWidth
        this.canvasHeight = video.clientHeight
        canvas.getContext('2d').drawImage(video, 0, 0, video.clientWidth, video.clientHeight)
      }
      // 保存为文件
      this.imageFile = { target: { files: [this.canvasToFile(canvas)] } }

      // blob转url:用于展示
      let p = new Promise((resolve, reject) => {
        canvas.toBlob(blob => {
          let url = URL.createObjectURL(blob)
          resolve(url)
        })
      })
      let that = this
      p.then(value => {
        that.imageUrl = value
        that.status = 2 // 表示拍摄完成
      })
    },

canvas转文件


    canvasToFile(canvas) {
      var dataurl = canvas.toDataURL('image/png')
      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)
      }
      var file = new File([u8arr], 'phone.png', { type: mime })
      return file
    },

兼容性问题

1、ios进入页面黑屏
const video = document.getElementById('video')
      video.play()
      // 一般情况下,这样就可以自动播放了,但是一些奇葩iPhone机不可以
      // 必须在微信Weixin JSAPI的WeixinJSBridgeReady才能生效
      document.addEventListener(
        'WeixinJSBridgeReady',
        function () {
          video.play()
        },
        false
      )
      let videoStatue = true
      // 监听 touchstart 事件进而调用 <audio> 元素提供的 play() 方法播放音频
      document.addEventListener(
        'touchstart',
        function (e) {
          if (videoStatue) {
            video.play()
            videoStatue = false
          }
        },
        false
      )
    })
    // 启动拍摄
    this.openCamera()
2、其他兼容性问题

1、需要配置HTTPS协议才可访问
2、支付宝不支持getUserMedia
3、对焦问题:视频无法自动对焦,导致拍摄会糊

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值