@sythos/js_barcode_universal 1.5.14 → 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 +372 -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 +52 -5
- package/package.json +40 -2
- 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,427 @@
|
|
|
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
|
+
/** Original dependency-free DotCode encoder. @module dotcode/encoder */
|
|
32
|
+
|
|
33
|
+
import { BitMatrix } from '../core/bit-matrix.js';
|
|
34
|
+
import { EncodeError } from '../core/errors.js';
|
|
35
|
+
import { rsEncode } from '../core/reed-solomon.js';
|
|
36
|
+
import {
|
|
37
|
+
DOTCODE_CODEWORD_COUNT,
|
|
38
|
+
DOTCODE_FIELD_SIZE,
|
|
39
|
+
DOTCODE_MAX_DIMENSION,
|
|
40
|
+
DOTCODE_MASK_STEPS,
|
|
41
|
+
DOTCODE_MIN_DIMENSION,
|
|
42
|
+
GF113_DOTCODE,
|
|
43
|
+
dotCodeActivePositions,
|
|
44
|
+
dotCodeCodewordCapacity,
|
|
45
|
+
dotCodeCornerOrder,
|
|
46
|
+
dotCodeDataCapacity,
|
|
47
|
+
dotCodeIsCorner,
|
|
48
|
+
dotCodeIsDataPosition,
|
|
49
|
+
dotCodePattern,
|
|
50
|
+
} from './tables.js';
|
|
51
|
+
|
|
52
|
+
export type DotCodeInput = string | Uint8Array | number[];
|
|
53
|
+
export type DotCodeEncoding = 'utf8' | 'latin1' | 'binary';
|
|
54
|
+
export type DotCodeMask = 0 | 1 | 2 | 3;
|
|
55
|
+
|
|
56
|
+
export interface DotCodeEncodeOptions {
|
|
57
|
+
/** Exact logical width. Must be paired with height, or used with auto height. */
|
|
58
|
+
width?: number;
|
|
59
|
+
/** Exact logical height. Must be paired with width, or used with auto width. */
|
|
60
|
+
height?: number;
|
|
61
|
+
/** Aliases for width and height used by other matrix format APIs. */
|
|
62
|
+
columns?: number;
|
|
63
|
+
rows?: number;
|
|
64
|
+
/** 0..3. The default chooses the least pathological of the four masks. */
|
|
65
|
+
mask?: DotCodeMask;
|
|
66
|
+
/** Interpret ASCII 29 as FNC1 and preserve GS1 semantics. */
|
|
67
|
+
gs1?: boolean;
|
|
68
|
+
/** String input encoding. UTF-8 is the default; byte arrays are unchanged. */
|
|
69
|
+
encoding?: DotCodeEncoding;
|
|
70
|
+
/** Target width/height ratio for automatic sizing. Defaults to 1.5. */
|
|
71
|
+
aspectRatio?: number;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
export interface DotCodeMetadata {
|
|
75
|
+
readonly format: 'dotcode';
|
|
76
|
+
readonly width: number;
|
|
77
|
+
readonly height: number;
|
|
78
|
+
readonly mask: DotCodeMask;
|
|
79
|
+
readonly dataCodewords: number;
|
|
80
|
+
readonly errorCodewords: number;
|
|
81
|
+
readonly modulePositions: number;
|
|
82
|
+
readonly gs1: boolean;
|
|
83
|
+
readonly encoding: DotCodeEncoding;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export type DotCodeMatrix = BitMatrix & { dotcode?: DotCodeMetadata };
|
|
87
|
+
|
|
88
|
+
function bytesFor(value: DotCodeInput, encoding: DotCodeEncoding): Uint8Array {
|
|
89
|
+
if (value instanceof Uint8Array) return new Uint8Array(value);
|
|
90
|
+
if (Array.isArray(value)) {
|
|
91
|
+
if (value.some((byte) => !Number.isInteger(byte) || byte < 0 || byte > 255)) {
|
|
92
|
+
throw new EncodeError('DotCode: byte input must contain integers from 0 to 255');
|
|
93
|
+
}
|
|
94
|
+
return Uint8Array.from(value);
|
|
95
|
+
}
|
|
96
|
+
if (typeof value !== 'string' || value.length === 0) {
|
|
97
|
+
throw new EncodeError('DotCode: value must be a non-empty string or byte array');
|
|
98
|
+
}
|
|
99
|
+
if (encoding === 'utf8') return new TextEncoder().encode(value);
|
|
100
|
+
const bytes = new Uint8Array(value.length);
|
|
101
|
+
for (let index = 0; index < value.length; index++) {
|
|
102
|
+
const code = value.charCodeAt(index);
|
|
103
|
+
if (code > 255) throw new EncodeError(`DotCode: character U+${code.toString(16).padStart(4, '0')} does not fit ${encoding}`);
|
|
104
|
+
bytes[index] = code;
|
|
105
|
+
}
|
|
106
|
+
return bytes;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
function digit(byte: number): boolean { return byte >= 48 && byte <= 57; }
|
|
110
|
+
function hasDigitPair(bytes: Uint8Array, index: number): boolean {
|
|
111
|
+
return index + 1 < bytes.length && digit(bytes[index]) && digit(bytes[index + 1]);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function appendUpperShift(out: number[], byte: number): void {
|
|
115
|
+
if (byte < 128 || byte > 255) throw new EncodeError('DotCode: upper-shift byte must be in 128..255');
|
|
116
|
+
if (byte < 160) out.push(110, byte - 64);
|
|
117
|
+
else out.push(111, byte - 160);
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function appendCodeSetA(out: number[], byte: number): void {
|
|
121
|
+
if (byte > 95) throw new EncodeError('DotCode: byte is not directly encodable in Code Set A');
|
|
122
|
+
out.push(byte < 32 ? byte + 64 : byte - 32);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
function appendCodeSetB(out: number[], byte: number): void {
|
|
126
|
+
if (byte >= 32 && byte <= 127) out.push(byte - 32);
|
|
127
|
+
else if (byte === 9) out.push(97);
|
|
128
|
+
else if (byte === 28) out.push(98);
|
|
129
|
+
else if (byte === 29) out.push(99);
|
|
130
|
+
else if (byte === 30) out.push(100);
|
|
131
|
+
else if (byte === 13) out.push(96);
|
|
132
|
+
else throw new EncodeError('DotCode: byte is not directly encodable in Code Set B');
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
/** Convert five base-259 bytes into six base-103 codewords (or a short tail). */
|
|
136
|
+
function appendBinaryGroup(out: number[], bytes: Uint8Array, start: number, count: number): void {
|
|
137
|
+
let value = 0;
|
|
138
|
+
for (let index = 0; index < count; index++) value = value * 259 + bytes[start + index];
|
|
139
|
+
const words = new Array<number>(count + 1).fill(0);
|
|
140
|
+
for (let index = words.length - 1; index >= 0; index--) {
|
|
141
|
+
words[index] = value % 103;
|
|
142
|
+
value = Math.floor(value / 103);
|
|
143
|
+
}
|
|
144
|
+
if (value !== 0) throw new EncodeError('DotCode: binary radix conversion overflow');
|
|
145
|
+
out.push(...words);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Encode the supported Code Set A/B/C subset and the complete binary-latch
|
|
150
|
+
* byte path. The result is deliberately deterministic and never depends on a
|
|
151
|
+
* third-party encoder.
|
|
152
|
+
*/
|
|
153
|
+
function encodeDataCodewords(bytes: Uint8Array, gs1: boolean, forceBinary: boolean): { words: number[]; encoding: DotCodeEncoding } {
|
|
154
|
+
if (!bytes.length) throw new EncodeError('DotCode: payload must not be empty');
|
|
155
|
+
const words: number[] = [];
|
|
156
|
+
let mode: 'A' | 'B' | 'C' | 'X' = 'C';
|
|
157
|
+
let position = 0;
|
|
158
|
+
let usedBinary = forceBinary;
|
|
159
|
+
|
|
160
|
+
// A leading numeric pair would be interpreted as GS1 by readers. FNC1 is
|
|
161
|
+
// the standard disambiguator for an ordinary numeric message.
|
|
162
|
+
if (!gs1 && hasDigitPair(bytes, 0)) words.push(107);
|
|
163
|
+
if (forceBinary) {
|
|
164
|
+
words.push(112);
|
|
165
|
+
usedBinary = true;
|
|
166
|
+
for (; position < bytes.length; position += 5) appendBinaryGroup(words, bytes, position, Math.min(5, bytes.length - position));
|
|
167
|
+
return { words, encoding: 'binary' };
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
while (position < bytes.length) {
|
|
171
|
+
const byte = bytes[position];
|
|
172
|
+
if (mode === 'X') {
|
|
173
|
+
for (; position < bytes.length; position += 5) appendBinaryGroup(words, bytes, position, Math.min(5, bytes.length - position));
|
|
174
|
+
break;
|
|
175
|
+
}
|
|
176
|
+
if (gs1 && byte === 29) { words.push(107); position++; continue; }
|
|
177
|
+
|
|
178
|
+
if (mode === 'C') {
|
|
179
|
+
if (hasDigitPair(bytes, position)) {
|
|
180
|
+
words.push((bytes[position] - 48) * 10 + bytes[position + 1] - 48);
|
|
181
|
+
position += 2;
|
|
182
|
+
} else if (byte >= 128) {
|
|
183
|
+
if (bytes.length - position >= 5) { words.push(112); mode = 'X'; usedBinary = true; }
|
|
184
|
+
else { appendUpperShift(words, byte); position++; }
|
|
185
|
+
} else if (byte < 32) { words.push(101); mode = 'A'; }
|
|
186
|
+
else { words.push(106); mode = 'B'; }
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
if (mode === 'A') {
|
|
191
|
+
if (hasDigitPair(bytes, position)) { words.push(106); mode = 'C'; continue; }
|
|
192
|
+
if (byte >= 128) {
|
|
193
|
+
if (bytes.length - position >= 5) { words.push(112); mode = 'X'; usedBinary = true; }
|
|
194
|
+
else { appendUpperShift(words, byte); position++; }
|
|
195
|
+
} else if (byte <= 95) { appendCodeSetA(words, byte); position++; }
|
|
196
|
+
else { words.push(102); mode = 'B'; }
|
|
197
|
+
continue;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
// Code Set B.
|
|
201
|
+
if (hasDigitPair(bytes, position)) { words.push(106); mode = 'C'; continue; }
|
|
202
|
+
if (byte >= 128) {
|
|
203
|
+
if (bytes.length - position >= 5) { words.push(112); mode = 'X'; usedBinary = true; }
|
|
204
|
+
else { appendUpperShift(words, byte); position++; }
|
|
205
|
+
} else if ((byte >= 32 && byte <= 127) || byte === 9 || byte === 28 || byte === 29 || byte === 30) {
|
|
206
|
+
appendCodeSetB(words, byte); position++;
|
|
207
|
+
} else { words.push(102); mode = 'A'; }
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
// Binary mode only occurs as the final payload segment above, but RS/data
|
|
211
|
+
// padding follows it. Terminate explicitly so the padding is not bytes.
|
|
212
|
+
if (usedBinary && mode === 'X') words.push(109);
|
|
213
|
+
return { words, encoding: usedBinary ? 'binary' : 'latin1' };
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
function codewordEccLength(dataLength: number): number { return 3 + Math.floor(dataLength / 2); }
|
|
217
|
+
|
|
218
|
+
function maxDataLength(codewordCapacity: number): number {
|
|
219
|
+
return dotCodeDataCapacity(codewordCapacity);
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
function validateDimension(name: string, value: number | undefined): number | undefined {
|
|
223
|
+
if (value === undefined) return undefined;
|
|
224
|
+
if (!Number.isInteger(value) || value < DOTCODE_MIN_DIMENSION || value > DOTCODE_MAX_DIMENSION) {
|
|
225
|
+
throw new EncodeError(`DotCode: ${name} must be an integer in ${DOTCODE_MIN_DIMENSION}..${DOTCODE_MAX_DIMENSION}`);
|
|
226
|
+
}
|
|
227
|
+
return value;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
function chooseDimensions(dataLength: number, options: DotCodeEncodeOptions): { width: number; height: number; dataLength: number } {
|
|
231
|
+
const requestedWidth = validateDimension('width', options.width ?? options.columns);
|
|
232
|
+
const requestedHeight = validateDimension('height', options.height ?? options.rows);
|
|
233
|
+
if (options.aspectRatio !== undefined && (!Number.isFinite(options.aspectRatio) || options.aspectRatio <= 0)) {
|
|
234
|
+
throw new EncodeError('DotCode: aspectRatio must be a finite positive number');
|
|
235
|
+
}
|
|
236
|
+
if (requestedWidth !== undefined && requestedHeight !== undefined && ((requestedWidth + requestedHeight) & 1) === 0) {
|
|
237
|
+
throw new EncodeError('DotCode: width plus height must be odd');
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
const fits = (width: number, height: number) => {
|
|
241
|
+
if (((width + height) & 1) === 0) return null;
|
|
242
|
+
const slots = dotCodeCodewordCapacity(width, height);
|
|
243
|
+
const capacity = maxDataLength(slots);
|
|
244
|
+
if (capacity < dataLength) return null;
|
|
245
|
+
return { width, height, dataLength: capacity };
|
|
246
|
+
};
|
|
247
|
+
|
|
248
|
+
if (requestedWidth !== undefined || requestedHeight !== undefined) {
|
|
249
|
+
if (requestedWidth !== undefined && requestedHeight !== undefined) {
|
|
250
|
+
const result = fits(requestedWidth, requestedHeight);
|
|
251
|
+
if (!result) throw new EncodeError('DotCode: payload does not fit the requested dimensions');
|
|
252
|
+
return result;
|
|
253
|
+
}
|
|
254
|
+
const fixed = requestedWidth ?? requestedHeight!;
|
|
255
|
+
let best: { width: number; height: number; dataLength: number } | null = null;
|
|
256
|
+
for (let varying = DOTCODE_MIN_DIMENSION; varying <= DOTCODE_MAX_DIMENSION; varying++) {
|
|
257
|
+
const width = requestedWidth === undefined ? varying : fixed;
|
|
258
|
+
const height = requestedWidth === undefined ? fixed : varying;
|
|
259
|
+
const candidate = fits(width, height);
|
|
260
|
+
if (candidate) { best = candidate; break; }
|
|
261
|
+
}
|
|
262
|
+
if (!best) throw new EncodeError('DotCode: payload does not fit the requested fixed dimension');
|
|
263
|
+
return best;
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
const aspect = options.aspectRatio ?? 1.5;
|
|
267
|
+
let best: { width: number; height: number; dataLength: number; score: number } | null = null;
|
|
268
|
+
for (let height = DOTCODE_MIN_DIMENSION; height <= DOTCODE_MAX_DIMENSION; height++) {
|
|
269
|
+
for (let width = DOTCODE_MIN_DIMENSION; width <= DOTCODE_MAX_DIMENSION; width++) {
|
|
270
|
+
const candidate = fits(width, height);
|
|
271
|
+
if (!candidate) continue;
|
|
272
|
+
const area = width * height;
|
|
273
|
+
const score = area * 100 + Math.abs(width / height - aspect) * 10 + (candidate.dataLength - dataLength);
|
|
274
|
+
if (!best || score < best.score) best = { ...candidate, score };
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
if (!best) throw new EncodeError('DotCode: payload exceeds the safe 200 by 200 implementation limit');
|
|
278
|
+
return best;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
function rsProtected(data: readonly number[], mask: DotCodeMask): number[] {
|
|
282
|
+
const step = DOTCODE_MASK_STEPS[mask];
|
|
283
|
+
const protectedData = [mask, ...data.map((value, index) => (value + step * index) % DOTCODE_FIELD_SIZE)];
|
|
284
|
+
const eccLength = codewordEccLength(data.length);
|
|
285
|
+
const total = protectedData.length + eccLength;
|
|
286
|
+
// DotCode interleaves Reed-Solomon blocks by residue class. A block is
|
|
287
|
+
// selected with `start + index * blockCount`, and its parity follows that
|
|
288
|
+
// block's data in the same residue class. Keeping the mask at wire index
|
|
289
|
+
// zero is important: it participates in the first RS block just like the
|
|
290
|
+
// public symbology procedure specifies.
|
|
291
|
+
const blockCount = Math.ceil(total / (DOTCODE_FIELD_SIZE - 1));
|
|
292
|
+
const wire = new Array<number>(total).fill(0);
|
|
293
|
+
for (let block = 0; block < blockCount; block++) {
|
|
294
|
+
const blockData = Math.ceil((protectedData.length - block) / blockCount);
|
|
295
|
+
const blockTotal = Math.ceil((total - block) / blockCount);
|
|
296
|
+
const blockEcc = blockTotal - blockData;
|
|
297
|
+
const values: number[] = [];
|
|
298
|
+
for (let index = 0; index < blockData; index++) values.push(protectedData[block + index * blockCount]);
|
|
299
|
+
const parity = rsEncode(values, blockEcc, GF113_DOTCODE, 1);
|
|
300
|
+
for (let index = 0; index < blockData; index++) wire[block + index * blockCount] = values[index];
|
|
301
|
+
for (let index = 0; index < blockEcc; index++) wire[block + blockData * blockCount + index * blockCount] = parity[index];
|
|
302
|
+
}
|
|
303
|
+
return wire;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
function streamFor(width: number, height: number, codewords: readonly number[]): boolean[] {
|
|
307
|
+
const mask = codewords[0];
|
|
308
|
+
const bits: boolean[] = [(mask & 2) !== 0, (mask & 1) !== 0];
|
|
309
|
+
for (let index = 1; index < codewords.length; index++) {
|
|
310
|
+
const pattern = dotCodePattern(codewords[index]);
|
|
311
|
+
for (let bit = 8; bit >= 0; bit--) bits.push(((pattern >>> bit) & 1) !== 0);
|
|
312
|
+
}
|
|
313
|
+
const active = dotCodeActivePositions(width, height);
|
|
314
|
+
if (bits.length > active) throw new EncodeError('DotCode: codeword stream exceeds matrix capacity');
|
|
315
|
+
while (bits.length < active) bits.push(true);
|
|
316
|
+
return bits;
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
function fold(width: number, height: number, stream: readonly boolean[]): BitMatrix {
|
|
320
|
+
const matrix = new BitMatrix(width, height);
|
|
321
|
+
let position = 0;
|
|
322
|
+
if (height & 1) {
|
|
323
|
+
for (let row = 0; row < height; row++) for (let column = 0; column < width; column++) {
|
|
324
|
+
if (!dotCodeIsDataPosition(column, row)) continue;
|
|
325
|
+
if (dotCodeIsCorner(column, row, width, height)) continue;
|
|
326
|
+
const targetY = height - row - 1;
|
|
327
|
+
matrix.setValue(column, targetY, stream[position++]);
|
|
328
|
+
}
|
|
329
|
+
} else {
|
|
330
|
+
for (let column = 0; column < width; column++) for (let row = 0; row < height; row++) {
|
|
331
|
+
if (!dotCodeIsDataPosition(column, row)) continue;
|
|
332
|
+
if (dotCodeIsCorner(column, row, width, height)) continue;
|
|
333
|
+
matrix.setValue(column, row, stream[position++]);
|
|
334
|
+
}
|
|
335
|
+
}
|
|
336
|
+
for (const [column, row] of dotCodeCornerOrder(width, height)) matrix.setValue(column, row, stream[position++]);
|
|
337
|
+
if (position !== stream.length) throw new EncodeError('DotCode: fold did not consume the complete dot stream');
|
|
338
|
+
return matrix;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
function maskScore(matrix: BitMatrix): number {
|
|
342
|
+
let score = 0;
|
|
343
|
+
for (let row = 0; row < matrix.height; row++) {
|
|
344
|
+
let count = 0;
|
|
345
|
+
for (let column = row & 1; column < matrix.width; column += 2) if (matrix.get(column, row)) count++;
|
|
346
|
+
if (count) score += 2 + Math.min(count, 10);
|
|
347
|
+
}
|
|
348
|
+
for (let column = 0; column < matrix.width; column++) {
|
|
349
|
+
let count = 0;
|
|
350
|
+
for (let row = column & 1; row < matrix.height; row += 2) if (matrix.get(column, row)) count++;
|
|
351
|
+
if (count) score += 2 + Math.min(count, 10);
|
|
352
|
+
}
|
|
353
|
+
for (let row = 0; row < matrix.height; row++) for (let column = row & 1; column < matrix.width; column += 2) {
|
|
354
|
+
if (!matrix.get(column, row) &&
|
|
355
|
+
!matrix.get(column - 1, row - 1) && !matrix.get(column + 1, row - 1) &&
|
|
356
|
+
!matrix.get(column - 1, row + 1) && !matrix.get(column + 1, row + 1)) score -= 1;
|
|
357
|
+
}
|
|
358
|
+
return score;
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
function validateMask(value: DotCodeMask | undefined): DotCodeMask | undefined {
|
|
362
|
+
if (value === undefined) return undefined;
|
|
363
|
+
if (!Number.isInteger(value) || value < 0 || value > 3) {
|
|
364
|
+
throw new EncodeError('DotCode: mask must be an integer in 0..3');
|
|
365
|
+
}
|
|
366
|
+
return value;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function matrixForData(data: number[], options: DotCodeEncodeOptions, encoding: DotCodeEncoding, gs1: boolean): DotCodeMatrix {
|
|
370
|
+
if (!data.length) throw new EncodeError('DotCode: payload must not be empty');
|
|
371
|
+
if (data.some((value) => !Number.isInteger(value) || value < 0 || value >= DOTCODE_CODEWORD_COUNT)) {
|
|
372
|
+
throw new EncodeError(`DotCode: data codewords must be integers in 0..${DOTCODE_CODEWORD_COUNT - 1}`);
|
|
373
|
+
}
|
|
374
|
+
const dimensions = chooseDimensions(data.length, options);
|
|
375
|
+
while (data.length < dimensions.dataLength) data.push(106);
|
|
376
|
+
const eccLength = codewordEccLength(data.length);
|
|
377
|
+
const selected = validateMask(options.mask);
|
|
378
|
+
let bestMask: DotCodeMask = selected ?? 0;
|
|
379
|
+
let bestMatrix: BitMatrix | null = null;
|
|
380
|
+
if (selected === undefined) {
|
|
381
|
+
let bestScore = Number.NEGATIVE_INFINITY;
|
|
382
|
+
for (let mask = 0; mask < 4; mask++) {
|
|
383
|
+
const matrix = fold(
|
|
384
|
+
dimensions.width,
|
|
385
|
+
dimensions.height,
|
|
386
|
+
streamFor(dimensions.width, dimensions.height, rsProtected(data, mask as DotCodeMask)),
|
|
387
|
+
);
|
|
388
|
+
const score = maskScore(matrix);
|
|
389
|
+
if (score >= bestScore) {
|
|
390
|
+
bestScore = score;
|
|
391
|
+
bestMask = mask as DotCodeMask;
|
|
392
|
+
bestMatrix = matrix;
|
|
393
|
+
}
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
const matrix = (bestMatrix ?? fold(
|
|
397
|
+
dimensions.width,
|
|
398
|
+
dimensions.height,
|
|
399
|
+
streamFor(dimensions.width, dimensions.height, rsProtected(data, bestMask)),
|
|
400
|
+
)) as DotCodeMatrix;
|
|
401
|
+
matrix.dotcode = {
|
|
402
|
+
format: 'dotcode', width: dimensions.width, height: dimensions.height,
|
|
403
|
+
mask: bestMask, dataCodewords: data.length, errorCodewords: eccLength,
|
|
404
|
+
modulePositions: dotCodeActivePositions(dimensions.width, dimensions.height),
|
|
405
|
+
gs1, encoding,
|
|
406
|
+
};
|
|
407
|
+
return matrix;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
/** Encode a string or byte payload into a DotCode module matrix. */
|
|
411
|
+
export function encodeDotCode(value: DotCodeInput, options: DotCodeEncodeOptions = {}): DotCodeMatrix {
|
|
412
|
+
const requestedEncoding = options.encoding ?? (value instanceof Uint8Array || Array.isArray(value) ? 'binary' : 'utf8');
|
|
413
|
+
const bytes = bytesFor(value, requestedEncoding);
|
|
414
|
+
if (!bytes.length) throw new EncodeError('DotCode: payload must not be empty');
|
|
415
|
+
const encoded = encodeDataCodewords(bytes, options.gs1 === true, requestedEncoding === 'binary');
|
|
416
|
+
return matrixForData(encoded.words, options, encoded.encoding, options.gs1 === true);
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** Encode an explicit set of unmasked data codewords for conformance fixtures. */
|
|
420
|
+
export function encodeDotCodeCodewords(codewords: readonly number[], options: DotCodeEncodeOptions = {}): DotCodeMatrix {
|
|
421
|
+
if (!Array.isArray(codewords) && !(codewords instanceof Uint8Array)) throw new EncodeError('DotCode: codewords must be an array');
|
|
422
|
+
const data = Array.from(codewords);
|
|
423
|
+
if (!data.length || data.some((value) => !Number.isInteger(value) || value < 0 || value >= DOTCODE_CODEWORD_COUNT)) {
|
|
424
|
+
throw new EncodeError(`DotCode: codewords must be integers in 0..${DOTCODE_CODEWORD_COUNT - 1}`);
|
|
425
|
+
}
|
|
426
|
+
return matrixForData(data, options, 'binary', options.gs1 === true);
|
|
427
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
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
|
+
/** Public DotCode module surface. @module dotcode */
|
|
31
|
+
export { encodeDotCode, encodeDotCodeCodewords } from './encoder.js';
|
|
32
|
+
export { decodeDotCode } from './decoder.js';
|
|
33
|
+
export { detectDotCode, detectAndDecodeDotCode } from './detector.js';
|
|
34
|
+
export { DOTCODE_CODEWORD_COUNT, DOTCODE_FIELD_SIZE, DOTCODE_MASK_STEPS, DOTCODE_MAX_DIMENSION, DOTCODE_MIN_DIMENSION, DOTCODE_PATTERNS, dotCodeActivePositions, dotCodeCodeword, dotCodeCodewordCapacity, dotCodeCornerOrder, dotCodeDataCapacity, dotCodeIsCorner, dotCodeIsDataPosition, dotCodePattern, validateDotCodeTables, } from './tables.js';
|
|
35
|
+
export type { DotCodeDecodeOptions, DotCodeDecodeResult, DotCodePolarity, DotCodeRotation, } from './decoder.js';
|
|
36
|
+
export type { DotCodeDetectOptions, DotCodeDetection, DotCodePoint, } from './detector.js';
|
|
37
|
+
export type { DotCodeEncodeOptions, DotCodeEncoding, DotCodeInput, DotCodeMask, DotCodeMatrix, DotCodeMetadata, } from './encoder.js';
|
|
@@ -0,0 +1,72 @@
|
|
|
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
|
+
/** Public DotCode module surface. @module dotcode */
|
|
32
|
+
|
|
33
|
+
export { encodeDotCode, encodeDotCodeCodewords } from './encoder.js';
|
|
34
|
+
export { decodeDotCode } from './decoder.js';
|
|
35
|
+
export { detectDotCode, detectAndDecodeDotCode } from './detector.js';
|
|
36
|
+
export {
|
|
37
|
+
DOTCODE_CODEWORD_COUNT,
|
|
38
|
+
DOTCODE_FIELD_SIZE,
|
|
39
|
+
DOTCODE_MASK_STEPS,
|
|
40
|
+
DOTCODE_MAX_DIMENSION,
|
|
41
|
+
DOTCODE_MIN_DIMENSION,
|
|
42
|
+
DOTCODE_PATTERNS,
|
|
43
|
+
dotCodeActivePositions,
|
|
44
|
+
dotCodeCodeword,
|
|
45
|
+
dotCodeCodewordCapacity,
|
|
46
|
+
dotCodeCornerOrder,
|
|
47
|
+
dotCodeDataCapacity,
|
|
48
|
+
dotCodeIsCorner,
|
|
49
|
+
dotCodeIsDataPosition,
|
|
50
|
+
dotCodePattern,
|
|
51
|
+
validateDotCodeTables,
|
|
52
|
+
} from './tables.js';
|
|
53
|
+
|
|
54
|
+
export type {
|
|
55
|
+
DotCodeDecodeOptions,
|
|
56
|
+
DotCodeDecodeResult,
|
|
57
|
+
DotCodePolarity,
|
|
58
|
+
DotCodeRotation,
|
|
59
|
+
} from './decoder.js';
|
|
60
|
+
export type {
|
|
61
|
+
DotCodeDetectOptions,
|
|
62
|
+
DotCodeDetection,
|
|
63
|
+
DotCodePoint,
|
|
64
|
+
} from './detector.js';
|
|
65
|
+
export type {
|
|
66
|
+
DotCodeEncodeOptions,
|
|
67
|
+
DotCodeEncoding,
|
|
68
|
+
DotCodeInput,
|
|
69
|
+
DotCodeMask,
|
|
70
|
+
DotCodeMatrix,
|
|
71
|
+
DotCodeMetadata,
|
|
72
|
+
} from './encoder.js';
|
|
@@ -0,0 +1,74 @@
|
|
|
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
|
+
* DotCode structural constants and the public 5-of-9 symbol assignment.
|
|
32
|
+
*
|
|
33
|
+
* The pattern assignment is a normative symbology table. It is recorded as
|
|
34
|
+
* compact hexadecimal values so the runtime does not need a third-party table
|
|
35
|
+
* or a generated dependency. Bit 8 is the first dot in the nine-dot pattern.
|
|
36
|
+
* Every entry contains exactly five dark dots.
|
|
37
|
+
*
|
|
38
|
+
* @module dotcode/tables
|
|
39
|
+
*/
|
|
40
|
+
import { GaloisField } from '../core/galois-field.js';
|
|
41
|
+
export declare const DOTCODE_MIN_DIMENSION = 5;
|
|
42
|
+
export declare const DOTCODE_MAX_DIMENSION = 200;
|
|
43
|
+
export declare const DOTCODE_FIELD_SIZE = 113;
|
|
44
|
+
export declare const DOTCODE_CODEWORD_COUNT = 113;
|
|
45
|
+
export declare const DOTCODE_MIN_ECC = 3;
|
|
46
|
+
export declare const DOTCODE_MASK_STEPS: readonly number[];
|
|
47
|
+
/** GF(113), with the primitive root required by the DotCode RS procedure. */
|
|
48
|
+
export declare const GF113_DOTCODE: GaloisField;
|
|
49
|
+
/**
|
|
50
|
+
* DotCode Annex C's 113 legal 5-of-9 patterns.
|
|
51
|
+
*
|
|
52
|
+
* This is format data, not executable code copied from an implementation.
|
|
53
|
+
* Keeping it in the authoritative TypeScript source makes the JS runtime and
|
|
54
|
+
* its declarations reproducible without a package-time generator.
|
|
55
|
+
*/
|
|
56
|
+
export declare const DOTCODE_PATTERNS: readonly number[];
|
|
57
|
+
/** Return the nine-dot pattern assigned to a codeword. */
|
|
58
|
+
export declare function dotCodePattern(codeword: number): number;
|
|
59
|
+
/** Return a codeword for a nine-dot pattern, or -1 when it is not assigned. */
|
|
60
|
+
export declare function dotCodeCodeword(pattern: number): number;
|
|
61
|
+
/** Number of active alternating positions in a W by H symbol. */
|
|
62
|
+
export declare function dotCodeActivePositions(width: number, height: number): number;
|
|
63
|
+
/** Number of complete nine-bit codewords available after the mask bits. */
|
|
64
|
+
export declare function dotCodeCodewordCapacity(width: number, height: number): number;
|
|
65
|
+
/** DotCode uses alternating positions; the six corner positions carry tail bits. */
|
|
66
|
+
export declare function dotCodeIsDataPosition(column: number, row: number): boolean;
|
|
67
|
+
/** Return true for one of the six corner positions used by the folded stream. */
|
|
68
|
+
export declare function dotCodeIsCorner(column: number, row: number, width: number, height: number): boolean;
|
|
69
|
+
/** Return the six corner coordinates in wire order for a canonical matrix. */
|
|
70
|
+
export declare function dotCodeCornerOrder(width: number, height: number): readonly [number, number][];
|
|
71
|
+
/** Largest data-codeword count that fits the supplied nine-bit capacity. */
|
|
72
|
+
export declare function dotCodeDataCapacity(codewordCapacity: number): number;
|
|
73
|
+
/** Check public structural constants and pattern invariants. */
|
|
74
|
+
export declare function validateDotCodeTables(): string[];
|