mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-12 21:21:42 +08:00
Merged master
This commit is contained in:
+21
-8
@@ -11,7 +11,8 @@ define([
|
||||
'codabar_reader',
|
||||
'upc_reader',
|
||||
'ean_8_reader',
|
||||
'upc_e_reader'
|
||||
'upc_e_reader',
|
||||
'i2of5_reader'
|
||||
], function(
|
||||
Bresenham,
|
||||
ImageDebug,
|
||||
@@ -22,7 +23,8 @@ define([
|
||||
CodabarReader,
|
||||
UPCReader,
|
||||
EAN8Reader,
|
||||
UPCEReader) {
|
||||
UPCEReader,
|
||||
I2of5Reader) {
|
||||
"use strict";
|
||||
|
||||
var readers = {
|
||||
@@ -33,7 +35,8 @@ define([
|
||||
code_39_vin_reader: Code39VINReader,
|
||||
codabar_reader: CodabarReader,
|
||||
upc_reader: UPCReader,
|
||||
upc_e_reader: UPCEReader
|
||||
upc_e_reader: UPCEReader,
|
||||
i2of5_reader: I2of5Reader
|
||||
};
|
||||
var BarcodeDecoder = {
|
||||
create : function(config, inputImageWrapper) {
|
||||
@@ -86,11 +89,21 @@ define([
|
||||
}
|
||||
|
||||
function initReaders() {
|
||||
var i;
|
||||
for ( i = 0; i < config.readers.length; i++) {
|
||||
console.log(config.readers[i]);
|
||||
_barcodeReaders.push(new readers[config.readers[i]]());
|
||||
}
|
||||
config.readers.forEach(function(readerConfig) {
|
||||
var reader,
|
||||
config = {};
|
||||
|
||||
if (typeof readerConfig === 'object') {
|
||||
reader = readerConfig.format;
|
||||
config = readerConfig.config;
|
||||
} else if (typeof readerConfig === 'string') {
|
||||
reader = readerConfig;
|
||||
}
|
||||
_barcodeReaders.push(new readers[reader](config));
|
||||
});
|
||||
console.log("Registered Readers: " + _barcodeReaders
|
||||
.map(function(reader) {return JSON.stringify({format: reader.FORMAT, config: reader.config});})
|
||||
.join(', '));
|
||||
}
|
||||
|
||||
function initConfig() {
|
||||
|
||||
+27
-1
@@ -5,8 +5,9 @@ define(
|
||||
function() {
|
||||
"use strict";
|
||||
|
||||
function BarcodeReader() {
|
||||
function BarcodeReader(config) {
|
||||
this._row = [];
|
||||
this.config = config || {};
|
||||
return this;
|
||||
}
|
||||
|
||||
@@ -184,6 +185,29 @@ define(
|
||||
return true;
|
||||
};
|
||||
|
||||
BarcodeReader.prototype._fillCounters = function(offset, end, isWhite) {
|
||||
var self = this,
|
||||
counterPos = 0,
|
||||
i,
|
||||
counters = [];
|
||||
|
||||
isWhite = (typeof isWhite !== 'undefined') ? isWhite : true;
|
||||
offset = (typeof offset !== 'undefined') ? offset : self._nextUnset(self._row);
|
||||
end = end || self._row.length;
|
||||
|
||||
counters[counterPos] = 0;
|
||||
for (i = offset; i < end; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counters[counterPos]++;
|
||||
} else {
|
||||
counterPos++;
|
||||
counters[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
return counters;
|
||||
};
|
||||
|
||||
Object.defineProperty(BarcodeReader.prototype, "FORMAT", {
|
||||
value: 'unknown',
|
||||
writeable: false
|
||||
@@ -199,6 +223,8 @@ define(
|
||||
CodeNotFoundException : "Code could not be found!",
|
||||
PatternNotFoundException : "Pattern could not be found!"
|
||||
};
|
||||
|
||||
BarcodeReader.CONFIG_KEYS = {};
|
||||
|
||||
return (BarcodeReader);
|
||||
}
|
||||
|
||||
+1
-21
@@ -36,7 +36,7 @@ define(
|
||||
nextStart,
|
||||
end;
|
||||
|
||||
self._fillCounters();
|
||||
this._counters = self._fillCounters();
|
||||
start = self._findStart();
|
||||
if (!start) {
|
||||
return null;
|
||||
@@ -186,26 +186,6 @@ define(
|
||||
return true;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._fillCounters = function() {
|
||||
var self = this,
|
||||
counterPos = 0,
|
||||
isWhite = true,
|
||||
offset = self._nextUnset(self._row),
|
||||
i;
|
||||
|
||||
self._counters.length = 0;
|
||||
self._counters[counterPos] = 0;
|
||||
for (i = offset; i < self._row.length; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
this._counters[counterPos]++;
|
||||
} else {
|
||||
counterPos++;
|
||||
this._counters[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
CodabarReader.prototype._patternToChar = function(pattern) {
|
||||
var i,
|
||||
self = this;
|
||||
|
||||
@@ -0,0 +1,344 @@
|
||||
/* jshint undef: true, unused: true, browser:true, devel: true */
|
||||
/* global define */
|
||||
|
||||
define(
|
||||
[
|
||||
"./barcode_reader",
|
||||
"./html_utils"
|
||||
],
|
||||
function(BarcodeReader, HTMLUtils) {
|
||||
"use strict";
|
||||
|
||||
function I2of5Reader(opts) {
|
||||
opts = HTMLUtils.mergeObjects(getDefaulConfig(), opts);
|
||||
BarcodeReader.call(this, opts);
|
||||
this.barSpaceRatio = [1, 1];
|
||||
if (opts.normalizeBarSpaceWidth) {
|
||||
this.SINGLE_CODE_ERROR = 0.38;
|
||||
this.AVG_CODE_ERROR = 0.09;
|
||||
}
|
||||
}
|
||||
|
||||
function getDefaulConfig() {
|
||||
var config = {};
|
||||
|
||||
Object.keys(I2of5Reader.CONFIG_KEYS).forEach(function(key) {
|
||||
config[key] = I2of5Reader.CONFIG_KEYS[key]['default'];
|
||||
});
|
||||
return config;
|
||||
}
|
||||
|
||||
var N = 1,
|
||||
W = 3,
|
||||
properties = {
|
||||
MODULO : {value: 10},
|
||||
START_PATTERN : {value: [N*2.5, N*2.5, N*2.5, N*2.5]},
|
||||
STOP_PATTERN : {value: [N*2, N*2, W*2]},
|
||||
CODE_PATTERN : {value: [
|
||||
[N, N, W, W, N],
|
||||
[W, N, N, N, W],
|
||||
[N, W, N, N, W],
|
||||
[W, W, N, N, N],
|
||||
[N, N, W, N, W],
|
||||
[W, N, W, N, N],
|
||||
[N, W, W, N, N],
|
||||
[N, N, N, W, W],
|
||||
[W, N, N, W, N],
|
||||
[N, W, N, W, N]
|
||||
]},
|
||||
SINGLE_CODE_ERROR: {value: 0.78, writable: true},
|
||||
AVG_CODE_ERROR: {value: 0.38, writable: true},
|
||||
MAX_CORRECTION_FACTOR: {value: 5},
|
||||
FORMAT: {value: "i2of5"}
|
||||
};
|
||||
|
||||
I2of5Reader.prototype = Object.create(BarcodeReader.prototype, properties);
|
||||
I2of5Reader.prototype.constructor = I2of5Reader;
|
||||
|
||||
I2of5Reader.prototype._matchPattern = function(counter, code) {
|
||||
if (this.config.normalizeBarSpaceWidth) {
|
||||
var i,
|
||||
counterSum = [0, 0],
|
||||
codeSum = [0, 0],
|
||||
correction = [0, 0],
|
||||
correctionRatio = this.MAX_CORRECTION_FACTOR,
|
||||
correctionRatioInverse = 1 / correctionRatio;
|
||||
|
||||
for (i = 0; i < counter.length; i++) {
|
||||
counterSum[i % 2] += counter[i];
|
||||
codeSum[i % 2] += code[i];
|
||||
}
|
||||
correction[0] = codeSum[0] / counterSum[0];
|
||||
correction[1] = codeSum[1] / counterSum[1];
|
||||
|
||||
correction[0] = Math.max(Math.min(correction[0], correctionRatio), correctionRatioInverse);
|
||||
correction[1] = Math.max(Math.min(correction[1], correctionRatio), correctionRatioInverse);
|
||||
this.barSpaceRatio = correction;
|
||||
for (i = 0; i < counter.length; i++) {
|
||||
counter[i] *= this.barSpaceRatio[i % 2];
|
||||
}
|
||||
}
|
||||
return BarcodeReader.prototype._matchPattern.call(this, counter, code);
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder) {
|
||||
var counter = [],
|
||||
self = this,
|
||||
i,
|
||||
counterPos = 0,
|
||||
bestMatch = {
|
||||
error : Number.MAX_VALUE,
|
||||
code : -1,
|
||||
start : 0,
|
||||
end : 0
|
||||
},
|
||||
error,
|
||||
j,
|
||||
sum,
|
||||
normalized,
|
||||
epsilon = self.AVG_CODE_ERROR;
|
||||
|
||||
isWhite = isWhite || false;
|
||||
tryHarder = tryHarder || false;
|
||||
|
||||
if (!offset) {
|
||||
offset = self._nextSet(self._row);
|
||||
}
|
||||
|
||||
for ( i = 0; i < pattern.length; i++) {
|
||||
counter[i] = 0;
|
||||
}
|
||||
|
||||
for ( i = offset; i < self._row.length; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counter[counterPos]++;
|
||||
} else {
|
||||
if (counterPos === counter.length - 1) {
|
||||
sum = 0;
|
||||
for ( j = 0; j < counter.length; j++) {
|
||||
sum += counter[j];
|
||||
}
|
||||
normalized = self._normalize(counter);
|
||||
if (normalized) {
|
||||
error = self._matchPattern(normalized, pattern);
|
||||
|
||||
if (error < epsilon) {
|
||||
bestMatch.error = error;
|
||||
bestMatch.start = i - sum;
|
||||
bestMatch.end = i;
|
||||
return bestMatch;
|
||||
}
|
||||
}
|
||||
if (tryHarder) {
|
||||
for (j = 0; j < counter.length - 2; j++) {
|
||||
counter[j] = counter[j + 2];
|
||||
}
|
||||
counter[counter.length - 2] = 0;
|
||||
counter[counter.length - 1] = 0;
|
||||
counterPos--;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
counterPos++;
|
||||
}
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._findStart = function() {
|
||||
var self = this,
|
||||
leadingWhitespaceStart,
|
||||
offset = self._nextSet(self._row),
|
||||
startInfo,
|
||||
narrowBarWidth = 1;
|
||||
|
||||
while(!startInfo) {
|
||||
startInfo = self._findPattern(self.START_PATTERN, offset, false, true);
|
||||
if (!startInfo) {
|
||||
return null;
|
||||
}
|
||||
narrowBarWidth = Math.floor((startInfo.end - startInfo.start) / 4);
|
||||
leadingWhitespaceStart = startInfo.start - narrowBarWidth*10;
|
||||
if (leadingWhitespaceStart >= 0) {
|
||||
if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
|
||||
return startInfo;
|
||||
}
|
||||
}
|
||||
offset = startInfo.end;
|
||||
startInfo = null;
|
||||
}
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._verifyTrailingWhitespace = function(endInfo) {
|
||||
var self = this,
|
||||
trailingWhitespaceEnd;
|
||||
|
||||
trailingWhitespaceEnd = endInfo.end + ((endInfo.end - endInfo.start) / 2);
|
||||
if (trailingWhitespaceEnd < self._row.length) {
|
||||
if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
|
||||
return endInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._findEnd = function() {
|
||||
var self = this,
|
||||
endInfo,
|
||||
tmp;
|
||||
|
||||
self._row.reverse();
|
||||
endInfo = self._findPattern(self.STOP_PATTERN);
|
||||
self._row.reverse();
|
||||
|
||||
if (endInfo === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// reverse numbers
|
||||
tmp = endInfo.start;
|
||||
endInfo.start = self._row.length - endInfo.end;
|
||||
endInfo.end = self._row.length - tmp;
|
||||
|
||||
return endInfo !== null ? self._verifyTrailingWhitespace(endInfo) : null;
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._decodePair = function(counterPair) {
|
||||
var i,
|
||||
code,
|
||||
codes = [],
|
||||
self = this;
|
||||
|
||||
for (i = 0; i < counterPair.length; i++) {
|
||||
code = self._decodeCode(counterPair[i]);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
codes.push(code);
|
||||
}
|
||||
return codes;
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._decodeCode = function(counter) {
|
||||
var j,
|
||||
self = this,
|
||||
sum = 0,
|
||||
normalized,
|
||||
error,
|
||||
epsilon = self.AVG_CODE_ERROR,
|
||||
code,
|
||||
bestMatch = {
|
||||
error : Number.MAX_VALUE,
|
||||
code : -1,
|
||||
start : 0,
|
||||
end : 0
|
||||
};
|
||||
|
||||
for ( j = 0; j < counter.length; j++) {
|
||||
sum += counter[j];
|
||||
}
|
||||
normalized = self._normalize(counter);
|
||||
if (normalized) {
|
||||
for (code = 0; code < self.CODE_PATTERN.length; code++) {
|
||||
error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
|
||||
if (error < bestMatch.error) {
|
||||
bestMatch.code = code;
|
||||
bestMatch.error = error;
|
||||
}
|
||||
}
|
||||
if (bestMatch.error < epsilon) {
|
||||
return bestMatch;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._decodePayload = function(counters, result, decodedCodes) {
|
||||
var i,
|
||||
self = this,
|
||||
pos = 0,
|
||||
counterLength = counters.length,
|
||||
counterPair = [[0, 0, 0, 0, 0], [0, 0, 0, 0, 0]],
|
||||
codes;
|
||||
|
||||
while (pos < counterLength) {
|
||||
for (i = 0; i < 5; i++) {
|
||||
counterPair[0][i] = counters[pos]*this.barSpaceRatio[0];
|
||||
counterPair[1][i] = counters[pos + 1]*this.barSpaceRatio[1];
|
||||
pos += 2;
|
||||
}
|
||||
codes = self._decodePair(counterPair);
|
||||
if (!codes) {
|
||||
return null;
|
||||
}
|
||||
for (i = 0; i < codes.length; i++) {
|
||||
result.push(codes[i].code + "");
|
||||
decodedCodes.push(codes[i]);
|
||||
}
|
||||
}
|
||||
return codes;
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._verifyCounterLength = function(counters) {
|
||||
return (counters.length % 10 === 0);
|
||||
};
|
||||
|
||||
I2of5Reader.prototype._decode = function() {
|
||||
var startInfo,
|
||||
endInfo,
|
||||
self = this,
|
||||
code,
|
||||
result = [],
|
||||
decodedCodes = [],
|
||||
counters;
|
||||
|
||||
startInfo = self._findStart();
|
||||
if (!startInfo) {
|
||||
return null;
|
||||
}
|
||||
decodedCodes.push(startInfo);
|
||||
|
||||
endInfo = self._findEnd();
|
||||
if (!endInfo) {
|
||||
return null;
|
||||
}
|
||||
|
||||
counters = self._fillCounters(startInfo.end, endInfo.start, false);
|
||||
if (!self._verifyCounterLength(counters)) {
|
||||
return null;
|
||||
}
|
||||
code = self._decodePayload(counters, result, decodedCodes);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
if (result.length % 2 !== 0 ||
|
||||
result.length < 6) {
|
||||
return null;
|
||||
}
|
||||
|
||||
decodedCodes.push(endInfo);
|
||||
return {
|
||||
code : result.join(""),
|
||||
start : startInfo.start,
|
||||
end : endInfo.end,
|
||||
startInfo : startInfo,
|
||||
decodedCodes : decodedCodes
|
||||
};
|
||||
};
|
||||
|
||||
I2of5Reader.CONFIG_KEYS = {
|
||||
normalizeBarSpaceWidth: {
|
||||
'type': 'boolean',
|
||||
'default': false,
|
||||
'description': 'If true, the reader tries to normalize the' +
|
||||
'width-difference between bars and spaces'
|
||||
}
|
||||
};
|
||||
|
||||
return (I2of5Reader);
|
||||
}
|
||||
);
|
||||
+7
-9
@@ -1,8 +1,6 @@
|
||||
/* jshint undef: true, unused: true, browser:true, devel: true, evil: true */
|
||||
/* global define */
|
||||
define([
|
||||
"code_128_reader",
|
||||
"ean_reader",
|
||||
"input_stream",
|
||||
"image_wrapper",
|
||||
"barcode_locator",
|
||||
@@ -15,9 +13,7 @@ define([
|
||||
"image_debug",
|
||||
"gl-matrix",
|
||||
"result_collector"],
|
||||
function(Code128Reader,
|
||||
EANReader,
|
||||
InputStream,
|
||||
function(InputStream,
|
||||
ImageWrapper,
|
||||
BarcodeLocator,
|
||||
BarcodeDecoder,
|
||||
@@ -457,9 +453,15 @@ function(Code128Reader,
|
||||
onDetected : function(callback) {
|
||||
Events.subscribe("detected", callback);
|
||||
},
|
||||
offDetected: function(callback) {
|
||||
Events.unsubscribe("detected", callback);
|
||||
},
|
||||
onProcessed: function(callback) {
|
||||
Events.subscribe("processed", callback);
|
||||
},
|
||||
offProcessed: function(callback) {
|
||||
Events.unsubscribe("processed", callback);
|
||||
},
|
||||
setReaders: function(readers) {
|
||||
setReaders(readers);
|
||||
},
|
||||
@@ -490,10 +492,6 @@ function(Code128Reader,
|
||||
start();
|
||||
});
|
||||
},
|
||||
Reader: {
|
||||
EANReader : EANReader,
|
||||
Code128Reader : Code128Reader
|
||||
},
|
||||
ImageWrapper: ImageWrapper,
|
||||
ImageDebug: ImageDebug,
|
||||
ResultCollector: ResultCollector
|
||||
|
||||
Reference in New Issue
Block a user