diff --git a/src/decoder/barcode_decoder.js b/src/decoder/barcode_decoder.js index 11a32a2..4ff70a6 100644 --- a/src/decoder/barcode_decoder.js +++ b/src/decoder/barcode_decoder.js @@ -7,12 +7,16 @@ import Code39VINReader from '../reader/code_39_vin_reader'; import CodabarReader from '../reader/codabar_reader'; import UPCReader from '../reader/upc_reader'; import EAN8Reader from '../reader/ean_8_reader'; +import EAN2Reader from '../reader/ean_2_reader'; +import EAN5Reader from '../reader/ean_5_reader'; import UPCEReader from '../reader/upc_e_reader'; import I2of5Reader from '../reader/i2of5_reader'; const READERS = { code_128_reader: Code128Reader, ean_reader: EANReader, + ean_5_reader: EAN5Reader, + ean_2_reader: EAN2Reader, ean_8_reader: EAN8Reader, code_39_reader: Code39Reader, code_39_vin_reader: Code39VINReader, @@ -74,7 +78,8 @@ export default { function initReaders() { config.readers.forEach(function(readerConfig) { var reader, - configuration = {}; + configuration = {}, + supplements = []; if (typeof readerConfig === 'object') { reader = readerConfig.format; @@ -85,7 +90,13 @@ export default { if (ENV.development) { console.log("Before registering reader: ", reader); } - _barcodeReaders.push(new READERS[reader](configuration)); + if (configuration.supplements) { + supplements = configuration + .supplements.map((supplement) => { + return new READERS[supplement](); + }); + } + _barcodeReaders.push(new READERS[reader](configuration, supplements)); }); if (ENV.development) { console.log("Registered Readers: " + _barcodeReaders @@ -243,7 +254,7 @@ export default { line = getLine(box); lineLength = getLineLength(line); lineAngle = Math.atan2(line[1].y - line[0].y, line[1].x - line[0].x); - line = getExtendedLine(line, lineAngle, Math.floor(lineLength * 0.1)); + line = getExtendedLine(line, lineAngle, Math.floor(lineLength * 0.2)); if (line === null){ return null; } diff --git a/src/reader/barcode_reader.js b/src/reader/barcode_reader.js index d834190..e346d00 100644 --- a/src/reader/barcode_reader.js +++ b/src/reader/barcode_reader.js @@ -1,6 +1,7 @@ -function BarcodeReader(config) { +function BarcodeReader(config, supplements) { this._row = []; this.config = config || {}; + this.supplements = supplements; return this; } diff --git a/src/reader/ean_2_reader.js b/src/reader/ean_2_reader.js new file mode 100644 index 0000000..6a90fb5 --- /dev/null +++ b/src/reader/ean_2_reader.js @@ -0,0 +1,46 @@ +import EANReader from './ean_reader'; + +function EAN2Reader() { + EANReader.call(this); +} + +var properties = { + FORMAT: {value: "ean_2", writeable: false} +}; + +EAN2Reader.prototype = Object.create(EANReader.prototype, properties); +EAN2Reader.prototype.constructor = EAN2Reader; + +EAN2Reader.prototype.decode = function(row, start) { + this._row = row; + var counters = [0, 0, 0, 0], + codeFrequency = 0, + i = 0, + offset = start, + end = this._row.length, + code, + result = []; + + for (i = 0; i < 2 && offset < end; i++) { + code = this._decodeCode(offset); + if (!code) { + return null; + } + result.push(code.code % 10); + if (code.code >= this.CODE_G_START) { + codeFrequency |= 1 << (1 - i); + } + if (i != 1) { + offset = this._nextSet(this._row, code.end); + offset = this._nextUnset(this._row, offset); + } + } + + if (result.length != 2 || (result.reduce((sum, i) => sum + i, 0) % 4 !== codeFrequency)) { + return null; + } + console.log(result); + return offset; +}; + +export default EAN2Reader; diff --git a/src/reader/ean_5_reader.js b/src/reader/ean_5_reader.js new file mode 100644 index 0000000..012e8e4 --- /dev/null +++ b/src/reader/ean_5_reader.js @@ -0,0 +1,79 @@ +import EANReader from './ean_reader'; + +function EAN5Reader() { + EANReader.call(this); +} + +var properties = { + FORMAT: {value: "ean_5", writeable: false} +}; + +const CHECK_DIGIT_ENCODINGS = [24, 20, 18, 17, 12, 6, 3, 10, 9, 5]; + +EAN5Reader.prototype = Object.create(EANReader.prototype, properties); +EAN5Reader.prototype.constructor = EAN5Reader; + +EAN5Reader.prototype.decode = function(row, start) { + this._row = row; + var counters = [0, 0, 0, 0], + codeFrequency = 0, + i = 0, + offset = start, + end = this._row.length, + code, + result = []; + + for (i = 0; i < 5 && offset < end; i++) { + code = this._decodeCode(offset); + if (!code) { + return null; + } + result.push(code.code % 10); + if (code.code >= this.CODE_G_START) { + codeFrequency |= 1 << (4 - i); + } + if (i != 4) { + offset = this._nextSet(this._row, code.end); + offset = this._nextUnset(this._row, offset); + } + } + + if (result.length != 5) { + return null; + } + + if (extensionChecksum(result) !== determineCheckDigit(codeFrequency)) { + return null; + } + console.log(result); + return offset; +}; + +function determineCheckDigit(codeFrequency) { + var i; + for (i = 0; i < 10; i++) { + if (codeFrequency === CHECK_DIGIT_ENCODINGS[i]) { + return i; + } + } + return null; +} + + +function extensionChecksum(result) { + var length = result.length, + sum = 0, + i; + + for (i = length - 2; i >= 0; i -= 2) { + sum += result[i]; + } + sum *= 3; + for (i = length - 1; i >= 0; i -= 2) { + sum += result[i]; + } + sum *= 3; + return sum % 10; +} + +export default EAN5Reader; diff --git a/src/reader/ean_reader.js b/src/reader/ean_reader.js index bb7e68c..be7a804 100644 --- a/src/reader/ean_reader.js +++ b/src/reader/ean_reader.js @@ -1,7 +1,18 @@ import BarcodeReader from './barcode_reader'; +import {merge} from 'lodash'; -function EANReader(opts) { - BarcodeReader.call(this, opts); +function EANReader(opts, supplements) { + opts = merge(getDefaulConfig(), opts); + BarcodeReader.call(this, opts, supplements); +} + +function getDefaulConfig() { + var config = {}; + + Object.keys(EANReader.CONFIG_KEYS).forEach(function(key) { + config[key] = EANReader.CONFIG_KEYS[key].default; + }); + return config; } var properties = { @@ -11,6 +22,7 @@ var properties = { START_PATTERN: {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]}, STOP_PATTERN: {value: [1 / 3 * 7, 1 / 3 * 7, 1 / 3 * 7]}, MIDDLE_PATTERN: {value: [1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7, 1 / 5 * 7]}, + EXTENSION_START_PATTERN: {value: [1 / 4 * 7, 1 / 4 * 7, 2 / 4 * 7]}, CODE_PATTERN: {value: [ [3, 2, 1, 1], [2, 2, 2, 1], @@ -301,6 +313,13 @@ EANReader.prototype._decode = function() { return null; } + if (this.supplements.length > 0) { + let ext = this._decodeExtensions(code.end); + if (!ext) { + return null; + } + } + return { code: result.join(""), start: startInfo.start, @@ -311,6 +330,25 @@ EANReader.prototype._decode = function() { }; }; +EANReader.prototype._decodeExtensions = function(offset) { + var i, + start = this._nextSet(this._row, offset), + code = this._findPattern(this.EXTENSION_START_PATTERN, start, false, false), + result; + + if (code === null) { + return null; + } + + for (i = 0; i < this.supplements.length; i++) { + result = this.supplements[i].decode(this._row, code.end); + if (result !== null) { + return result; + } + } + return null; +}; + EANReader.prototype._checksum = function(result) { var sum = 0, i; @@ -324,4 +362,12 @@ EANReader.prototype._checksum = function(result) { return sum % 10 === 0; }; +EANReader.CONFIG_KEYS = { + supplements: { + 'type': 'arrayOf(string)', + 'default': [], + 'description': 'Allowed extensions to be decoded (2 and/or 5)' + } +}; + export default (EANReader);