{"id":353219,"date":"2021-10-15T14:24:46","date_gmt":"2021-10-15T11:24:46","guid":{"rendered":"https:\/\/en.buradabiliyorum.com\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/"},"modified":"2021-10-15T14:24:46","modified_gmt":"2021-10-15T11:24:46","slug":"how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it","status":"publish","type":"post","link":"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/","title":{"rendered":"#How to Scan QR Codes in Web Browsers With Web Workers and jsQR \u2013 CloudSavvy IT"},"content":{"rendered":"<div id=\"ez-toc-container\" class=\"ez-toc-v2_0_89 counter-hierarchy ez-toc-counter ez-toc-custom ez-toc-container-direction\">\n<p class=\"ez-toc-title\" style=\"cursor:inherit\">Table of Contents<\/p>\n<label for=\"ez-toc-cssicon-toggle-item-6aee7571ef998\" class=\"ez-toc-cssicon-toggle-label\"><span class=\"\"><span class=\"eztoc-hide\" style=\"display:none;\">Toggle<\/span><span class=\"ez-toc-icon-toggle-span\"><svg style=\"fill: #dd3333;color:#dd3333\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" class=\"list-377408\" width=\"20px\" height=\"20px\" viewBox=\"0 0 24 24\" fill=\"none\"><path d=\"M6 6H4v2h2V6zm14 0H8v2h12V6zM4 11h2v2H4v-2zm16 0H8v2h12v-2zM4 16h2v2H4v-2zm16 0H8v2h12v-2z\" fill=\"currentColor\"><\/path><\/svg><svg style=\"fill: #dd3333;color:#dd3333\" class=\"arrow-unsorted-368013\" xmlns=\"http:\/\/www.w3.org\/2000\/svg\" width=\"10px\" height=\"10px\" viewBox=\"0 0 24 24\" version=\"1.2\" baseProfile=\"tiny\"><path d=\"M18.2 9.3l-6.2-6.3-6.2 6.3c-.2.2-.3.4-.3.7s.1.5.3.7c.2.2.4.3.7.3h11c.3 0 .5-.1.7-.3.2-.2.3-.5.3-.7s-.1-.5-.3-.7zM5.8 14.7l6.2 6.3 6.2-6.3c.2-.2.3-.5.3-.7s-.1-.5-.3-.7c-.2-.2-.4-.3-.7-.3h-11c-.3 0-.5.1-.7.3-.2.2-.3.5-.3.7s.1.5.3.7z\"\/><\/svg><\/span><\/span><\/label><input type=\"checkbox\"  id=\"ez-toc-cssicon-toggle-item-6aee7571ef998\" checked aria-label=\"Toggle\" \/><nav><ul class='ez-toc-list ez-toc-list-level-1 ' ><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-1\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/#1_Getting_Started\" >1. Getting Started<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-2\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/#2_Getting_a_Camera_Feed\" >2. Getting a Camera Feed<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-3\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/#3_Creating_a_Canvas\" >3. Creating a Canvas<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-4\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/#4_Adding_jsQR\" >4. Adding jsQR<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-5\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/#5_Wiring_Everything_Up\" >5. Wiring Everything Up<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-6\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/#6_jsQR_Result_Data\" >6. jsQR Result Data<\/a><\/li><li class='ez-toc-page-1 ez-toc-heading-level-2'><a class=\"ez-toc-link ez-toc-heading-7\" href=\"https:\/\/buradabiliyorum.com\/en\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr-cloudsavvy-it\/#7_Conclusion\" >7. Conclusion<\/a><\/li><\/ul><\/nav><\/div>\n<p><strong>&#8220;#How to Scan QR Codes in Web Browsers With Web Workers and jsQR \u2013 CloudSavvy IT&#8221;<\/strong><\/p>\n<div id=\"article-content-area\">\n<figure style=\"width: 1200px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" class=\"type:primaryImage size-full wp-image-14381\" srcset=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/fa4a560f.jpg?width=398&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1 400w, https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/fa4a560f.jpg?width=1198&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1 1200w\" sizes=\"auto, 400w, 1200w\" src=\"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/fa4a560f.jpg?width=1198&amp;trim=1,1&amp;bg-color=000&amp;pad=1,1\" alt=\"Photo of scanning a QR code with a smartphone\" width=\"1200\" height=\"675\" onload=\"pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\" onerror=\"this.onerror=null;pagespeed.lazyLoadImages.loadIfVisibleAndMaybeBeacon(this);\"\/><figcaption class=\"wp-caption-text\"><span class=\"type:primaryImage imagecredit\"><a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/www.shutterstock.com\/image-photo\/womens-hand-uses-mobile-phone-application-1648721011\">shisu_ka\/Shutterstock.com<\/a><\/span><\/figcaption><\/figure>\n<p>QR codes have become much more popular in recent years. They\u2019re widely used to deliver information and facilitate check-ins. While most commonly found as part of native mobile <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/download-scripts-themes-apps\/\" data-internallinksmanager029f6b8e52c=\"9\" title=\"Download Scripts &amp; Themes &amp; Apps\" target=\"_blank\" rel=\"noopener\">app<\/a>s, you can also incorporate QR scans into your websites.<\/p>\n<p>Here\u2019s how to use the popular jsQR library in combination with Web Workers to offer a high-performance QR scanning experience on the web. We\u2019ll assume you\u2019re already familiar with JavaScript basics and you\u2019ve got a functioning site which you\u2019re ready to add your code to.<\/p>\n<h2 id=\"getting-started\"><span class=\"ez-toc-section\" id=\"1_Getting_Started\"><\/span>1. Getting Started<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Begin by downloading the <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/github.com\/cozmo\/jsQR\/blob\/master\/dist\/jsQR.js\">jsQR library<\/a> in pre-compiled distributable format. Make sure it\u2019s publicly accessible on your web server; in this article, we\u2019re assuming the URL is <code>\/jsQR.js<\/code>. jsQR is also available as an npm package if you\u2019ve got a build routine configured.<\/p>\n<p>This package provides real-time detection of QR codes visible in a video stream. It retrieves the data within the code and supplies it to your application.<\/p>\n<h2 id=\"getting-a-camera-feed\"><span class=\"ez-toc-section\" id=\"2_Getting_a_Camera_Feed\"><\/span>2. Getting a Camera Feed<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The next step is to acquire a <a href=\"https:\/\/buradabiliyorum.com\/en\/category\/social-mediaa\/\" data-internallinksmanager029f6b8e52c=\"1\" title=\"Social Media\" target=\"_blank\" rel=\"noopener\">Media<\/a>Stream from the browser. Use the <code>mediaDevices<\/code> API to get a new stream from the user\u2019s camera:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"javascript\">\n<pre class=\"de1\"><span class=\"kw1\">const<\/span> getCamera <span class=\"sy0\">=<\/span> async <span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span><span class=\"sy0\">!<\/span>navigator.<span class=\"me1\">mediaDevices<\/span><span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n        <span class=\"kw1\">throw<\/span> <span class=\"kw1\">new<\/span> Error<span class=\"br0\">(<\/span><span class=\"st0\">\"mediaDevices API unavailable.\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"br0\">}<\/span>\n\u00a0\n    <span class=\"kw1\">const<\/span> devices <span class=\"sy0\">=<\/span> await navigator.<span class=\"me1\">mediaDevices<\/span>.<span class=\"me1\">enumerateDevices<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"kw1\">const<\/span> cameras <span class=\"sy0\">=<\/span> devices.<span class=\"me1\">filter<\/span><span class=\"br0\">(<\/span>d <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">(<\/span>d.<span class=\"me1\">kind<\/span> <span class=\"sy0\">===<\/span> <span class=\"st0\">\"videoinput\"<\/span><span class=\"br0\">)<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"kw1\">return<\/span> cameras<span class=\"br0\">[<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">]<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"br0\">}<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>We\u2019re selecting the first camera which is found. You could add extra logic to enable selection of a specific camera indicated by the user. In a real app, you should also improve the error handling when the <code>mediaDevices<\/code> API is unavailable. This could be because the user is in an old web browser or they\u2019ve permanently blocked the camera access permission.<\/p>\n<p>Use the <code>getCamera()<\/code> function to acquire the video stream. Attach the stream to a <code>&lt;video&gt;<\/code> element so it can be played and displayed to the user:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"html\">\n<pre class=\"de1\">&lt;video  &#13;\n    autoplay=\"true\"&#13;\n    id=\"video\"&#13;\n    muted=\"true\" \/&gt;<\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"javascript\">\n<pre class=\"de1\"><span class=\"kw1\">const<\/span> stream <span class=\"sy0\">=<\/span> await getCamera<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">const<\/span> video <span class=\"sy0\">=<\/span> document.<span class=\"me1\">getElementById<\/span><span class=\"br0\">(<\/span><span class=\"st0\">\"video\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\nvideo.<span class=\"me1\">srcObject<\/span> <span class=\"sy0\">=<\/span> stream<span class=\"sy0\">;<\/span>\nawait video.<span class=\"me1\">play<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<h2 id=\"creating-a-canvas\"><span class=\"ez-toc-section\" id=\"3_Creating_a_Canvas\"><\/span>3. Creating a Canvas<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The next step is to create a <code>canvas<\/code> element. The video data will be streamed from the camera onto the <code>canvas<\/code> where the image pixels will be extracted and fed to jsQR. The canvas needs to be sized to match the dimensions of the video stream.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"javascript\">\n<pre class=\"de1\"><span class=\"kw1\">const<\/span> videoTracks <span class=\"sy0\">=<\/span> await stream.<span class=\"me1\">getVideoTracks<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"kw1\">const<\/span> videoTrackSettings <span class=\"sy0\">=<\/span> videoTracks<span class=\"br0\">[<\/span><span class=\"nu0\">0<\/span><span class=\"br0\">]<\/span>.<span class=\"me1\">getSettings<\/span><span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"kw1\">const<\/span> canvas <span class=\"sy0\">=<\/span> document.<span class=\"me1\">createElement<\/span><span class=\"br0\">(<\/span><span class=\"st0\">\"canvas\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\ncanvas.<span class=\"me1\">height<\/span> <span class=\"sy0\">=<\/span> videoTrackSettings.<span class=\"me1\">height<\/span><span class=\"sy0\">;<\/span>\ncanvas.<span class=\"me1\">width<\/span> <span class=\"sy0\">=<\/span> videoTrackSettings.<span class=\"me1\">width<\/span><span class=\"sy0\">;<\/span>\n\u00a0\n<span class=\"kw1\">const<\/span> canvasContext <span class=\"sy0\">=<\/span> canvas.<span class=\"me1\">getContext<\/span><span class=\"br0\">(<\/span><span class=\"st0\">\"2d\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>The canvas context will be used in the next step to draw each frame of the video stream onto the canvas.<\/p>\n<h2 id=\"adding-jsqr\"><span class=\"ez-toc-section\" id=\"4_Adding_jsQR\"><\/span>4. Adding jsQR<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Add jsQR to your code next. Running jsQR in a <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/API\/Web_Workers_API\/Using_web_workers\">web worker<\/a> lets the browser delegate it to a background process, improving performance. jsQR needs to scan every video frame so running it in your main JavaScript thread can incur severe slowdowns on low-end devices.<\/p>\n<p>The main thread and your web worker can communicate using messages. Your main thread will message the jsQR worker each time a new video frame is available. The worker will inspect that frame for QR codes in its background thread, then send a message to the main thread when the frame has been processed.<\/p>\n<p>Load your worker in your main JavaScript code and add a message listener:<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"javascript\">\n<pre class=\"de1\"><span class=\"kw1\">const<\/span> qrWorker <span class=\"sy0\">=<\/span> <span class=\"kw1\">new<\/span> Worker<span class=\"br0\">(<\/span><span class=\"st0\">\"\/qr-worker.js\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\nqrWorker.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">(<\/span><span class=\"st0\">\"message\"<\/span><span class=\"sy0\">,<\/span> <span class=\"br0\">(<\/span><span class=\"br0\">{<\/span>data<span class=\"br0\">}<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">{<\/span>\n\u00a0\n    <span class=\"kw1\">if<\/span> <span class=\"br0\">(<\/span>data<span class=\"br0\">)<\/span> <span class=\"br0\">{<\/span>\n        <span class=\"co1\">\/\/ Data from QR code available <\/span>\n        <span class=\"co1\">\/\/ <\/span>\n        <span class=\"co1\">\/\/ Handle a successful scan here.<\/span>\n    <span class=\"br0\">}<\/span>\n    <span class=\"kw1\">else<\/span> <span class=\"br0\">{<\/span>\n        <span class=\"co1\">\/\/ No QR code detected in this frame<\/span>\n        <span class=\"co1\">\/\/ <\/span>\n        <span class=\"co1\">\/\/ Feed the next frame to the QR worker <\/span>\n        <span class=\"co1\">\/\/ now (this code is introduced below).<\/span>\n        tick<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>     \n    <span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"br0\">}<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>Next add <code>qr-worker.js<\/code> to your project. This needs to be publicly accessible at the URL given to the <code>Worker<\/code> constructor. Browsers will download the web worker at the time it\u2019s needed.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"javascript\">\n<pre class=\"de1\">importScripts<span class=\"br0\">(<\/span><span class=\"st0\">\"jsQR.js\"<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\nself.<span class=\"me1\">addEventListener<\/span><span class=\"br0\">(<\/span><span class=\"st0\">\"message\"<\/span><span class=\"sy0\">,<\/span> e <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">{<\/span>\n    <span class=\"kw1\">const<\/span> <span class=\"br0\">{<\/span>data<span class=\"sy0\">,<\/span> width<span class=\"sy0\">,<\/span> height<span class=\"br0\">}<\/span> <span class=\"sy0\">=<\/span> e.<span class=\"me1\">data<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"kw1\">const<\/span> qrData <span class=\"sy0\">=<\/span> jsQR<span class=\"br0\">(<\/span>data<span class=\"sy0\">,<\/span> width<span class=\"sy0\">,<\/span> height<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    self.<span class=\"me1\">postMessage<\/span><span class=\"br0\">(<\/span>qrData<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>The <code>importScripts()<\/code> function downloads the jsQR library. This call is equivalent to a <code>&lt;script&gt;<\/code> tag in your HTML but makes the script\u2019s contents available to your web worker.<\/p>\n<p>A message listener is added to receive events from your JavaScript\u2019s main thread. Each event needs to include the data, width, and height of a video frame streamed from the camera. These values are fed to jsQR which will attempt to detect a QR code within the frame. The result is posted back to the main thread.<\/p>\n<h2 id=\"wiring-everything-up\"><span class=\"ez-toc-section\" id=\"5_Wiring_Everything_Up\"><\/span>5. Wiring Everything Up<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>The final step is to create an update loop that feeds video frames to the jsQR worker periodically.<\/p>\n<div class=\"wp-geshi-highlight-wrap5\">\n<div class=\"wp-geshi-highlight-wrap4\">\n<div class=\"wp-geshi-highlight-wrap3\">\n<div class=\"wp-geshi-highlight-wrap2\">\n<div class=\"wp-geshi-highlight-wrap\">\n<div class=\"wp-geshi-highlight\">\n<div class=\"javascript\">\n<pre class=\"de1\"><span class=\"kw1\">const<\/span> updateJsQr <span class=\"sy0\">=<\/span> <span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">=&gt;<\/span> <span class=\"br0\">{<\/span>\n    canvasContext.<span class=\"me1\">drawImage<\/span><span class=\"br0\">(<\/span>video<span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> canvas.<span class=\"me1\">width<\/span><span class=\"sy0\">,<\/span> canvas.<span class=\"me1\">height<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    <span class=\"kw1\">const<\/span> imageData <span class=\"sy0\">=<\/span> canvasContext.<span class=\"me1\">getImageData<\/span><span class=\"br0\">(<\/span><span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> <span class=\"nu0\">0<\/span><span class=\"sy0\">,<\/span> canvas.<span class=\"me1\">width<\/span><span class=\"sy0\">,<\/span> canvas.<span class=\"me1\">height<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n    qrWorker.<span class=\"me1\">postMessage<\/span><span class=\"br0\">(<\/span><span class=\"br0\">{<\/span>data<span class=\"sy0\">:<\/span> imageData<span class=\"sy0\">,<\/span> height<span class=\"sy0\">:<\/span> canvas.<span class=\"me1\">height<\/span><span class=\"sy0\">,<\/span> width<span class=\"sy0\">:<\/span> canvas.<span class=\"me1\">width<\/span><span class=\"br0\">}<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n<span class=\"br0\">}<\/span>\n\u00a0\n<span class=\"kw1\">const<\/span> tick <span class=\"sy0\">=<\/span> <span class=\"br0\">(<\/span><span class=\"br0\">)<\/span> <span class=\"sy0\">=&gt;<\/span> requestAnimationFrame<span class=\"br0\">(<\/span>updateJsQr<span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span>\n\u00a0\ntick<span class=\"br0\">(<\/span><span class=\"br0\">)<\/span><span class=\"sy0\">;<\/span><\/pre>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<p>The <code>tick()<\/code> function requests the browser allocate time to calling <code>updateJsQr()<\/code> before the next repaint. This function gets the current video frame, draws it to the canvas, and then pulls out the resulting image data ready to pass to jsQR. The <code>postMessage()<\/code> method on the worker instance actually sends the data.<\/p>\n<p>The worker will then act on the data as shown in the code above. The detection result is communicated back to the main thread which processes it as shown in Step 4. When a QR code is detected, your application should use the retrieved data to move forward in its flow. When there\u2019s no detected code, <code>tick()<\/code> is called again to pass the next frame to the QR worker, ready for assessment.<\/p>\n<p>This mechanism ensures you don\u2019t end up overloading the browser by running multiple frame detections concurrently. Each call to <code>jsQR()<\/code> is potentially expensive so you want to wait until the result is known before scheduling another. The loop is only sustained until a successful result is obtained, with jsQR handling one frame at a time. Your site\u2019s UI and its real-time camera preview will remain responsive throughout as the worker runs independently in the background.<\/p>\n<h2 id=\"jsqr-result-data\"><span class=\"ez-toc-section\" id=\"6_jsQR_Result_Data\"><\/span>6. jsQR Result Data<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Each successful call to <code>jsQR()<\/code> returns a result object with the following properties:<\/p>\n<ul>\n<li><code>data<\/code> \u2013 String data extracted from the QR code (this is the only property used in the example above).<\/li>\n<li><code>binaryData<\/code> \u2013 A <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/developer.mozilla.org\/en-US\/docs\/Web\/JavaScript\/Reference\/Global_Objects\/Uint8ClampedArray\"><code>Uint8ClampedArray<\/code><\/a> containing the raw bytes read from the QR code.<\/li>\n<li><code>version<\/code> \u2013 Detected QR code version.<\/li>\n<li><code>location<\/code> \u2013 An object that <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/github.com\/cozmo\/jsQR#return-value\">describes the position<\/a> of the detected QR code within the video frame, including points for each corner.<\/li>\n<\/ul>\n<p>No data is available when jsQR fails to detect a code in the provided image.<\/p>\n<h2 id=\"conclusion\"><span class=\"ez-toc-section\" id=\"7_Conclusion\"><\/span>7. Conclusion<span class=\"ez-toc-section-end\"><\/span><\/h2>\n<p>Combining jsQR with Web Workers lets you implement high performance QR code scans in your web application. QR codes are an easy and convenient data sharing mechanism which most mobile users are now familiar with.<\/p>\n<p>Although you could use jsQR as part of your main loop, you\u2019d need to implement aggressive throttling to keep your UI responsive. This would result in a longer delay before a successful detection. Web Workers <a rel=\"nofollow noopener\" target=\"_blank\" href=\"https:\/\/caniuse.com\/webworkers\">are supported<\/a> in all modern browsers and provide a substantial performance boost to this solution, enabling split-second scans under optimal lighting conditions.\n<\/div>\n<blockquote><p><strong><span style=\"color: #ff6600;\">If you liked the article, do not forget to share it with your friends. Follow us on\u00a0<span style=\"color: #ff0000;\"><a style=\"color: #ff0000;\" href=\"https:\/\/news.google.com\/publications\/CAAqBwgKMLG0nwswvr63Aw\" target=\"_blank\" rel=\"nofollow noopener noreferrer\">Google News<\/a><\/span>\u00a0too, click on the star and choose us from your favorites.<\/span><\/strong><\/p><\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\">For forums sites go to <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/forum.buradabiliyorum.com\/\" target=\"_blank\" rel=\"noopener\">Forum.BuradaBiliyorum.Com<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<blockquote>\n<p style=\"text-align: center;\"><strong>If you want to read more like this article, you can visit our <span style=\"color: #ff9900;\"><a style=\"color: #ff9900;\" href=\"https:\/\/en.buradabiliyorum.com\/technology\/\" target=\"_blank\" rel=\"noopener\">Technology category.<\/a><\/span><\/strong><\/p>\n<\/blockquote>\n<p><span style=\"color: black;\"><a style=\"color: #ff9900;\" href=\"https:\/\/www.cloudsavvyit.com\/14380\/how-to-scan-qr-codes-in-web-browsers-with-web-workers-and-jsqr\/\" target=\"_blank\" rel=\"noopener\">Source<\/a><\/span><\/p>\n","protected":false},"excerpt":{"rendered":"<p>&#8220;#How to Scan QR Codes in Web Browsers With Web Workers and jsQR \u2013 CloudSavvy IT&#8221; shisu_ka\/Shutterstock.com QR codes have become much more popular in recent years. They\u2019re widely used to deliver information and facilitate check-ins. While most commonly found as part of native mobile apps, you can also incorporate QR scans into your websites&#8230;.<\/p>\n","protected":false},"author":1,"featured_media":353220,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"fifu_image_url":"https:\/\/www.cloudsavvyit.com\/p\/uploads\/2021\/09\/fa4a560f.jpg","fifu_image_alt":"","footnotes":""},"categories":[18],"tags":[],"class_list":["post-353219","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-technology"],"_links":{"self":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/353219","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/comments?post=353219"}],"version-history":[{"count":0,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/posts\/353219\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media\/353220"}],"wp:attachment":[{"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/media?parent=353219"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/categories?post=353219"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/buradabiliyorum.com\/en\/wp-json\/wp\/v2\/tags?post=353219"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}