UNPKG

scandit-sdk

Version:

Scandit Barcode Scanner SDK for the Web

584 lines 23.8 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); /** * @hidden * @returns Engine */ // tslint:disable-next-line:max-func-body-length function engine() { var scanQueue = []; var parseQueue = []; var gpuAccelerationAvailable = typeof self.OffscreenCanvas === "function"; var browserName; var imageBufferPointer; var licenseKey; var settings; var imageSettings; var scanWorkSubmitted = false; var fileSystemSynced = false; var runtimeLoaded = false; var wasmReady = false; var scannerSettingsReady = false; var scannerImageSettingsReady = false; var contextAvailable = false; var fsSyncInProgress; var fsSyncScheduled = false; // Public // Promise is used only during testing function loadLibrary(deviceId, libraryLocation, locationPath, deviceModelName, uaBrowserName) { function start() { if (!wasmReady && fileSystemSynced && runtimeLoaded) { wasmReady = true; Module.callMain(); postMessage(["status", "ready"]); workOnScanQueue(); workOnParseQueue(); } } var _a = getLibraryLocationURIs(libraryLocation), jsURI = _a.jsURI, wasmURI = _a.wasmURI; Module = { arguments: [deviceId], canvas: gpuAccelerationAvailable ? new self.OffscreenCanvas(32, 32) : /* istanbul ignore next */ undefined, instantiateWasm: function (importObject, successCallback) { // wasmJSVersion is globally defined inside scandit-engine-sdk.min.js var wasmJSVersion = self.wasmJSVersion; // istanbul ignore if if (wasmJSVersion == null) { wasmJSVersion = "undefined"; } // istanbul ignore if if (wasmJSVersion !== "4.6.1") { console.error("The Scandit SDK Engine library JS file found at " + jsURI + " seems invalid: " + ("expected version doesn't match (received: " + wasmJSVersion + ", expected: " + "4.6.1" + "). ") + "Please ensure the correct Scandit SDK Engine file (with correct version) is retrieved."); } if (typeof self.WebAssembly.instantiateStreaming === "function") { instantiateWebAssemblyStreaming(importObject, wasmURI, successCallback); } else { instantiateWebAssembly(importObject, wasmURI, successCallback); } return {}; }, noInitialRun: true, preRun: function () { try { FS.mkdir("/scandit_sync_folder"); } catch (error) { // istanbul ignore next if (error.code !== "EEXIST") { throw error; } } FS.mount(IDBFS, {}, "/scandit_sync_folder"); FS.syncfs(true, function () { fileSystemSynced = true; start(); }); }, onRuntimeInitialized: function () { runtimeLoaded = true; start(); } }; browserName = uaBrowserName; self.window = self.document = self; // Fix some Emscripten quirks self.path = locationPath; // Used by the Scandit SDK Engine library self.deviceModelName = deviceModelName; // Used by the Scandit SDK Engine library function tryImportScripts() { try { var importScriptsResults = importScripts(jsURI); // istanbul ignore else if (importScriptsResults != null) { return importScriptsResults; } else { return Promise.resolve(); } } catch (error) { return Promise.reject(error); } } return retryWithExponentialBackoff(tryImportScripts, 250, 4000, function (error) { console.warn(error); console.warn("Couldn't retrieve Scandit SDK Engine library at " + jsURI + ", retrying..."); }).catch(function (error) { console.error(error); console.error("Couldn't retrieve Scandit SDK Engine library at " + jsURI + ", did you configure the path for it correctly?"); return Promise.resolve(error); // Promise is used only during testing }); } function createContext(newLicenseKey) { licenseKey = newLicenseKey; if (contextAvailable || licenseKey == null || !wasmReady) { return; } var licenseKeyLength = Module.lengthBytesUTF8(licenseKey) + 1; var licenseKeyPointer = Module._malloc(licenseKeyLength); Module.stringToUTF8(licenseKey, licenseKeyPointer, licenseKeyLength); Module._create_context(licenseKeyPointer, false); Module._free(licenseKeyPointer); contextAvailable = true; postMessage([ "license-features", { hiddenScanditLogoAllowed: Module._can_hide_logo() === 1 } ]); } function setSettings(newSettings) { settings = newSettings; applySettings(); } function setImageSettings(newImageSettings) { imageSettings = newImageSettings; applyImageSettings(); } function augmentErrorInformation(error) { if (error.errorCode === 260) { var hostname = void 0; // istanbul ignore if if (location.href != null && location.href.indexOf("blob:null/") === 0) { hostname = "localhost"; } else { hostname = new URL(location.pathname != null && location.pathname !== "" && !location.pathname.startsWith("/") ? /* istanbul ignore next */ location.pathname : location.origin).hostname; } // istanbul ignore next if (hostname[0].startsWith("[") && hostname.endsWith("]")) { hostname = hostname.slice(1, -1); } error.errorMessage = error.errorMessage.replace("domain name", "domain name (" + hostname + ")"); } } function processScanWorkUnit(currentScanWorkUnit) { if (currentScanWorkUnit.highQualitySingleFrameMode) { applySettings(true); } var resultData = scanImage(currentScanWorkUnit.data); if (currentScanWorkUnit.highQualitySingleFrameMode) { applySettings(false); } var result = JSON.parse(resultData); // Important! We transfer data back even if we don't use it on the receiving end on Firefox. // Not doing so can result in memory and stability issues. // https://developer.mozilla.org/en-US/docs/Web/API/Transferable // https://developer.mozilla.org/en-US/docs/Web/API/Worker/postMessage var postMessageTransfer = browserName === "Firefox" ? [currentScanWorkUnit.data.buffer] : undefined; if (result.error != null) { augmentErrorInformation(result.error); postMessage([ "work-error", { requestId: currentScanWorkUnit.requestId, error: result.error } ], postMessageTransfer); } else { // istanbul ignore else if (result.scanResult != null) { if (result.scanResult.length > 0 || fsSyncInProgress == null) { syncFS(); } postMessage([ "work-result", { requestId: currentScanWorkUnit.requestId, result: result } ], postMessageTransfer); } else { console.error("Unrecognized Scandit Engine result:", result); postMessage([""], postMessageTransfer); } } } function workOnScanQueue() { if ((!scannerSettingsReady || !scannerImageSettingsReady) && scanQueue.length !== 0) { // First submitted work unit createContext(licenseKey); applySettings(); applyImageSettings(); } if (!scannerSettingsReady || !scannerImageSettingsReady || scanQueue.length === 0) { return; } while (scanQueue.length !== 0) { processScanWorkUnit(scanQueue.shift()); } } function processParseWorkUnit(parseWorkUnit) { var resultData = parseString(parseWorkUnit.dataFormat, parseWorkUnit.dataString, parseWorkUnit.options); var result = JSON.parse(resultData); if (result.error != null) { augmentErrorInformation(result.error); postMessage([ "parse-string-error", { requestId: parseWorkUnit.requestId, error: result.error } ]); } else { // istanbul ignore else if (result.result != null) { postMessage([ "parse-string-result", { requestId: parseWorkUnit.requestId, result: result.result } ]); } else { console.error("Unrecognized Scandit Parser result:", result); postMessage([ "parse-string-error", { requestId: parseWorkUnit.requestId, error: { errorCode: -1, errorMessage: "Unknown Scandit Parser error" } } ]); } } } function workOnParseQueue() { if (!contextAvailable && parseQueue.length !== 0) { // First submitted work unit createContext(licenseKey); } if (!contextAvailable || !wasmReady || parseQueue.length === 0) { return; } while (parseQueue.length !== 0) { processParseWorkUnit(parseQueue.shift()); } syncFS(); } function addScanWorkUnit(scanWorkUnit) { scanWorkSubmitted = true; scanQueue.push(scanWorkUnit); workOnScanQueue(); } function addParseWorkUnit(parseWorkUnit) { parseQueue.push(parseWorkUnit); workOnParseQueue(); } function clearSession() { if (scannerSettingsReady) { Module._scanner_session_clear(); } } // Private function retryWithExponentialBackoff(handler, backoffMs, maxBackoffMs, singleTryRejectionCallback) { return new Promise(function (resolve, reject) { handler() .then(resolve) .catch(function (error) { var newBackoffMs = backoffMs * 2; if (newBackoffMs > maxBackoffMs) { return reject(error); } singleTryRejectionCallback(error); setTimeout(function () { retryWithExponentialBackoff(handler, newBackoffMs, maxBackoffMs, singleTryRejectionCallback) .then(resolve) .catch(reject); }, backoffMs); }); }); } function getLibraryLocationURIs(libraryLocation) { var cdnURI = false; if (/^https?:\/\/([^\/.]*\.)*cdn.jsdelivr.net\//.test(libraryLocation)) { libraryLocation = "https://cdn.jsdelivr.net/npm/scandit-sdk@4.6.1/build/"; cdnURI = true; } else if (/^https?:\/\/([^\/.]*\.)*unpkg.com\//.test(libraryLocation)) { libraryLocation = "https://unpkg.com/scandit-sdk@4.6.1/build/"; cdnURI = true; } if (cdnURI) { return { jsURI: libraryLocation + "scandit-engine-sdk.min.js", wasmURI: libraryLocation + "scandit-engine-sdk.wasm" }; } return { jsURI: libraryLocation + "scandit-engine-sdk.min.js?v=4.6.1", wasmURI: libraryLocation + "scandit-engine-sdk.wasm?v=4.6.1" }; } function arrayBufferToHexString(arrayBuffer) { return Array.from(new Uint8Array(arrayBuffer)) .map(function (byteNumber) { var byteHex = byteNumber.toString(16); return byteHex.length === 1 ? /* istanbul ignore next */ "0" + byteHex : byteHex; }) .join(""); } function applySettings(highQualitySingleFrameMode) { if (highQualitySingleFrameMode === void 0) { highQualitySingleFrameMode = false; } if (settings == null || !contextAvailable || !wasmReady || !scanWorkSubmitted) { return; } scannerSettingsReady = false; var parsedSettings = JSON.parse(settings); var settingsLength = Module.lengthBytesUTF8(settings) + 1; var settingsPointer = Module._malloc(settingsLength); Module.stringToUTF8(settings, settingsPointer, settingsLength); var resultPointer = Module._scanner_settings_new_from_json(settingsPointer, parsedSettings.blurryRecognition, parsedSettings.matrixScanEnabled, highQualitySingleFrameMode, gpuAccelerationAvailable && parsedSettings.gpuAcceleration); Module._free(settingsPointer); var result = Module.UTF8ToString(resultPointer); if (result !== "") { scannerSettingsReady = true; console.debug(JSON.parse(result)); } } function applyImageSettings() { if (imageSettings == null || !wasmReady || !scanWorkSubmitted) { return; } scannerImageSettingsReady = false; var channels; // TODO: For now it's not possible to use imported variables as the worker doesn't have access at runtime if (imageSettings.format.valueOf() === 1) { // RGB_8U channels = 3; } else if (imageSettings.format.valueOf() === 2) { // RGBA_8U channels = 4; } else { // GRAY_8U channels = 1; } Module._scanner_image_settings_new(imageSettings.width, imageSettings.height, channels); if (imageBufferPointer != null) { Module._free(imageBufferPointer); imageBufferPointer = undefined; } imageBufferPointer = Module._malloc(imageSettings.width * imageSettings.height * channels); scannerImageSettingsReady = true; } function scanImage(imageData) { Module.HEAPU8.set(imageData, imageBufferPointer); return Module.UTF8ToString(Module._scanner_scan(imageBufferPointer)); } function parseString(dataFormat, dataString, options) { var dataStringLength = Module.lengthBytesUTF8(dataString) + 1; var dataStringPointer = Module._malloc(dataStringLength); Module.stringToUTF8(dataString, dataStringPointer, dataStringLength); var optionsLength = Module.lengthBytesUTF8(options) + 1; var optionsPointer = Module._malloc(optionsLength); Module.stringToUTF8(options, optionsPointer, optionsLength); var resultPointer = Module._parser_parse_string(dataFormat.valueOf(), dataStringPointer, dataStringLength - 1, optionsPointer); Module._free(dataStringPointer); Module._free(optionsPointer); return Module.UTF8ToString(resultPointer); } function verifiedWasmFetch(wasmURI, awaitFullResponse) { function verifyResponseData(responseData) { // istanbul ignore else if (crypto.subtle != null && typeof crypto.subtle === "object" && typeof crypto.subtle.digest === "function") { crypto.subtle.digest("SHA-256", responseData).then(function (hash) { var hashString = arrayBufferToHexString(hash); // istanbul ignore if if (hashString !== "5b0d98f64fbb1ae195263e35d905f965a2cafec2f48f1125337a62f8236c75f1") { console.error("The Scandit SDK Engine library WASM file found at " + wasmURI + " seems invalid: " + ("expected file hash doesn't match (received: " + hashString + ", ") + ("expected: " + "5b0d98f64fbb1ae195263e35d905f965a2cafec2f48f1125337a62f8236c75f1" + "). ") + "Please ensure the correct Scandit SDK Engine file (with correct version) is retrieved."); } }); } else { console.warn("Insecure origin (see https://goo.gl/Y0ZkNV): " + ("The hash of the Scandit SDK Engine library WASM file found at " + wasmURI + " could not be verified")); } } function tryFetch() { return new Promise(function (resolve, reject) { fetch(wasmURI) .then(function (response) { // istanbul ignore else if (response.ok) { response .clone() .arrayBuffer() .then(function (responseData) { if (awaitFullResponse) { resolve(response); } verifyResponseData(responseData); }) .catch( // istanbul ignore next function (error) { if (awaitFullResponse) { reject(error); } }); if (!awaitFullResponse) { resolve(response); } } else { reject(new Error("HTTP status code is not ok")); } }) .catch(function (error) { reject(error); }); }); } return retryWithExponentialBackoff(tryFetch, 250, 4000, function (error) { console.warn(error); console.warn("Couldn't retrieve Scandit SDK Engine library at " + wasmURI + ", retrying..."); }).catch(function (error) { console.error(error); console.error("Couldn't retrieve/instantiate Scandit SDK Engine library at " + wasmURI + ", " + "did you configure the path for it correctly?"); return Promise.reject(error); }); } function instantiateWebAssembly(importObject, wasmURI, successCallback) { verifiedWasmFetch(wasmURI, true) .then(function (response) { return response.arrayBuffer(); }) .then(function (bytes) { return self.WebAssembly.instantiate(bytes, importObject) .then(function (results) { successCallback(results.instance); }) .catch(function (error) { console.error(error); console.error("Couldn't instantiate Scandit SDK Engine library at " + wasmURI + ", " + "did you configure the path for it correctly?"); }); }) .catch( /* istanbul ignore next */ function () { // Ignored }); } function instantiateWebAssemblyStreaming(importObject, wasmURI, successCallback) { verifiedWasmFetch(wasmURI, false) .then(function (response) { self.WebAssembly.instantiateStreaming(response, importObject) .then(function (results) { successCallback(results.instance); }) .catch(function (error) { console.warn(error); console.warn("WebAssembly streaming compile failed. " + "Falling back to ArrayBuffer instantiation (this will make things slower)"); instantiateWebAssembly(importObject, wasmURI, successCallback); }); }) .catch( /* istanbul ignore next */ function () { // Ignored }); } function syncFS() { // istanbul ignore if if (fsSyncInProgress === true) { fsSyncScheduled = true; } else { fsSyncInProgress = true; fsSyncScheduled = false; FS.syncfs(false, function () { fsSyncInProgress = false; // istanbul ignore if if (fsSyncScheduled) { syncFS(); } }); } } return { loadLibrary: loadLibrary, createContext: createContext, setSettings: setSettings, setImageSettings: setImageSettings, workOnScanQueue: workOnScanQueue, workOnParseQueue: workOnParseQueue, addScanWorkUnit: addScanWorkUnit, addParseWorkUnit: addParseWorkUnit, clearSession: clearSession }; } exports.engine = engine; /** * @hidden */ // istanbul ignore next function engineWorkerFunction() { var engineInstance = engine(); onmessage = function (e) { // Setting settings triggers license verification and activation: delay until first frame processed // tslint:disable:no-reserved-keywords max-union-size var data = e.data; // tslint:enable:no-reserved-keywords max-union-size switch (data.type) { case "load-library": // tslint:disable-next-line: no-floating-promises engineInstance.loadLibrary(data.deviceId, data.libraryLocation, data.path, data.deviceModelName, data.uaBrowserName); break; case "license-key": engineInstance.createContext(data.licenseKey); engineInstance.workOnParseQueue(); break; case "settings": engineInstance.setSettings(data.settings); engineInstance.workOnScanQueue(); break; case "image-settings": engineInstance.setImageSettings(data.imageSettings); engineInstance.workOnScanQueue(); break; case "work": engineInstance.addScanWorkUnit({ requestId: data.requestId, data: data.data, highQualitySingleFrameMode: data.highQualitySingleFrameMode }); break; case "parse-string": engineInstance.addParseWorkUnit({ requestId: data.requestId, dataFormat: data.dataFormat, dataString: data.dataString, options: data.options }); break; case "clear-session": engineInstance.clearSession(); break; default: break; } }; } exports.engineWorkerFunction = engineWorkerFunction; /** * @hidden */ exports.engineWorkerBlob = new Blob(["var Module;" + engine.toString() + "(" + engineWorkerFunction.toString() + ")()"], { type: "text/javascript" }); //# sourceMappingURL=engineWorker.js.map