mirror of
https://github.com/serratus/quaggaJS.git
synced 2026-08-13 05:31:37 +08:00
Moved files into meaningful folders
This commit is contained in:
@@ -0,0 +1,222 @@
|
||||
function BarcodeReader(config) {
|
||||
this._row = [];
|
||||
this.config = config || {};
|
||||
return this;
|
||||
}
|
||||
|
||||
BarcodeReader.prototype._nextUnset = function(line, start) {
|
||||
var i;
|
||||
|
||||
if (start === undefined) {
|
||||
start = 0;
|
||||
}
|
||||
for (i = start; i < line.length; i++) {
|
||||
if (!line[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return line.length;
|
||||
};
|
||||
|
||||
BarcodeReader.prototype._matchPattern = function(counter, code) {
|
||||
var i,
|
||||
error = 0,
|
||||
singleError = 0,
|
||||
modulo = this.MODULO,
|
||||
maxSingleError = this.SINGLE_CODE_ERROR || 1;
|
||||
|
||||
for (i = 0; i < counter.length; i++) {
|
||||
singleError = Math.abs(code[i] - counter[i]);
|
||||
if (singleError > maxSingleError) {
|
||||
return Number.MAX_VALUE;
|
||||
}
|
||||
error += singleError;
|
||||
}
|
||||
return error / modulo;
|
||||
};
|
||||
|
||||
BarcodeReader.prototype._nextSet = function(line, offset) {
|
||||
var i;
|
||||
|
||||
offset = offset || 0;
|
||||
for (i = offset; i < line.length; i++) {
|
||||
if (line[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return line.length;
|
||||
};
|
||||
|
||||
BarcodeReader.prototype._normalize = function(counter, modulo) {
|
||||
var i,
|
||||
self = this,
|
||||
sum = 0,
|
||||
ratio,
|
||||
numOnes = 0,
|
||||
normalized = [],
|
||||
norm = 0;
|
||||
|
||||
if (!modulo) {
|
||||
modulo = self.MODULO;
|
||||
}
|
||||
for (i = 0; i < counter.length; i++) {
|
||||
if (counter[i] === 1) {
|
||||
numOnes++;
|
||||
} else {
|
||||
sum += counter[i];
|
||||
}
|
||||
}
|
||||
ratio = sum / (modulo - numOnes);
|
||||
if (ratio > 1.0) {
|
||||
for (i = 0; i < counter.length; i++) {
|
||||
norm = counter[i] === 1 ? counter[i] : counter[i] / ratio;
|
||||
normalized.push(norm);
|
||||
}
|
||||
} else {
|
||||
ratio = (sum + numOnes) / modulo;
|
||||
for (i = 0; i < counter.length; i++) {
|
||||
norm = counter[i] / ratio;
|
||||
normalized.push(norm);
|
||||
}
|
||||
}
|
||||
return normalized;
|
||||
};
|
||||
|
||||
BarcodeReader.prototype._matchTrace = function(cmpCounter, epsilon) {
|
||||
var counter = [],
|
||||
i,
|
||||
self = this,
|
||||
offset = self._nextSet(self._row),
|
||||
isWhite = !self._row[offset],
|
||||
counterPos = 0,
|
||||
bestMatch = {
|
||||
error: Number.MAX_VALUE,
|
||||
code: -1,
|
||||
start: 0
|
||||
},
|
||||
error;
|
||||
|
||||
if (cmpCounter) {
|
||||
for ( i = 0; i < cmpCounter.length; i++) {
|
||||
counter.push(0);
|
||||
}
|
||||
for ( i = offset; i < self._row.length; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counter[counterPos]++;
|
||||
} else {
|
||||
if (counterPos === counter.length - 1) {
|
||||
error = self._matchPattern(counter, cmpCounter);
|
||||
|
||||
if (error < epsilon) {
|
||||
bestMatch.start = i - offset;
|
||||
bestMatch.end = i;
|
||||
bestMatch.counter = counter;
|
||||
return bestMatch;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
} else {
|
||||
counterPos++;
|
||||
}
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
counter.push(0);
|
||||
for ( i = offset; i < self._row.length; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counter[counterPos]++;
|
||||
} else {
|
||||
counterPos++;
|
||||
counter.push(0);
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if cmpCounter was not given
|
||||
bestMatch.start = offset;
|
||||
bestMatch.end = self._row.length - 1;
|
||||
bestMatch.counter = counter;
|
||||
return bestMatch;
|
||||
};
|
||||
|
||||
BarcodeReader.prototype.decodePattern = function(pattern) {
|
||||
var self = this,
|
||||
result;
|
||||
|
||||
self._row = pattern;
|
||||
result = self._decode();
|
||||
if (result === null) {
|
||||
self._row.reverse();
|
||||
result = self._decode();
|
||||
if (result) {
|
||||
result.direction = BarcodeReader.DIRECTION.REVERSE;
|
||||
result.start = self._row.length - result.start;
|
||||
result.end = self._row.length - result.end;
|
||||
}
|
||||
} else {
|
||||
result.direction = BarcodeReader.DIRECTION.FORWARD;
|
||||
}
|
||||
if (result) {
|
||||
result.format = self.FORMAT;
|
||||
}
|
||||
return result;
|
||||
};
|
||||
|
||||
BarcodeReader.prototype._matchRange = function(start, end, value) {
|
||||
var i;
|
||||
|
||||
start = start < 0 ? 0 : start;
|
||||
for (i = start; i < end; i++) {
|
||||
if (this._row[i] !== value) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
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
|
||||
});
|
||||
|
||||
BarcodeReader.DIRECTION = {
|
||||
FORWARD: 1,
|
||||
REVERSE: -1
|
||||
};
|
||||
|
||||
BarcodeReader.Exception = {
|
||||
StartNotFoundException: "Start-Info was not found!",
|
||||
CodeNotFoundException: "Code could not be found!",
|
||||
PatternNotFoundException: "Pattern could not be found!"
|
||||
};
|
||||
|
||||
BarcodeReader.CONFIG_KEYS = {};
|
||||
|
||||
export default BarcodeReader;
|
||||
@@ -0,0 +1,288 @@
|
||||
import BarcodeReader from './barcode_reader';
|
||||
|
||||
function CodabarReader() {
|
||||
BarcodeReader.call(this);
|
||||
this._counters = [];
|
||||
}
|
||||
|
||||
var properties = {
|
||||
ALPHABETH_STRING: {value: "0123456789-$:/.+ABCD"},
|
||||
ALPHABET: {value: [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 45, 36, 58, 47, 46, 43, 65, 66, 67, 68]},
|
||||
CHARACTER_ENCODINGS: {value: [0x003, 0x006, 0x009, 0x060, 0x012, 0x042, 0x021, 0x024, 0x030, 0x048, 0x00c, 0x018,
|
||||
0x045, 0x051, 0x054, 0x015, 0x01A, 0x029, 0x00B, 0x00E]},
|
||||
START_END: {value: [0x01A, 0x029, 0x00B, 0x00E]},
|
||||
MIN_ENCODED_CHARS: {value: 4},
|
||||
MAX_ACCEPTABLE: {value: 2.0},
|
||||
PADDING: {value: 1.5},
|
||||
FORMAT: {value: "codabar", writeable: false}
|
||||
};
|
||||
|
||||
CodabarReader.prototype = Object.create(BarcodeReader.prototype, properties);
|
||||
CodabarReader.prototype.constructor = CodabarReader;
|
||||
|
||||
CodabarReader.prototype._decode = function() {
|
||||
var self = this,
|
||||
result = [],
|
||||
start,
|
||||
decodedChar,
|
||||
pattern,
|
||||
nextStart,
|
||||
end;
|
||||
|
||||
this._counters = self._fillCounters();
|
||||
start = self._findStart();
|
||||
if (!start) {
|
||||
return null;
|
||||
}
|
||||
nextStart = start.startCounter;
|
||||
|
||||
do {
|
||||
pattern = self._toPattern(nextStart);
|
||||
if (pattern < 0) {
|
||||
return null;
|
||||
}
|
||||
decodedChar = self._patternToChar(pattern);
|
||||
if (decodedChar < 0){
|
||||
return null;
|
||||
}
|
||||
result.push(decodedChar);
|
||||
nextStart += 8;
|
||||
if (result.length > 1 && self._isStartEnd(pattern)) {
|
||||
break;
|
||||
}
|
||||
} while (nextStart < self._counters.length);
|
||||
|
||||
// verify end
|
||||
if ((result.length - 2) < self.MIN_ENCODED_CHARS || !self._isStartEnd(pattern)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// verify end white space
|
||||
if (!self._verifyWhitespace(start.startCounter, nextStart - 8)){
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!self._validateResult(result, start.startCounter)){
|
||||
return null;
|
||||
}
|
||||
|
||||
nextStart = nextStart > self._counters.length ? self._counters.length : nextStart;
|
||||
end = start.start + self._sumCounters(start.startCounter, nextStart - 8);
|
||||
|
||||
return {
|
||||
code: result.join(""),
|
||||
start: start.start,
|
||||
end: end,
|
||||
startInfo: start,
|
||||
decodedCodes: result
|
||||
};
|
||||
};
|
||||
|
||||
CodabarReader.prototype._verifyWhitespace = function(startCounter, endCounter) {
|
||||
if ((startCounter - 1 <= 0)
|
||||
|| this._counters[startCounter - 1] >= (this._calculatePatternLength(startCounter) / 2.0)) {
|
||||
if ((endCounter + 8 >= this._counters.length)
|
||||
|| this._counters[endCounter + 7] >= (this._calculatePatternLength(endCounter) / 2.0)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._calculatePatternLength = function(offset) {
|
||||
var i,
|
||||
sum = 0;
|
||||
|
||||
for (i = offset; i < offset + 7; i++) {
|
||||
sum += this._counters[i];
|
||||
}
|
||||
|
||||
return sum;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._thresholdResultPattern = function(result, startCounter){
|
||||
var self = this,
|
||||
categorization = {
|
||||
space: {
|
||||
narrow: { size: 0, counts: 0, min: 0, max: Number.MAX_VALUE},
|
||||
wide: {size: 0, counts: 0, min: 0, max: Number.MAX_VALUE}
|
||||
},
|
||||
bar: {
|
||||
narrow: { size: 0, counts: 0, min: 0, max: Number.MAX_VALUE},
|
||||
wide: { size: 0, counts: 0, min: 0, max: Number.MAX_VALUE}
|
||||
}
|
||||
},
|
||||
kind,
|
||||
cat,
|
||||
i,
|
||||
j,
|
||||
pos = startCounter,
|
||||
pattern;
|
||||
|
||||
for (i = 0; i < result.length; i++){
|
||||
pattern = self._charToPattern(result[i]);
|
||||
for (j = 6; j >= 0; j--) {
|
||||
kind = (j & 1) === 2 ? categorization.bar : categorization.space;
|
||||
cat = (pattern & 1) === 1 ? kind.wide : kind.narrow;
|
||||
cat.size += self._counters[pos + j];
|
||||
cat.counts++;
|
||||
pattern >>= 1;
|
||||
}
|
||||
pos += 8;
|
||||
}
|
||||
|
||||
["space", "bar"].forEach(function(key) {
|
||||
var newkind = categorization[key];
|
||||
newkind.wide.min =
|
||||
Math.floor((newkind.narrow.size / newkind.narrow.counts + newkind.wide.size / newkind.wide.counts) / 2);
|
||||
newkind.narrow.max = Math.ceil(newkind.wide.min);
|
||||
newkind.wide.max = Math.ceil((newkind.wide.size * self.MAX_ACCEPTABLE + self.PADDING) / newkind.wide.counts);
|
||||
});
|
||||
|
||||
return categorization;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._charToPattern = function(char) {
|
||||
var self = this,
|
||||
charCode = char.charCodeAt(0),
|
||||
i;
|
||||
|
||||
for (i = 0; i < self.ALPHABET.length; i++) {
|
||||
if (self.ALPHABET[i] === charCode){
|
||||
return self.CHARACTER_ENCODINGS[i];
|
||||
}
|
||||
}
|
||||
return 0x0;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._validateResult = function(result, startCounter) {
|
||||
var self = this,
|
||||
thresholds = self._thresholdResultPattern(result, startCounter),
|
||||
i,
|
||||
j,
|
||||
kind,
|
||||
cat,
|
||||
size,
|
||||
pos = startCounter,
|
||||
pattern;
|
||||
|
||||
for (i = 0; i < result.length; i++) {
|
||||
pattern = self._charToPattern(result[i]);
|
||||
for (j = 6; j >= 0; j--) {
|
||||
kind = (j & 1) === 0 ? thresholds.bar : thresholds.space;
|
||||
cat = (pattern & 1) === 1 ? kind.wide : kind.narrow;
|
||||
size = self._counters[pos + j];
|
||||
if (size < cat.min || size > cat.max) {
|
||||
return false;
|
||||
}
|
||||
pattern >>= 1;
|
||||
}
|
||||
pos += 8;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._patternToChar = function(pattern) {
|
||||
var i,
|
||||
self = this;
|
||||
|
||||
for (i = 0; i < self.CHARACTER_ENCODINGS.length; i++) {
|
||||
if (self.CHARACTER_ENCODINGS[i] === pattern) {
|
||||
return String.fromCharCode(self.ALPHABET[i]);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._computeAlternatingThreshold = function(offset, end) {
|
||||
var i,
|
||||
min = Number.MAX_VALUE,
|
||||
max = 0,
|
||||
counter;
|
||||
|
||||
for (i = offset; i < end; i += 2){
|
||||
counter = this._counters[i];
|
||||
if (counter > max) {
|
||||
max = counter;
|
||||
}
|
||||
if (counter < min) {
|
||||
min = counter;
|
||||
}
|
||||
}
|
||||
|
||||
return ((min + max) / 2.0) | 0;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._toPattern = function(offset) {
|
||||
var numCounters = 7,
|
||||
end = offset + numCounters,
|
||||
barThreshold,
|
||||
spaceThreshold,
|
||||
bitmask = 1 << (numCounters - 1),
|
||||
pattern = 0,
|
||||
i,
|
||||
threshold;
|
||||
|
||||
if (end > this._counters.length) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
barThreshold = this._computeAlternatingThreshold(offset, end);
|
||||
spaceThreshold = this._computeAlternatingThreshold(offset + 1, end);
|
||||
|
||||
for (i = 0; i < numCounters; i++){
|
||||
threshold = (i & 1) === 0 ? barThreshold : spaceThreshold;
|
||||
if (this._counters[offset + i] > threshold) {
|
||||
pattern |= bitmask;
|
||||
}
|
||||
bitmask >>= 1;
|
||||
}
|
||||
|
||||
return pattern;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._isStartEnd = function(pattern) {
|
||||
var i;
|
||||
|
||||
for (i = 0; i < this.START_END.length; i++) {
|
||||
if (this.START_END[i] === pattern) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._sumCounters = function(start, end) {
|
||||
var i,
|
||||
sum = 0;
|
||||
|
||||
for (i = start; i < end; i++) {
|
||||
sum += this._counters[i];
|
||||
}
|
||||
return sum;
|
||||
};
|
||||
|
||||
CodabarReader.prototype._findStart = function() {
|
||||
var self = this,
|
||||
i,
|
||||
pattern,
|
||||
start = self._nextUnset(self._row),
|
||||
end;
|
||||
|
||||
for (i = 1; i < this._counters.length; i++) {
|
||||
pattern = self._toPattern(i);
|
||||
if (pattern !== -1 && self._isStartEnd(pattern)) {
|
||||
// TODO: Look for whitespace ahead
|
||||
start += self._sumCounters(0, i);
|
||||
end = start + self._sumCounters(i, i + 8);
|
||||
return {
|
||||
start: start,
|
||||
end: end,
|
||||
startCounter: i,
|
||||
endCounter: i + 8
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default CodabarReader;
|
||||
@@ -0,0 +1,422 @@
|
||||
import BarcodeReader from './barcode_reader';
|
||||
|
||||
function Code128Reader() {
|
||||
BarcodeReader.call(this);
|
||||
}
|
||||
|
||||
var properties = {
|
||||
CODE_SHIFT: {value: 98},
|
||||
CODE_C: {value: 99},
|
||||
CODE_B: {value: 100},
|
||||
CODE_A: {value: 101},
|
||||
START_CODE_A: {value: 103},
|
||||
START_CODE_B: {value: 104},
|
||||
START_CODE_C: {value: 105},
|
||||
STOP_CODE: {value: 106},
|
||||
MODULO: {value: 11},
|
||||
CODE_PATTERN: {value: [
|
||||
[2, 1, 2, 2, 2, 2],
|
||||
[2, 2, 2, 1, 2, 2],
|
||||
[2, 2, 2, 2, 2, 1],
|
||||
[1, 2, 1, 2, 2, 3],
|
||||
[1, 2, 1, 3, 2, 2],
|
||||
[1, 3, 1, 2, 2, 2],
|
||||
[1, 2, 2, 2, 1, 3],
|
||||
[1, 2, 2, 3, 1, 2],
|
||||
[1, 3, 2, 2, 1, 2],
|
||||
[2, 2, 1, 2, 1, 3],
|
||||
[2, 2, 1, 3, 1, 2],
|
||||
[2, 3, 1, 2, 1, 2],
|
||||
[1, 1, 2, 2, 3, 2],
|
||||
[1, 2, 2, 1, 3, 2],
|
||||
[1, 2, 2, 2, 3, 1],
|
||||
[1, 1, 3, 2, 2, 2],
|
||||
[1, 2, 3, 1, 2, 2],
|
||||
[1, 2, 3, 2, 2, 1],
|
||||
[2, 2, 3, 2, 1, 1],
|
||||
[2, 2, 1, 1, 3, 2],
|
||||
[2, 2, 1, 2, 3, 1],
|
||||
[2, 1, 3, 2, 1, 2],
|
||||
[2, 2, 3, 1, 1, 2],
|
||||
[3, 1, 2, 1, 3, 1],
|
||||
[3, 1, 1, 2, 2, 2],
|
||||
[3, 2, 1, 1, 2, 2],
|
||||
[3, 2, 1, 2, 2, 1],
|
||||
[3, 1, 2, 2, 1, 2],
|
||||
[3, 2, 2, 1, 1, 2],
|
||||
[3, 2, 2, 2, 1, 1],
|
||||
[2, 1, 2, 1, 2, 3],
|
||||
[2, 1, 2, 3, 2, 1],
|
||||
[2, 3, 2, 1, 2, 1],
|
||||
[1, 1, 1, 3, 2, 3],
|
||||
[1, 3, 1, 1, 2, 3],
|
||||
[1, 3, 1, 3, 2, 1],
|
||||
[1, 1, 2, 3, 1, 3],
|
||||
[1, 3, 2, 1, 1, 3],
|
||||
[1, 3, 2, 3, 1, 1],
|
||||
[2, 1, 1, 3, 1, 3],
|
||||
[2, 3, 1, 1, 1, 3],
|
||||
[2, 3, 1, 3, 1, 1],
|
||||
[1, 1, 2, 1, 3, 3],
|
||||
[1, 1, 2, 3, 3, 1],
|
||||
[1, 3, 2, 1, 3, 1],
|
||||
[1, 1, 3, 1, 2, 3],
|
||||
[1, 1, 3, 3, 2, 1],
|
||||
[1, 3, 3, 1, 2, 1],
|
||||
[3, 1, 3, 1, 2, 1],
|
||||
[2, 1, 1, 3, 3, 1],
|
||||
[2, 3, 1, 1, 3, 1],
|
||||
[2, 1, 3, 1, 1, 3],
|
||||
[2, 1, 3, 3, 1, 1],
|
||||
[2, 1, 3, 1, 3, 1],
|
||||
[3, 1, 1, 1, 2, 3],
|
||||
[3, 1, 1, 3, 2, 1],
|
||||
[3, 3, 1, 1, 2, 1],
|
||||
[3, 1, 2, 1, 1, 3],
|
||||
[3, 1, 2, 3, 1, 1],
|
||||
[3, 3, 2, 1, 1, 1],
|
||||
[3, 1, 4, 1, 1, 1],
|
||||
[2, 2, 1, 4, 1, 1],
|
||||
[4, 3, 1, 1, 1, 1],
|
||||
[1, 1, 1, 2, 2, 4],
|
||||
[1, 1, 1, 4, 2, 2],
|
||||
[1, 2, 1, 1, 2, 4],
|
||||
[1, 2, 1, 4, 2, 1],
|
||||
[1, 4, 1, 1, 2, 2],
|
||||
[1, 4, 1, 2, 2, 1],
|
||||
[1, 1, 2, 2, 1, 4],
|
||||
[1, 1, 2, 4, 1, 2],
|
||||
[1, 2, 2, 1, 1, 4],
|
||||
[1, 2, 2, 4, 1, 1],
|
||||
[1, 4, 2, 1, 1, 2],
|
||||
[1, 4, 2, 2, 1, 1],
|
||||
[2, 4, 1, 2, 1, 1],
|
||||
[2, 2, 1, 1, 1, 4],
|
||||
[4, 1, 3, 1, 1, 1],
|
||||
[2, 4, 1, 1, 1, 2],
|
||||
[1, 3, 4, 1, 1, 1],
|
||||
[1, 1, 1, 2, 4, 2],
|
||||
[1, 2, 1, 1, 4, 2],
|
||||
[1, 2, 1, 2, 4, 1],
|
||||
[1, 1, 4, 2, 1, 2],
|
||||
[1, 2, 4, 1, 1, 2],
|
||||
[1, 2, 4, 2, 1, 1],
|
||||
[4, 1, 1, 2, 1, 2],
|
||||
[4, 2, 1, 1, 1, 2],
|
||||
[4, 2, 1, 2, 1, 1],
|
||||
[2, 1, 2, 1, 4, 1],
|
||||
[2, 1, 4, 1, 2, 1],
|
||||
[4, 1, 2, 1, 2, 1],
|
||||
[1, 1, 1, 1, 4, 3],
|
||||
[1, 1, 1, 3, 4, 1],
|
||||
[1, 3, 1, 1, 4, 1],
|
||||
[1, 1, 4, 1, 1, 3],
|
||||
[1, 1, 4, 3, 1, 1],
|
||||
[4, 1, 1, 1, 1, 3],
|
||||
[4, 1, 1, 3, 1, 1],
|
||||
[1, 1, 3, 1, 4, 1],
|
||||
[1, 1, 4, 1, 3, 1],
|
||||
[3, 1, 1, 1, 4, 1],
|
||||
[4, 1, 1, 1, 3, 1],
|
||||
[2, 1, 1, 4, 1, 2],
|
||||
[2, 1, 1, 2, 1, 4],
|
||||
[2, 1, 1, 2, 3, 2],
|
||||
[2, 3, 3, 1, 1, 1, 2]
|
||||
]},
|
||||
SINGLE_CODE_ERROR: {value: 1},
|
||||
AVG_CODE_ERROR: {value: 0.5},
|
||||
FORMAT: {value: "code_128", writeable: false}
|
||||
};
|
||||
|
||||
Code128Reader.prototype = Object.create(BarcodeReader.prototype, properties);
|
||||
Code128Reader.prototype.constructor = Code128Reader;
|
||||
|
||||
Code128Reader.prototype._decodeCode = function(start) {
|
||||
var counter = [0, 0, 0, 0, 0, 0],
|
||||
i,
|
||||
self = this,
|
||||
offset = start,
|
||||
isWhite = !self._row[offset],
|
||||
counterPos = 0,
|
||||
bestMatch = {
|
||||
error: Number.MAX_VALUE,
|
||||
code: -1,
|
||||
start: start,
|
||||
end: start
|
||||
},
|
||||
code,
|
||||
error,
|
||||
normalized;
|
||||
|
||||
for ( i = offset; i < self._row.length; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counter[counterPos]++;
|
||||
} else {
|
||||
if (counterPos === counter.length - 1) {
|
||||
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;
|
||||
}
|
||||
}
|
||||
bestMatch.end = i;
|
||||
return bestMatch;
|
||||
}
|
||||
} else {
|
||||
counterPos++;
|
||||
}
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Code128Reader.prototype._findStart = function() {
|
||||
var counter = [0, 0, 0, 0, 0, 0],
|
||||
i,
|
||||
self = this,
|
||||
offset = self._nextSet(self._row),
|
||||
isWhite = false,
|
||||
counterPos = 0,
|
||||
bestMatch = {
|
||||
error: Number.MAX_VALUE,
|
||||
code: -1,
|
||||
start: 0,
|
||||
end: 0
|
||||
},
|
||||
code,
|
||||
error,
|
||||
j,
|
||||
sum,
|
||||
normalized;
|
||||
|
||||
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) {
|
||||
for (code = self.START_CODE_A; code <= self.START_CODE_C; code++) {
|
||||
error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
|
||||
if (error < bestMatch.error) {
|
||||
bestMatch.code = code;
|
||||
bestMatch.error = error;
|
||||
}
|
||||
}
|
||||
if (bestMatch.error < self.AVG_CODE_ERROR) {
|
||||
bestMatch.start = i - sum;
|
||||
bestMatch.end = i;
|
||||
return bestMatch;
|
||||
}
|
||||
}
|
||||
|
||||
for ( j = 0; j < 4; j++) {
|
||||
counter[j] = counter[j + 2];
|
||||
}
|
||||
counter[4] = 0;
|
||||
counter[5] = 0;
|
||||
counterPos--;
|
||||
} else {
|
||||
counterPos++;
|
||||
}
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
Code128Reader.prototype._decode = function() {
|
||||
var self = this,
|
||||
startInfo = self._findStart(),
|
||||
code = null,
|
||||
done = false,
|
||||
result = [],
|
||||
multiplier = 0,
|
||||
checksum = 0,
|
||||
codeset,
|
||||
rawResult = [],
|
||||
decodedCodes = [],
|
||||
shiftNext = false,
|
||||
unshift,
|
||||
removeLastCharacter = true;
|
||||
|
||||
if (startInfo === null) {
|
||||
return null;
|
||||
}
|
||||
code = {
|
||||
code: startInfo.code,
|
||||
start: startInfo.start,
|
||||
end: startInfo.end
|
||||
};
|
||||
decodedCodes.push(code);
|
||||
checksum = code.code;
|
||||
switch (code.code) {
|
||||
case self.START_CODE_A:
|
||||
codeset = self.CODE_A;
|
||||
break;
|
||||
case self.START_CODE_B:
|
||||
codeset = self.CODE_B;
|
||||
break;
|
||||
case self.START_CODE_C:
|
||||
codeset = self.CODE_C;
|
||||
break;
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
|
||||
while (!done) {
|
||||
unshift = shiftNext;
|
||||
shiftNext = false;
|
||||
code = self._decodeCode(code.end);
|
||||
if (code !== null) {
|
||||
if (code.code !== self.STOP_CODE) {
|
||||
removeLastCharacter = true;
|
||||
}
|
||||
|
||||
if (code.code !== self.STOP_CODE) {
|
||||
rawResult.push(code.code);
|
||||
multiplier++;
|
||||
checksum += multiplier * code.code;
|
||||
}
|
||||
decodedCodes.push(code);
|
||||
|
||||
switch (codeset) {
|
||||
case self.CODE_A:
|
||||
if (code.code < 64) {
|
||||
result.push(String.fromCharCode(32 + code.code));
|
||||
} else if (code.code < 96) {
|
||||
result.push(String.fromCharCode(code.code - 64));
|
||||
} else {
|
||||
if (code.code !== self.STOP_CODE) {
|
||||
removeLastCharacter = false;
|
||||
}
|
||||
switch (code.code) {
|
||||
case self.CODE_SHIFT:
|
||||
shiftNext = true;
|
||||
codeset = self.CODE_B;
|
||||
break;
|
||||
case self.CODE_B:
|
||||
codeset = self.CODE_B;
|
||||
break;
|
||||
case self.CODE_C:
|
||||
codeset = self.CODE_C;
|
||||
break;
|
||||
case self.STOP_CODE:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case self.CODE_B:
|
||||
if (code.code < 96) {
|
||||
result.push(String.fromCharCode(32 + code.code));
|
||||
} else {
|
||||
if (code.code !== self.STOP_CODE) {
|
||||
removeLastCharacter = false;
|
||||
}
|
||||
switch (code.code) {
|
||||
case self.CODE_SHIFT:
|
||||
shiftNext = true;
|
||||
codeset = self.CODE_A;
|
||||
break;
|
||||
case self.CODE_A:
|
||||
codeset = self.CODE_A;
|
||||
break;
|
||||
case self.CODE_C:
|
||||
codeset = self.CODE_C;
|
||||
break;
|
||||
case self.STOP_CODE:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
case self.CODE_C:
|
||||
if (code.code < 100) {
|
||||
result.push(code.code < 10 ? "0" + code.code : code.code);
|
||||
} else {
|
||||
if (code.code !== self.STOP_CODE) {
|
||||
removeLastCharacter = false;
|
||||
}
|
||||
switch (code.code) {
|
||||
case self.CODE_A:
|
||||
codeset = self.CODE_A;
|
||||
break;
|
||||
case self.CODE_B:
|
||||
codeset = self.CODE_B;
|
||||
break;
|
||||
case self.STOP_CODE:
|
||||
done = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
done = true;
|
||||
}
|
||||
if (unshift) {
|
||||
codeset = codeset === self.CODE_A ? self.CODE_B : self.CODE_A;
|
||||
}
|
||||
}
|
||||
|
||||
if (code === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
code.end = self._nextUnset(self._row, code.end);
|
||||
if (!self._verifyTrailingWhitespace(code)){
|
||||
return null;
|
||||
}
|
||||
|
||||
checksum -= multiplier * rawResult[rawResult.length - 1];
|
||||
if (checksum % 103 !== rawResult[rawResult.length - 1]) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!result.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// remove last code from result (checksum)
|
||||
if (removeLastCharacter) {
|
||||
result.splice(result.length - 1, 1);
|
||||
}
|
||||
|
||||
|
||||
return {
|
||||
code: result.join(""),
|
||||
start: startInfo.start,
|
||||
end: code.end,
|
||||
codeset: codeset,
|
||||
startInfo: startInfo,
|
||||
decodedCodes: decodedCodes,
|
||||
endInfo: code
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
BarcodeReader.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;
|
||||
};
|
||||
|
||||
export default Code128Reader;
|
||||
@@ -0,0 +1,215 @@
|
||||
import BarcodeReader from './barcode_reader';
|
||||
import ArrayHelper from '../common/array_helper';
|
||||
|
||||
function Code39Reader() {
|
||||
BarcodeReader.call(this);
|
||||
}
|
||||
|
||||
var properties = {
|
||||
ALPHABETH_STRING: {value: "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. *$/+%"},
|
||||
ALPHABET: {value: [48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78,
|
||||
79, 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 45, 46, 32, 42, 36, 47, 43, 37]},
|
||||
CHARACTER_ENCODINGS: {value: [0x034, 0x121, 0x061, 0x160, 0x031, 0x130, 0x070, 0x025, 0x124, 0x064, 0x109, 0x049,
|
||||
0x148, 0x019, 0x118, 0x058, 0x00D, 0x10C, 0x04C, 0x01C, 0x103, 0x043, 0x142, 0x013, 0x112, 0x052, 0x007, 0x106,
|
||||
0x046, 0x016, 0x181, 0x0C1, 0x1C0, 0x091, 0x190, 0x0D0, 0x085, 0x184, 0x0C4, 0x094, 0x0A8, 0x0A2, 0x08A, 0x02A
|
||||
]},
|
||||
ASTERISK: {value: 0x094},
|
||||
FORMAT: {value: "code_39", writeable: false}
|
||||
};
|
||||
|
||||
Code39Reader.prototype = Object.create(BarcodeReader.prototype, properties);
|
||||
Code39Reader.prototype.constructor = Code39Reader;
|
||||
|
||||
Code39Reader.prototype._toCounters = function(start, counter) {
|
||||
var self = this,
|
||||
numCounters = counter.length,
|
||||
end = self._row.length,
|
||||
isWhite = !self._row[start],
|
||||
i,
|
||||
counterPos = 0;
|
||||
|
||||
ArrayHelper.init(counter, 0);
|
||||
|
||||
for ( i = start; i < end; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counter[counterPos]++;
|
||||
} else {
|
||||
counterPos++;
|
||||
if (counterPos === numCounters) {
|
||||
break;
|
||||
} else {
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return counter;
|
||||
};
|
||||
|
||||
Code39Reader.prototype._decode = function() {
|
||||
var self = this,
|
||||
counters = [0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
result = [],
|
||||
start = self._findStart(),
|
||||
decodedChar,
|
||||
lastStart,
|
||||
pattern,
|
||||
nextStart;
|
||||
|
||||
if (!start) {
|
||||
return null;
|
||||
}
|
||||
nextStart = self._nextSet(self._row, start.end);
|
||||
|
||||
do {
|
||||
counters = self._toCounters(nextStart, counters);
|
||||
pattern = self._toPattern(counters);
|
||||
if (pattern < 0) {
|
||||
return null;
|
||||
}
|
||||
decodedChar = self._patternToChar(pattern);
|
||||
if (decodedChar < 0){
|
||||
return null;
|
||||
}
|
||||
result.push(decodedChar);
|
||||
lastStart = nextStart;
|
||||
nextStart += ArrayHelper.sum(counters);
|
||||
nextStart = self._nextSet(self._row, nextStart);
|
||||
} while (decodedChar !== '*');
|
||||
result.pop();
|
||||
|
||||
if (!result.length) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!self._verifyTrailingWhitespace(lastStart, nextStart, counters)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
code: result.join(""),
|
||||
start: start.start,
|
||||
end: nextStart,
|
||||
startInfo: start,
|
||||
decodedCodes: result
|
||||
};
|
||||
};
|
||||
|
||||
Code39Reader.prototype._verifyTrailingWhitespace = function(lastStart, nextStart, counters) {
|
||||
var trailingWhitespaceEnd,
|
||||
patternSize = ArrayHelper.sum(counters);
|
||||
|
||||
trailingWhitespaceEnd = nextStart - lastStart - patternSize;
|
||||
if ((trailingWhitespaceEnd * 3) >= patternSize) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
Code39Reader.prototype._patternToChar = function(pattern) {
|
||||
var i,
|
||||
self = this;
|
||||
|
||||
for (i = 0; i < self.CHARACTER_ENCODINGS.length; i++) {
|
||||
if (self.CHARACTER_ENCODINGS[i] === pattern) {
|
||||
return String.fromCharCode(self.ALPHABET[i]);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
Code39Reader.prototype._findNextWidth = function(counters, current) {
|
||||
var i,
|
||||
minWidth = Number.MAX_VALUE;
|
||||
|
||||
for (i = 0; i < counters.length; i++) {
|
||||
if (counters[i] < minWidth && counters[i] > current) {
|
||||
minWidth = counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
return minWidth;
|
||||
};
|
||||
|
||||
Code39Reader.prototype._toPattern = function(counters) {
|
||||
var numCounters = counters.length,
|
||||
maxNarrowWidth = 0,
|
||||
numWideBars = numCounters,
|
||||
wideBarWidth = 0,
|
||||
self = this,
|
||||
pattern,
|
||||
i;
|
||||
|
||||
while (numWideBars > 3) {
|
||||
maxNarrowWidth = self._findNextWidth(counters, maxNarrowWidth);
|
||||
numWideBars = 0;
|
||||
pattern = 0;
|
||||
for (i = 0; i < numCounters; i++) {
|
||||
if (counters[i] > maxNarrowWidth) {
|
||||
pattern |= 1 << (numCounters - 1 - i);
|
||||
numWideBars++;
|
||||
wideBarWidth += counters[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (numWideBars === 3) {
|
||||
for (i = 0; i < numCounters && numWideBars > 0; i++) {
|
||||
if (counters[i] > maxNarrowWidth) {
|
||||
numWideBars--;
|
||||
if ((counters[i] * 2) >= wideBarWidth) {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
return pattern;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
};
|
||||
|
||||
Code39Reader.prototype._findStart = function() {
|
||||
var self = this,
|
||||
offset = self._nextSet(self._row),
|
||||
patternStart = offset,
|
||||
counter = [0, 0, 0, 0, 0, 0, 0, 0, 0],
|
||||
counterPos = 0,
|
||||
isWhite = false,
|
||||
i,
|
||||
j,
|
||||
whiteSpaceMustStart;
|
||||
|
||||
for ( i = offset; i < self._row.length; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counter[counterPos]++;
|
||||
} else {
|
||||
if (counterPos === counter.length - 1) {
|
||||
// find start pattern
|
||||
if (self._toPattern(counter) === self.ASTERISK) {
|
||||
whiteSpaceMustStart = Math.floor(Math.max(0, patternStart - ((i - patternStart) / 4)));
|
||||
if (self._matchRange(whiteSpaceMustStart, patternStart, 0)) {
|
||||
return {
|
||||
start: patternStart,
|
||||
end: i
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
patternStart += counter[0] + counter[1];
|
||||
for ( j = 0; j < 7; j++) {
|
||||
counter[j] = counter[j + 2];
|
||||
}
|
||||
counter[7] = 0;
|
||||
counter[8] = 0;
|
||||
counterPos--;
|
||||
} else {
|
||||
counterPos++;
|
||||
}
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default Code39Reader;
|
||||
@@ -0,0 +1,49 @@
|
||||
import Code39Reader from './code_39_reader';
|
||||
|
||||
function Code39VINReader() {
|
||||
Code39Reader.call(this);
|
||||
}
|
||||
|
||||
var patterns = {
|
||||
IOQ: /[IOQ]/g,
|
||||
AZ09: /[A-Z0-9]{17}/
|
||||
};
|
||||
|
||||
Code39VINReader.prototype = Object.create(Code39Reader.prototype);
|
||||
Code39VINReader.prototype.constructor = Code39VINReader;
|
||||
|
||||
// Cribbed from:
|
||||
// https://github.com/zxing/zxing/blob/master/core/src/main/java/com/google/zxing/client/result/VINResultParser.java
|
||||
Code39VINReader.prototype._decode = function() {
|
||||
var result = Code39Reader.prototype._decode.apply(this);
|
||||
if (!result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
var code = result.code;
|
||||
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
|
||||
code = code.replace(patterns.IOQ, '');
|
||||
|
||||
if (!code.match(patterns.AZ09)) {
|
||||
console.log('Failed AZ09 pattern code:', code);
|
||||
return null;
|
||||
}
|
||||
|
||||
if (!this._checkChecksum(code)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
result.code = code;
|
||||
return result;
|
||||
};
|
||||
|
||||
Code39VINReader.prototype._checkChecksum = function(code) {
|
||||
// TODO
|
||||
return !!code;
|
||||
};
|
||||
|
||||
export default Code39VINReader;
|
||||
@@ -0,0 +1,45 @@
|
||||
import EANReader from './ean_reader';
|
||||
|
||||
function EAN8Reader() {
|
||||
EANReader.call(this);
|
||||
}
|
||||
|
||||
var properties = {
|
||||
FORMAT: {value: "ean_8", writeable: false}
|
||||
};
|
||||
|
||||
EAN8Reader.prototype = Object.create(EANReader.prototype, properties);
|
||||
EAN8Reader.prototype.constructor = EAN8Reader;
|
||||
|
||||
EAN8Reader.prototype._decodePayload = function(code, result, decodedCodes) {
|
||||
var i,
|
||||
self = this;
|
||||
|
||||
for ( i = 0; i < 4; i++) {
|
||||
code = self._decodeCode(code.end, self.CODE_G_START);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
result.push(code.code);
|
||||
decodedCodes.push(code);
|
||||
}
|
||||
|
||||
code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
|
||||
if (code === null) {
|
||||
return null;
|
||||
}
|
||||
decodedCodes.push(code);
|
||||
|
||||
for ( i = 0; i < 4; i++) {
|
||||
code = self._decodeCode(code.end, self.CODE_G_START);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
decodedCodes.push(code);
|
||||
result.push(code.code);
|
||||
}
|
||||
|
||||
return code;
|
||||
};
|
||||
|
||||
export default EAN8Reader;
|
||||
@@ -0,0 +1,327 @@
|
||||
import BarcodeReader from './barcode_reader';
|
||||
|
||||
function EANReader(opts) {
|
||||
BarcodeReader.call(this, opts);
|
||||
}
|
||||
|
||||
var properties = {
|
||||
CODE_L_START: {value: 0},
|
||||
MODULO: {value: 7},
|
||||
CODE_G_START: {value: 10},
|
||||
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]},
|
||||
CODE_PATTERN: {value: [
|
||||
[3, 2, 1, 1],
|
||||
[2, 2, 2, 1],
|
||||
[2, 1, 2, 2],
|
||||
[1, 4, 1, 1],
|
||||
[1, 1, 3, 2],
|
||||
[1, 2, 3, 1],
|
||||
[1, 1, 1, 4],
|
||||
[1, 3, 1, 2],
|
||||
[1, 2, 1, 3],
|
||||
[3, 1, 1, 2],
|
||||
[1, 1, 2, 3],
|
||||
[1, 2, 2, 2],
|
||||
[2, 2, 1, 2],
|
||||
[1, 1, 4, 1],
|
||||
[2, 3, 1, 1],
|
||||
[1, 3, 2, 1],
|
||||
[4, 1, 1, 1],
|
||||
[2, 1, 3, 1],
|
||||
[3, 1, 2, 1],
|
||||
[2, 1, 1, 3]
|
||||
]},
|
||||
CODE_FREQUENCY: {value: [0, 11, 13, 14, 19, 25, 28, 21, 22, 26]},
|
||||
SINGLE_CODE_ERROR: {value: 0.67},
|
||||
AVG_CODE_ERROR: {value: 0.27},
|
||||
FORMAT: {value: "ean_13", writeable: false}
|
||||
};
|
||||
|
||||
EANReader.prototype = Object.create(BarcodeReader.prototype, properties);
|
||||
EANReader.prototype.constructor = EANReader;
|
||||
|
||||
EANReader.prototype._decodeCode = function(start, coderange) {
|
||||
var counter = [0, 0, 0, 0],
|
||||
i,
|
||||
self = this,
|
||||
offset = start,
|
||||
isWhite = !self._row[offset],
|
||||
counterPos = 0,
|
||||
bestMatch = {
|
||||
error: Number.MAX_VALUE,
|
||||
code: -1,
|
||||
start: start,
|
||||
end: start
|
||||
},
|
||||
code,
|
||||
error,
|
||||
normalized;
|
||||
|
||||
if (!coderange) {
|
||||
coderange = self.CODE_PATTERN.length;
|
||||
}
|
||||
|
||||
for ( i = offset; i < self._row.length; i++) {
|
||||
if (self._row[i] ^ isWhite) {
|
||||
counter[counterPos]++;
|
||||
} else {
|
||||
if (counterPos === counter.length - 1) {
|
||||
normalized = self._normalize(counter);
|
||||
if (normalized) {
|
||||
for (code = 0; code < coderange; code++) {
|
||||
error = self._matchPattern(normalized, self.CODE_PATTERN[code]);
|
||||
if (error < bestMatch.error) {
|
||||
bestMatch.code = code;
|
||||
bestMatch.error = error;
|
||||
}
|
||||
}
|
||||
bestMatch.end = i;
|
||||
if (bestMatch.error > self.AVG_CODE_ERROR) {
|
||||
return null;
|
||||
}
|
||||
return bestMatch;
|
||||
}
|
||||
} else {
|
||||
counterPos++;
|
||||
}
|
||||
counter[counterPos] = 1;
|
||||
isWhite = !isWhite;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
EANReader.prototype._findPattern = function(pattern, offset, isWhite, tryHarder, epsilon) {
|
||||
var counter = [],
|
||||
self = this,
|
||||
i,
|
||||
counterPos = 0,
|
||||
bestMatch = {
|
||||
error: Number.MAX_VALUE,
|
||||
code: -1,
|
||||
start: 0,
|
||||
end: 0
|
||||
},
|
||||
error,
|
||||
j,
|
||||
sum,
|
||||
normalized;
|
||||
|
||||
if (!offset) {
|
||||
offset = self._nextSet(self._row);
|
||||
}
|
||||
|
||||
if (isWhite === undefined) {
|
||||
isWhite = false;
|
||||
}
|
||||
|
||||
if (tryHarder === undefined) {
|
||||
tryHarder = true;
|
||||
}
|
||||
|
||||
if ( epsilon === undefined) {
|
||||
epsilon = self.AVG_CODE_ERROR;
|
||||
}
|
||||
|
||||
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;
|
||||
};
|
||||
|
||||
EANReader.prototype._findStart = function() {
|
||||
var self = this,
|
||||
leadingWhitespaceStart,
|
||||
offset = self._nextSet(self._row),
|
||||
startInfo;
|
||||
|
||||
while (!startInfo) {
|
||||
startInfo = self._findPattern(self.START_PATTERN, offset);
|
||||
if (!startInfo) {
|
||||
return null;
|
||||
}
|
||||
leadingWhitespaceStart = startInfo.start - (startInfo.end - startInfo.start);
|
||||
if (leadingWhitespaceStart >= 0) {
|
||||
if (self._matchRange(leadingWhitespaceStart, startInfo.start, 0)) {
|
||||
return startInfo;
|
||||
}
|
||||
}
|
||||
offset = startInfo.end;
|
||||
startInfo = null;
|
||||
}
|
||||
};
|
||||
|
||||
EANReader.prototype._verifyTrailingWhitespace = function(endInfo) {
|
||||
var self = this,
|
||||
trailingWhitespaceEnd;
|
||||
|
||||
trailingWhitespaceEnd = endInfo.end + (endInfo.end - endInfo.start);
|
||||
if (trailingWhitespaceEnd < self._row.length) {
|
||||
if (self._matchRange(endInfo.end, trailingWhitespaceEnd, 0)) {
|
||||
return endInfo;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
EANReader.prototype._findEnd = function(offset, isWhite) {
|
||||
var self = this,
|
||||
endInfo = self._findPattern(self.STOP_PATTERN, offset, isWhite, false);
|
||||
|
||||
return endInfo !== null ? self._verifyTrailingWhitespace(endInfo) : null;
|
||||
};
|
||||
|
||||
EANReader.prototype._calculateFirstDigit = function(codeFrequency) {
|
||||
var i,
|
||||
self = this;
|
||||
|
||||
for ( i = 0; i < self.CODE_FREQUENCY.length; i++) {
|
||||
if (codeFrequency === self.CODE_FREQUENCY[i]) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
EANReader.prototype._decodePayload = function(code, result, decodedCodes) {
|
||||
var i,
|
||||
self = this,
|
||||
codeFrequency = 0x0,
|
||||
firstDigit;
|
||||
|
||||
for ( i = 0; i < 6; i++) {
|
||||
code = self._decodeCode(code.end);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
if (code.code >= self.CODE_G_START) {
|
||||
code.code = code.code - self.CODE_G_START;
|
||||
codeFrequency |= 1 << (5 - i);
|
||||
} else {
|
||||
codeFrequency |= 0 << (5 - i);
|
||||
}
|
||||
result.push(code.code);
|
||||
decodedCodes.push(code);
|
||||
}
|
||||
|
||||
firstDigit = self._calculateFirstDigit(codeFrequency);
|
||||
if (firstDigit === null) {
|
||||
return null;
|
||||
}
|
||||
result.unshift(firstDigit);
|
||||
|
||||
code = self._findPattern(self.MIDDLE_PATTERN, code.end, true, false);
|
||||
if (code === null) {
|
||||
return null;
|
||||
}
|
||||
decodedCodes.push(code);
|
||||
|
||||
for ( i = 0; i < 6; i++) {
|
||||
code = self._decodeCode(code.end, self.CODE_G_START);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
decodedCodes.push(code);
|
||||
result.push(code.code);
|
||||
}
|
||||
|
||||
return code;
|
||||
};
|
||||
|
||||
EANReader.prototype._decode = function() {
|
||||
var startInfo,
|
||||
self = this,
|
||||
code,
|
||||
result = [],
|
||||
decodedCodes = [];
|
||||
|
||||
startInfo = self._findStart();
|
||||
if (!startInfo) {
|
||||
return null;
|
||||
}
|
||||
code = {
|
||||
code: startInfo.code,
|
||||
start: startInfo.start,
|
||||
end: startInfo.end
|
||||
};
|
||||
decodedCodes.push(code);
|
||||
code = self._decodePayload(code, result, decodedCodes);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
code = self._findEnd(code.end, false);
|
||||
if (!code){
|
||||
return null;
|
||||
}
|
||||
|
||||
decodedCodes.push(code);
|
||||
|
||||
// Checksum
|
||||
if (!self._checksum(result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return {
|
||||
code: result.join(""),
|
||||
start: startInfo.start,
|
||||
end: code.end,
|
||||
codeset: "",
|
||||
startInfo: startInfo,
|
||||
decodedCodes: decodedCodes
|
||||
};
|
||||
};
|
||||
|
||||
EANReader.prototype._checksum = function(result) {
|
||||
var sum = 0, i;
|
||||
|
||||
for ( i = result.length - 2; i >= 0; i -= 2) {
|
||||
sum += result[i];
|
||||
}
|
||||
sum *= 3;
|
||||
for ( i = result.length - 1; i >= 0; i -= 2) {
|
||||
sum += result[i];
|
||||
}
|
||||
return sum % 10 === 0;
|
||||
};
|
||||
|
||||
export default (EANReader);
|
||||
@@ -0,0 +1,334 @@
|
||||
import BarcodeReader from './barcode_reader';
|
||||
const merge = require('lodash/object/merge');
|
||||
|
||||
function I2of5Reader(opts) {
|
||||
opts = merge(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'
|
||||
}
|
||||
};
|
||||
|
||||
export default I2of5Reader;
|
||||
@@ -0,0 +1,103 @@
|
||||
import EANReader from './ean_reader';
|
||||
|
||||
function UPCEReader() {
|
||||
EANReader.call(this);
|
||||
}
|
||||
|
||||
var properties = {
|
||||
CODE_FREQUENCY: {value: [
|
||||
[ 56, 52, 50, 49, 44, 38, 35, 42, 41, 37 ],
|
||||
[7, 11, 13, 14, 19, 25, 28, 21, 22, 26]]},
|
||||
STOP_PATTERN: { value: [1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7, 1 / 6 * 7]},
|
||||
FORMAT: {value: "upc_e", writeable: false}
|
||||
};
|
||||
|
||||
UPCEReader.prototype = Object.create(EANReader.prototype, properties);
|
||||
UPCEReader.prototype.constructor = UPCEReader;
|
||||
|
||||
UPCEReader.prototype._decodePayload = function(code, result, decodedCodes) {
|
||||
var i,
|
||||
self = this,
|
||||
codeFrequency = 0x0;
|
||||
|
||||
for ( i = 0; i < 6; i++) {
|
||||
code = self._decodeCode(code.end);
|
||||
if (!code) {
|
||||
return null;
|
||||
}
|
||||
if (code.code >= self.CODE_G_START) {
|
||||
code.code = code.code - self.CODE_G_START;
|
||||
codeFrequency |= 1 << (5 - i);
|
||||
}
|
||||
result.push(code.code);
|
||||
decodedCodes.push(code);
|
||||
}
|
||||
if (!self._determineParity(codeFrequency, result)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return code;
|
||||
};
|
||||
|
||||
UPCEReader.prototype._determineParity = function(codeFrequency, result) {
|
||||
var i,
|
||||
nrSystem;
|
||||
|
||||
for (nrSystem = 0; nrSystem < this.CODE_FREQUENCY.length; nrSystem++){
|
||||
for ( i = 0; i < this.CODE_FREQUENCY[nrSystem].length; i++) {
|
||||
if (codeFrequency === this.CODE_FREQUENCY[nrSystem][i]) {
|
||||
result.unshift(nrSystem);
|
||||
result.push(i);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
UPCEReader.prototype._convertToUPCA = function(result) {
|
||||
var upca = [result[0]],
|
||||
lastDigit = result[result.length - 2];
|
||||
|
||||
if (lastDigit <= 2) {
|
||||
upca = upca.concat(result.slice(1, 3))
|
||||
.concat([lastDigit, 0, 0, 0, 0])
|
||||
.concat(result.slice(3, 6));
|
||||
} else if (lastDigit === 3) {
|
||||
upca = upca.concat(result.slice(1, 4))
|
||||
.concat([0, 0, 0, 0, 0])
|
||||
.concat(result.slice(4, 6));
|
||||
} else if (lastDigit === 4) {
|
||||
upca = upca.concat(result.slice(1, 5))
|
||||
.concat([0, 0, 0, 0, 0, result[5]]);
|
||||
} else {
|
||||
upca = upca.concat(result.slice(1, 6))
|
||||
.concat([0, 0, 0, 0, lastDigit]);
|
||||
}
|
||||
|
||||
upca.push(result[result.length - 1]);
|
||||
return upca;
|
||||
};
|
||||
|
||||
UPCEReader.prototype._checksum = function(result) {
|
||||
return EANReader.prototype._checksum.call(this, this._convertToUPCA(result));
|
||||
};
|
||||
|
||||
UPCEReader.prototype._findEnd = function(offset, isWhite) {
|
||||
isWhite = true;
|
||||
return EANReader.prototype._findEnd.call(this, offset, isWhite);
|
||||
};
|
||||
|
||||
UPCEReader.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;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
export default UPCEReader;
|
||||
@@ -0,0 +1,24 @@
|
||||
import EANReader from './ean_reader';
|
||||
|
||||
function UPCReader() {
|
||||
EANReader.call(this);
|
||||
}
|
||||
|
||||
var properties = {
|
||||
FORMAT: {value: "upc_a", writeable: false}
|
||||
};
|
||||
|
||||
UPCReader.prototype = Object.create(EANReader.prototype, properties);
|
||||
UPCReader.prototype.constructor = UPCReader;
|
||||
|
||||
UPCReader.prototype._decode = function() {
|
||||
var result = EANReader.prototype._decode.call(this);
|
||||
|
||||
if (result && result.code && result.code.length === 13 && result.code.charAt(0) === "0") {
|
||||
result.code = result.code.substring(1);
|
||||
return result;
|
||||
}
|
||||
return null;
|
||||
};
|
||||
|
||||
export default UPCReader;
|
||||
Reference in New Issue
Block a user