Web Worker — это способ запуска JavaScript в фоновых потоках. Рабочий поток может выполнять некоторые тяжелые работы, не мешая пользовательскому интерфейсу. В этой статье рассказывается, как загрузить WebAssembly и вызвать API Dynamsoft штрих-код JavaScript в веб-воркере.

Веб-воркер для WASM

Если вы пробовали пример Dynamsoft JavaScript Barcode SDK hello world, вы должны знать, что SDK построен на основе технологии WebAssembly, которая позволяет разрабатывать веб-приложение для чтения штрих-кода на стороне клиента на чистом JavaScript. Простой пример демонстрирует, как декодировать штрих-код из входного файла.

Однако в большинстве сценариев веб-считыватель штрих-кодов обеспечивает декодирование видеопотока с камеры в режиме реального времени. Принцип создания приложения камеры — не блокировать поток пользовательского интерфейса. Если вы вызываете API штрих-кода в основном потоке JavaScript, а API требует более 100 мс для декодирования штрих-кода, пользовательский интерфейс не может отображаться плавно. Вот почему нам нужно использовать веб-воркеров.

При использовании WebAssembly загрузка и компиляция файла wasm может занять много времени. Dynamsoft предоставляет две версии штрих-кода JavaScript, созданные с разными уровнями оптимизации, которые влияют на окончательный размер файла wasm и время инициализации. В worker.js добавьте следующий код:

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');
}

Чтобы загрузить WebAssembly в iOS Safari быстрее, используйте https://demo.dynamsoft.com/dbr_wasm/js/dbr-6.3.0.1.mobile.min.js.

Инициализируйте считыватель штрих-кода:

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=";

Дождитесь события декодирования штрих-кода:

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;
}
};

В основном потоке создайте веб-воркер:

if (window.Worker) {
myWorker = new Worker('worker.js');
myWorker.onmessage = function (e) {
let data = e.data;
if (data.event) {
switch (data.event) {
case 'onload':
{
document.getElementById('anim-loading').style.display = 'none';
buttonFile.disabled = false;
buttonVideo.disabled = false;
break;
}
case 'onerror':
{
document.getElementById('anim-loading').style.display = 'none';
break
}
case 'onresult':
{
let context = clearOverlay();
let txts = [];
try {
let results = data.body;
let localization;
for (var i = 0; i < results.length; ++i) {
if (results[i].LocalizationResult.ExtendedResultArray[0].Confidence >= 30) {
txts.push(results[i].BarcodeText);
localization = results[i].LocalizationResult
if (isVideoMode) {
drawResult(context, localization, results[i].BarcodeText);
}
}
}
barcode_result.textContent = txts.join(', ');
if (isVideoMode) {
scanBarcode();
}
} catch (e) {
if (isVideoMode) {
scanBarcode();
} else {
barcode_result.textContent = data.body;
}
}
break;
}
}
}
};
}

Захватите кадр из видео и отправьте его веб-воркеру:

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
});
}
}

Draw возвращал результаты при наложении:

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);
}

Разверните проект, а затем перейдите на страницу приложения:

Исходный код

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

Первоначально опубликовано на www.codepool.biz 3 сентября 2018 г.