@sythos/js_barcode_universal 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +215 -0
- package/NOTICE.md +106 -0
- package/README.md +433 -0
- package/bundle/sythos-barcode.esm.js +7998 -0
- package/bundle/sythos-barcode.js +7948 -0
- package/examples/create.html +731 -0
- package/examples/read.html +341 -0
- package/licenses/README.md +42 -0
- package/licenses/codabar.license +74 -0
- package/licenses/code-11.license +69 -0
- package/licenses/code-128.license +69 -0
- package/licenses/code-39.license +70 -0
- package/licenses/code-93.license +71 -0
- package/licenses/ean-13.license +70 -0
- package/licenses/ean-8.license +70 -0
- package/licenses/gs1-128.license +71 -0
- package/licenses/isbn.license +76 -0
- package/licenses/itf-14.license +69 -0
- package/licenses/itf.license +70 -0
- package/licenses/msi-plessey.license +72 -0
- package/licenses/pharmacode.license +71 -0
- package/licenses/qr-code.license +75 -0
- package/licenses/upc-a.license +72 -0
- package/licenses/upc-e.license +69 -0
- package/package.json +89 -0
- package/src/core/bit-buffer.js +174 -0
- package/src/core/bit-matrix.js +241 -0
- package/src/core/errors.js +61 -0
- package/src/core/galois-field.js +204 -0
- package/src/core/index.js +56 -0
- package/src/core/reed-solomon.js +313 -0
- package/src/image/binarizer.js +270 -0
- package/src/image/grid-sampler.js +164 -0
- package/src/image/index.js +40 -0
- package/src/image/luminance.js +196 -0
- package/src/image/perspective.js +195 -0
- package/src/index.js +240 -0
- package/src/oned/index.js +89 -0
- package/src/oned/patterns.js +384 -0
- package/src/oned/reader.js +918 -0
- package/src/oned/writers.js +741 -0
- package/src/qr/decoder.js +575 -0
- package/src/qr/detector.js +630 -0
- package/src/qr/encoder.js +958 -0
- package/src/qr/index.js +44 -0
- package/src/qr/tables.js +737 -0
- package/src/render/image-data.js +125 -0
- package/src/render/index.js +130 -0
- package/src/render/options.js +160 -0
- package/src/render/png.js +295 -0
- package/src/render/svg.js +120 -0
- package/src/render/webgl.js +206 -0
- package/src/render/webgpu.js +369 -0
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* A 2D bit grid — the common currency of this library.
|
|
33
|
+
*
|
|
34
|
+
* Every writer produces one; every reader consumes one; every renderer draws
|
|
35
|
+
* one. Keeping it as the single interchange type is what lets formats and
|
|
36
|
+
* output targets stay independent of each other.
|
|
37
|
+
*
|
|
38
|
+
* Storage is row-packed into a Uint32Array: one allocation, cache-friendly row
|
|
39
|
+
* scans, and cheap whole-row operations for the 1D readers.
|
|
40
|
+
*
|
|
41
|
+
* Convention: a set bit is a DARK module (ink). This matches how symbols are
|
|
42
|
+
* described in every specification, and renderers invert as needed.
|
|
43
|
+
*
|
|
44
|
+
* @module core/bit-matrix
|
|
45
|
+
*/
|
|
46
|
+
|
|
47
|
+
export class BitMatrix {
|
|
48
|
+
/**
|
|
49
|
+
* @param {number} width
|
|
50
|
+
* @param {number} height
|
|
51
|
+
*/
|
|
52
|
+
constructor(width, height = width) {
|
|
53
|
+
if (width < 1 || height < 1) {
|
|
54
|
+
throw new Error(`BitMatrix: dimensions must be positive, got ${width}x${height}`);
|
|
55
|
+
}
|
|
56
|
+
this.width = width;
|
|
57
|
+
this.height = height;
|
|
58
|
+
this.rowWords = Math.ceil(width / 32);
|
|
59
|
+
this.bits = new Uint32Array(this.rowWords * height);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
/**
|
|
63
|
+
* @param {number} x @param {number} y
|
|
64
|
+
* @returns {boolean} True if the module is dark.
|
|
65
|
+
*/
|
|
66
|
+
get(x, y) {
|
|
67
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height) return false;
|
|
68
|
+
return ((this.bits[y * this.rowWords + (x >>> 5)] >>> (x & 31)) & 1) === 1;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** @param {number} x @param {number} y */
|
|
72
|
+
set(x, y) {
|
|
73
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height) return;
|
|
74
|
+
this.bits[y * this.rowWords + (x >>> 5)] |= 1 << (x & 31);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
/** @param {number} x @param {number} y */
|
|
78
|
+
unset(x, y) {
|
|
79
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height) return;
|
|
80
|
+
this.bits[y * this.rowWords + (x >>> 5)] &= ~(1 << (x & 31));
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** @param {number} x @param {number} y */
|
|
84
|
+
flip(x, y) {
|
|
85
|
+
if (x < 0 || y < 0 || x >= this.width || y >= this.height) return;
|
|
86
|
+
this.bits[y * this.rowWords + (x >>> 5)] ^= 1 << (x & 31);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/**
|
|
90
|
+
* @param {number} x @param {number} y @param {boolean} value
|
|
91
|
+
*/
|
|
92
|
+
setValue(x, y, value) {
|
|
93
|
+
if (value) this.set(x, y);
|
|
94
|
+
else this.unset(x, y);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/** Fill a rectangle. @param {number} x @param {number} y @param {number} w @param {number} h */
|
|
98
|
+
setRegion(x, y, w, h) {
|
|
99
|
+
for (let j = y; j < y + h; j++) {
|
|
100
|
+
for (let i = x; i < x + w; i++) this.set(i, j);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
clear() {
|
|
105
|
+
this.bits.fill(0);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
/** @returns {BitMatrix} */
|
|
109
|
+
clone() {
|
|
110
|
+
const m = new BitMatrix(this.width, this.height);
|
|
111
|
+
m.bits.set(this.bits);
|
|
112
|
+
return m;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Copy row `y` into a reusable array, avoiding an allocation per row in the
|
|
117
|
+
* 1D scanning loops which run this thousands of times per image.
|
|
118
|
+
*
|
|
119
|
+
* @param {number} y
|
|
120
|
+
* @param {Uint8Array} [out]
|
|
121
|
+
* @returns {Uint8Array}
|
|
122
|
+
*/
|
|
123
|
+
getRow(y, out) {
|
|
124
|
+
const row = out && out.length >= this.width ? out : new Uint8Array(this.width);
|
|
125
|
+
const base = y * this.rowWords;
|
|
126
|
+
for (let x = 0; x < this.width; x++) {
|
|
127
|
+
row[x] = (this.bits[base + (x >>> 5)] >>> (x & 31)) & 1;
|
|
128
|
+
}
|
|
129
|
+
return row;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Add a uniform light border. Symbols need a quiet zone to be scannable at
|
|
134
|
+
* all, so this is applied by default when rendering.
|
|
135
|
+
*
|
|
136
|
+
* @param {number} size Modules of margin on every side.
|
|
137
|
+
* @returns {BitMatrix}
|
|
138
|
+
*/
|
|
139
|
+
withMargin(size) {
|
|
140
|
+
if (size <= 0) return this.clone();
|
|
141
|
+
const m = new BitMatrix(this.width + size * 2, this.height + size * 2);
|
|
142
|
+
for (let y = 0; y < this.height; y++) {
|
|
143
|
+
for (let x = 0; x < this.width; x++) {
|
|
144
|
+
if (this.get(x, y)) m.set(x + size, y + size);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
return m;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
/**
|
|
151
|
+
* Nearest-neighbour upscale. Integer factors only — a barcode resampled with
|
|
152
|
+
* interpolation stops being readable.
|
|
153
|
+
*
|
|
154
|
+
* @param {number} factor
|
|
155
|
+
* @returns {BitMatrix}
|
|
156
|
+
*/
|
|
157
|
+
scale(factor) {
|
|
158
|
+
const f = Math.max(1, Math.floor(factor));
|
|
159
|
+
if (f === 1) return this.clone();
|
|
160
|
+
const m = new BitMatrix(this.width * f, this.height * f);
|
|
161
|
+
for (let y = 0; y < this.height; y++) {
|
|
162
|
+
for (let x = 0; x < this.width; x++) {
|
|
163
|
+
if (this.get(x, y)) m.setRegion(x * f, y * f, f, f);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
return m;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
/**
|
|
170
|
+
* Bounding box of the dark modules, or null if the matrix is empty.
|
|
171
|
+
* @returns {{x: number, y: number, width: number, height: number} | null}
|
|
172
|
+
*/
|
|
173
|
+
getBounds() {
|
|
174
|
+
let minX = this.width, minY = this.height, maxX = -1, maxY = -1;
|
|
175
|
+
for (let y = 0; y < this.height; y++) {
|
|
176
|
+
for (let x = 0; x < this.width; x++) {
|
|
177
|
+
if (this.get(x, y)) {
|
|
178
|
+
if (x < minX) minX = x;
|
|
179
|
+
if (x > maxX) maxX = x;
|
|
180
|
+
if (y < minY) minY = y;
|
|
181
|
+
if (y > maxY) maxY = y;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
if (maxX < 0) return null;
|
|
186
|
+
return { x: minX, y: minY, width: maxX - minX + 1, height: maxY - minY + 1 };
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Rotate 180 degrees, in place. Cheaper than re-detecting when a reader
|
|
191
|
+
* discovers a symbol is upside down.
|
|
192
|
+
*/
|
|
193
|
+
rotate180() {
|
|
194
|
+
const w = this.width, h = this.height;
|
|
195
|
+
for (let y = 0; y < Math.ceil(h / 2); y++) {
|
|
196
|
+
for (let x = 0; x < w; x++) {
|
|
197
|
+
const oy = h - 1 - y, ox = w - 1 - x;
|
|
198
|
+
if (y === oy && x >= ox) break;
|
|
199
|
+
const a = this.get(x, y);
|
|
200
|
+
const b = this.get(ox, oy);
|
|
201
|
+
this.setValue(x, y, b);
|
|
202
|
+
this.setValue(ox, oy, a);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Build from a string of '1'/'X'/'#' (dark) and anything else (light),
|
|
209
|
+
* newline-separated. Test fixtures are far more legible this way.
|
|
210
|
+
*
|
|
211
|
+
* @param {string} text
|
|
212
|
+
* @returns {BitMatrix}
|
|
213
|
+
*/
|
|
214
|
+
static parse(text) {
|
|
215
|
+
const lines = text.trim().split('\n').map((l) => l.trim()).filter((l) => l.length);
|
|
216
|
+
const height = lines.length;
|
|
217
|
+
const width = Math.max(...lines.map((l) => l.length));
|
|
218
|
+
const m = new BitMatrix(width, height);
|
|
219
|
+
for (let y = 0; y < height; y++) {
|
|
220
|
+
for (let x = 0; x < lines[y].length; x++) {
|
|
221
|
+
const c = lines[y][x];
|
|
222
|
+
if (c === '1' || c === 'X' || c === 'x' || c === '#') m.set(x, y);
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
return m;
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
/**
|
|
229
|
+
* @param {string} [dark] @param {string} [light]
|
|
230
|
+
* @returns {string}
|
|
231
|
+
*/
|
|
232
|
+
toString(dark = '##', light = ' ') {
|
|
233
|
+
const rows = [];
|
|
234
|
+
for (let y = 0; y < this.height; y++) {
|
|
235
|
+
let s = '';
|
|
236
|
+
for (let x = 0; x < this.width; x++) s += this.get(x, y) ? dark : light;
|
|
237
|
+
rows.push(s);
|
|
238
|
+
}
|
|
239
|
+
return rows.join('\n');
|
|
240
|
+
}
|
|
241
|
+
}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Error types.
|
|
33
|
+
*
|
|
34
|
+
* Decoding uses exceptions for control flow internally: a detector that fails
|
|
35
|
+
* on one candidate should be cheap to abandon, and a `try` around a candidate
|
|
36
|
+
* loop reads better than threading `null` through six call frames. The public
|
|
37
|
+
* API converts them to results.
|
|
38
|
+
*
|
|
39
|
+
* @module core/errors
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
/** Base class so consumers can `catch (e) { if (e instanceof BarcodeError) ... }`. */
|
|
43
|
+
export class BarcodeError extends Error {
|
|
44
|
+
/** @param {string} message */
|
|
45
|
+
constructor(message) {
|
|
46
|
+
super(message);
|
|
47
|
+
this.name = new.target.name;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/** Input could not be encoded — bad payload, or it does not fit the symbology. */
|
|
52
|
+
export class EncodeError extends BarcodeError {}
|
|
53
|
+
|
|
54
|
+
/** No symbol was found in the image. Not an error condition for `decode()`. */
|
|
55
|
+
export class NotFoundError extends BarcodeError {}
|
|
56
|
+
|
|
57
|
+
/** A symbol was found, but its geometry or content is malformed. */
|
|
58
|
+
export class FormatError extends BarcodeError {}
|
|
59
|
+
|
|
60
|
+
/** A symbol was found and read, but error correction could not repair it. */
|
|
61
|
+
export class ChecksumError extends BarcodeError {}
|
|
@@ -0,0 +1,204 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Finite field arithmetic.
|
|
33
|
+
*
|
|
34
|
+
* One class serves every field this suite needs:
|
|
35
|
+
*
|
|
36
|
+
* GF(2^4) Aztec, small layer counts
|
|
37
|
+
* GF(2^6) Aztec
|
|
38
|
+
* GF(2^8) QR Code, Data Matrix, Aztec
|
|
39
|
+
* GF(2^10) Aztec
|
|
40
|
+
* GF(2^12) Aztec
|
|
41
|
+
* GF(929) PDF417 <- a PRIME field, not a binary one
|
|
42
|
+
*
|
|
43
|
+
* ## The prime-field trap
|
|
44
|
+
*
|
|
45
|
+
* Multiplication unifies cleanly: exp/log tables work for the multiplicative
|
|
46
|
+
* group of any finite field. Addition does NOT.
|
|
47
|
+
*
|
|
48
|
+
* binary GF(2^m): a + b == a - b == a XOR b (self-inverse)
|
|
49
|
+
* prime GF(p): a + b == (a+b) % p
|
|
50
|
+
* a - b == (a-b+p) % p (NOT self-inverse)
|
|
51
|
+
*
|
|
52
|
+
* So `add`, `sub` and `neg` are methods on the field, never inlined. Any code
|
|
53
|
+
* that writes a bare `^` for field arithmetic works perfectly for every binary
|
|
54
|
+
* field and silently corrupts PDF417 — the failure is invisible until a real
|
|
55
|
+
* scanner rejects the symbol. Route every operation through the field object.
|
|
56
|
+
*
|
|
57
|
+
* @module core/galois-field
|
|
58
|
+
*/
|
|
59
|
+
|
|
60
|
+
export class GaloisField {
|
|
61
|
+
/**
|
|
62
|
+
* @param {object} opts
|
|
63
|
+
* @param {number} opts.size Field order: 2^m for binary, p for prime.
|
|
64
|
+
* @param {boolean} [opts.prime] True for a prime field (mod arithmetic).
|
|
65
|
+
* @param {number} [opts.primitive] Primitive polynomial, binary fields only.
|
|
66
|
+
* @param {number} [opts.generator] Multiplicative generator. Defaults to 2
|
|
67
|
+
* for binary fields (x), and must be given explicitly for prime fields.
|
|
68
|
+
* @param {string} [opts.name]
|
|
69
|
+
*/
|
|
70
|
+
constructor({ size, prime = false, primitive = 0, generator = 2, name = '' }) {
|
|
71
|
+
this.size = size;
|
|
72
|
+
this.prime = prime;
|
|
73
|
+
this.primitive = primitive;
|
|
74
|
+
this.generator = generator;
|
|
75
|
+
this.name = name || (prime ? `GF(${size})` : `GF(2^${Math.log2(size)})`);
|
|
76
|
+
|
|
77
|
+
/** Multiplicative order: every non-zero element is generator^i for some i < order. */
|
|
78
|
+
this.order = size - 1;
|
|
79
|
+
|
|
80
|
+
const exp = new Int32Array(this.order * 2);
|
|
81
|
+
const log = new Int32Array(size).fill(-1);
|
|
82
|
+
|
|
83
|
+
let x = 1;
|
|
84
|
+
for (let i = 0; i < this.order; i++) {
|
|
85
|
+
exp[i] = x;
|
|
86
|
+
log[x] = i;
|
|
87
|
+
if (prime) {
|
|
88
|
+
x = (x * generator) % size;
|
|
89
|
+
} else {
|
|
90
|
+
x <<= 1;
|
|
91
|
+
if (x >= size) x ^= primitive;
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
// Wrapped copy lets mul() skip a modulo on the common path.
|
|
95
|
+
for (let i = 0; i < this.order; i++) exp[this.order + i] = exp[i];
|
|
96
|
+
|
|
97
|
+
// A short cycle still returns to 1 after `order` steps whenever its length
|
|
98
|
+
// divides `order`, so "did we end at 1" does not detect a bad generator.
|
|
99
|
+
// The reliable test is coverage: a true generator visits every non-zero
|
|
100
|
+
// element exactly once, leaving no -1 in the log table.
|
|
101
|
+
for (let v = 1; v < size; v++) {
|
|
102
|
+
if (log[v] === -1) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`${this.name}: generator ${generator} does not generate the ` +
|
|
105
|
+
`multiplicative group (element ${v} is unreachable). ` +
|
|
106
|
+
(prime ? 'Choose a primitive root.' : 'Check the primitive polynomial.')
|
|
107
|
+
);
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
this.expTable = exp;
|
|
112
|
+
this.logTable = log;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Additive identity is 0 and multiplicative identity is 1 in every field here. */
|
|
116
|
+
get zero() { return 0; }
|
|
117
|
+
get one() { return 1; }
|
|
118
|
+
|
|
119
|
+
/**
|
|
120
|
+
* a + b.
|
|
121
|
+
* @param {number} a @param {number} b @returns {number}
|
|
122
|
+
*/
|
|
123
|
+
add(a, b) {
|
|
124
|
+
return this.prime ? (a + b) % this.size : a ^ b;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* a - b. Distinct from add() in prime fields — see the module note.
|
|
129
|
+
* @param {number} a @param {number} b @returns {number}
|
|
130
|
+
*/
|
|
131
|
+
sub(a, b) {
|
|
132
|
+
return this.prime ? (a - b + this.size) % this.size : a ^ b;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/**
|
|
136
|
+
* -a.
|
|
137
|
+
* @param {number} a @returns {number}
|
|
138
|
+
*/
|
|
139
|
+
neg(a) {
|
|
140
|
+
return this.prime ? (this.size - a) % this.size : a;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* a * b.
|
|
145
|
+
* @param {number} a @param {number} b @returns {number}
|
|
146
|
+
*/
|
|
147
|
+
mul(a, b) {
|
|
148
|
+
if (a === 0 || b === 0) return 0;
|
|
149
|
+
return this.expTable[this.logTable[a] + this.logTable[b]];
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
/**
|
|
153
|
+
* a / b.
|
|
154
|
+
* @param {number} a @param {number} b @returns {number}
|
|
155
|
+
*/
|
|
156
|
+
div(a, b) {
|
|
157
|
+
if (b === 0) throw new Error(`${this.name}: division by zero`);
|
|
158
|
+
if (a === 0) return 0;
|
|
159
|
+
return this.expTable[this.logTable[a] - this.logTable[b] + this.order];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/**
|
|
163
|
+
* 1 / a.
|
|
164
|
+
* @param {number} a @returns {number}
|
|
165
|
+
*/
|
|
166
|
+
inv(a) {
|
|
167
|
+
if (a === 0) throw new Error(`${this.name}: zero has no inverse`);
|
|
168
|
+
return this.expTable[this.order - this.logTable[a]];
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* generator^i, for any integer i (negative included).
|
|
173
|
+
* @param {number} i @returns {number}
|
|
174
|
+
*/
|
|
175
|
+
exp(i) {
|
|
176
|
+
let k = i % this.order;
|
|
177
|
+
if (k < 0) k += this.order;
|
|
178
|
+
return this.expTable[k];
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Discrete log base generator.
|
|
183
|
+
* @param {number} a @returns {number}
|
|
184
|
+
*/
|
|
185
|
+
log(a) {
|
|
186
|
+
if (a === 0) throw new Error(`${this.name}: log of zero`);
|
|
187
|
+
return this.logTable[a];
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
/** QR Code, Data Matrix uses its own — see below. x^8 + x^4 + x^3 + x^2 + 1 */
|
|
192
|
+
export const GF256_QR = new GaloisField({ size: 256, primitive: 0x011d, name: 'GF(256)/QR' });
|
|
193
|
+
|
|
194
|
+
/** Data Matrix ECC200. x^8 + x^5 + x^3 + x^2 + 1 */
|
|
195
|
+
export const GF256_DM = new GaloisField({ size: 256, primitive: 0x012d, name: 'GF(256)/DataMatrix' });
|
|
196
|
+
|
|
197
|
+
/** PDF417. Prime field; 3 is a primitive root modulo 929. */
|
|
198
|
+
export const GF929 = new GaloisField({ size: 929, prime: true, generator: 3, name: 'GF(929)' });
|
|
199
|
+
|
|
200
|
+
/** Aztec, by layer count. */
|
|
201
|
+
export const GF16 = new GaloisField({ size: 16, primitive: 0x13, name: 'GF(16)' });
|
|
202
|
+
export const GF64 = new GaloisField({ size: 64, primitive: 0x43, name: 'GF(64)' });
|
|
203
|
+
export const GF1024 = new GaloisField({ size: 1024, primitive: 0x409, name: 'GF(1024)' });
|
|
204
|
+
export const GF4096 = new GaloisField({ size: 4096, primitive: 0x1069, name: 'GF(4096)' });
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
*
|
|
6
|
+
* Copyright (c) 2026 Sythos
|
|
7
|
+
*
|
|
8
|
+
* Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
9
|
+
* of this software and associated documentation files (the "Software"), to deal
|
|
10
|
+
* in the Software without restriction, including without limitation the rights
|
|
11
|
+
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
12
|
+
* copies of the Software, and to permit persons to whom the Software is
|
|
13
|
+
* furnished to do so, subject to the following conditions:
|
|
14
|
+
*
|
|
15
|
+
* The above copyright notice and this permission notice shall be included in all
|
|
16
|
+
* copies or substantial portions of the Software.
|
|
17
|
+
*
|
|
18
|
+
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
19
|
+
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
20
|
+
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
21
|
+
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
22
|
+
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
23
|
+
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
24
|
+
* SOFTWARE.
|
|
25
|
+
*
|
|
26
|
+
* SPDX-License-Identifier: MIT
|
|
27
|
+
*
|
|
28
|
+
* Original work. No code from any other barcode implementation.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Core primitives, re-exported.
|
|
33
|
+
*
|
|
34
|
+
* @module core
|
|
35
|
+
*/
|
|
36
|
+
|
|
37
|
+
export { BitMatrix } from './bit-matrix.js';
|
|
38
|
+
export { BitWriter, BitReader } from './bit-buffer.js';
|
|
39
|
+
export {
|
|
40
|
+
GaloisField,
|
|
41
|
+
GF256_QR,
|
|
42
|
+
GF256_DM,
|
|
43
|
+
GF929,
|
|
44
|
+
GF16,
|
|
45
|
+
GF64,
|
|
46
|
+
GF1024,
|
|
47
|
+
GF4096,
|
|
48
|
+
} from './galois-field.js';
|
|
49
|
+
export { rsEncode, rsDecode, generatorPoly } from './reed-solomon.js';
|
|
50
|
+
export {
|
|
51
|
+
BarcodeError,
|
|
52
|
+
EncodeError,
|
|
53
|
+
NotFoundError,
|
|
54
|
+
FormatError,
|
|
55
|
+
ChecksumError,
|
|
56
|
+
} from './errors.js';
|