纯web端实现二维码识别

11,954 阅读3分钟

前言

最近公司的业务场景中有个生成二维码和识别二维码的需求。生成二维码之前有做过,选用的 qrcode.js这个前端库,操作比较简单。这里不再赘述。 刚开始看到二维识别这个需求觉得很简单,以为有相应的前端库直接用就行了。但当真正开始写功能时,发现二维识别会涉及到很多其他的功能。废话不再多说,还是来看看如何实现的吧。

实现流程

  • 调用摄像头

    通过浏览器调用摄像头在h5中已经有个属性可以兼容大部分平台了。 navigator.getUserMedia = navigator.mediaDevices.getUserMedia || navigator.mediaDevices.webkitGetUserMedia || navigator.mediaDevices..mozGetUserMedia; 我们来看下mdn中的介绍: MediaDevices.getUserMedia()会提示用户给予使用媒体输入的许可,媒体输入会产生一个MediaStream,里面包含了请求的媒体类型的轨道。此流可以包含一个视频轨道(来自硬件或者虚拟视频源,比如相机、视频采集设备和屏幕共享服务等等)、一个音频轨道(同样来自硬件或虚拟音频源,比如麦克风、A/D转换器等等),也可能是其它轨道类型。它返回一个 Promise 对象,成功后会resolve回调一个 MediaStream 对象。若用户拒绝了使用权限,或者需要的媒体源不可用,promise会reject回调一个 PermissionDeniedError 或者 NotFoundError 。查看详情 也就是说这个属性的返回值中我们可以获取摄像头正在拍摄的视频流动。

  • 获取视频流并显示在video 视频流通过getUserMedia已经可以获取到接下需要把他放到video中:

let option = {
                    width: 1280,
                    height: 720
                }
if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
                            navigator.mediaDevices.getUserMedia({
                                video: option
                            }).then(function(stream) {
                              //将视频流实时播放在video
                                self.$refs.video.srcObject = stream
                                self.$refs.video.style.display = 'block'
                                //截取video内容
                                setTimeout(() => {
                                    self.screenShot()
                                }, 2000);
                            }).catch(function(err) {
                                alert(err);
                            });
                } else if (navigator.getUserMedia) {
                    navigator.getUserMedia({
                        video: true
                    }).then(function(stream) {
                        self.$refs.video.srcObject = stream
                        self.$refs.video.style.display = 'block'
                        setTimeout(() => {
                            self.screenShot()
                        }, 2000);
                    }).catch(function(err) {
                        alert(err);
                    });
                }
  • canvas实现截图

当录像正常显示时,我们可以实时的进行截图。b

                let $canvas = $('canvas');
                let $video = $('video');
                $canvas.attr({
                    width: $video.width(),
                    height: $video.height(),
                })
                let ctx = $canvas[0].getContext('2d');
                ctx.drawImage($video[0], 0, 0, $video.width(), $video.height());
                let base64 = $canvas[0].toDataURL('images/png');
                //截图成功对图片进行识别
                this.decodeQrcode(base64)
  • 图片识别(判断是否是二维码)

使用二维码识别库reqrcode.js,识别截取的视频图片,如果失败则继续截图重新识别


decodeQrcode(base64) {
                let self = this
                // $('#screenshot_img').attr('src', base64)
                qrcode.decode(base64)
                qrcode.callback = function(imgMsg) {
                    if (!self.visible) {
                        return
                    }
                    if (imgMsg == 'error decoding QR Code') {
                        setTimeout(function() {
                        //截图重新识别
                            self.screenShot()
                        }, 2000)
                    } else {
                        alert(imgMsg)
                        window.location.href = imgMsg
                    }
                }
                // }
            }
  • 获取识别内容

识别成功获取二维码内容

总结

最后二维码功能虽然实现了,但是远远超过我的预估时间,这里原因大部分是因为二维码识别不仅仅需要识别二维码这一功能。在识别前我们需要实现JavaScript调用摄像头功能,canvas截图功能等等一系列问题。所以下次再遇到自己未接触过的需求,就需要有充分的调研,详细的分析的需求的难点。