当前位置:   article > 正文

js 通过摄像头识别二维码,可以控制闪光灯。原生 HTML 调用摄像头,有 原生HTML + JS 版本 和 VUE3 + TS 版本与 uniapp 版本_js 监控手机闪光灯是否打开?

js 监控手机闪光灯是否打开?

开发背景

最开始公司说到这个需求的时候第一个想法是使用微信的 js SDK 接入微信的扫一扫。但是得知所做的这个功能模块是需要嵌入到之前开发的app中,所以就只有使用 js 原生的 API 来开发了。最后选用了 navigator.mediaDevices.getUserMedia 用来获取摄像头的视频流,通过 canvas 展示到页面上,同时获取到 canvas 生成的图片对象数据,传递个 jsQR 这个开源库进行二维码的解析。

功能开发完成之后我就在 uniapp 插件社区中,把我写的组件给发布了。发布之后大受欢迎,同时也收到了各种反馈,如:识别二维码速度过慢、识别范围小、能否有一直识别、可调用闪关灯吗等问题。后面一直在持续更新,完善了很多的功能。

之后换了一家公司也接到了类型的需求,但是没有选用 uniapp 这个技术栈,而是选用了 vue3+TS 的开发规范。没有办法只有把之前写好的组件进行了重写。

最近闲下来后,发现在网络上真正分享这个功能的文章比较少,要么说的不清不楚的,要么就还是在使用 navigator.getUserMedia 这个已经废除的 API 规范,要么就是不兼容苹果系统,还有就是大量复制的水文章。

所以决定写一篇文章来说说怎么实现这个功能,并且使用原生 js再次重写了这个功能。一下代码都使用原生 js 进行讲解。同时提供 uniappvue3+TS原生js 的 demo 下载。

demo 演示 与 下载

当前只开发手机页面版,请使用手机直接扫码查看 demo 演示。闪光灯只有在安卓系统下谷歌内核浏览器中可以控制
闪光灯只有在安卓系统下谷歌内核浏览器中可以控制
闪光灯只有在安卓系统下谷歌内核浏览器中可以控制
其他环境我是默认隐藏按钮的

地址:https://h5plugin.mumudev.top/#/pages/getQrcode/getQrcode

img

请添加图片描述
请添加图片描述

使用到的相关技术

  1. navigator.mediaDevices.getUserMedia 用于唤起摄像头,并且获取到摄像头的视频流数据

    文档地址:MediaDevices.getUserMedia()

    此 API 必须要 HTTPS 环境才能调用,所以就必须要我们的测试环境与生成环境都配置 HTTPS,测试环境如果是 VUE 或者 UNIAPP 就直接在 DEV SERVER 中进行配置就可以了,原生的话推荐使用 VS CODE 中的 Live Server 插件生成假的证书进行配置与启动服务

       "liveServer.settings.https": {
            "enable": true,
            "cert": "D:\\vsCode\\https\\example.com+5.pem", //本地证书地址
            "key": "D:\\vsCode\\https\\example.com+5-key.pem", //本地密钥地址
            "passphrase": ""
        },
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  2. jsQR.js 用于对图片中的二维码进行解析

    GitHub地址:cozmo/jsQR

    一款大佬写的开源库。

  3. canvas 标签 这个算是 HTML 基础吧

  4. viod 标签 基础中的基础

开始写代码

这里就使用原生HTML写法给大家讲解当中的核心代码,完整的mode与其他框架的代码可以在上面小程序中进行下载

完整的mode中都是封装好的代码,可直接开箱即用。

// index.html
  <div id="mumuQrcode">
    <!-- canvas 用于展示视频流与识别到的二维码位置 -->
    <canvas id='canvas'></canvas>
    <!-- 中间的扫描框 -->
    <div class="box">
      <div class="line"></div>
      <div class="angle"></div>
    </div>
  </div>

  <!-- 先引入 jsQR 库,后引入自己写的代码 -->
  <script src="./jsQR.js"></script>
  <script src="./index.js"></script>

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
// index.js

  // 判断当前是否是 https 环境
  if (origin.indexOf('https') === -1) throw '请在 https 环境中调用摄像头。'
  // 获取当前屏幕可用的宽高,用于设置全屏扫描
  const windowWidth = document.documentElement.clientWidth
  const windowHeight = document.documentElement.clientHeight

  // 获取页面上的 canvas 组件,用上面获取的宽高来设置 canvas 为全屏,并且创建出 画布
  const canvas = document.getElementById('canvas')
  canvas.width = windowWidth
  canvas.height = windowHeight
  // 创建画布
  const canvas2d = canvas.getContext('2d')

  // 创建一个 video 标签,并且设置 video 的尺寸为全屏,用于接收摄像头的数据
  const video = document.createElement('video')
  video.width = windowWidth
  video.height = windowHeight
  // 设置 video 标签不显示进度条
  video.setAttribute('playsinline', 'true')
  video.setAttribute('webkit-playsinline', 'true')

  // 设置调用摄像头的参数
  // 调用摄像头时的分辨率,摄像头的分辨率是以横屏计算的,所以要把屏幕的高度当作视频宽度,屏幕的宽度当作视频高度度,这样就可以获取到一个和手机物理分辨率一样的视频尺寸。这里是可以传递比分辨率高的数字,只要尺寸的比例是一样即可
  const width = windowHeight
  const height = windowWidth

  const videoParam = {
    audio: false,
    video: {
      facingMode: {
        /** 使用后置还是前置摄像头 后:environment  前:user*/
        exact: 'environment'
      },
      width, // 刚刚设置的宽度
      height // 刚刚设置的高度
    }
  }
  // 调用摄像头。此 api 是一个 promise
  navigator.mediaDevices.getUserMedia(videoParam).then(stream => {
    // 回调中回返回 stream 获取到的视频流数据
    // 把视频流数据给到 video 中
    video.srcObject = stream
    // 播放 video
    video.play()

    // 调用下面写的解析函数
    tick()
  })

  // 解析函数,用于截取视频每一帧来解析二维码
  function tick() {
    // 判断video中是否加载好视频流数据,只有加载好后才解析
    if (video.readyState === video.HAVE_ENOUGH_DATA) {
      // 把视频的每一帧截取画到刚刚创建的画布上
      canvas2d.drawImage(video, 0, 0, windowWidth, windowHeight)
      // 通过 canvas画布 获取到当前每一帧的 图片对象 数据
      const imageData = canvas2d.getImageData(0, 0, windowWidth, windowHeight)

      // 把 图片对象 数据交给 jsQR 这个库进行解析
      const codeRes = jsQR(imageData.data, imageData.width, imageData.height, {
        inversionAttempts: 'dontInvert'
      })

      // 判断是否获取到二维码数据
      if (codeRes && codeRes.data) {
        // codeRes.data 中就是二维码中的数据了
        console.log(codeRes.data)
        alert(codeRes.data)
      }
    }

    // 每当这个函数执行完后,马上就执行这个函数
    // requestAnimationFrame 这个方法可以百度一下
    requestAnimationFrame(tick)
  }
  • 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
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77

大功告成

进测试。发现现代中的浏览器都支持,微信内部与跨平台app中也完美调用。

不支持的浏览器有:

  1. 苹果系统下的 阿里系浏览器(UC、夸克等)

    使用的 Webkit 内核较低,而且还会抓取视频流数据,导致无法正常预先

  2. open 浏览器

    不知道具体原因,听说国内的open没有采用他自己的内核

  3. IE

    IE就不多说了

附带一张兼容图
请添加图片描述

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小惠珠哦/article/detail/964119
推荐阅读
相关标签
  

闽ICP备14008679号