@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,225 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* Sythos Barcode Suite — shared stacked Code 128 helpers
|
|
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
|
+
import { BitMatrix } from '../core/bit-matrix.js';
|
|
12
|
+
import { EncodeError } from '../core/errors.js';
|
|
13
|
+
import {
|
|
14
|
+
CODE128,
|
|
15
|
+
CODE128_START_A,
|
|
16
|
+
CODE128_START_B,
|
|
17
|
+
CODE128_START_C,
|
|
18
|
+
CODE128_STOP,
|
|
19
|
+
CODE128_FNC1,
|
|
20
|
+
CODE128_CODE_A,
|
|
21
|
+
CODE128_CODE_B,
|
|
22
|
+
CODE128_CODE_C,
|
|
23
|
+
CODE128_SHIFT,
|
|
24
|
+
} from '../oned/patterns.js';
|
|
25
|
+
|
|
26
|
+
/** A row candidate returned by the integer-module scanner. */
|
|
27
|
+
export interface StackedRowCandidate<T = unknown> {
|
|
28
|
+
readonly x: number;
|
|
29
|
+
readonly y: number;
|
|
30
|
+
readonly moduleSize: number;
|
|
31
|
+
readonly parsed: T;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/** Expand a Code 128 width string into dark/light modules. */
|
|
35
|
+
export function code128PatternModules(value: number): string {
|
|
36
|
+
if (!Number.isInteger(value) || value < 0 || value >= CODE128.length) {
|
|
37
|
+
throw new EncodeError(`Code 128: invalid symbol value ${value}`);
|
|
38
|
+
}
|
|
39
|
+
const pattern = CODE128[value];
|
|
40
|
+
let modules = '';
|
|
41
|
+
let dark = true;
|
|
42
|
+
for (const digit of pattern) {
|
|
43
|
+
const width = Number(digit);
|
|
44
|
+
modules += (dark ? '1' : '0').repeat(width);
|
|
45
|
+
dark = !dark;
|
|
46
|
+
}
|
|
47
|
+
return modules;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
/** Render complete Code 128 codewords, including their 13-module stop. */
|
|
51
|
+
export function code128CodewordsModules(values: readonly number[]): string {
|
|
52
|
+
return values.map((value) => code128PatternModules(value)).join('');
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/** Code 128 checksum for a sequence that includes the start symbol. */
|
|
56
|
+
export function code128Checksum(values: readonly number[]): number {
|
|
57
|
+
if (values.length === 0) throw new EncodeError('Code 128: checksum needs a start symbol');
|
|
58
|
+
let sum = values[0];
|
|
59
|
+
for (let i = 1; i < values.length; i++) sum += values[i] * i;
|
|
60
|
+
return sum % 103;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const CODE128_BITS = new Map<string, number>();
|
|
64
|
+
for (let value = 0; value < CODE128.length; value++) {
|
|
65
|
+
CODE128_BITS.set(code128PatternModules(value), value);
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
/** Decode a single 11-module Code 128 symbol from a sampled module string. */
|
|
69
|
+
export function code128ValueFromModules(modules: string, offset: number): number | null {
|
|
70
|
+
const slice = modules.slice(offset, offset + 11);
|
|
71
|
+
if (slice.length !== 11) return null;
|
|
72
|
+
return CODE128_BITS.get(slice) ?? null;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
/**
|
|
76
|
+
* Interpret Code 128 data values after the start symbol and checksum.
|
|
77
|
+
*
|
|
78
|
+
* This deliberately mirrors the public Code 128 reader but keeps stacked
|
|
79
|
+
* decoders independent from scanline state. The result is null for an empty
|
|
80
|
+
* or structurally impossible stream.
|
|
81
|
+
*/
|
|
82
|
+
export function decodeCode128Values(
|
|
83
|
+
startCode: number,
|
|
84
|
+
dataValues: readonly number[],
|
|
85
|
+
): { text: string; fnc1AtStart?: boolean; fnc1Positions?: number[] } | null {
|
|
86
|
+
if (![CODE128_START_A, CODE128_START_B, CODE128_START_C].includes(startCode)) return null;
|
|
87
|
+
if (dataValues.length === 0) return null;
|
|
88
|
+
|
|
89
|
+
let mode: 'A' | 'B' | 'C' = startCode === CODE128_START_A
|
|
90
|
+
? 'A' : startCode === CODE128_START_B ? 'B' : 'C';
|
|
91
|
+
let shifted: 'A' | 'B' | null = null;
|
|
92
|
+
let text = '';
|
|
93
|
+
const fnc1AtStart = dataValues[0] === CODE128_FNC1;
|
|
94
|
+
const fnc1Positions: number[] = [];
|
|
95
|
+
|
|
96
|
+
for (let index = 0; index < dataValues.length; index++) {
|
|
97
|
+
const value = dataValues[index];
|
|
98
|
+
const active = shifted ?? mode;
|
|
99
|
+
shifted = null;
|
|
100
|
+
|
|
101
|
+
if (value === CODE128_CODE_A && mode !== 'A') { mode = 'A'; continue; }
|
|
102
|
+
if (value === CODE128_CODE_B && mode !== 'B') { mode = 'B'; continue; }
|
|
103
|
+
if (value === CODE128_CODE_C) { mode = 'C'; continue; }
|
|
104
|
+
if (value === CODE128_SHIFT) {
|
|
105
|
+
shifted = mode === 'A' ? 'B' : 'A';
|
|
106
|
+
continue;
|
|
107
|
+
}
|
|
108
|
+
if (value === CODE128_FNC1) {
|
|
109
|
+
if (index > 0) {
|
|
110
|
+
fnc1Positions.push(text.length);
|
|
111
|
+
text += '\x1d';
|
|
112
|
+
}
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
// FNC2, FNC3 and FNC4 are control values. They are not part of the
|
|
116
|
+
// textual payload exposed by this SDK, but remain valid Code 128 symbols.
|
|
117
|
+
if (value >= 96 && value <= 102) continue;
|
|
118
|
+
|
|
119
|
+
if (active === 'C') {
|
|
120
|
+
if (value > 99) return null;
|
|
121
|
+
text += String(value).padStart(2, '0');
|
|
122
|
+
} else if (active === 'A') {
|
|
123
|
+
if (value > 95) return null;
|
|
124
|
+
text += value < 64 ? String.fromCharCode(value + 32) : String.fromCharCode(value - 64);
|
|
125
|
+
} else {
|
|
126
|
+
if (value > 95) return null;
|
|
127
|
+
text += String.fromCharCode(value + 32);
|
|
128
|
+
}
|
|
129
|
+
if (text.length > 100000) return null;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
if (text.length === 0) return null;
|
|
133
|
+
return fnc1AtStart
|
|
134
|
+
? { text, fnc1AtStart: true, fnc1Positions }
|
|
135
|
+
: { text };
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/** Sample one module at the centre of every integer-sized module. */
|
|
139
|
+
export function sampleModules(row: Uint8Array, start: number, moduleSize: number, count: number): string | null {
|
|
140
|
+
if (!Number.isInteger(moduleSize) || moduleSize < 1 || start < 0) return null;
|
|
141
|
+
const end = start + moduleSize * count;
|
|
142
|
+
if (end > row.length) return null;
|
|
143
|
+
let modules = '';
|
|
144
|
+
const centre = Math.floor((moduleSize - 1) / 2);
|
|
145
|
+
for (let index = 0; index < count; index++) {
|
|
146
|
+
modules += row[start + index * moduleSize + centre] ? '1' : '0';
|
|
147
|
+
}
|
|
148
|
+
return modules;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Scan a binarized image for stacked symbols with integer module scaling.
|
|
153
|
+
* The parser receives every plausible dark-run origin and can try one or more
|
|
154
|
+
* geometry variants. A bounded scale keeps camera frames predictable.
|
|
155
|
+
*/
|
|
156
|
+
export function scanStackedRows<T>(
|
|
157
|
+
image: BitMatrix,
|
|
158
|
+
minimumModules: number,
|
|
159
|
+
parser: (row: Uint8Array, start: number, moduleSize: number) => T | null,
|
|
160
|
+
maximumModules = 900,
|
|
161
|
+
): StackedRowCandidate<T>[] {
|
|
162
|
+
const candidates: StackedRowCandidate<T>[] = [];
|
|
163
|
+
const rowBuffer = new Uint8Array(image.width);
|
|
164
|
+
const maximumScale = Math.min(32, Math.max(1, Math.floor(maximumModules / Math.max(1, minimumModules))));
|
|
165
|
+
for (let y = 0; y < image.height; y++) {
|
|
166
|
+
const row = image.getRow(y, rowBuffer);
|
|
167
|
+
for (let start = 0; start < row.length; start++) {
|
|
168
|
+
if (!row[start] || (start > 0 && row[start - 1])) continue;
|
|
169
|
+
for (let moduleSize = 1; moduleSize <= maximumScale; moduleSize++) {
|
|
170
|
+
if (start + minimumModules * moduleSize > row.length) break;
|
|
171
|
+
const parsed = parser(row, start, moduleSize);
|
|
172
|
+
if (parsed !== null) candidates.push({ x: start, y, moduleSize, parsed });
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return candidates;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
/** Paint a set of row module strings with separator bars and quiet rows. */
|
|
180
|
+
export function renderStackedRows(
|
|
181
|
+
rowModules: readonly string[],
|
|
182
|
+
rowHeight: number,
|
|
183
|
+
separatorHeight: number,
|
|
184
|
+
): BitMatrix {
|
|
185
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 1 || rowHeight > 128) {
|
|
186
|
+
throw new EncodeError('Stacked Code 128: rowHeight must be an integer in 1..128');
|
|
187
|
+
}
|
|
188
|
+
if (!Number.isInteger(separatorHeight) || separatorHeight < 1 || separatorHeight > 16) {
|
|
189
|
+
throw new EncodeError('Stacked Code 128: separatorHeight must be an integer in 1..16');
|
|
190
|
+
}
|
|
191
|
+
if (rowModules.length < 1) throw new EncodeError('Stacked Code 128: at least one row is required');
|
|
192
|
+
const width = rowModules[0].length;
|
|
193
|
+
if (width < 1 || rowModules.some((modules) => modules.length !== width)) {
|
|
194
|
+
throw new EncodeError('Stacked Code 128: rows must have equal module widths');
|
|
195
|
+
}
|
|
196
|
+
const height = 2 + rowModules.length * rowHeight + (rowModules.length - 1) * separatorHeight;
|
|
197
|
+
const matrix = new BitMatrix(width, height);
|
|
198
|
+
matrix.setRegion(0, 0, width, 1);
|
|
199
|
+
matrix.setRegion(0, height - 1, width, 1);
|
|
200
|
+
let y = 1;
|
|
201
|
+
for (let row = 0; row < rowModules.length; row++) {
|
|
202
|
+
const modules = rowModules[row];
|
|
203
|
+
for (let x = 0; x < width; x++) {
|
|
204
|
+
if (modules[x] === '1') matrix.setRegion(x, y, 1, rowHeight);
|
|
205
|
+
}
|
|
206
|
+
y += rowHeight;
|
|
207
|
+
if (row < rowModules.length - 1) {
|
|
208
|
+
matrix.setRegion(0, y, width, separatorHeight);
|
|
209
|
+
y += separatorHeight;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
return matrix;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
/** Build an alternating-width pattern, starting with dark or light. */
|
|
216
|
+
export function alternatingWidths(widths: readonly number[], startsDark: boolean): string {
|
|
217
|
+
let modules = '';
|
|
218
|
+
let dark = startsDark;
|
|
219
|
+
for (const width of widths) {
|
|
220
|
+
if (!Number.isInteger(width) || width < 1) throw new EncodeError('Stacked barcode: invalid guard width');
|
|
221
|
+
modules += (dark ? '1' : '0').repeat(width);
|
|
222
|
+
dark = !dark;
|
|
223
|
+
}
|
|
224
|
+
return modules;
|
|
225
|
+
}
|