shape-detection
Version:
Web ShapeDetection (QR Codes, Text, more) polyfill
146 lines (126 loc) • 5.07 kB
JavaScript
// ShapeDetection polyfill.
export var BarcodeDetector = window.BarcodeDetector;
if (typeof window.BarcodeDetector === 'undefined') {
// https://wicg.github.io/shape-detection-api/#barcode-detection-api
BarcodeDetector = class {
constructor() {
// |qrcode| should be defined by `qrcode = require('qrcode-reader');`
if (typeof this._qrcode === 'undefined') {
var lib = require('qrcode-reader');
this._qrcode = new lib.default();
}
if (typeof this._quagga === 'undefined')
this._quagga = require('quagga');
this._debug = true;
}
/**
* Implements https://wicg.github.io/shape-detection-api/#dom-barcodedetector-detect
* @param {ImageBitmapSource} image - Image/Video/Canvas input.
* @returns {Promise<sequence<DetectedBarcode>>} Fulfilled promise with detected codes.
*/
detect(image) {
var that = this;
var result = [];
var image = image;
return that.detectQRCodes(image)
.then((qrCodes) => {
if ('rawValue' in qrCodes[0])
result = result.concat(qrCodes);
return that.detectBarcodes(image)
})
.then((barCodes) => {
if ('rawValue' in barCodes[0])
result = result.concat(barCodes);
return result;
})
.catch(() => { console.error('Detection error'); })
}
/**
QR Code detection is based on ZXing port to JS; provides the decoded string
but no |boundingBox| nor |cornerPoints|: These are always undefined and an
emtpy string, respectively. If anything is detected, |rawValue| will have
the decoded data, otherwise it's not defined.
*/
detectQRCodes(image) {
var that = this;
return new Promise(function executorQRD(resolve, reject) {
that._qrcode.callback = function(err, result) {
var detectedBarcode = new Object;
detectedBarcode.boundingBox = undefined;
detectedBarcode.cornerPoints = [];
if (err != null) {
console.error('no qr codes detected: ' + err);
} else {
// |result.result| contains the decoded string, url or otherwise.
console.log('qr detected: ', result.result);
detectedBarcode.rawValue = result.result;
if (result.points) {
detectedBarcode.cornerPoints = [
{ x: result.points[0].X, y:result.points[0].Y },
{ x: result.points[1].X, y:result.points[1].Y },
{ x: result.points[2].X, y:result.points[2].Y },
{ x: result.points[3].X, y:result.points[3].Y }];
}
}
resolve( [detectedBarcode] );
};
that._qrcode.decode(that.getImageAsBase64(image));
});
};
/**
Barcode detection is based on ZXing port to JS; provides the decoded string
but no |boundingBox| nor |cornerPoints|: These are always undefined and an
emtpy string, respectively. If anything is detected, |rawValue| will have
the decoded data, otherwise it's not defined.
*/
detectBarcodes(image) {
var that = this;
return new Promise(function executorBCD(resolve, reject) {
const what = that.getImageAsBase64(image);
that._quagga.decodeSingle({
src: what,
numOfWorkers: 0, // Needs to be 0 when used within node
locate: true,
inputStream: {
size: image.width > image.height ? image.width : image.height
},
decoder: {
readers : [
'upc_reader', 'code_128_reader', 'code_39_reader',
'code_39_vin_reader', 'ean_8_reader', 'ean_reader',
'upc_e_reader', 'codabar_reader'
]
},
multiple: true,
}, function(result) {
var detectedBarcode = new Object;
detectedBarcode.boundingBox = undefined;
detectedBarcode.cornerPoints = [];
if(result) {
if (result.codeResult) {
console.log('detected: ', result.codeResult.code);
detectedBarcode.rawValue = result.codeResult.code;
detectedBarcode.cornerPoints = [
{ x: result.boxes[0][0][0], y:result.boxes[0][0][1] },
{ x: result.boxes[0][1][0], y:result.boxes[0][1][1] },
{ x: result.boxes[0][2][0], y:result.boxes[0][2][1] },
{ x: result.boxes[0][3][0], y:result.boxes[0][3][1] }];
}
} else {
console.error('no barcodes detected');
}
resolve( [detectedBarcode] );
});
});
};
getImageAsBase64(image) {
var canvas = document.createElement('canvas');
canvas.style.visibility = 'hidden';
var ctx = canvas.getContext('2d');
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
return canvas.toDataURL();
};
};
}