
This post provides is a quick-and-dirty demonstration of the LazarSoft / jsqrcode Javascript QR Code scanner library available at https://github.com/LazarSoft/jsqrcode. The HTML and JavaScript provided below is designed to show how a simple capture and decode program could be implemented using the library.
Provided the code from the GitHub repository above has been downloaded, simply copy the code posted below into an html file in the same directory. Upon loading the page the browser may ask for permission to access the camera. If not, and the stream does not appear, see the “important notes” paragraph below.
Clicking the “Capture Snapshot” button will grab a frame from the stream and write it to the snapshot canvas. Clicking the “Attempt Decode” button will then invoke the qrcode.decode() function from the jsqrcode library which will attempt to decode any image found on the <canvas id=”qr-canvas”> element.
The “Start Auto-Capture” button will automate the above by taking a series of periodic snapshots and attempting to decode each until either a successful decode occurs or the user clicks the “Stop Auto-Capture” button.
Finally, the “Stop Camera” button will stop capturing the camera stream. Reload the browser page to restart the camera.
Important notes: This code has been tested in Chrome 83 only. It should also be noted that browser security restrictions will prevent access to the camera unless the file is served from a secure https:// address or directly from the the localhost. Also, I have noticed a few decode errors in my testing, though to be fair to the library’s creator, I cannot vouch for the quality of the software used to generate those barcodes.
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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 |
<!DOCTYPE html> <html> <head> <title>QR Code Reader</title> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> canvas {background-color: lightblue} </style> <script type="text/javascript" src="grid.js"></script> <script type="text/javascript" src="version.js"></script> <script type="text/javascript" src="detector.js"></script> <script type="text/javascript" src="formatinf.js"></script> <script type="text/javascript" src="errorlevel.js"></script> <script type="text/javascript" src="bitmat.js"></script> <script type="text/javascript" src="datablock.js"></script> <script type="text/javascript" src="bmparser.js"></script> <script type="text/javascript" src="datamask.js"></script> <script type="text/javascript" src="rsdecoder.js"></script> <script type="text/javascript" src="gf256poly.js"></script> <script type="text/javascript" src="gf256.js"></script> <script type="text/javascript" src="decoder.js"></script> <script type="text/javascript" src="qrcode.js"></script> <script type="text/javascript" src="findpat.js"></script> <script type="text/javascript" src="alignpat.js"></script> <script type="text/javascript" src="databr.js"></script> </head> <body> <video id="player" controls autoplay></video> <canvas id="qr-canvas" width=320 height=240></canvas> <div> <button id="captureSnapshotButton">Capture Snapshot</button> <button id="attemptDecodeButton" disabled>Attempt Decode</button> <button id="startAutoCaptureButton">Start Auto-Capture</button> <button id="stopAutoCaptureButton">Stop Auto-Capture</button> <button id="stopCameraButton">Stop Camera</button> </div> <div id="output"><h2>Decoded value: </h2></div> <script> const canvas = document.getElementById('qr-canvas'); const context = canvas.getContext('2d'); let autoCaptureStatus = false; let decodeFailures = 0; const constraints = { video: { width: 320, height: 240 } }; showDefaultCanvas(); // Attach the video stream to the video element and autoplay. navigator.mediaDevices.getUserMedia(constraints) .then((stream) => { player.srcObject = stream; }); captureSnapshotButton.addEventListener('click', () => { // Draw the video frame to the canvas. attemptDecodeButton.disabled = false; context.drawImage(player, 0, 0, canvas.width, canvas.height); }); stopCameraButton.addEventListener('click', () => { // Stop video capture. player.srcObject.getVideoTracks().forEach(track => track.stop()); disableButtons(); autoCapture = false; output.innerHTML = '<h2 style="color:#F00">Reload page to restart camera.</h2>'; showDefaultCanvas(); }); attemptDecodeButton.addEventListener('click', () => { // Decode QR Code try { decodedValue = qrcode.decode(); console.log(decodedValue); updateOutputValue(decodedValue); autoCaptureStatus = false; } catch (err) { updateOutputValue("[Failed to decode (" + ++decodeFailures + ")]"); if (err !== "Couldn't find enough finder patterns (found 0)") { throw err; } } }); startAutoCaptureButton.addEventListener('click', () => { // Start taking snapshots to canvas autoCaptureStatus = true; decodeFailures = 0; autoCapture(); }); stopAutoCaptureButton.addEventListener('click', () => { // Stop taking snapshots to canvas autoCaptureStatus = false; }); function autoCapture() { if (autoCaptureStatus) { captureSnapshotButton.click(); attemptDecodeButton.click(); setTimeout(autoCapture, 100); } } function updateOutputValue(val) { output.innerHTML = "<h2>Decoded value: " + val + "</h2>"; } function disableButtons() { buttons = document.getElementsByTagName("button"); Array.from(buttons).map(button => button.disabled = true); } function showDefaultCanvas() { context.clearRect(0, 0, canvas.width, canvas.height); context.font = "30px Arial"; context.fillText("Snapshot Canvas", 50, 130); } </script> </body> </html> |
Thanks to LazarSoft for making this library available. Below are links to the jsqrcode GitHub repository and a Google developer document I found useful.