純web端實現二維碼識別

暴走的snail發表於2019-05-06

前言

最近公司的業務場景中有個生成二維碼和識別二維碼的需求。生成二維碼之前有做過,選用的 qrcode.js這個前端庫,操作比較簡單。這裡不再贅述。 剛開始看到二維識別這個需求覺得很簡單,以為有相應的前端庫直接用就行了。但當真正開始寫功能時,發現二維識別會涉及到很多其他的功能。廢話不再多說,還是來看看如何實現的吧。

實現流程

純web端實現二維碼識別

  • 呼叫攝像頭

    通過瀏覽器呼叫攝像頭在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');
                let test = $('#source');
                $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截圖功能等等一系列問題。所以下次再遇到自己未接觸過的需求,就需要有充分的調研,詳細的分析的需求的難點。

相關文章