@sythos/js_barcode_universal 1.5.13 → 1.5.15
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 +22 -4
- package/NOTICE.md +10 -1
- package/README.md +416 -22
- package/bundle/sythos-barcode.esm.js +22176 -11991
- package/bundle/sythos-barcode.js +22059 -11991
- package/licenses/README.md +12 -1
- package/licenses/codablockf.license +51 -0
- package/licenses/code16k.license +52 -0
- package/licenses/code25.license +58 -0
- package/licenses/code32.license +51 -0
- package/licenses/dotcode.license +66 -0
- package/licenses/gs1-composite.license +106 -0
- package/licenses/gs1-databar.license +21 -14
- package/licenses/hanxin.license +95 -0
- package/licenses/maxicode.license +62 -0
- package/licenses/postal.license +61 -0
- package/licenses/pzn.license +53 -0
- package/licenses/telepen.license +73 -0
- package/llms.txt +62 -6
- package/package.json +47 -3
- package/src/index.d.ts +111 -6
- package/src/index.js +362 -13
- package/src/js/codablockf/decoder.js +198 -0
- package/src/js/codablockf/encoder.js +97 -0
- package/src/js/codablockf/index.js +3 -0
- package/src/js/code16k/decoder.js +303 -0
- package/src/js/code16k/detector.js +187 -0
- package/src/js/code16k/encoder.js +153 -0
- package/src/js/code16k/index.js +14 -0
- package/src/js/code16k/tables.js +152 -0
- package/src/js/composite/index.js +570 -0
- package/src/js/core/detection-contract.js +185 -0
- package/src/js/core/symbol-layout.js +155 -0
- package/src/js/databar/expanded.js +968 -0
- package/src/js/databar/index.js +4 -0
- package/src/js/databar/layout.js +192 -0
- package/src/js/databar/limited.js +533 -0
- package/src/js/databar/stacked-omnidirectional.js +548 -0
- package/src/js/databar/stacked.js +528 -0
- package/src/js/dotcode/decoder.js +548 -0
- package/src/js/dotcode/detector.js +251 -0
- package/src/js/dotcode/encoder.js +453 -0
- package/src/js/dotcode/index.js +34 -0
- package/src/js/dotcode/tables.js +168 -0
- package/src/js/hanxin/decoder.js +299 -0
- package/src/js/hanxin/detector.js +122 -0
- package/src/js/hanxin/encoder.js +259 -0
- package/src/js/hanxin/index.js +16 -0
- package/src/js/hanxin/tables.js +316 -0
- package/src/js/image/height-coded.js +164 -0
- package/src/js/maxicode/decoder.js +275 -0
- package/src/js/maxicode/detector.js +118 -0
- package/src/js/maxicode/encoder.js +438 -0
- package/src/js/maxicode/index.js +34 -0
- package/src/js/maxicode/tables.js +132 -0
- package/src/js/oned/code25.js +148 -0
- package/src/js/oned/index.js +21 -3
- package/src/js/oned/postal.js +889 -0
- package/src/js/oned/reader.js +272 -7
- package/src/js/oned/telepen.js +361 -0
- package/src/js/oned/writers.js +186 -12
- package/src/js/stacked128/common.js +208 -0
- package/src/ts/codablockf/decoder.ts +212 -0
- package/src/ts/codablockf/encoder.ts +128 -0
- package/src/ts/codablockf/index.d.ts +31 -0
- package/src/ts/codablockf/index.ts +6 -0
- package/src/ts/code16k/decoder.d.ts +25 -0
- package/src/ts/code16k/decoder.ts +313 -0
- package/src/ts/code16k/detector.d.ts +21 -0
- package/src/ts/code16k/detector.ts +203 -0
- package/src/ts/code16k/encoder.d.ts +26 -0
- package/src/ts/code16k/encoder.ts +198 -0
- package/src/ts/code16k/index.d.ts +10 -0
- package/src/ts/code16k/index.ts +47 -0
- package/src/ts/code16k/tables.d.ts +54 -0
- package/src/ts/code16k/tables.ts +195 -0
- package/src/ts/composite/index.d.ts +74 -0
- package/src/ts/composite/index.ts +547 -0
- package/src/ts/core/detection-contract.d.ts +119 -0
- package/src/ts/core/detection-contract.ts +267 -0
- package/src/ts/core/symbol-layout.d.ts +108 -0
- package/src/ts/core/symbol-layout.ts +236 -0
- package/src/ts/databar/expanded.d.ts +40 -0
- package/src/ts/databar/expanded.ts +948 -0
- package/src/ts/databar/index.d.ts +48 -0
- package/src/ts/databar/index.ts +48 -0
- package/src/ts/databar/layout.d.ts +122 -0
- package/src/ts/databar/layout.ts +275 -0
- package/src/ts/databar/limited.d.ts +85 -0
- package/src/ts/databar/limited.ts +553 -0
- package/src/ts/databar/stacked-omnidirectional.d.ts +128 -0
- package/src/ts/databar/stacked-omnidirectional.ts +559 -0
- package/src/ts/databar/stacked.d.ts +96 -0
- package/src/ts/databar/stacked.ts +549 -0
- package/src/ts/dotcode/decoder.d.ts +58 -0
- package/src/ts/dotcode/decoder.ts +467 -0
- package/src/ts/dotcode/detector.d.ts +63 -0
- package/src/ts/dotcode/detector.ts +263 -0
- package/src/ts/dotcode/encoder.d.ts +69 -0
- package/src/ts/dotcode/encoder.ts +427 -0
- package/src/ts/dotcode/index.d.ts +37 -0
- package/src/ts/dotcode/index.ts +72 -0
- package/src/ts/dotcode/tables.d.ts +74 -0
- package/src/ts/dotcode/tables.ts +174 -0
- package/src/ts/hanxin/decoder.d.ts +48 -0
- package/src/ts/hanxin/decoder.ts +314 -0
- package/src/ts/hanxin/detector.d.ts +45 -0
- package/src/ts/hanxin/detector.ts +124 -0
- package/src/ts/hanxin/encoder.d.ts +41 -0
- package/src/ts/hanxin/encoder.ts +290 -0
- package/src/ts/hanxin/index.d.ts +16 -0
- package/src/ts/hanxin/index.ts +18 -0
- package/src/ts/hanxin/tables.d.ts +80 -0
- package/src/ts/hanxin/tables.ts +348 -0
- package/src/ts/image/height-coded.d.ts +101 -0
- package/src/ts/image/height-coded.ts +227 -0
- package/src/ts/index.d.ts +46 -2
- package/src/ts/index.ts +380 -13
- package/src/ts/maxicode/decoder.ts +265 -0
- package/src/ts/maxicode/detector.ts +109 -0
- package/src/ts/maxicode/encoder.ts +414 -0
- package/src/ts/maxicode/index.d.ts +96 -0
- package/src/ts/maxicode/index.ts +44 -0
- package/src/ts/maxicode/tables.ts +136 -0
- package/src/ts/oned/code25.d.ts +42 -0
- package/src/ts/oned/code25.ts +170 -0
- package/src/ts/oned/index.d.ts +7 -2
- package/src/ts/oned/index.ts +45 -3
- package/src/ts/oned/postal.d.ts +44 -0
- package/src/ts/oned/postal.ts +819 -0
- package/src/ts/oned/reader.d.ts +35 -0
- package/src/ts/oned/reader.ts +261 -7
- package/src/ts/oned/telepen.d.ts +65 -0
- package/src/ts/oned/telepen.ts +368 -0
- package/src/ts/oned/writers.d.ts +32 -0
- package/src/ts/oned/writers.ts +184 -13
- package/src/ts/stacked128/common.ts +225 -0
|
@@ -0,0 +1,198 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
* Copyright (c) 2026 Sythos
|
|
6
|
+
* SPDX-License-Identifier: MIT
|
|
7
|
+
*
|
|
8
|
+
* Original work. No code from any other barcode implementation.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Code 16K encoder. @module code16k/encoder */
|
|
12
|
+
|
|
13
|
+
import { BitMatrix } from '../core/bit-matrix.js';
|
|
14
|
+
import { EncodeError } from '../core/errors.js';
|
|
15
|
+
import {
|
|
16
|
+
code128DataCodewords,
|
|
17
|
+
} from '../oned/writers.js';
|
|
18
|
+
import { renderStackedRows } from '../stacked128/common.js';
|
|
19
|
+
import {
|
|
20
|
+
CODE16K_CODEWORD_WIDTH,
|
|
21
|
+
CODE16K_PAD,
|
|
22
|
+
CODE16K_SYMBOLS_PER_ROW,
|
|
23
|
+
code16kModeInfo,
|
|
24
|
+
code16kStartModules,
|
|
25
|
+
code16kStopModules,
|
|
26
|
+
validateCode16KOptions,
|
|
27
|
+
type Code16KEncodeOptions,
|
|
28
|
+
} from './tables.js';
|
|
29
|
+
import { code128PatternModules } from '../stacked128/common.js';
|
|
30
|
+
|
|
31
|
+
/** Metadata carried by matrices produced by {@link encodeCode16K}. */
|
|
32
|
+
export type Code16KMetadata = {
|
|
33
|
+
format: 'code16k';
|
|
34
|
+
rows: number;
|
|
35
|
+
columns: number;
|
|
36
|
+
rowHeight: number;
|
|
37
|
+
separatorHeight: number;
|
|
38
|
+
mode: number;
|
|
39
|
+
codewords: number[];
|
|
40
|
+
checksum: true;
|
|
41
|
+
};
|
|
42
|
+
|
|
43
|
+
/** A Code 16K matrix with optional non-authoritative encoder metadata. */
|
|
44
|
+
export type Code16KMatrix = BitMatrix & { code16k?: Code16KMetadata };
|
|
45
|
+
|
|
46
|
+
function asciiText(value: string | Uint8Array | readonly number[]): string {
|
|
47
|
+
if (typeof value === 'string') {
|
|
48
|
+
if (value.length > 4096) throw new EncodeError('Code 16K: value is too long for the 16-row symbol limit');
|
|
49
|
+
for (const character of value) {
|
|
50
|
+
if (character.codePointAt(0)! > 127) {
|
|
51
|
+
throw new EncodeError('Code 16K: value must contain seven-bit ASCII characters');
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
const bytes = value instanceof Uint8Array ? Array.from(value) :
|
|
57
|
+
Array.isArray(value) ? value : null;
|
|
58
|
+
if (!bytes) throw new EncodeError('Code 16K: value must be text or seven-bit bytes');
|
|
59
|
+
if (bytes.length > 4096) throw new EncodeError('Code 16K: value is too long for the 16-row symbol limit');
|
|
60
|
+
if (bytes.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 127)) {
|
|
61
|
+
throw new EncodeError('Code 16K: byte input must contain values from 0 to 127');
|
|
62
|
+
}
|
|
63
|
+
return bytes.map((byte) => String.fromCharCode(byte)).join('');
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
function checksumOne(values: readonly number[]): number {
|
|
67
|
+
let sum = 0;
|
|
68
|
+
for (let index = 0; index < values.length; index++) sum += (index + 2) * values[index];
|
|
69
|
+
return sum % 107;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
function checksumTwo(valuesThroughC1: readonly number[]): number {
|
|
73
|
+
let sum = 0;
|
|
74
|
+
for (let index = 0; index < valuesThroughC1.length; index++) {
|
|
75
|
+
sum += (index + 1) * valuesThroughC1[index];
|
|
76
|
+
}
|
|
77
|
+
return sum % 107;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
function rowModules(row: number, values: readonly number[]): string {
|
|
81
|
+
if (values.length !== CODE16K_SYMBOLS_PER_ROW) {
|
|
82
|
+
throw new EncodeError('Code 16K: every row must contain exactly five symbol characters');
|
|
83
|
+
}
|
|
84
|
+
let modules = code16kStartModules(row) + '1';
|
|
85
|
+
for (const value of values) {
|
|
86
|
+
if (!Number.isInteger(value) || value < 0 || value > 106) {
|
|
87
|
+
throw new EncodeError(`Code 16K: invalid Code 128 symbol value ${value}`);
|
|
88
|
+
}
|
|
89
|
+
const symbol = code128PatternModules(value);
|
|
90
|
+
if (symbol.length !== CODE16K_CODEWORD_WIDTH) {
|
|
91
|
+
throw new EncodeError('Code 16K: Code 128 symbol width invariant failed');
|
|
92
|
+
}
|
|
93
|
+
modules += symbol;
|
|
94
|
+
}
|
|
95
|
+
modules += code16kStopModules(row);
|
|
96
|
+
if (modules.length !== 70) throw new EncodeError('Code 16K: internal row width mismatch');
|
|
97
|
+
return modules;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
/**
|
|
101
|
+
* Encode a Code 16K symbol.
|
|
102
|
+
*
|
|
103
|
+
* The implementation accepts seven-bit ASCII and the standard Code 128 A/B/C
|
|
104
|
+
* data sets. It chooses the smallest legal row count unless `rows` is given.
|
|
105
|
+
* The first symbol character carries the row count and mode; C1 and C2 are
|
|
106
|
+
* calculated over every preceding symbol character exactly as specified.
|
|
107
|
+
*
|
|
108
|
+
* @param {string|Uint8Array|number[]} value
|
|
109
|
+
* @param {Code16KEncodeOptions} [options]
|
|
110
|
+
* @returns {Code16KMatrix}
|
|
111
|
+
*/
|
|
112
|
+
export function encodeCode16K(
|
|
113
|
+
value: string | Uint8Array | readonly number[],
|
|
114
|
+
options: Code16KEncodeOptions = {},
|
|
115
|
+
): Code16KMatrix {
|
|
116
|
+
const text = asciiText(value);
|
|
117
|
+
if (text.length === 0) throw new EncodeError('Code 16K: value must not be empty');
|
|
118
|
+
|
|
119
|
+
const validated = validateCode16KOptions(options);
|
|
120
|
+
const info = code16kModeInfo(options.mode, options.gs1 === true);
|
|
121
|
+
const tokenized = code128DataCodewords(text, {
|
|
122
|
+
gs1: info.gs1,
|
|
123
|
+
startSet: info.startSet,
|
|
124
|
+
});
|
|
125
|
+
const data = tokenized.values.slice();
|
|
126
|
+
|
|
127
|
+
const minimumRows = Math.max(2, Math.ceil((data.length + 3) / CODE16K_SYMBOLS_PER_ROW));
|
|
128
|
+
const rows = validated.rows ?? minimumRows;
|
|
129
|
+
if (rows < 2 || rows > 16) {
|
|
130
|
+
throw new EncodeError('Code 16K: payload needs between 2 and 16 rows');
|
|
131
|
+
}
|
|
132
|
+
const capacity = rows * CODE16K_SYMBOLS_PER_ROW - 3;
|
|
133
|
+
if (data.length > capacity) {
|
|
134
|
+
throw new EncodeError(`Code 16K: payload needs ${data.length} data symbols but ${capacity} fit in ${rows} rows`);
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
const first = 7 * (rows - 2) + info.mode;
|
|
138
|
+
if (first > 104) throw new EncodeError('Code 16K: row count and mode do not fit the S symbol');
|
|
139
|
+
while (data.length < capacity) data.push(CODE16K_PAD);
|
|
140
|
+
|
|
141
|
+
const beforeChecks = [first, ...data];
|
|
142
|
+
const c1 = checksumOne(beforeChecks);
|
|
143
|
+
const c2 = checksumTwo([...beforeChecks, c1]);
|
|
144
|
+
const codewords = [...beforeChecks, c1, c2];
|
|
145
|
+
if (codewords.length !== rows * CODE16K_SYMBOLS_PER_ROW) {
|
|
146
|
+
throw new EncodeError('Code 16K: internal codeword packing mismatch');
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
const rowsModules = [];
|
|
150
|
+
for (let row = 0; row < rows; row++) {
|
|
151
|
+
rowsModules.push(rowModules(
|
|
152
|
+
row,
|
|
153
|
+
codewords.slice(row * CODE16K_SYMBOLS_PER_ROW, (row + 1) * CODE16K_SYMBOLS_PER_ROW),
|
|
154
|
+
));
|
|
155
|
+
}
|
|
156
|
+
const matrix = renderStackedRows(
|
|
157
|
+
rowsModules,
|
|
158
|
+
validated.rowHeight,
|
|
159
|
+
validated.separatorHeight,
|
|
160
|
+
) as Code16KMatrix;
|
|
161
|
+
matrix.code16k = {
|
|
162
|
+
format: 'code16k',
|
|
163
|
+
rows,
|
|
164
|
+
columns: CODE16K_SYMBOLS_PER_ROW,
|
|
165
|
+
rowHeight: validated.rowHeight,
|
|
166
|
+
separatorHeight: validated.separatorHeight,
|
|
167
|
+
mode: info.mode,
|
|
168
|
+
codewords,
|
|
169
|
+
checksum: true,
|
|
170
|
+
};
|
|
171
|
+
return matrix;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/** Return the dimensions selected for a Code 16K payload without rendering it. */
|
|
175
|
+
export function code16kDimensions(
|
|
176
|
+
value: string | Uint8Array | readonly number[],
|
|
177
|
+
options: Code16KEncodeOptions = {},
|
|
178
|
+
): { rows: number; columns: number; width: number; height: number; rowHeight: number; separatorHeight: number } {
|
|
179
|
+
const text = asciiText(value);
|
|
180
|
+
if (text.length === 0) throw new EncodeError('Code 16K: value must not be empty');
|
|
181
|
+
const validated = validateCode16KOptions(options);
|
|
182
|
+
const info = code16kModeInfo(options.mode, options.gs1 === true);
|
|
183
|
+
const tokenized = code128DataCodewords(text, { gs1: info.gs1, startSet: info.startSet });
|
|
184
|
+
const dataLength = tokenized.values.length;
|
|
185
|
+
const rows = validated.rows ?? Math.max(2, Math.ceil((dataLength + 3) / CODE16K_SYMBOLS_PER_ROW));
|
|
186
|
+
const capacity = rows * CODE16K_SYMBOLS_PER_ROW - 3;
|
|
187
|
+
if (rows > 16 || dataLength > capacity) {
|
|
188
|
+
throw new EncodeError('Code 16K: payload does not fit the requested row count');
|
|
189
|
+
}
|
|
190
|
+
return {
|
|
191
|
+
rows,
|
|
192
|
+
columns: CODE16K_SYMBOLS_PER_ROW,
|
|
193
|
+
width: 70,
|
|
194
|
+
height: 2 + rows * validated.rowHeight + (rows - 1) * validated.separatorHeight,
|
|
195
|
+
rowHeight: validated.rowHeight,
|
|
196
|
+
separatorHeight: validated.separatorHeight,
|
|
197
|
+
};
|
|
198
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/*! SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net) */
|
|
2
|
+
/*! SPDX-License-Identifier: MIT */
|
|
3
|
+
export { CODE16K_MIN_ROWS, CODE16K_MAX_ROWS, CODE16K_SYMBOLS_PER_ROW, CODE16K_MODULE_WIDTH, CODE16K_START_WIDTH, CODE16K_GUARD_WIDTH, CODE16K_CODEWORD_WIDTH, CODE16K_STOP_WIDTH, CODE16K_DEFAULT_ROW_HEIGHT, CODE16K_DEFAULT_SEPARATOR_HEIGHT, CODE16K_PAD, CODE16K_ROW_PAIRS, CODE16K_START_WIDTHS, code16kModeNumber, code16kModeInfo, code16kStartModules, code16kStopModules, code16kWidth, code16kGeometry, validateCode16KOptions, validateCode16KTables, } from './tables.js';
|
|
4
|
+
export type { Code16KMode, Code16KModeName, Code16KEncodeOptions, Code16KDecodeOptions, } from './tables.js';
|
|
5
|
+
export { encodeCode16K, code16kDimensions } from './encoder.js';
|
|
6
|
+
export type { Code16KMetadata, Code16KMatrix } from './encoder.js';
|
|
7
|
+
export { decodeCode16K, decodeCode16KRow } from './decoder.js';
|
|
8
|
+
export type { Code16KRow, Code16KDecodeResult } from './decoder.js';
|
|
9
|
+
export { detectCode16K, detectAndDecodeCode16K } from './detector.js';
|
|
10
|
+
export type { Code16KDetectOptions, Code16KPoint, Code16KDetectedResult } from './detector.js';
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
* Copyright (c) 2026 Sythos
|
|
6
|
+
* SPDX-License-Identifier: MIT
|
|
7
|
+
*
|
|
8
|
+
* Original work. No code from any other barcode implementation.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/** Code 16K public module exports. @module code16k */
|
|
12
|
+
|
|
13
|
+
export {
|
|
14
|
+
CODE16K_MIN_ROWS,
|
|
15
|
+
CODE16K_MAX_ROWS,
|
|
16
|
+
CODE16K_SYMBOLS_PER_ROW,
|
|
17
|
+
CODE16K_MODULE_WIDTH,
|
|
18
|
+
CODE16K_START_WIDTH,
|
|
19
|
+
CODE16K_GUARD_WIDTH,
|
|
20
|
+
CODE16K_CODEWORD_WIDTH,
|
|
21
|
+
CODE16K_STOP_WIDTH,
|
|
22
|
+
CODE16K_DEFAULT_ROW_HEIGHT,
|
|
23
|
+
CODE16K_DEFAULT_SEPARATOR_HEIGHT,
|
|
24
|
+
CODE16K_PAD,
|
|
25
|
+
CODE16K_ROW_PAIRS,
|
|
26
|
+
CODE16K_START_WIDTHS,
|
|
27
|
+
code16kModeNumber,
|
|
28
|
+
code16kModeInfo,
|
|
29
|
+
code16kStartModules,
|
|
30
|
+
code16kStopModules,
|
|
31
|
+
code16kWidth,
|
|
32
|
+
code16kGeometry,
|
|
33
|
+
validateCode16KOptions,
|
|
34
|
+
validateCode16KTables,
|
|
35
|
+
} from './tables.js';
|
|
36
|
+
export type {
|
|
37
|
+
Code16KMode,
|
|
38
|
+
Code16KModeName,
|
|
39
|
+
Code16KEncodeOptions,
|
|
40
|
+
Code16KDecodeOptions,
|
|
41
|
+
} from './tables.js';
|
|
42
|
+
export { encodeCode16K, code16kDimensions } from './encoder.js';
|
|
43
|
+
export type { Code16KMetadata, Code16KMatrix } from './encoder.js';
|
|
44
|
+
export { decodeCode16K, decodeCode16KRow } from './decoder.js';
|
|
45
|
+
export type { Code16KRow, Code16KDecodeResult } from './decoder.js';
|
|
46
|
+
export { detectCode16K, detectAndDecodeCode16K } from './detector.js';
|
|
47
|
+
export type { Code16KDetectOptions, Code16KPoint, Code16KDetectedResult } from './detector.js';
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/*! SPDX-FileCopyrightText: 2026 Sythos (https://www.sythos.net) */
|
|
2
|
+
/*! SPDX-License-Identifier: MIT */
|
|
3
|
+
export declare const CODE16K_MIN_ROWS = 2;
|
|
4
|
+
export declare const CODE16K_MAX_ROWS = 16;
|
|
5
|
+
export declare const CODE16K_SYMBOLS_PER_ROW = 5;
|
|
6
|
+
export declare const CODE16K_MODULE_WIDTH = 70;
|
|
7
|
+
export declare const CODE16K_START_WIDTH = 7;
|
|
8
|
+
export declare const CODE16K_GUARD_WIDTH = 1;
|
|
9
|
+
export declare const CODE16K_CODEWORD_WIDTH = 11;
|
|
10
|
+
export declare const CODE16K_STOP_WIDTH = 7;
|
|
11
|
+
export declare const CODE16K_DEFAULT_ROW_HEIGHT = 8;
|
|
12
|
+
export declare const CODE16K_DEFAULT_SEPARATOR_HEIGHT = 1;
|
|
13
|
+
export declare const CODE16K_PAD = 103;
|
|
14
|
+
export declare const CODE16K_ROW_PAIRS: readonly (readonly [number, number])[];
|
|
15
|
+
export declare const CODE16K_START_WIDTHS: readonly (readonly [number, number, number, number])[];
|
|
16
|
+
export type Code16KMode = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
17
|
+
export type Code16KModeName = 'A' | 'B' | 'C';
|
|
18
|
+
export type Code16KEncodeOptions = {
|
|
19
|
+
rows?: number;
|
|
20
|
+
rowHeight?: number;
|
|
21
|
+
separatorHeight?: number;
|
|
22
|
+
mode?: Code16KMode | Code16KModeName;
|
|
23
|
+
gs1?: boolean;
|
|
24
|
+
};
|
|
25
|
+
export type Code16KDecodeOptions = {
|
|
26
|
+
rowHeight?: number;
|
|
27
|
+
separatorHeight?: number;
|
|
28
|
+
rows?: number;
|
|
29
|
+
};
|
|
30
|
+
export declare function code16kModeNumber(mode: Code16KMode | Code16KModeName | undefined, gs1?: boolean): Code16KMode;
|
|
31
|
+
export declare function code16kModeInfo(mode: Code16KMode | Code16KModeName | undefined, gs1?: boolean): {
|
|
32
|
+
mode: Code16KMode;
|
|
33
|
+
startSet: Code16KModeName;
|
|
34
|
+
gs1: boolean;
|
|
35
|
+
};
|
|
36
|
+
export declare function code16kStartModules(row: number): string;
|
|
37
|
+
export declare function code16kStopModules(row: number): string;
|
|
38
|
+
export declare function code16kWidth(): number;
|
|
39
|
+
export declare function code16kGeometry(width: number, height: number, rows: number, rowHeight: number, separatorHeight: number, outerSeparators?: boolean): {
|
|
40
|
+
width: number;
|
|
41
|
+
height: number;
|
|
42
|
+
rows: number;
|
|
43
|
+
rowHeight: number;
|
|
44
|
+
separatorHeight: number;
|
|
45
|
+
};
|
|
46
|
+
export declare function validateCode16KOptions(options?: Code16KEncodeOptions): {
|
|
47
|
+
rows?: number;
|
|
48
|
+
rowHeight: number;
|
|
49
|
+
separatorHeight: number;
|
|
50
|
+
mode: Code16KMode;
|
|
51
|
+
startSet: Code16KModeName;
|
|
52
|
+
gs1: boolean;
|
|
53
|
+
};
|
|
54
|
+
export declare function validateCode16KTables(): string[];
|
|
@@ -0,0 +1,195 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite
|
|
3
|
+
*
|
|
4
|
+
* MIT License
|
|
5
|
+
* Copyright (c) 2026 Sythos
|
|
6
|
+
* SPDX-License-Identifier: MIT
|
|
7
|
+
*
|
|
8
|
+
* Original work. No code from any other barcode implementation.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Structural facts and option validation for Code 16K.
|
|
13
|
+
*
|
|
14
|
+
* A Code 16K row is 70 modules wide: a seven-module start pattern, a one
|
|
15
|
+
* module guard bar, five eleven-module Code 128 symbols and a seven-module
|
|
16
|
+
* stop pattern. The row start and stop pair identifies its one-based row
|
|
17
|
+
* number. This module contains only the public table facts; packing and
|
|
18
|
+
* decoding live in encoder.ts and decoder.ts.
|
|
19
|
+
*
|
|
20
|
+
* @module code16k/tables
|
|
21
|
+
*/
|
|
22
|
+
|
|
23
|
+
import { EncodeError } from '../core/errors.js';
|
|
24
|
+
import { alternatingWidths } from '../stacked128/common.js';
|
|
25
|
+
|
|
26
|
+
export const CODE16K_MIN_ROWS = 2;
|
|
27
|
+
export const CODE16K_MAX_ROWS = 16;
|
|
28
|
+
export const CODE16K_SYMBOLS_PER_ROW = 5;
|
|
29
|
+
export const CODE16K_MODULE_WIDTH = 70;
|
|
30
|
+
export const CODE16K_START_WIDTH = 7;
|
|
31
|
+
export const CODE16K_GUARD_WIDTH = 1;
|
|
32
|
+
export const CODE16K_CODEWORD_WIDTH = 11;
|
|
33
|
+
export const CODE16K_STOP_WIDTH = 7;
|
|
34
|
+
export const CODE16K_DEFAULT_ROW_HEIGHT = 8;
|
|
35
|
+
export const CODE16K_DEFAULT_SEPARATOR_HEIGHT = 1;
|
|
36
|
+
export const CODE16K_PAD = 103;
|
|
37
|
+
|
|
38
|
+
/** Start/stop values used to identify rows, in top-to-bottom order. */
|
|
39
|
+
export const CODE16K_ROW_PAIRS = Object.freeze([
|
|
40
|
+
Object.freeze([0, 0]), Object.freeze([1, 1]),
|
|
41
|
+
Object.freeze([2, 2]), Object.freeze([3, 3]),
|
|
42
|
+
Object.freeze([4, 4]), Object.freeze([5, 5]),
|
|
43
|
+
Object.freeze([6, 6]), Object.freeze([7, 7]),
|
|
44
|
+
Object.freeze([0, 4]), Object.freeze([1, 5]),
|
|
45
|
+
Object.freeze([2, 6]), Object.freeze([3, 7]),
|
|
46
|
+
Object.freeze([4, 0]), Object.freeze([5, 1]),
|
|
47
|
+
Object.freeze([6, 2]), Object.freeze([7, 3]),
|
|
48
|
+
] as const);
|
|
49
|
+
|
|
50
|
+
/** Widths for the eight edge-decodable start patterns. */
|
|
51
|
+
export const CODE16K_START_WIDTHS = Object.freeze([
|
|
52
|
+
Object.freeze([3, 2, 1, 1]), Object.freeze([2, 2, 2, 1]),
|
|
53
|
+
Object.freeze([2, 1, 2, 2]), Object.freeze([1, 4, 1, 1]),
|
|
54
|
+
Object.freeze([1, 1, 3, 2]), Object.freeze([1, 2, 3, 1]),
|
|
55
|
+
Object.freeze([1, 1, 1, 4]), Object.freeze([3, 1, 1, 2]),
|
|
56
|
+
] as const);
|
|
57
|
+
|
|
58
|
+
export type Code16KMode = 0 | 1 | 2 | 3 | 4 | 5 | 6;
|
|
59
|
+
export type Code16KModeName = 'A' | 'B' | 'C';
|
|
60
|
+
|
|
61
|
+
export type Code16KEncodeOptions = {
|
|
62
|
+
rows?: number;
|
|
63
|
+
rowHeight?: number;
|
|
64
|
+
separatorHeight?: number;
|
|
65
|
+
mode?: Code16KMode | Code16KModeName;
|
|
66
|
+
gs1?: boolean;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
export type Code16KDecodeOptions = {
|
|
70
|
+
rowHeight?: number;
|
|
71
|
+
separatorHeight?: number;
|
|
72
|
+
rows?: number;
|
|
73
|
+
};
|
|
74
|
+
|
|
75
|
+
/** Return the canonical mode number used by the first symbol character. */
|
|
76
|
+
export function code16kModeNumber(
|
|
77
|
+
mode: Code16KMode | Code16KModeName | undefined,
|
|
78
|
+
gs1 = false,
|
|
79
|
+
): Code16KMode {
|
|
80
|
+
if (mode === undefined) return gs1 ? 3 : 1;
|
|
81
|
+
if (typeof mode === 'string') {
|
|
82
|
+
if (mode === 'A') return 0;
|
|
83
|
+
if (mode === 'B') return gs1 ? 3 : 1;
|
|
84
|
+
return gs1 ? 4 : 2;
|
|
85
|
+
}
|
|
86
|
+
if (!Number.isInteger(mode) || mode < 0 || mode > 6) {
|
|
87
|
+
throw new EncodeError('Code 16K: mode must be A, B, C or an integer in 0..6');
|
|
88
|
+
}
|
|
89
|
+
return mode as Code16KMode;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/** Resolve the initial Code 128 set and whether the first data value is FNC1. */
|
|
93
|
+
export function code16kModeInfo(
|
|
94
|
+
mode: Code16KMode | Code16KModeName | undefined,
|
|
95
|
+
gs1 = false,
|
|
96
|
+
): { mode: Code16KMode; startSet: Code16KModeName; gs1: boolean } {
|
|
97
|
+
const resolved = code16kModeNumber(mode, gs1);
|
|
98
|
+
if (resolved === 5 || resolved === 6) {
|
|
99
|
+
throw new EncodeError('Code 16K: modes 5 and 6 require a dedicated shift encoder');
|
|
100
|
+
}
|
|
101
|
+
const startSet: Code16KModeName = resolved === 0 ? 'A' :
|
|
102
|
+
resolved === 1 || resolved === 3 ? 'B' : 'C';
|
|
103
|
+
return {
|
|
104
|
+
mode: resolved,
|
|
105
|
+
startSet,
|
|
106
|
+
gs1: resolved === 3 || resolved === 4,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/** Return the seven-module start pattern for a zero-based row index. */
|
|
111
|
+
export function code16kStartModules(row: number): string {
|
|
112
|
+
if (!Number.isInteger(row) || row < 0 || row >= CODE16K_MAX_ROWS) {
|
|
113
|
+
throw new RangeError('Code 16K: row index must be an integer in 0..15');
|
|
114
|
+
}
|
|
115
|
+
return alternatingWidths(CODE16K_START_WIDTHS[CODE16K_ROW_PAIRS[row][0]], true);
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/** Return the seven-module stop pattern for a zero-based row index. */
|
|
119
|
+
export function code16kStopModules(row: number): string {
|
|
120
|
+
if (!Number.isInteger(row) || row < 0 || row >= CODE16K_MAX_ROWS) {
|
|
121
|
+
throw new RangeError('Code 16K: row index must be an integer in 0..15');
|
|
122
|
+
}
|
|
123
|
+
return alternatingWidths(CODE16K_START_WIDTHS[CODE16K_ROW_PAIRS[row][1]], false);
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/** Return a complete row's bare module width. */
|
|
127
|
+
export function code16kWidth(): number {
|
|
128
|
+
return CODE16K_MODULE_WIDTH;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Validate a matrix geometry and return its row count and separator height. */
|
|
132
|
+
export function code16kGeometry(
|
|
133
|
+
width: number,
|
|
134
|
+
height: number,
|
|
135
|
+
rows: number,
|
|
136
|
+
rowHeight: number,
|
|
137
|
+
separatorHeight: number,
|
|
138
|
+
outerSeparators = true,
|
|
139
|
+
): { width: number; height: number; rows: number; rowHeight: number; separatorHeight: number } {
|
|
140
|
+
if (width !== CODE16K_MODULE_WIDTH) {
|
|
141
|
+
throw new RangeError(`Code 16K: width must be ${CODE16K_MODULE_WIDTH} modules`);
|
|
142
|
+
}
|
|
143
|
+
if (!Number.isInteger(rows) || rows < CODE16K_MIN_ROWS || rows > CODE16K_MAX_ROWS) {
|
|
144
|
+
throw new RangeError('Code 16K: rows must be an integer in 2..16');
|
|
145
|
+
}
|
|
146
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 1 || rowHeight > 128) {
|
|
147
|
+
throw new RangeError('Code 16K: rowHeight must be an integer in 1..128');
|
|
148
|
+
}
|
|
149
|
+
if (!Number.isInteger(separatorHeight) || separatorHeight < 1 || separatorHeight > 16) {
|
|
150
|
+
throw new RangeError('Code 16K: separatorHeight must be an integer in 1..16');
|
|
151
|
+
}
|
|
152
|
+
const outer = outerSeparators ? 2 : 0;
|
|
153
|
+
const expected = outer + rows * rowHeight + (rows - 1) * separatorHeight;
|
|
154
|
+
if (height !== expected) {
|
|
155
|
+
throw new RangeError(`Code 16K: height ${height} does not match the row geometry`);
|
|
156
|
+
}
|
|
157
|
+
return { width, height, rows, rowHeight, separatorHeight };
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
/** Validate public encoder options before any large matrix allocation. */
|
|
161
|
+
export function validateCode16KOptions(options: Code16KEncodeOptions = {}): {
|
|
162
|
+
rows?: number;
|
|
163
|
+
rowHeight: number;
|
|
164
|
+
separatorHeight: number;
|
|
165
|
+
mode: Code16KMode;
|
|
166
|
+
startSet: Code16KModeName;
|
|
167
|
+
gs1: boolean;
|
|
168
|
+
} {
|
|
169
|
+
const rowHeight = options.rowHeight ?? CODE16K_DEFAULT_ROW_HEIGHT;
|
|
170
|
+
const separatorHeight = options.separatorHeight ?? CODE16K_DEFAULT_SEPARATOR_HEIGHT;
|
|
171
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 1 || rowHeight > 128) {
|
|
172
|
+
throw new EncodeError('Code 16K: rowHeight must be an integer in 1..128');
|
|
173
|
+
}
|
|
174
|
+
if (!Number.isInteger(separatorHeight) || separatorHeight < 1 || separatorHeight > 16) {
|
|
175
|
+
throw new EncodeError('Code 16K: separatorHeight must be an integer in 1..16');
|
|
176
|
+
}
|
|
177
|
+
if (options.rows !== undefined &&
|
|
178
|
+
(!Number.isInteger(options.rows) || options.rows < CODE16K_MIN_ROWS || options.rows > CODE16K_MAX_ROWS)) {
|
|
179
|
+
throw new EncodeError('Code 16K: rows must be an integer in 2..16');
|
|
180
|
+
}
|
|
181
|
+
const info = code16kModeInfo(options.mode, options.gs1 === true);
|
|
182
|
+
return { rows: options.rows, rowHeight, separatorHeight, ...info };
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Check table invariants used by tests and CI. */
|
|
186
|
+
export function validateCode16KTables(): string[] {
|
|
187
|
+
const problems: string[] = [];
|
|
188
|
+
if (CODE16K_ROW_PAIRS.length !== CODE16K_MAX_ROWS) problems.push('row pair count mismatch');
|
|
189
|
+
if (CODE16K_START_WIDTHS.length !== 8) problems.push('start pattern count mismatch');
|
|
190
|
+
for (let row = 0; row < CODE16K_MAX_ROWS; row++) {
|
|
191
|
+
if (code16kStartModules(row).length !== CODE16K_START_WIDTH) problems.push(`row ${row + 1} start width mismatch`);
|
|
192
|
+
if (code16kStopModules(row).length !== CODE16K_STOP_WIDTH) problems.push(`row ${row + 1} stop width mismatch`);
|
|
193
|
+
}
|
|
194
|
+
return problems;
|
|
195
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/*!
|
|
2
|
+
* Sythos Barcode Suite — GS1 Composite declarations
|
|
3
|
+
* SPDX-License-Identifier: MIT
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
import type { BitMatrix } from '../core/bit-matrix.js';
|
|
7
|
+
|
|
8
|
+
export const GS1_COMPOSITE_PROFILE: 'sythos-gs1-composite-bounded';
|
|
9
|
+
export const GS1_COMPOSITE_HOSTS: readonly [
|
|
10
|
+
'databar14',
|
|
11
|
+
'databar-truncated',
|
|
12
|
+
'databar-stacked',
|
|
13
|
+
'databar-stacked-omnidirectional',
|
|
14
|
+
'databar-limited',
|
|
15
|
+
'databar-expanded',
|
|
16
|
+
];
|
|
17
|
+
|
|
18
|
+
export type GS1CompositeHostFormat = typeof GS1_COMPOSITE_HOSTS[number];
|
|
19
|
+
export type GS1CompositeComponent = 'auto' | 'cc-a' | 'cc-b';
|
|
20
|
+
export type GS1Element = { ai: string; value: string };
|
|
21
|
+
|
|
22
|
+
export type GS1CompositeInput = {
|
|
23
|
+
linear: {
|
|
24
|
+
format: GS1CompositeHostFormat | string;
|
|
25
|
+
value: string | number | GS1Element[];
|
|
26
|
+
options?: Record<string, unknown>;
|
|
27
|
+
};
|
|
28
|
+
data: string | GS1Element[];
|
|
29
|
+
component?: GS1CompositeComponent;
|
|
30
|
+
rowHeight?: number;
|
|
31
|
+
separatorGap?: 1 | 2 | 3;
|
|
32
|
+
moduleScale?: number;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
export type GS1CompositeOptions = {
|
|
36
|
+
component?: GS1CompositeComponent;
|
|
37
|
+
rowHeight?: number;
|
|
38
|
+
separatorGap?: 1 | 2 | 3;
|
|
39
|
+
moduleScale?: number;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type GS1CompositeResult = {
|
|
43
|
+
format: 'gs1composite';
|
|
44
|
+
profile: typeof GS1_COMPOSITE_PROFILE;
|
|
45
|
+
certified: false;
|
|
46
|
+
text: string;
|
|
47
|
+
raw: string;
|
|
48
|
+
gs1: true;
|
|
49
|
+
linkage: true;
|
|
50
|
+
elements: ReadonlyArray<GS1Element & { fixed?: boolean }>;
|
|
51
|
+
linearFormat: GS1CompositeHostFormat;
|
|
52
|
+
linear: Record<string, unknown>;
|
|
53
|
+
component: 'cc-a' | 'cc-b';
|
|
54
|
+
componentVariant: number;
|
|
55
|
+
componentRows: number;
|
|
56
|
+
componentColumns: number;
|
|
57
|
+
componentRowHeight: number;
|
|
58
|
+
corrections: number;
|
|
59
|
+
moduleScale: number;
|
|
60
|
+
separatorGap?: number;
|
|
61
|
+
symbologyIdentifier: ']e1' | ']e2';
|
|
62
|
+
bounds?: { x: number; y: number; width: number; height: number };
|
|
63
|
+
corners?: Array<{ x: number; y: number }>;
|
|
64
|
+
matrix?: BitMatrix;
|
|
65
|
+
moduleSize?: number;
|
|
66
|
+
rotation?: 0 | 90 | 180 | 270;
|
|
67
|
+
confidence?: number;
|
|
68
|
+
quality?: { quietZone: boolean; checksum: boolean; rows: number; consistency: number };
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
export function encodeGS1Composite(input: GS1CompositeInput, options?: GS1CompositeOptions): BitMatrix;
|
|
72
|
+
export function decodeGS1Composite(matrix: BitMatrix): GS1CompositeResult;
|
|
73
|
+
export function detectGS1Composite(binaryImage: BitMatrix): GS1CompositeResult | null;
|
|
74
|
+
export const detectAndDecodeGS1Composite: typeof detectGS1Composite;
|