背景
不久前我做了关于获取浏览器摄像头并扫码识别的功能,本文中梳理了涉及到知识点及具体代码实现,整理成此篇文章内容。
本文主要介绍,通过使用基于 vue
技术栈的前端开发技术,在浏览器端调起摄像头 📷
,并进行扫码识别功能,对识别到的二维码进行跳转或其他操作处理。本文内容分为背景介绍、实现效果、技术简介、代码实现、总结等部分组成。
实现效果
本实例中主要有两个页面首页和扫码页,具体实现效果如下图所示。
- 首页:点击
SCAN QRCODE
按钮,进入到扫码页。 - 扫码页:首次进入时,或弹出
获取摄像头访问权限的系统提示框
,点击允许访问,页面开始加载摄像头数据并开始进行二维码捕获拾取,若捕获到二维码,开始进行二维码解析,解析成功后加载识别成功弹窗。
📸
在线体验:https://dragonir.github.io/h5-scan-qrcode
📌
提示:需要在有摄像头设备的浏览器中竖屏访问。手机横竖屏检测小知识可前往我的另一篇文章《五十音小游戏中的前端知识》 中进行了解。
技术简介
WebRTC API
WebRTC (Web Real-Time Communications) 是一项实时通讯技术,它允许网络应用或者站点,在不借助中间媒介的情况下,建立浏览器之间 点对点(Peer-to-Peer)
的连接,实现视频流和(或)音频流或者其他任意数据的传输。WebRTC
包含的这些标准使用户在无需安装任何插件或者第三方的软件的情况下,创建 点对点(Peer-to-Peer)
的数据分享和电话会议成为可能。
三个主要接口:
MediaStream
:能够通过设备的摄像头及话筒获得视频、音频的同步流。RTCPeerConnection
:是WebRTC
用于构建点对点之间稳定、高效的流传输的组件。RTCDataChannel
:使得浏览器之间建立一个高吞吐量、低延时的信道,用于传输任意数据。
🔗
前往MDN
深入学习:WebRTC_API
WebRTC adapter
虽然 WebRTC
规范已经相对健全稳固了,但是并不是所有的浏览器都实现了它所有的功能,有些浏览器需要在一些或者所有的 WebRTC API
上添加前缀才能正常使用。
WebRTC
组织在 github
上提供了一个 WebRTC适配器(WebRTC adapter)
来解决在不同浏览器上实现 WebRTC
的兼容性问题。这个适配器是一个 JavaScript垫片
,它可以让你根据 WebRTC
规范描述的那样去写代码,在所有支持 WebRTC
的浏览器中不用去写前缀或者其他兼容性解决方法。
🔗
前往MDN
深入学习:WebRTC adapter
核心的API navigator.mediaDevices.getUserMedia
网页调用摄像头需要调用 getUserMedia API
,MediaDevices.getUserMedia()
会提示用户给予使用媒体输入的许可,媒体输入会产生一个 MediaStream
,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器
等等),也可能是其它轨道类型。
它返回一个 Promise
对象,成功后会 resolve
回调一个 MediaStream对象
;若用户拒绝了使用权限,或者需要的媒体源不可用,promise
会 reject
回调一个 PermissionDeniedError
或者 NotFoundError
。(返回的 promise对象
可能既不会 resolve
也不会 reject
,因为用户不是必须选择允许或拒绝。)
通常可以使用 navigator.mediaDevices
来获取 MediaDevices
,例如:
navigator.mediaDevices.getUserMedia(constraints)
.then(function(stream) {
// 使用这个stream
})
.catch(function(err) {
// 处理error
})
🔗
前往MDN
深入学习:navigator.mediaDevices.getUserMedia
二维码解析库 JSQR
jsQR
是一个纯 JavaScript
二维码解析库,该库读取原始图像或者是摄像头,并将定位,提取和解析其中的任何 QR码
。
如果要使用 jsQR
扫描网络摄像头流,则需要 ImageData
从视频流中提取,然后可以将其传递给 jsQR
。
jsQR
导出一个方法,该方法接受 4
个参数,分别是解码的 图像数据
,宽
、高
以及 可选的对象
进一步配置扫描行为。
imageData
:格式为 [r0, g0, b0, a0, r1, g1, b1, a1, ...]
的 Uint8ClampedArray( 8位无符号整型固定数组)
的 rgba
像素值。
const code = jsQR(imageData, width, height, options);
if (code) {
console.log('找到二维码!', code);
}
🔗
前往github
深入了解:jsQR
代码实现
流程
整个扫码流程如下图所示:页面初始化,先检查浏览器是否支持 mediaDevices
相关API
,浏览器进行调去摄像头,调用失败,就执行失败回调;调用成功,进行捕获视频流,然后进行扫码识别,没有扫瞄到可识别的二维码就继续扫描,扫码成功后绘制扫描成功图案并进行成功回调。
下文内容对流程进行拆分,分别实现对应的功能。
扫码组件 Scaner
页面结构
我们先看下页面结构,主要由 4
部分组成:
- 提示框。
- 扫码框。
video
:展示摄像头捕获视频流。canvas
: 绘制视频帧,用于二维码识别。
<template>
<div class="scaner" ref="scaner">
<!-- 提示框:用于在不兼容的浏览器中显示提示语 -->
<div class="banner" v-if="showBanner">
<i class="close_icon" @click="() => showBanner = false"></i>
<p class="text">若当前浏览器无法扫码,请切换其他浏览器尝试</p>
</div>
<!-- 扫码框:显示扫码动画 -->
<div class="cover">
<p class="line"></p>
<span class="square top left"></span>
<span class="square top rig