Skip to content

Commit 16c6fe7

Browse files
authored
Merge pull request #468 from atessmer/master
Added support for CODE93
2 parents 5ed2a2b + c7fcc9d commit 16c6fe7

10 files changed

Lines changed: 295 additions & 0 deletions

File tree

README.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ Supported barcodes:
4242
* MSI1110
4343
* [Pharmacode](https://github.com/lindell/JsBarcode/wiki/pharmacode)
4444
* [Codabar](https://github.com/lindell/JsBarcode/wiki/codabar)
45+
* CODE93
4546

4647
Examples for browsers:
4748
----
@@ -142,6 +143,7 @@ Download or get the CDN link to the script:
142143
| MSI | MSI, MSI10, MSI11, MSI1010, MSI1110 | 5 kB | [JsBarcode.msi.min.js][6] |
143144
| Pharmacode | Pharmacode | 4.7 kB | [JsBarcode.pharmacode.min.js][7] |
144145
| Codabar | Codabar | 4.9 kB | [JsBarcode.codabar.min.js][8] |
146+
| CODE93 | CODE93 | | JsBarcode.code93.min.js |
145147

146148

147149
### Step 2:

automation/barcode-building.json

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,5 +33,10 @@
3333
"name": "codabar",
3434
"names": "codabar",
3535
"barcodeFile": "./codabar"
36+
},
37+
{
38+
"name": "code93",
39+
"names": ["CODE93", "CODE93FullASCII"],
40+
"barcodeFile": "./CODE93"
3641
}
3742
]

jsbarcode.d.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ declare namespace JsBarcode {
6464
MSI1110(value: string, options?: BaseOptions): api;
6565
pharmacode(value: string, options?: BaseOptions): api;
6666
codabar(value: string, options?: BaseOptions): api;
67+
CODE93(value: string, options?: BaseOptions): api;
6768
}
6869
}
6970

src/barcodes/CODE93/CODE93.js

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// Encoding documentation:
2+
// https://en.wikipedia.org/wiki/Code_93#Detailed_outline
3+
4+
import { SYMBOLS, BINARIES, MULTI_SYMBOLS } from './constants';
5+
import Barcode from "../Barcode.js";
6+
7+
class CODE93 extends Barcode {
8+
constructor(data, options){
9+
super(data, options);
10+
}
11+
12+
valid(){
13+
return /^[0-9A-Z\-. $/+%]+$/.test(this.data);
14+
}
15+
16+
encode(){
17+
const symbols = this.data
18+
.split('')
19+
.flatMap(c => MULTI_SYMBOLS[c] || c);
20+
const encoded = symbols
21+
.map(s => CODE93.getEncoding(s))
22+
.join('');
23+
24+
// Compute checksum symbols
25+
const csumC = CODE93.checksum(symbols, 20);
26+
const csumK = CODE93.checksum(symbols.concat(csumC), 15);
27+
28+
return {
29+
text: this.text,
30+
data:
31+
// Add the start bits
32+
CODE93.getEncoding('\xff') +
33+
// Add the encoded bits
34+
encoded +
35+
// Add the checksum
36+
CODE93.getEncoding(csumC) + CODE93.getEncoding(csumK) +
37+
// Add the stop bits
38+
CODE93.getEncoding('\xff') +
39+
// Add the termination bit
40+
'1'
41+
};
42+
}
43+
44+
// Get the binary encoding of a symbol
45+
static getEncoding(symbol) {
46+
return BINARIES[CODE93.symbolValue(symbol)];
47+
}
48+
49+
// Get the symbol for a symbol value
50+
static getSymbol(symbolValue) {
51+
return SYMBOLS[symbolValue];
52+
}
53+
54+
// Get the symbol value of a symbol
55+
static symbolValue(symbol) {
56+
return SYMBOLS.indexOf(symbol);
57+
}
58+
59+
// Calculate a checksum symbol
60+
static checksum(symbols, maxWeight) {
61+
const csum = symbols
62+
.slice()
63+
.reverse()
64+
.reduce((sum, symbol, idx) => {
65+
const weight = (idx % maxWeight) + 1;
66+
return sum + (CODE93.symbolValue(symbol) * weight);
67+
}, 0);
68+
69+
return CODE93.getSymbol(csum % 47);
70+
}
71+
}
72+
73+
export default CODE93;
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Encoding documentation
2+
// https://en.wikipedia.org/wiki/Code_93#Full_ASCII_Code_93
3+
4+
import CODE93 from './CODE93.js';
5+
6+
class CODE93FullASCII extends CODE93 {
7+
constructor(data, options) {
8+
super(data, options);
9+
}
10+
11+
valid() {
12+
return /^[\x00-\x7f]+$/.test(this.data);
13+
}
14+
}
15+
16+
export default CODE93FullASCII;

src/barcodes/CODE93/constants.js

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
// The position in the array is the (checksum) value
2+
export const SYMBOLS = [
3+
'0', '1', '2', '3',
4+
'4', '5', '6', '7',
5+
'8', '9', 'A', 'B',
6+
'C', 'D', 'E', 'F',
7+
'G', 'H', 'I', 'J',
8+
'K', 'L', 'M', 'N',
9+
'O', 'P', 'Q', 'R',
10+
'S', 'T', 'U', 'V',
11+
'W', 'X', 'Y', 'Z',
12+
'-', '.', ' ', '$',
13+
'/', '+', '%',
14+
// Only used for csum and multi-symbols character encodings
15+
'($)', '(%)', '(/)', '(+)',
16+
// Start/Stop
17+
'\xff',
18+
];
19+
20+
// Order matches SYMBOLS array
21+
export const BINARIES = [
22+
'100010100', '101001000', '101000100', '101000010',
23+
'100101000', '100100100', '100100010', '101010000',
24+
'100010010', '100001010', '110101000', '110100100',
25+
'110100010', '110010100', '110010010', '110001010',
26+
'101101000', '101100100', '101100010', '100110100',
27+
'100011010', '101011000', '101001100', '101000110',
28+
'100101100', '100010110', '110110100', '110110010',
29+
'110101100', '110100110', '110010110', '110011010',
30+
'101101100', '101100110', '100110110', '100111010',
31+
'100101110', '111010100', '111010010', '111001010',
32+
'101101110', '101110110', '110101110', '100100110',
33+
'111011010', '111010110', '100110010', '101011110',
34+
];
35+
36+
// Multi-symbol characters (Full ASCII Code 93)
37+
export const MULTI_SYMBOLS = {
38+
'\x00': ['(%)', 'U'],
39+
'\x01': ['($)', 'A'],
40+
'\x02': ['($)', 'B'],
41+
'\x03': ['($)', 'C'],
42+
'\x04': ['($)', 'D'],
43+
'\x05': ['($)', 'E'],
44+
'\x06': ['($)', 'F'],
45+
'\x07': ['($)', 'G'],
46+
'\x08': ['($)', 'H'],
47+
'\x09': ['($)', 'I'],
48+
'\x0a': ['($)', 'J'],
49+
'\x0b': ['($)', 'K'],
50+
'\x0c': ['($)', 'L'],
51+
'\x0d': ['($)', 'M'],
52+
'\x0e': ['($)', 'N'],
53+
'\x0f': ['($)', 'O'],
54+
'\x10': ['($)', 'P'],
55+
'\x11': ['($)', 'Q'],
56+
'\x12': ['($)', 'R'],
57+
'\x13': ['($)', 'S'],
58+
'\x14': ['($)', 'T'],
59+
'\x15': ['($)', 'U'],
60+
'\x16': ['($)', 'V'],
61+
'\x17': ['($)', 'W'],
62+
'\x18': ['($)', 'X'],
63+
'\x19': ['($)', 'Y'],
64+
'\x1a': ['($)', 'Z'],
65+
'\x1b': ['(%)', 'A'],
66+
'\x1c': ['(%)', 'B'],
67+
'\x1d': ['(%)', 'C'],
68+
'\x1e': ['(%)', 'D'],
69+
'\x1f': ['(%)', 'E'],
70+
'!': ['(/)', 'A'],
71+
'"': ['(/)', 'B'],
72+
'#': ['(/)', 'C'],
73+
'&': ['(/)', 'F'],
74+
'\'': ['(/)', 'G'],
75+
'(': ['(/)', 'H'],
76+
')': ['(/)', 'I'],
77+
'*': ['(/)', 'J'],
78+
',': ['(/)', 'L'],
79+
':': ['(/)', 'Z'],
80+
';': ['(%)', 'F'],
81+
'<': ['(%)', 'G'],
82+
'=': ['(%)', 'H'],
83+
'>': ['(%)', 'I'],
84+
'?': ['(%)', 'J'],
85+
'@': ['(%)', 'V'],
86+
'[': ['(%)', 'K'],
87+
'\\': ['(%)', 'L'],
88+
']': ['(%)', 'M'],
89+
'^': ['(%)', 'N'],
90+
'_': ['(%)', 'O'],
91+
'`': ['(%)', 'W'],
92+
'a': ['(+)', 'A'],
93+
'b': ['(+)', 'B'],
94+
'c': ['(+)', 'C'],
95+
'd': ['(+)', 'D'],
96+
'e': ['(+)', 'E'],
97+
'f': ['(+)', 'F'],
98+
'g': ['(+)', 'G'],
99+
'h': ['(+)', 'H'],
100+
'i': ['(+)', 'I'],
101+
'j': ['(+)', 'J'],
102+
'k': ['(+)', 'K'],
103+
'l': ['(+)', 'L'],
104+
'm': ['(+)', 'M'],
105+
'n': ['(+)', 'N'],
106+
'o': ['(+)', 'O'],
107+
'p': ['(+)', 'P'],
108+
'q': ['(+)', 'Q'],
109+
'r': ['(+)', 'R'],
110+
's': ['(+)', 'S'],
111+
't': ['(+)', 'T'],
112+
'u': ['(+)', 'U'],
113+
'v': ['(+)', 'V'],
114+
'w': ['(+)', 'W'],
115+
'x': ['(+)', 'X'],
116+
'y': ['(+)', 'Y'],
117+
'z': ['(+)', 'Z'],
118+
'{': ['(%)', 'P'],
119+
'|': ['(%)', 'Q'],
120+
'}': ['(%)', 'R'],
121+
'~': ['(%)', 'S'],
122+
'\x7f': ['(%)', 'T'],
123+
};

src/barcodes/CODE93/index.js

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import CODE93 from './CODE93.js';
2+
import CODE93FullASCII from './CODE93FullASCII.js';
3+
4+
export {CODE93, CODE93FullASCII};

src/barcodes/index.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import {ITF, ITF14} from './ITF/';
55
import {MSI, MSI10, MSI11, MSI1010, MSI1110} from './MSI/';
66
import {pharmacode} from './pharmacode/';
77
import {codabar} from './codabar';
8+
import {CODE93, CODE93FullASCII} from './CODE93/';
89
import {GenericBarcode} from './GenericBarcode/';
910

1011
export default {
@@ -16,5 +17,6 @@ export default {
1617
MSI, MSI10, MSI11, MSI1010, MSI1110,
1718
pharmacode,
1819
codabar,
20+
CODE93, CODE93FullASCII,
1921
GenericBarcode
2022
};

test/browser/tests.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ function createTests(newTest){
2323
newTest("1234567890", {format: "codabar", width: 1});
2424
newTest("A1234567890A", {format: "codabar", width: 1});
2525
newTest("C1234567890D", {format: "codabar", width: 1});
26+
newTest("ABCDEFG", {format: "CODE93", width: 1});
27+
newTest("ABCDefg!", {format: "CODE93FullASCII", width: 1});
2628
newTest("12345674", {format: "GenericBarcode", width: 1});
2729
newTest("Such customize!", {
2830
width: 1,

test/node/CODE93.test.js

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
var assert = require('assert');
2+
var JsBarcode = require('../../bin/JsBarcode.js');
3+
var Canvas = require("canvas");
4+
5+
6+
describe('CODE93', function() {
7+
it('should be able to include the encoder(s)', function () {
8+
CODE93 = JsBarcode.getModule("CODE93");
9+
CODE93FullASCII = JsBarcode.getModule("CODE93FullASCII");
10+
});
11+
12+
it('should be able to encode normal text', function () {
13+
const encoded = "1010111101101010001101001001010010001010001001100101101110101001010111101";
14+
15+
var enc = new CODE93("AB12", {});
16+
assert.equal(encoded, enc.encode().data);
17+
18+
var enc = new CODE93FullASCII("AB12", {});
19+
assert.equal(encoded, enc.encode().data);
20+
});
21+
22+
it('should be able to encode full ASCII', function () {
23+
// Lowercase characters
24+
var enc = new CODE93FullASCII("ABab12", {});
25+
assert.equal("1010111101101010001101001001001100101101010001001100101101001001010010001010001001001100101011101101010111101",
26+
enc.encode().data);
27+
28+
// Special characters
29+
var enc = new CODE93FullASCII("AB!*12", {});
30+
assert.equal("1010111101101010001101001001110101101101010001110101101001101001010010001010001001100101001101011001010111101",
31+
enc.encode().data);
32+
33+
// Non-printable ASCII characters
34+
var enc = new CODE93FullASCII("AB\x07\x09", {});
35+
assert.equal("1010111101101010001101001001001001101011010001001001101011000101011010001011011001010111101",
36+
enc.encode().data);
37+
});
38+
39+
it('should warn with invalid text', function () {
40+
// Lowercase characters
41+
var enc = new CODE93("ABab12", {});
42+
assert.equal(false, enc.valid());
43+
44+
// Special characters
45+
var enc = new CODE93("AB!12", {});
46+
assert.equal(false, enc.valid());
47+
48+
// Non-printable ASCII
49+
var enc = new CODE93("AB\x07 ", {});
50+
assert.equal(false, enc.valid());
51+
52+
// Non-ASCII
53+
var enc = new CODE93FullASCII("ABð", {});
54+
assert.equal(false, enc.valid());
55+
});
56+
57+
it('should calculate correct checksums with special character checksum values', function () {
58+
var enc = new CODE93("ABCDEF123456", {});
59+
assert.equal("1010111101101010001101001001101000101100101001100100101100010101010010001010001001010000101001010001001001001001000101001100101000101001010111101"
60+
, enc.encode().data);
61+
});
62+
63+
it('should work with text option', function () {
64+
var enc = new CODE93("AB12", {text: "THISISTEXT"});
65+
assert.equal("THISISTEXT", enc.encode().text);
66+
});
67+
});

0 commit comments

Comments
 (0)