@sythos/js_barcode_universal 0.1.0 → 1.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/README.md +483 -425
- package/bundle/sythos-barcode.esm.js +3089 -1181
- package/bundle/sythos-barcode.js +3081 -1181
- package/examples/create.html +732 -730
- package/licenses/README.md +2 -0
- package/licenses/aztec-code.license +74 -0
- package/licenses/data-matrix.license +82 -0
- package/package.json +94 -88
- package/src/aztec/decoder.js +317 -0
- package/src/aztec/detector.js +224 -0
- package/src/aztec/encoder.js +257 -0
- package/src/aztec/high-level.js +211 -0
- package/src/aztec/index.js +45 -0
- package/src/aztec/tables.js +210 -0
- package/src/core/galois-field.js +3 -0
- package/src/core/reed-solomon.js +313 -313
- package/src/datamatrix/decoder.js +262 -0
- package/src/datamatrix/detector.js +225 -0
- package/src/datamatrix/encoder.js +191 -0
- package/src/datamatrix/index.js +42 -0
- package/src/datamatrix/tables.js +123 -0
- package/src/index.js +70 -2
|
@@ -0,0 +1,42 @@
|
|
|
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
|
+
/** Data Matrix ECC 200 entry points. @module datamatrix */
|
|
32
|
+
|
|
33
|
+
export { encodeDataMatrix, encodeDataMatrixCodewords } from './encoder.js';
|
|
34
|
+
export { decodeDataMatrix } from './decoder.js';
|
|
35
|
+
export { detectDataMatrix, detectAndDecodeDataMatrix } from './detector.js';
|
|
36
|
+
export {
|
|
37
|
+
DATAMATRIX_SYMBOLS,
|
|
38
|
+
SYMBOLS,
|
|
39
|
+
symbolForDataCodewords,
|
|
40
|
+
validateDataMatrixTables,
|
|
41
|
+
validateTables,
|
|
42
|
+
} from './tables.js';
|
|
@@ -0,0 +1,123 @@
|
|
|
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
|
+
* Data Matrix ECC 200 symbol parameters.
|
|
33
|
+
*
|
|
34
|
+
* Width and height include finder borders. `regionWidth` and `regionHeight`
|
|
35
|
+
* describe the usable modules inside one data region. The last three columns
|
|
36
|
+
* make the Reed-Solomon block split explicit instead of hiding the 144x144
|
|
37
|
+
* exception in encoder control flow.
|
|
38
|
+
*
|
|
39
|
+
* @module datamatrix/tables
|
|
40
|
+
*/
|
|
41
|
+
|
|
42
|
+
function symbol(width, height, dataRegionWidth, dataRegionHeight, dataCodewords, errorCodewords, dataBlockLengths) {
|
|
43
|
+
const blockCount = dataBlockLengths.length;
|
|
44
|
+
return Object.freeze({
|
|
45
|
+
width, height, rows: height, columns: width,
|
|
46
|
+
// Region dimensions include their one-module finder border on each side;
|
|
47
|
+
// dataRegion* expose the inner placement lattice explicitly.
|
|
48
|
+
regionWidth: dataRegionWidth + 2, regionHeight: dataRegionHeight + 2,
|
|
49
|
+
dataRegionWidth, dataRegionHeight,
|
|
50
|
+
dataRegionRows: dataRegionHeight, dataRegionColumns: dataRegionWidth,
|
|
51
|
+
dataCodewords, errorCodewords, blockCount,
|
|
52
|
+
eccPerBlock: errorCodewords / blockCount,
|
|
53
|
+
dataBlockLengths: Object.freeze(dataBlockLengths),
|
|
54
|
+
});
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
/** Classic ISO/IEC 16022 ECC 200 symbols; DMRE is deliberately excluded. */
|
|
58
|
+
export const DATAMATRIX_SYMBOLS = Object.freeze([
|
|
59
|
+
symbol(10, 10, 8, 8, 3, 5, [3]),
|
|
60
|
+
symbol(12, 12, 10, 10, 5, 7, [5]),
|
|
61
|
+
symbol(14, 14, 12, 12, 8, 10, [8]),
|
|
62
|
+
symbol(16, 16, 14, 14, 12, 12, [12]),
|
|
63
|
+
symbol(18, 18, 16, 16, 18, 14, [18]),
|
|
64
|
+
symbol(20, 20, 18, 18, 22, 18, [22]),
|
|
65
|
+
symbol(22, 22, 20, 20, 30, 20, [30]),
|
|
66
|
+
symbol(24, 24, 22, 22, 36, 24, [36]),
|
|
67
|
+
symbol(26, 26, 24, 24, 44, 28, [44]),
|
|
68
|
+
symbol(32, 32, 14, 14, 62, 36, [62]),
|
|
69
|
+
symbol(36, 36, 16, 16, 86, 42, [86]),
|
|
70
|
+
symbol(40, 40, 18, 18, 114, 48, [114]),
|
|
71
|
+
symbol(44, 44, 20, 20, 144, 56, [144]),
|
|
72
|
+
symbol(48, 48, 22, 22, 174, 68, [174]),
|
|
73
|
+
symbol(52, 52, 24, 24, 204, 84, [102, 102]),
|
|
74
|
+
symbol(64, 64, 14, 14, 280, 112, [140, 140]),
|
|
75
|
+
symbol(72, 72, 16, 16, 368, 144, [92, 92, 92, 92]),
|
|
76
|
+
symbol(80, 80, 18, 18, 456, 192, [114, 114, 114, 114]),
|
|
77
|
+
symbol(88, 88, 20, 20, 576, 224, [144, 144, 144, 144]),
|
|
78
|
+
symbol(96, 96, 22, 22, 696, 272, [174, 174, 174, 174]),
|
|
79
|
+
symbol(104, 104, 24, 24, 816, 336, [136, 136, 136, 136, 136, 136]),
|
|
80
|
+
symbol(120, 120, 18, 18, 1050, 408, [175, 175, 175, 175, 175, 175]),
|
|
81
|
+
symbol(132, 132, 20, 20, 1304, 496, [163, 163, 163, 163, 163, 163, 163, 163]),
|
|
82
|
+
symbol(144, 144, 22, 22, 1558, 620, [156, 156, 156, 156, 156, 156, 156, 156, 155, 155]),
|
|
83
|
+
symbol(18, 8, 16, 6, 5, 7, [5]),
|
|
84
|
+
symbol(32, 8, 14, 6, 10, 11, [10]),
|
|
85
|
+
symbol(26, 12, 24, 10, 16, 14, [16]),
|
|
86
|
+
symbol(36, 12, 16, 10, 22, 18, [22]),
|
|
87
|
+
symbol(36, 16, 16, 14, 32, 24, [32]),
|
|
88
|
+
symbol(48, 16, 22, 14, 49, 28, [49]),
|
|
89
|
+
]);
|
|
90
|
+
|
|
91
|
+
/** Compatibility alias. */
|
|
92
|
+
export const SYMBOLS = DATAMATRIX_SYMBOLS;
|
|
93
|
+
|
|
94
|
+
/** Return the smallest permitted symbol that holds `count` data codewords. */
|
|
95
|
+
export function symbolForDataCodewords(count, shape = 'any') {
|
|
96
|
+
for (const s of DATAMATRIX_SYMBOLS) {
|
|
97
|
+
const rectangular = s.width !== s.height;
|
|
98
|
+
if ((shape === 'square' && rectangular) || (shape === 'rectangular' && !rectangular)) continue;
|
|
99
|
+
if (count <= s.dataCodewords) return s;
|
|
100
|
+
}
|
|
101
|
+
throw new RangeError(`Data Matrix: ${count} data codewords do not fit an ECC 200 ${shape} symbol`);
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
/** Check redundant geometry and block identities in the static table. */
|
|
105
|
+
export function validateDataMatrixTables() {
|
|
106
|
+
const issues = [];
|
|
107
|
+
for (const s of DATAMATRIX_SYMBOLS) {
|
|
108
|
+
const regionsX = s.width / s.regionWidth;
|
|
109
|
+
const regionsY = s.height / s.regionHeight;
|
|
110
|
+
if (!Number.isInteger(regionsX) || !Number.isInteger(regionsY)) issues.push(`${s.width}x${s.height}: non-integral regions`);
|
|
111
|
+
const modules = regionsX * regionsY * s.dataRegionWidth * s.dataRegionHeight;
|
|
112
|
+
// Annex F reserves four terminal modules on a few lattice dimensions.
|
|
113
|
+
// They are set to dark after codeword placement and do not carry data.
|
|
114
|
+
const unused = modules - (s.dataCodewords + s.errorCodewords) * 8;
|
|
115
|
+
if (unused !== 0 && unused !== 4) issues.push(`${s.width}x${s.height}: geometry/codeword mismatch`);
|
|
116
|
+
if (s.dataBlockLengths.reduce((a, b) => a + b, 0) !== s.dataCodewords) issues.push(`${s.width}x${s.height}: data block mismatch`);
|
|
117
|
+
if (s.eccPerBlock * s.blockCount !== s.errorCodewords) issues.push(`${s.width}x${s.height}: ecc block mismatch`);
|
|
118
|
+
}
|
|
119
|
+
return issues;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** Compatibility alias. */
|
|
123
|
+
export const validateTables = validateDataMatrixTables;
|
package/src/index.js
CHANGED
|
@@ -51,7 +51,9 @@ import { LuminanceSource } from './image/luminance.js';
|
|
|
51
51
|
import { binarize } from './image/binarizer.js';
|
|
52
52
|
import { ONED_FORMATS } from './oned/index.js';
|
|
53
53
|
import { decodeOneD } from './oned/reader.js';
|
|
54
|
+
import * as datamatrix from './datamatrix/index.js';
|
|
54
55
|
import * as qr from './qr/index.js';
|
|
56
|
+
import * as aztec from './aztec/index.js';
|
|
55
57
|
|
|
56
58
|
export { BitMatrix };
|
|
57
59
|
export {
|
|
@@ -66,6 +68,10 @@ export { toPNG, toPNGDataURI } from './render/png.js';
|
|
|
66
68
|
export { renderToCanvasAuto, isWebGL2Available } from './render/index.js';
|
|
67
69
|
export { renderToCanvasAutoAsync, isWebGPUAvailable } from './render/index.js';
|
|
68
70
|
export { encodeQR, decodeQR, detectQR, detectAndDecodeQR } from './qr/index.js';
|
|
71
|
+
export {
|
|
72
|
+
encodeDataMatrix, decodeDataMatrix, detectDataMatrix, detectAndDecodeDataMatrix,
|
|
73
|
+
} from './datamatrix/index.js';
|
|
74
|
+
export { encodeAztec, decodeAztec, detectAztec, detectAndDecodeAztec } from './aztec/index.js';
|
|
69
75
|
|
|
70
76
|
/**
|
|
71
77
|
* @typedef {object} FormatInfo
|
|
@@ -89,6 +95,10 @@ const qrCanEncode = qrPresent &&
|
|
|
89
95
|
typeof qr.encodeQR === 'function' && qr.QR_CAN_ENCODE !== false;
|
|
90
96
|
const qrCanDecode = qrPresent &&
|
|
91
97
|
typeof qr.detectAndDecodeQR === 'function' && qr.QR_CAN_DECODE !== false;
|
|
98
|
+
const dataMatrixCanEncode = typeof datamatrix.encodeDataMatrix === 'function';
|
|
99
|
+
const dataMatrixCanDecode = typeof datamatrix.detectAndDecodeDataMatrix === 'function';
|
|
100
|
+
const aztecCanEncode = typeof aztec.encodeAztec === 'function';
|
|
101
|
+
const aztecCanDecode = typeof aztec.detectAndDecodeAztec === 'function';
|
|
92
102
|
|
|
93
103
|
/**
|
|
94
104
|
* Every format this build supports.
|
|
@@ -116,6 +126,20 @@ export function listFormats() {
|
|
|
116
126
|
canRead: qrCanDecode,
|
|
117
127
|
kind: /** @type {'2D'} */ ('2D'),
|
|
118
128
|
});
|
|
129
|
+
formats.push({
|
|
130
|
+
id: 'datamatrix',
|
|
131
|
+
label: 'Data Matrix ECC 200',
|
|
132
|
+
canWrite: dataMatrixCanEncode,
|
|
133
|
+
canRead: dataMatrixCanDecode,
|
|
134
|
+
kind: /** @type {'2D'} */ ('2D'),
|
|
135
|
+
});
|
|
136
|
+
formats.push({
|
|
137
|
+
id: 'aztec',
|
|
138
|
+
label: 'Aztec Code',
|
|
139
|
+
canWrite: aztecCanEncode,
|
|
140
|
+
canRead: aztecCanDecode,
|
|
141
|
+
kind: /** @type {'2D'} */ ('2D'),
|
|
142
|
+
});
|
|
119
143
|
|
|
120
144
|
return formats;
|
|
121
145
|
}
|
|
@@ -136,6 +160,9 @@ export function listFormats() {
|
|
|
136
160
|
* @param {boolean} [options.checkDigit] Append a check digit, where optional.
|
|
137
161
|
* @param {boolean} [options.fullAscii] Code 39 extended encoding.
|
|
138
162
|
* @param {boolean} [options.gs1] Emit a leading FNC1.
|
|
163
|
+
* @param {number} [options.layers] Aztec layer count; automatic if omitted.
|
|
164
|
+
* @param {boolean} [options.compact] Force an Aztec Compact or Full symbol.
|
|
165
|
+
* @param {number} [options.eccPercent] Requested Aztec error-correction percentage.
|
|
139
166
|
* @returns {BitMatrix}
|
|
140
167
|
*/
|
|
141
168
|
export function encode(text, options = {}) {
|
|
@@ -145,10 +172,16 @@ export function encode(text, options = {}) {
|
|
|
145
172
|
if (format === 'qr' || format === 'qrcode') {
|
|
146
173
|
return qr.encodeQR(value, options);
|
|
147
174
|
}
|
|
175
|
+
if (format === 'datamatrix' || format === 'data-matrix') {
|
|
176
|
+
return datamatrix.encodeDataMatrix(value, options);
|
|
177
|
+
}
|
|
178
|
+
if (format === 'aztec' || format === 'aztec-code') {
|
|
179
|
+
return aztec.encodeAztec(value, options);
|
|
180
|
+
}
|
|
148
181
|
|
|
149
182
|
const entry = ONED_FORMATS[format];
|
|
150
183
|
if (!entry) {
|
|
151
|
-
const known = [...Object.keys(ONED_FORMATS), 'qr'].join(', ');
|
|
184
|
+
const known = [...Object.keys(ONED_FORMATS), 'qr', 'datamatrix', 'aztec'].join(', ');
|
|
152
185
|
throw new EncodeError(`Unknown format "${format}". Known formats: ${known}`);
|
|
153
186
|
}
|
|
154
187
|
return entry.encode(value, options);
|
|
@@ -161,6 +194,9 @@ export function encode(text, options = {}) {
|
|
|
161
194
|
* @property {Uint8Array} [bytes] Raw payload, before text decoding.
|
|
162
195
|
* @property {number} [version] QR version.
|
|
163
196
|
* @property {string} [ecc] QR error-correction level.
|
|
197
|
+
* @property {number} [layers] Aztec layer count.
|
|
198
|
+
* @property {boolean} [compact] Whether an Aztec symbol is Compact.
|
|
199
|
+
* @property {number} [corrections] Reed–Solomon corrections applied by an Aztec decode.
|
|
164
200
|
*/
|
|
165
201
|
|
|
166
202
|
/**
|
|
@@ -181,6 +217,8 @@ export function decode(image, options = {}) {
|
|
|
181
217
|
const { formats = null, tryHarder = true, binarizer = 'auto' } = options;
|
|
182
218
|
const want = formats ? new Set(formats.map((f) => f.toLowerCase())) : null;
|
|
183
219
|
const wantQR = !want || want.has('qr') || want.has('qrcode');
|
|
220
|
+
const wantDataMatrix = !want || want.has('datamatrix') || want.has('data-matrix');
|
|
221
|
+
const wantAztec = !want || want.has('aztec') || want.has('aztec-code');
|
|
184
222
|
const wantOneD = !want || [...want].some((f) => f in ONED_FORMATS);
|
|
185
223
|
|
|
186
224
|
const source = LuminanceSource.fromImageData(image);
|
|
@@ -203,6 +241,36 @@ export function decode(image, options = {}) {
|
|
|
203
241
|
}
|
|
204
242
|
}
|
|
205
243
|
|
|
244
|
+
if (wantDataMatrix && dataMatrixCanDecode) {
|
|
245
|
+
// Hybrid thresholding can erase the interior of very large, perfectly
|
|
246
|
+
// uniform modules. In auto mode keep the local-threshold attempt, then
|
|
247
|
+
// retry Data Matrix once with the global threshold before giving up.
|
|
248
|
+
const dataMatrixBits = binarizer === 'auto' ? [bits, binarize(pass, 'global')] : [bits];
|
|
249
|
+
for (const candidateBits of dataMatrixBits) {
|
|
250
|
+
try {
|
|
251
|
+
const found = datamatrix.detectAndDecodeDataMatrix(candidateBits);
|
|
252
|
+
if (found) { results.push({ ...found, format: 'datamatrix' }); break; }
|
|
253
|
+
} catch {
|
|
254
|
+
/* no Data Matrix with this threshold */
|
|
255
|
+
}
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
if (wantAztec && aztecCanDecode) {
|
|
260
|
+
// The central bull's-eye is a small, high-contrast target. Hybrid
|
|
261
|
+
// thresholding can flatten it on clean rendered symbols, so mirror the
|
|
262
|
+
// Data Matrix global fallback in auto mode.
|
|
263
|
+
const aztecBits = binarizer === 'auto' ? [bits, binarize(pass, 'global')] : [bits];
|
|
264
|
+
for (const candidateBits of aztecBits) {
|
|
265
|
+
try {
|
|
266
|
+
const found = aztec.detectAndDecodeAztec(candidateBits);
|
|
267
|
+
if (found) { results.push({ ...found, format: 'aztec' }); break; }
|
|
268
|
+
} catch {
|
|
269
|
+
/* no Aztec code with this threshold */
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
|
|
206
274
|
if (wantOneD) {
|
|
207
275
|
const oneDFormats = want ? [...want].filter((f) => f in ONED_FORMATS) : null;
|
|
208
276
|
for (const found of decodeOneD(bits, { formats: oneDFormats, tryHarder })) {
|
|
@@ -237,4 +305,4 @@ export function decodeStrict(image, options) {
|
|
|
237
305
|
}
|
|
238
306
|
|
|
239
307
|
/** Library version, matching package.json. */
|
|
240
|
-
export const VERSION = '
|
|
308
|
+
export const VERSION = '1.1.0';
|