如果你想開發基於瀏覽器的HTML5條形碼掃描應用,你可以在Google首頁中找到最好的JavaScript Barcode SDK.
Dynamsoft和Scandit這兩家公司都開發了基於WebAssembly的條形碼SDK,可以讓Web應用的掃碼性能接近原生應用。我們可以從hello world入手,來深度體驗下這兩個SDK之間的差異。
Hello World快速入門
Dynamsoft
網址:https://www.npmjs.com/package/dynamsoft-javascript-barcode
- 提供完整的示例代碼
- 在沒有license的情況下,依然可以識別,只是結果無法完整顯示
- 所有攝像頭使用默認邏輯。物體水平移動方向和筆記本內置攝像頭畫面方向相反
- 分辨率可選
- 默認支持所有主流類型的1D/2D條形碼
- 默認識別多個條形碼
Scandit
網址:https://www.npmjs.com/package/scandit-sdk
- 沒有提供完整代碼。用戶需要逐段拷貝到HTML頁面裏
- 強制使用license。在沒有license的情況下無任何反應和提示
- 對攝像頭進行了判斷。筆記本的內置攝像頭做了鏡像,物體運動方向和畫面方向保持一致
- 沒有可選分辨率
- 無默認條形碼類型,不設置就無法使用
- 默認最多識別1個條形碼
入門對比
Hello World Sample | Dynamsoft | Scandit |
---|---|---|
是否提供完整代碼 | 是 | 否 |
無License可否運行 | 是 | 否 |
是否可以切換攝像頭 | 是 | 是 |
是否可以選擇分辨率 | 是 | 否 |
是否支持各種碼型 | 是 | 否 |
是否支持多碼識別 | 是 | 否 |
靜態圖片條形碼識別
Dynamsoft
支持多種輸入類型,接口非常豐富。
- decode(source: Blob | Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | HTMLImageElement | HTMLCanvasElement | HTMLVideoElement | string): Promise<TextResult[]>
- decodeBase64String(base64: string): Promise<TextResult[]>
- decodeBuffer(buffer: Uint8Array | Uint8ClampedArray | ArrayBuffer | Blob | Buffer, width: number, height: number, stride: number, format: EnumImagePixelFormat, config?: any): Promise<any>
- decodeUrl(url: string): Promise<TextResult[]>
參考文檔:https://www.dynamsoft.com/help/Barcode-Reader-wasm/classes/barcodereader.html#decodebuffer
Scandit
只支持Uint8Array。必須先把數據通過HTML5的canvas解碼之後才能調用接口識別,非常不方便。
- processImage(imageData: Uint8Array | HTMLImageElement, highQualitySingleFrameMode?: boolean): Promise<ScanResult>
參考文檔:https://docs.scandit.com/stable/web/classes/scanner.html
性能對比
爲了統一測試條件,傳入數據使用Uint8Array:
<input type="file" id="barcode-file" onchange="loadfile()" accept=".jpg,.jpeg,.png,.bmp" />
function loadfile() {
let name = document.getElementById('barcode-file');
var img = document.getElementById('image');
var reader = new FileReader();
reader.onload = function (evt) {
img.onload = function () {
var canvas = document.createElement('canvas');
canvas.width = img.width;
canvas.height = img.height;
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0);
var buffer = context.getImageData(0, 0, canvas.width, canvas.height).data;
// TODO: call barcode decoding API
};
img.src = evt.target.result;
};
reader.readAsDataURL(name.files[0]);
};
解碼耗時的一個重要因素是傳入圖像的尺寸。傳入圖像大,耗時多,傳入圖像小,耗時少。
Dynamsoft提供的接口是對原圖解碼,而Scandit的接口內部會對圖像進行壓縮,因此如果傳入圖片尺寸很大,Dynamsoft接口就會比較耗時。但是通過canvas壓縮圖像之後,會發現Dynamsoft的接口耗時大幅下降。在處理複雜條形碼或者多條形碼的圖片時,Dynamsoft的性能優勢對比Scandit非常大。
以下代碼用於縮小圖片:
var ratio = 0.6;
var canvas = document.createElement('canvas');
var tmpWidth = img.width, tmpHeight = img.height;
while (tmpWidth > 1000 || tmpHeight > 1000) {
tmpWidth *= ratio;
tmpHeight *= ratio;
}
canvas.width = tmpWidth;
canvas.height = tmpHeight;
var context = canvas.getContext('2d');
context.drawImage(img, 0, 0, img.width, img.height, 0, 0, canvas.width, canvas.height);
在參數設置的時候,儘可能保持一致。靜態圖片中可能包含很多條形碼,比如文檔。所以最大條形碼數量都設置成了20。
Dynamsoft參數設置:
(async () => {
barcodereader = await Dynamsoft.BarcodeReader.createInstance();
await barcodereader.updateRuntimeSettings('balance');
let settings = await barcodereader.getRuntimeSettings();
settings.expectedBarcodesCount = 20;
barcodereader.updateRuntimeSettings(settings);
})();
Scandit參數設置:
scanditScanner = new ScanditSDK.Scanner({ imageSettings: {}, scanSettings: new ScanditSDK.ScanSettings({gpuAcceleration: true, enabledSymbologies: ["ean8", "ean13", "upca", "upce", "qr", "code93", "codabar", "code128", "aztec", "data-matrix", "maxicode", "pdf417"], maxNumberOfCodesPerFrame: 20 }) });
測試圖片
圖像壓縮前的解碼時間:
圖像壓縮後的解碼時間:
從數據看出,圖片縮放前後,Scandit的性能跨度不是很大。而Dynamsoft的性能提升非常明顯,受圖片尺寸的影響比較大。
再來看下多碼場景測試。 在設置了最大條碼數量20之後,Dynamsoft可以解出20個條形碼:
而Scandit的算法可能主要專注在移動使用場景(條形碼比較少),所以碰到多碼的圖,表現不理想:
從MP4視頻文件中識別條形碼
視頻文件可以當作模擬攝像頭,用於測試連續幀下,不同SDK之間的性能。 視頻文件必須和HTML文件放在同一個目錄才能正常加載。代碼如下:
function loadvideo() {
let name = document.getElementById('videofile');
performanceReport.innerHTML = "";
videoContainer = document.getElementById('videoContainer');
videoContainer.src = name.files.item(0).name;
videoContainer.addEventListener("loadedmetadata", function (e) {
var width = this.videoWidth,
height = this.videoHeight;
console.log(width, height);
}, false);
videoContainer.addEventListener("playing", function () {
decoding_start = 0;
isPlaying = true;
decodeVideo(this.videoWidth, this.videoHeight);
});
videoContainer.addEventListener("pause", function () {
isPlaying = false;
});
};
通過loadedmetadata事件可以獲得視頻幀的寬高。
視頻幀可以通過context.drawImage(videoContainer, 0, 0, width, height, 0, 0, canvas.width, canvas.height);
繪製到canvas上。讀取方法和靜態圖片一樣。
在我的視頻測試中,Scandit的平均耗時相對少點。對比靜態圖片,參數做了修改。最大條形碼數量都設成了1,支持的碼型都改成了3個。
Dynamsoft開啓了速度模式:
(async () => {
barcodereader = await Dynamsoft.BarcodeReader.createInstance();
await barcodereader.updateRuntimeSettings('speed');
let settings = await barcodereader.getRuntimeSettings();
settings.expectedBarcodesCount = 1
settings.barcodeFormatIds = Dynamsoft.EnumBarcodeFormat.BF_CODE_128 | Dynamsoft.EnumBarcodeFormat.BF_UPC_A | Dynamsoft.EnumBarcodeFormat.BF_QR_CODE;
barcodereader.updateRuntimeSettings(settings);
})();
Scandit關閉了高質量檢測模式,減少耗時:
scanditScanner = new ScanditSDK.Scanner({ imageSettings: {}, scanSettings: new ScanditSDK.ScanSettings({ gpuAcceleration: true, enabledSymbologies: ["code128", "qr", "upca"], maxNumberOfCodesPerFrame: 1 }) });
scanditScanner.processImage(buffer)
運行結果:
攝像頭掃碼
在商用場景中,攝像頭實時掃碼的需求比較多。用HTML5開發掃碼app的成本也會比原生應用低不少。
攝像頭列表
Dynamsoft提供了一個接口來獲取攝像頭列表:
cameras = await scanner.getAllCameras();
Scandit沒有提供攝像頭列表接口,默認只支持前後攝像頭,完全是針對手機的設計。那麼要獲取攝像頭列表並顯示在下拉菜單中,只能自己寫代碼實現:
navigator.mediaDevices.enumerateDevices().then(gotDevices);
var index = 0;
function gotDevices(cameras) {
for (var i = 0; i < cameras.length; i++) {
}
}
攝像頭切換
Dynamsoft提供了攝像頭切換接口:
await scanner.setCurrentCamera()
Scandit也提供了切換接口:
scanditScanner.setActiveCamera()
但是通過編程發現,Scandit的接口在PC上無法正常工作。要正常切換,只能通過銷燬來重新創建:
scanditScanner.destroy(true);
createScanditScanner()
性能對比
在640x480的分辨率下,Dynamsoft因爲用了多幀處理算法,解碼速度比Scandit更快。不過在使用更高分辨率的時候,Dynamsoft因爲是對全圖解碼的,性能會比Scandit差。所以在使用Dynamsoft接口的時候,可以通過設置scanner._canvasMaxWH = 640
,把任意大的圖像壓縮到640x480來提速。
Scandit的畫面相比Dynamsoft略顯模糊,因爲Scandit通過CSS做了全屏顯示。但實際獲取的視頻尺寸和Dynamsoft是完全一樣的,也是640x480。
關於硬件優化
Dynamsoft提供了SIMD CPU指令優化。
Scandit提供了基於WebGL的GPU加速。
文檔頁面
Dynamsoft https://www.dynamsoft.com/help/Barcode-Reader-wasm/
Scandit https://docs.scandit.com/stable/web/index.html
源碼
https://github.com/yushulx/dynamsoft-scandit-javascript-barcode