Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added support for Code 93 barcodes #197

Merged
merged 2 commits into from
May 23, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions example/file_input.html
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ <h3>Working with file-input</h3>
<option value="codabar">Codabar</option>
<option value="i2of5">Interleaved 2 of 5</option>
<option value="2of5">Standard 2 of 5</option>
<option value="code_93">Code 93</option>
</select>
</label>
<label>
Expand Down
1 change: 1 addition & 0 deletions example/live_w_locator.html
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ <h3>The user's camera</h3>
<option value="codabar">Codabar</option>
<option value="i2of5">Interleaved 2 of 5</option>
<option value="2of5">Standard 2 of 5</option>
<option value="code_93">Code 93</option>
</select>
</label>
<label>
Expand Down
12 changes: 6 additions & 6 deletions example/live_w_locator.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ $(function() {
capture: true,
capacity: 20,
blacklist: [{
code: "9577149002", format: "2of5"
code: "WIWV8ETQZ1", format: "code_93"
}, {
code: "5776158811", format: "2of5"
code: "EH3C-%GU23RK3", format: "code_93"
}, {
code: "0463381455", format: "2of5"
code: "O308SIHQOXN5SA/PJ", format: "code_93"
}, {
code: "3261594101", format: "2of5"
code: "DG7Q$TV8JQ/EN", format: "code_93"
}, {
code: "6730705801", format: "2of5"
code: "VOFD1DB5A.1F6QU", format: "code_93"
}, {
code: "8568166929", format: "2of5"
code: "4SO64P4X8 U4YUU1T-", format: "code_93"
}],
filter: function(codeResult) {
// only store results which match this constraint
Expand Down
1 change: 1 addition & 0 deletions example/static_images.html
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ <h3>Working with static images</h3>
<option value="i2of5">I2of5</option>
<option value="i2of5">Interleaved 2 of 5</option>
<option value="2of5">Standard 2 of 5</option>
<option value="code_93">Code 93</option>
</select>
</fieldset>
</div>
Expand Down
2 changes: 2 additions & 0 deletions src/decoder/barcode_decoder.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import EAN5Reader from '../reader/ean_5_reader';
import UPCEReader from '../reader/upc_e_reader';
import I2of5Reader from '../reader/i2of5_reader';
import TwoOfFiveReader from '../reader/2of5_reader';
import Code93Reader from '../reader/code_93_reader';

const READERS = {
code_128_reader: Code128Reader,
Expand All @@ -26,6 +27,7 @@ const READERS = {
upc_e_reader: UPCEReader,
i2of5_reader: I2of5Reader,
'2of5_reader': TwoOfFiveReader,
code_93_reader: Code93Reader
};
export default {
create: function(config, inputImageWrapper) {
Expand Down
29 changes: 29 additions & 0 deletions src/reader/barcode_reader.js
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import ArrayHelper from '../common/array_helper';

function BarcodeReader(config, supplements) {
this._row = [];
this.config = config || {};
Expand Down Expand Up @@ -195,6 +197,33 @@ BarcodeReader.prototype._fillCounters = function(offset, end, isWhite) {
return counters;
};

BarcodeReader.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;
};

Object.defineProperty(BarcodeReader.prototype, "FORMAT", {
value: 'unknown',
writeable: false
Expand Down
27 changes: 0 additions & 27 deletions src/reader/code_39_reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,33 +20,6 @@ var properties = {
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],
Expand Down
251 changes: 251 additions & 0 deletions src/reader/code_93_reader.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,251 @@
import BarcodeReader from './barcode_reader';
import ArrayHelper from '../common/array_helper';

function Code93Reader() {
BarcodeReader.call(this);
}

const ALPHABETH_STRING = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ-. $/+%abcd*";

var properties = {
ALPHABETH_STRING: {value: ALPHABETH_STRING},
ALPHABET: {value: ALPHABETH_STRING.split('').map(char => char.charCodeAt(0))},
CHARACTER_ENCODINGS: {value: [
0x114, 0x148, 0x144, 0x142, 0x128, 0x124, 0x122, 0x150, 0x112, 0x10A,
0x1A8, 0x1A4, 0x1A2, 0x194, 0x192, 0x18A, 0x168, 0x164, 0x162, 0x134,
0x11A, 0x158, 0x14C, 0x146, 0x12C, 0x116, 0x1B4, 0x1B2, 0x1AC, 0x1A6,
0x196, 0x19A, 0x16C, 0x166, 0x136, 0x13A, 0x12E, 0x1D4, 0x1D2, 0x1CA,
0x16E, 0x176, 0x1AE, 0x126, 0x1DA, 0x1D6, 0x132, 0x15E
]},
ASTERISK: {value: 0x15E},
FORMAT: {value: "code_93", writeable: false}
};

Code93Reader.prototype = Object.create(BarcodeReader.prototype, properties);
Code93Reader.prototype.constructor = Code93Reader;

Code93Reader.prototype._decode = function() {
var self = this,
counters = [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._verifyEnd(lastStart, nextStart, counters)) {
return null;
}

if (!self._verifyChecksums(result)) {
return null;
}

result = result.slice(0, result.length - 2);
if ((result = self._decodeExtended(result)) === null) {
return null;
};

return {
code: result.join(""),
start: start.start,
end: nextStart,
startInfo: start,
decodedCodes: result
};
};

Code93Reader.prototype._verifyEnd = function(lastStart, nextStart) {
if (lastStart === nextStart || !this._row[nextStart]) {
return false;
}
return true;
};

Code93Reader.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;
};

Code93Reader.prototype._toPattern = function(counters) {
const numCounters = counters.length;
let pattern = 0;
let sum = 0;
for (let i = 0; i < numCounters; i++) {
sum += counters[i];
}

for (let i = 0; i < numCounters; i++) {
let normalized = Math.round(counters[i] * 9 / sum);
if (normalized < 1 || normalized > 4) {
return -1;
}
if ((i & 1) === 0) {
for (let j = 0; j < normalized; j++) {
pattern = (pattern << 1) | 1;
}
} else {
pattern <<= normalized;
}
}

return pattern;
};

Code93Reader.prototype._findStart = function() {
var self = this,
offset = self._nextSet(self._row),
patternStart = offset,
counter = [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 < 4; j++) {
counter[j] = counter[j + 2];
}
counter[4] = 0;
counter[5] = 0;
counterPos--;
} else {
counterPos++;
}
counter[counterPos] = 1;
isWhite = !isWhite;
}
}
return null;
};

Code93Reader.prototype._decodeExtended = function(charArray) {
const length = charArray.length;
const result = [];
for (let i = 0; i < length; i++) {
const char = charArray[i];
if (char >= 'a' && char <= 'd') {
if (i > (length - 2)) {
return null;
}
const nextChar = charArray[++i];
const nextCharCode = nextChar.charCodeAt(0);
let decodedChar;
switch (char) {
case 'a':
if (nextChar >= 'A' && nextChar <= 'Z') {
decodedChar = String.fromCharCode(nextCharCode - 64);
} else {
return null;
}
break;
case 'b':
if (nextChar >= 'A' && nextChar <= 'E') {
decodedChar = String.fromCharCode(nextCharCode - 38);
} else if (nextChar >= 'F' && nextChar <= 'J') {
decodedChar = String.fromCharCode(nextCharCode - 11);
} else if (nextChar >= 'K' && nextChar <= 'O') {
decodedChar = String.fromCharCode(nextCharCode + 16);
} else if (nextChar >= 'P' && nextChar <= 'S') {
decodedChar = String.fromCharCode(nextCharCode + 43);
} else if (nextChar >= 'T' && nextChar <= 'Z') {
decodedChar = String.fromCharCode(127);
} else {
return null;
}
break;
case 'c':
if (nextChar >= 'A' && nextChar <= 'O') {
decodedChar = String.fromCharCode(nextCharCode - 32);
} else if (nextChar === 'Z') {
decodedChar = ':';
} else {
return null;
}
break;
case 'd':
if (nextChar >= 'A' && nextChar <= 'Z') {
decodedChar = String.fromCharCode(nextCharCode + 32);
} else {
return null;
}
break;
}
result.push(decodedChar);
} else {
result.push(char);
}
}
return result;
};

Code93Reader.prototype._verifyChecksums = function(charArray) {
return this._matchCheckChar(charArray, charArray.length - 2, 20)
&& this._matchCheckChar(charArray, charArray.length - 1, 15);
};

Code93Reader.prototype._matchCheckChar = function(charArray, index, maxWeight) {
const arrayToCheck = charArray.slice(0, index);
const length = arrayToCheck.length;
const weightedSums = arrayToCheck.reduce((sum, char, i) => {
const weight = (((i * -1) + (length - 1)) % maxWeight) + 1;
const value = this.ALPHABET.indexOf(char.charCodeAt(0));
return sum + (weight * value);
}, 0);

const checkChar = this.ALPHABET[(weightedSums % 47)];
return checkChar === charArray[index].charCodeAt(0);
};

export default Code93Reader;
Binary file added test/fixtures/code_93/image-001.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-002.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-003.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-004.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-005.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-006.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-007.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-008.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-009.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added test/fixtures/code_93/image-010.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading