How to use Web Worker to optimize the application of web bar code recognition

Posted by gdogfunk on Thu, 02 Jan 2020 05:31:04 +0100

Now the mainstream browsers all support WebRTC, through getUserMedia, you can easily open the camera in the browser. Web developers can use JavaScript to develop barcode scanning applications for web pages. Through the tests of chrome and safari, it is found that when JS code takes a lot of time, the video in Chrome is still smooth, while Safari is seriously stuck. It is speculated that Chrome's video rendering and JavaScript are not in the same thread, but if you want to draw the UI through canvas, there will still be a jam. To solve this problem, we can put the time-consuming and computational code into the web worker.

Using Web Worker to load and execute JavaScript barcode recognition library

The detection interface of barcode may take hundreds of milliseconds, so this part is put into the web worker. It's used here Dynamsoft WebAssembly Barcode SDK.

Create worker.js and import JavaScript barcode recognition library:

function browserRedirect() {
    var deviceType;
    var sUserAgent = navigator.userAgent.toLowerCase();
    var bIsIpad = sUserAgent.match(/ipad/i) == "ipad";
    var bIsIphoneOs = sUserAgent.match(/iphone os/i) == "iphone os";
    var bIsMidp = sUserAgent.match(/midp/i) == "midp";
    var bIsUc7 = sUserAgent.match(/rv:1.2.3.4/i) == "rv:1.2.3.4";
    var bIsUc = sUserAgent.match(/ucweb/i) == "ucweb";
    var bIsAndroid = sUserAgent.match(/android/i) == "android";
    var bIsCE = sUserAgent.match(/windows ce/i) == "windows ce";
    var bIsWM = sUserAgent.match(/windows mobile/i) == "windows mobile";
    if (bIsIpad || bIsIphoneOs || bIsMidp || bIsUc7 || bIsUc || bIsAndroid || bIsCE || bIsWM) {
      deviceType = 'phone';
    } else {
      deviceType = 'pc';
    }
    return deviceType;
}
 
if (browserRedirect() === 'pc') {
    importScripts('https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.min.js');
}
else {
    importScripts('https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.mobile.min.js');
}

Due to the performance gap between desktop and mobile devices, different versions can be loaded.

Initialize barcode recognition library:

var reader;
var dynamsoft = self.dynamsoft || {};
dynamsoft.dbrEnv = dynamsoft.dbrEnv || {};
dynamsoft.dbrEnv.resourcesPath = 'https://demo.dynamsoft.com/dbr_wasm/js/';
 
dynamsoft.dbrEnv.onAutoLoadWasmSuccess = function () {
    reader = new dynamsoft.BarcodeReader();
    postMessage({
        event: "onload",
        body: "Successfully loaded wasm."
    });
};
dynamsoft.dbrEnv.onAutoLoadWasmError = function (status) {
    postMessage({
        event: "onerror",
        body: "Failed to load wasm."
    });
};
//https://www.dynamsoft.com/CustomerPortal/Portal/TrialLicense.aspx
dynamsoft.dbrEnv.licenseKey = "t0068MgAAAD2IrA1WJjiVx78RfaZ46qMyCY8DaqpvAD57z5QWkwVQkVwZEf7lE+M2QYbnPx9Fu/aFvCL1mz0Kh2YK0milUng=";

Identify and decode the video image sent by JS main thread:

onmessage = function (e) {
    e = e.data;
    switch (e.type) {
        case "decodeBuffer":
            {
                self.reader.decodeBuffer(e.body, e.width, e.height, e.width * 4, dynamsoft.BarcodeReader.EnumImagePixelFormat.IPF_ARGB_8888).then(results => {
                    postMessage({
                        event: 'onresult',
                        body: results
                    });
                }).catch(ex => {
                    postMessage({
                        event: 'onresult',
                        body: 'No barcode detected'
                    });
                });
                break;
            }
        default:
            break;
    }
};

Get the sending video frame in the main thread:

function scanBarcode() {
 
  let context = ctx,
    width = videoWidth,
    height = videoHeight;
 
  context.drawImage(videoElement, 0, 0, width, height);
  var barcodeCanvas = document.createElement("canvas");
  barcodeCanvas.width = width;
  barcodeCanvas.height = height;
  var barcodeContext = barcodeCanvas.getContext('2d');
  barcodeContext.drawImage(videoElement, 0, 0, width, height);
  // read barcode
  if (myWorker) {
    myWorker.postMessage({
      type: 'decodeBuffer',
      body: barcodeContext.getImageData(0, 0, width, height).data,
      width: width,
      height: height
    });
  }
}

Finally, draw the results:

function drawResult(context, localization, text) {
  context.beginPath();
  context.moveTo(localization.X1, localization.Y1);
  context.lineTo(localization.X2, localization.Y2);
  context.lineTo(localization.X3, localization.Y3);
  context.lineTo(localization.X4, localization.Y4);
  context.lineTo(localization.X1, localization.Y1);
  context.stroke();
 
  context.font = "18px Verdana";
  context.fillStyle = '#ff0000';
  let x = [localization.X1, localization.X2, localization.X3, localization.X4];
  let y = [localization.Y1, localization.Y2, localization.Y3, localization.Y4];
  x.sort(function (a, b) {
    return a - b
  });
  y.sort(function (a, b) {
    return b - a
  });
  let left = x[0];
  let top = y[0];
 
  context.fillText(text, left, top + 50);
}

Run in browser:

Source Code

https://github.com/dynamsoft-dbr/javascript-barcode/tree/master/examples/webworker

Topics: Javascript Windows Mobile Android