HTML5 QR Code scanning with javascript - launched v1.0.1
- Edit 1 (14th June 2021)
- Introduction
- Demo
- How to use
- Changelog in v1.0.0
- Cross-platform support - Legends
- Existing issues and plan to fix them
- How to contribute
- License and Credits
- Updates to this article
In 2015 I had written an HTML5 based QR code scanning library as a jQuery extension. Recently I realized there was some consistent traffic on my Github Project and the demo page. As I dug more into what was going on and I was embarrassed to see the poor design and obsolete support to the latest HTML APIs around Camera. I recently fixed some of the issues and refactored the javascript library that is now independent of jQuery library and supports Promise
based APIs. In this article I’ll explain how to use the new version of the library, some changes and reasons for them and existing issues and plan to fix them. To callout loud, the major changes are:
- Removed jQuery dependency
- Refactored the APIs to return Promise rather than being purely based on callbacks.
Edit 1 (14th June 2021)
Lot of things have changed since v1.0.1
and latest release for the library is v2.0.9
- Please visit QR and barcode scanner using HTML and Javascript for latest content.
Introduction
QR Code is a very common technique of encoding information as images. Its a very common used in physical stores for identifying products like bar code is used.
Figure: A sample QR code
The javascript library available at mebjas/html5-qrcode on Github allows users to add a QR code scanner in their web applications. It works cross-platform and across different devices like PC, Mac or smartphones. It uses the stream
from the camera and try to decode frames at a certain frequency (configurable) and notify the caller about results via callbacks. Requesting camera permissions in browsers usually results in a permission dialog popup to users for requesting permissions and can only be used if the user grants them.
Figure: Sample permission flow triggered by Chrome browser on Mac
Demo
A demo for this project is hosted at https://blog.minhazav.dev/research/html5-qrcode.html
How to use
Download the Javascript code or use the Github version
The code is hosted at mebjas/html5-qrcode on Github. You can download the library and add it to your codebase from release page or use it directly like:
<script src="https://raw.githubusercontent.com/mebjas/html5-qrcode/master/minified/html5-qrcode.min.js"></script>
I highly recommend using the minified version for the following reasons:
- It’s smaller in size and would load faster.
- The actual code
html5-qrcode.js
is written using ECMAScript which is supported only in the latest browsers. It may not be supported in older browsers. The minified script has been transpiled usingBabel
.
Not recommended If you still wish to use the non-minified library, try including these:
<script src="./jsqrcode-combined.js"></script>
<script src="./html5-qrcode.js"></script>
Add a palceholder element in HTML
<div id="reader"></div>
Add an empty HTML element at the appropriate position in your HTML code, give it an id
. The library uses this element to insert some hidden HTML elements which shows up as a viewfinder (camera input is shown in this HTML element) to the user performing QR code scan.
Enumerate all available cameras
The Html5Qrcode
exposes a static
method to enumerate all supported cameras in the device. Calling this method would trigger user permissions as these permissions are required to get the name of the cameras in certain browsers. This method returns a Promise with a list of supported cameras.
// This method will trigger user permissions
Html5Qrcode.getCameras().then(devices => {
/**
* devices would be an array of objects of type:
* { id: "id", label: "label" }
*/
if (devices && devices.length) {
var cameraId = devices[0].id;
// .. use this to start scanning.
}
}).catch(err => {
// handle err
});
The returned object is an Array
of Object
with the following fields:
id
: Id of the camera. This is needed to start scanning the QR Code.label
: Label for the camera. This is human-readable name for the camera device likeFront Camera
orBack Camera
.
Once you have cameraId
you can perform start/stop operations
Starting the camera implicitly starts QR Code scanning. It runs at a certain fps
(frame per seconds) provided in configuration
argument. This is an optional field and by default the scanner runs at 2 fps.
To start
scanning you need to create an instance of Html5Qrcode
and call start()
API. This method returns a Promise
which succeeds when QR Code scanning starts: Real-time feed starts to show up and QR code scanning starts. When the code is detected the callback qrCodeSuccessCallback
is called and when its not detected, the qrCodeErrorCallback
callback is called.
// Create instance of the object. The only argument is the "id" of HTML element created above.
const html5QrCode = new Html5Qrcode("reader");
html5QrCode.start(
cameraId, // retreived in the previous step.
{
fps: 10, // sets the framerate to 10 frame per second
qrbox: 250 // sets only 250 X 250 region of viewfinder to
// scannable, rest shaded.
},
qrCodeMessage => {
// do something when code is read. For example:
console.log(`QR Code detected: ${qrCodeMessage}`);
},
errorMessage => {
// parse error, ideally ignore it. For example:
console.log(`QR Code no longer in front of camera.`);
})
.catch(err => {
// Start failed, handle it. For example,
console.log(`Unable to start scanning, error: ${err}`);
});
Extra optional configuration
in start()
method
The configuration argument in start()
method can effect both scanning behavior and UI. There are two optional properties right now, if you don’t want them you can just pass an empty Object like {}
.
fps
- Integer, Example = 10
Also known as frame per seconds, the default value for this is 2
but it can be increased to get faster scanning. Increasing to a very high value could affect performance. Value >1000
will simply fail. Ideal value for this could be 10
.
qrbox
- Integer, Example = 250
Use this property to limit the region of the viewfinder you want to use for scanning. The rest of the viewfinder would be shaded and ignored by the QR code scanner. For example by passing config { qrbox : 250 }
, the screen will look like:
This is an optional property, if nothing is passed, the scanner will scan the entire region of the viewfinder.
To stop scanning, use stop() method
The stop()
member method in Html5Qrcode
returns a Promise
which finishes when the video feed is closed and held resources are released.
html5QrCode.stop().then(ignore => {
// QR Code scanning is stopped.
console.log("QR Code scanning stopped.");
}).catch(err => {
// Stop failed, handle it.
console.log("Unable to stop scanning.");
});
This should only be called after QR Code has been started successfully.
For more clarity I have dumped the javascript
code used in demo in this public gist.
This code uses jQuery but it’s not really needed.
Changelog in v1.0.0
- Removed
jQuery
dependency - Refactored the library to
Promise
based APIs. - Refactored the code to ECMAScript
- Merged
Babel
transpiled minifed library withjsqrcode
to a single52Kb
library.
Cross-platform support
I am working on adding support for more and more platforms. If you find a platform or browser where the library is not working please feel free to file an issue. Check the demo link to test out.
Legends
Means supported
Means work in progress to add support
Windows / Mac OS
![]() Firefox |
![]() Chrome |
![]() Safari |
![]() Opera |
![]() Edge |
---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
Android
![]() Chrome |
![]() Firefox |
![]() Edge |
![]() Opera |
![]() Opera Mini |
![]() UC |
---|---|---|---|---|---|
![]() |
![]() |
![]() |
![]() |
![]() |
![]() |
IOS
![]() Safari |
![]() Chrome |
![]() Firefox |
![]() Edge |
---|---|---|---|
![]() |
![]() |
![]() |
![]() |
Apparently, Webkit for IOS is used by Chrome, Firefox, and other browsers in IOS and they do not have webcam permissions yet. There is an ongoing issue on fixing the support for iOS - issue/14
Existing issues and plan to fix them
In milestore/v1.0.1 I plan to fix compatibility issues with Opera
browser and IOS
based browsers.
Some open issues are:
- [Blocked] issue/14 Fix camera query issue in IOS browsers - Chrome, Mozilla, Edge, Opera.
Blocked by pending support for camera in Webkit for IOS.
- [FIXED]
issue/14 - Fix stuck camera issues in IOS Safari - issue/13 - Fix camera query issue in Android Opera Mini
- [FIXED]
issue/16 - Fix Camera Query issue in Mac OS Opera browser
How to contribute
If you are excited or interested you can contribute to this project by:
- If you find compatibility issues with certain browser, create an issue here.
- Raising issues for bugs faced, at Github issue page for the project. Feel free to add some related interesting discussions which could be taken up as work-item.
- Sending a Pull Request for bugs fixed by you.
- Rating the project with stars and shares.
License and Credits
- The library is released under Apache License, Version 2.0.
- The decoder used for the QRcode reading is from
LazarSoft
- LazarSoft/jsqrcode.
Updates to this article
14th June 2021
- QR and barcode scanner using HTML and Javascript18th April 2020
- Added support for local file scanning and using default camera on smartphones
Want to read more such similar contents?
I like to write articles on topic less covered on internet. They revolve around writing fast algorithms, image processing as well as general software engineering.
I publish many of them on Medium.
If you are already on medium - Please join 4200+ other members and Subscribe to my articles to get updates as I publish.
If you are not on Medium - Medium has millions of amazing articles from 100K+ authors. To get access to those, please join using my referral link. This will give you access to all the benefits of Medium and Medium shall pay me a piece to support my writing!
Thanks!