@sythos/js_barcode_universal 1.1.0 → 1.2.5
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 +16 -17
- package/NOTICE.md +24 -22
- package/README.md +100 -49
- package/bundle/sythos-barcode.esm.js +2058 -54
- package/bundle/sythos-barcode.js +2050 -54
- package/examples/create.html +2 -1
- package/licenses/README.md +58 -30
- package/licenses/aztec-code.license +12 -12
- package/licenses/codabar.license +9 -9
- package/licenses/code-11.license +9 -9
- package/licenses/code-128.license +6 -6
- package/licenses/code-39.license +6 -6
- package/licenses/code-93.license +7 -7
- package/licenses/data-matrix.license +11 -11
- package/licenses/ean-13.license +6 -6
- package/licenses/ean-8.license +6 -6
- package/licenses/gs1-128.license +6 -6
- package/licenses/isbn.license +7 -7
- package/licenses/itf-14.license +6 -6
- package/licenses/itf.license +6 -6
- package/licenses/micropdf417.license +96 -0
- package/licenses/msi-plessey.license +7 -7
- package/licenses/pdf417.license +37 -0
- package/licenses/pharmacode.license +7 -7
- package/licenses/qr-code.license +6 -6
- package/licenses/upc-a.license +7 -7
- package/licenses/upc-e.license +6 -6
- package/package.json +9 -2
- package/src/core/reed-solomon.js +326 -312
- package/src/index.js +77 -3
- package/src/micropdf417/compaction.js +116 -0
- package/src/micropdf417/decoder.js +183 -0
- package/src/micropdf417/detector.js +149 -0
- package/src/micropdf417/encoder.js +209 -0
- package/src/micropdf417/error-correction.js +55 -0
- package/src/micropdf417/index.js +49 -0
- package/src/micropdf417/tables.js +184 -0
- package/src/pdf417/compaction.js +298 -0
- package/src/pdf417/decoder.js +75 -0
- package/src/pdf417/detector.js +468 -0
- package/src/pdf417/encoder.js +91 -0
- package/src/pdf417/error-correction.js +47 -0
- package/src/pdf417/index.js +6 -0
- package/src/pdf417/tables.js +317 -0
package/bundle/sythos-barcode.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/*!
|
|
2
|
-
* Sythos Barcode Suite v1.
|
|
2
|
+
* Sythos Barcode Suite v1.2.5
|
|
3
3
|
*
|
|
4
4
|
* MIT License
|
|
5
5
|
*
|
|
@@ -3066,6 +3066,44 @@ function evalPoly(poly, x, field) {
|
|
|
3066
3066
|
return acc;
|
|
3067
3067
|
}
|
|
3068
3068
|
|
|
3069
|
+
function multiplyAscending(left, right, field, limit) {
|
|
3070
|
+
const out = new Array(Math.min(limit, left.length + right.length - 1)).fill(0);
|
|
3071
|
+
for (let i = 0; i < left.length; i++) for (let j = 0; j < right.length && i + j < out.length; j++) {
|
|
3072
|
+
out[i + j] = field.add(out[i + j], field.mul(left[i], right[j]));
|
|
3073
|
+
}
|
|
3074
|
+
return out;
|
|
3075
|
+
}
|
|
3076
|
+
|
|
3077
|
+
function berlekampMassey(syndromes, field) {
|
|
3078
|
+
const limit = syndromes.length;
|
|
3079
|
+
const lambda = new Array(limit + 1).fill(0);
|
|
3080
|
+
const previous = new Array(limit + 1).fill(0);
|
|
3081
|
+
const temporary = new Array(limit + 1).fill(0);
|
|
3082
|
+
lambda[0] = 1;
|
|
3083
|
+
previous[0] = 1;
|
|
3084
|
+
let errorCount = 0;
|
|
3085
|
+
let shift = 1;
|
|
3086
|
+
let lastDiscrepancy = 1;
|
|
3087
|
+
|
|
3088
|
+
for (let step = 0; step < limit; step++) {
|
|
3089
|
+
let discrepancy = syndromes[step];
|
|
3090
|
+
for (let i = 1; i <= errorCount; i++) discrepancy = field.add(discrepancy, field.mul(lambda[i], syndromes[step - i]));
|
|
3091
|
+
if (discrepancy === 0) { shift++; continue; }
|
|
3092
|
+
const scale = field.div(discrepancy, lastDiscrepancy);
|
|
3093
|
+
for (let i = 0; i <= limit; i++) temporary[i] = lambda[i];
|
|
3094
|
+
for (let i = 0; i + shift <= limit; i++) if (previous[i] !== 0) {
|
|
3095
|
+
lambda[i + shift] = field.sub(lambda[i + shift], field.mul(scale, previous[i]));
|
|
3096
|
+
}
|
|
3097
|
+
if (2 * errorCount <= step) {
|
|
3098
|
+
errorCount = step + 1 - errorCount;
|
|
3099
|
+
for (let i = 0; i <= limit; i++) previous[i] = temporary[i];
|
|
3100
|
+
lastDiscrepancy = discrepancy;
|
|
3101
|
+
shift = 1;
|
|
3102
|
+
} else shift++;
|
|
3103
|
+
}
|
|
3104
|
+
return { locator: lambda.slice(0, errorCount + 1), errorCount };
|
|
3105
|
+
}
|
|
3106
|
+
|
|
3069
3107
|
/**
|
|
3070
3108
|
* Correct errors in a received codeword, in place.
|
|
3071
3109
|
*
|
|
@@ -3073,11 +3111,16 @@ function evalPoly(poly, x, field) {
|
|
|
3073
3111
|
* @param {number} eccLen
|
|
3074
3112
|
* @param {import('./galois-field.js').GaloisField} field
|
|
3075
3113
|
* @param {number} [base]
|
|
3114
|
+
* @param {number[]} [erasures] Known damaged indexes, counted from wire order.
|
|
3076
3115
|
* @returns {number} Number of symbols corrected.
|
|
3077
3116
|
* @throws {ChecksumError} If the damage exceeds the correction capacity.
|
|
3078
3117
|
*/
|
|
3079
|
-
function rsDecode(received, eccLen, field, base = 0) {
|
|
3118
|
+
function rsDecode(received, eccLen, field, base = 0, erasures = []) {
|
|
3080
3119
|
const n = received.length;
|
|
3120
|
+
if (!Array.isArray(erasures) || new Set(erasures).size !== erasures.length || erasures.some((index) => !Number.isInteger(index) || index < 0 || index >= n)) {
|
|
3121
|
+
throw new ChecksumError('Reed-Solomon: erasure positions must be unique codeword indexes');
|
|
3122
|
+
}
|
|
3123
|
+
if (erasures.length > eccLen) throw new ChecksumError(`Reed-Solomon: ${erasures.length} erasures exceeds correction capacity ${eccLen} (${field.name})`);
|
|
3081
3124
|
|
|
3082
3125
|
// --- Syndromes. S[i] = R(a^(base+i)); all zero means an intact codeword.
|
|
3083
3126
|
const syn = new Array(eccLen).fill(0);
|
|
@@ -3089,53 +3132,24 @@ function rsDecode(received, eccLen, field, base = 0) {
|
|
|
3089
3132
|
}
|
|
3090
3133
|
if (!damaged) return 0;
|
|
3091
3134
|
|
|
3092
|
-
//
|
|
3093
|
-
//
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
const
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3101
|
-
|
|
3102
|
-
|
|
3103
|
-
for (let step = 0; step < eccLen; step++) {
|
|
3104
|
-
let disc = syn[step];
|
|
3105
|
-
for (let i = 1; i <= errCount; i++) {
|
|
3106
|
-
disc = field.add(disc, field.mul(lambda[i], syn[step - i]));
|
|
3107
|
-
}
|
|
3108
|
-
|
|
3109
|
-
if (disc === 0) {
|
|
3110
|
-
shift++;
|
|
3111
|
-
continue;
|
|
3112
|
-
}
|
|
3113
|
-
|
|
3114
|
-
const scale = field.div(disc, lastDisc);
|
|
3115
|
-
tmp.fill(0);
|
|
3116
|
-
for (let i = 0; i <= eccLen; i++) tmp[i] = lambda[i];
|
|
3117
|
-
|
|
3118
|
-
for (let i = 0; i + shift <= eccLen; i++) {
|
|
3119
|
-
if (prev[i] === 0) continue;
|
|
3120
|
-
lambda[i + shift] = field.sub(lambda[i + shift], field.mul(scale, prev[i]));
|
|
3121
|
-
}
|
|
3122
|
-
|
|
3123
|
-
if (2 * errCount <= step) {
|
|
3124
|
-
errCount = step + 1 - errCount;
|
|
3125
|
-
for (let i = 0; i <= eccLen; i++) prev[i] = tmp[i];
|
|
3126
|
-
lastDisc = disc;
|
|
3127
|
-
shift = 1;
|
|
3128
|
-
} else {
|
|
3129
|
-
shift++;
|
|
3130
|
-
}
|
|
3131
|
-
}
|
|
3132
|
-
|
|
3133
|
-
if (errCount === 0 || errCount > eccLen / 2) {
|
|
3135
|
+
// Remove the known roots before locating unknown errors. The leading
|
|
3136
|
+
// erasureCount terms contain only the known-location transient and are not
|
|
3137
|
+
// part of the error-only recurrence.
|
|
3138
|
+
let erasureLocator = [1];
|
|
3139
|
+
for (const index of erasures) {
|
|
3140
|
+
const location = field.exp(n - 1 - index);
|
|
3141
|
+
erasureLocator = multiplyAscending(erasureLocator, [1, field.neg(location)], field, eccLen + 1);
|
|
3142
|
+
}
|
|
3143
|
+
const modified = multiplyAscending(syn, erasureLocator, field, eccLen).slice(erasures.length);
|
|
3144
|
+
const { locator: errorLocator, errorCount } = berlekampMassey(modified, field);
|
|
3145
|
+
if (2 * errorCount + erasures.length > eccLen) {
|
|
3134
3146
|
throw new ChecksumError(
|
|
3135
|
-
`Reed-Solomon: ${
|
|
3136
|
-
`${
|
|
3147
|
+
`Reed-Solomon: ${errorCount} errors and ${erasures.length} erasures exceed correction capacity ` +
|
|
3148
|
+
`${eccLen} (${field.name})`
|
|
3137
3149
|
);
|
|
3138
3150
|
}
|
|
3151
|
+
const lambda = multiplyAscending(erasureLocator, errorLocator, field, eccLen + 1);
|
|
3152
|
+
const totalCount = errorCount + erasures.length;
|
|
3139
3153
|
|
|
3140
3154
|
// --- Chien search. Position p (counted from the low-order end) is in error
|
|
3141
3155
|
// when lambda(a^-p) == 0.
|
|
@@ -3144,16 +3158,16 @@ function rsDecode(received, eccLen, field, base = 0) {
|
|
|
3144
3158
|
const xInv = field.exp(-p);
|
|
3145
3159
|
let acc = 0;
|
|
3146
3160
|
let term = 1;
|
|
3147
|
-
for (let i = 0; i <=
|
|
3161
|
+
for (let i = 0; i <= totalCount; i++) {
|
|
3148
3162
|
acc = field.add(acc, field.mul(lambda[i], term));
|
|
3149
3163
|
term = field.mul(term, xInv);
|
|
3150
3164
|
}
|
|
3151
3165
|
if (acc === 0) positions.push(p);
|
|
3152
3166
|
}
|
|
3153
3167
|
|
|
3154
|
-
if (positions.length !==
|
|
3168
|
+
if (positions.length !== totalCount) {
|
|
3155
3169
|
throw new ChecksumError(
|
|
3156
|
-
`Reed-Solomon: located ${positions.length} of ${
|
|
3170
|
+
`Reed-Solomon: located ${positions.length} of ${totalCount} error positions`
|
|
3157
3171
|
);
|
|
3158
3172
|
}
|
|
3159
3173
|
|
|
@@ -3162,7 +3176,7 @@ function rsDecode(received, eccLen, field, base = 0) {
|
|
|
3162
3176
|
const omega = new Array(eccLen).fill(0);
|
|
3163
3177
|
for (let i = 0; i < eccLen; i++) {
|
|
3164
3178
|
let acc = 0;
|
|
3165
|
-
for (let j = 0; j <= i && j <=
|
|
3179
|
+
for (let j = 0; j <= i && j <= totalCount; j++) {
|
|
3166
3180
|
acc = field.add(acc, field.mul(lambda[j], syn[i - j]));
|
|
3167
3181
|
}
|
|
3168
3182
|
omega[i] = acc;
|
|
@@ -3186,7 +3200,7 @@ function rsDecode(received, eccLen, field, base = 0) {
|
|
|
3186
3200
|
// in a prime field every term contributes with an integer multiplier.
|
|
3187
3201
|
let den = 0;
|
|
3188
3202
|
term = 1;
|
|
3189
|
-
for (let i = 1; i <=
|
|
3203
|
+
for (let i = 1; i <= totalCount; i++) {
|
|
3190
3204
|
if (field.prime) {
|
|
3191
3205
|
// i * lambda[i] * x^(i-1), where `i` is repeated addition.
|
|
3192
3206
|
let mult = 0;
|
|
@@ -8329,6 +8343,1916 @@ const __reexport2 = __require("aztec/detector.js"); __exports.detectAztec = __re
|
|
|
8329
8343
|
const __reexport3 = __require("aztec/tables.js"); __exports.AZTEC_COMPACT_LAYERS = __reexport3.AZTEC_COMPACT_LAYERS; __exports.AZTEC_FULL_LAYERS = __reexport3.AZTEC_FULL_LAYERS; __exports.AZTEC_LAYERS = __reexport3.AZTEC_LAYERS; __exports.AZTEC_DEFAULT_ECC_PERCENT = __reexport3.AZTEC_DEFAULT_ECC_PERCENT; __exports.AZTEC_RS_GENERATOR_BASE = __reexport3.AZTEC_RS_GENERATOR_BASE; __exports.aztecLayer = __reexport3.aztecLayer; __exports.aztecSymbolSize = __reexport3.aztecSymbolSize; __exports.validateAztecTables = __reexport3.validateAztecTables;
|
|
8330
8344
|
|
|
8331
8345
|
|
|
8346
|
+
};
|
|
8347
|
+
|
|
8348
|
+
__modules["pdf417/compaction.js"] = function (__require, __exports) {
|
|
8349
|
+
/** PDF417 high-level text, byte and numeric compaction. @module pdf417/compaction */
|
|
8350
|
+
const { EncodeError, FormatError } = __require("core/errors.js");
|
|
8351
|
+
|
|
8352
|
+
const ALPHA = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ ';
|
|
8353
|
+
const LOWER = 'abcdefghijklmnopqrstuvwxyz ';
|
|
8354
|
+
const MIXED = '0123456789&\r\t,:#-.$/+%*=^';
|
|
8355
|
+
const PUNCT = ';<>@[\\]_`~!\r\t,:\n-.$/"|*()?{}\'';
|
|
8356
|
+
|
|
8357
|
+
function packBase30(values) {
|
|
8358
|
+
const out = [];
|
|
8359
|
+
for (let i = 0; i < values.length; i += 2) out.push(values[i] * 30 + (i + 1 < values.length ? values[i + 1] : 29));
|
|
8360
|
+
return out;
|
|
8361
|
+
}
|
|
8362
|
+
|
|
8363
|
+
/** Compact a value using the PDF417 Text Compaction alphabet. */
|
|
8364
|
+
function compactPdf417Text(value) {
|
|
8365
|
+
if (typeof value !== 'string') throw new EncodeError('PDF417 text: value must be a string');
|
|
8366
|
+
const values = [];
|
|
8367
|
+
let submode = 'alpha';
|
|
8368
|
+
for (const character of value) {
|
|
8369
|
+
const inAlpha = ALPHA.indexOf(character), inLower = LOWER.indexOf(character);
|
|
8370
|
+
const inMixed = MIXED.indexOf(character), inPunct = PUNCT.indexOf(character);
|
|
8371
|
+
if (submode === 'alpha') {
|
|
8372
|
+
if (inAlpha >= 0) values.push(inAlpha);
|
|
8373
|
+
else if (inLower >= 0) { values.push(27, inLower); submode = 'lower'; }
|
|
8374
|
+
else if (inMixed >= 0 || character === ' ') { values.push(28, character === ' ' ? 26 : inMixed); submode = 'mixed'; }
|
|
8375
|
+
else if (inPunct >= 0) values.push(29, inPunct);
|
|
8376
|
+
else throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
|
|
8377
|
+
} else if (submode === 'lower') {
|
|
8378
|
+
if (inLower >= 0) values.push(inLower);
|
|
8379
|
+
else if (inAlpha >= 0) values.push(27, inAlpha);
|
|
8380
|
+
else if (inMixed >= 0 || character === ' ') { values.push(28, character === ' ' ? 26 : inMixed); submode = 'mixed'; }
|
|
8381
|
+
else if (inPunct >= 0) values.push(29, inPunct);
|
|
8382
|
+
else throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
|
|
8383
|
+
} else {
|
|
8384
|
+
if (inMixed >= 0) values.push(inMixed);
|
|
8385
|
+
else if (character === ' ') values.push(26);
|
|
8386
|
+
else if (inAlpha >= 0) { values.push(28); submode = 'alpha'; values.push(inAlpha); }
|
|
8387
|
+
else if (inLower >= 0) { values.push(27); submode = 'lower'; values.push(inLower); }
|
|
8388
|
+
else if (inPunct >= 0) values.push(29, inPunct);
|
|
8389
|
+
else throw new EncodeError(`PDF417 text: unsupported character ${JSON.stringify(character)}`);
|
|
8390
|
+
}
|
|
8391
|
+
}
|
|
8392
|
+
return packBase30(values);
|
|
8393
|
+
}
|
|
8394
|
+
|
|
8395
|
+
function asBytes(value) {
|
|
8396
|
+
if (value instanceof Uint8Array) return value;
|
|
8397
|
+
if (ArrayBuffer.isView(value)) return new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
8398
|
+
if (typeof value === 'string') return new TextEncoder().encode(value);
|
|
8399
|
+
throw new EncodeError('PDF417 byte: value must be text or a byte array');
|
|
8400
|
+
}
|
|
8401
|
+
|
|
8402
|
+
/** Compact bytes using latch 924 for exact six-byte blocks and 901 otherwise. */
|
|
8403
|
+
function compactPdf417Bytes(value) {
|
|
8404
|
+
const bytes = asBytes(value);
|
|
8405
|
+
const utf8 = typeof value === 'string' && /[^\x00-\x7f]/.test(value);
|
|
8406
|
+
const out = utf8 ? [927, 26] : [];
|
|
8407
|
+
out.push(bytes.length > 0 && bytes.length % 6 === 0 ? 924 : 901);
|
|
8408
|
+
let at = 0;
|
|
8409
|
+
while (at + 6 <= bytes.length) {
|
|
8410
|
+
let number = 0n;
|
|
8411
|
+
for (let i = 0; i < 6; i++) number = (number << 8n) | BigInt(bytes[at++]);
|
|
8412
|
+
const group = new Array(5);
|
|
8413
|
+
for (let i = 4; i >= 0; i--) { group[i] = Number(number % 900n); number /= 900n; }
|
|
8414
|
+
out.push(...group);
|
|
8415
|
+
}
|
|
8416
|
+
while (at < bytes.length) out.push(bytes[at++]);
|
|
8417
|
+
return out;
|
|
8418
|
+
}
|
|
8419
|
+
|
|
8420
|
+
/** Compact decimal digits using latch 902 and groups of at most 44 digits. */
|
|
8421
|
+
function compactPdf417Numeric(value) {
|
|
8422
|
+
if (typeof value !== 'string' || !/^\d+$/.test(value)) throw new EncodeError('PDF417 numeric: value must contain decimal digits only');
|
|
8423
|
+
const out = [902];
|
|
8424
|
+
for (let at = 0; at < value.length; at += 44) {
|
|
8425
|
+
let number = BigInt(`1${value.slice(at, at + 44)}`);
|
|
8426
|
+
const group = [];
|
|
8427
|
+
do { group.unshift(Number(number % 900n)); number /= 900n; } while (number > 0n);
|
|
8428
|
+
out.push(...group);
|
|
8429
|
+
}
|
|
8430
|
+
return out;
|
|
8431
|
+
}
|
|
8432
|
+
|
|
8433
|
+
/** Compact a single value, selecting text, numeric or byte mode. */
|
|
8434
|
+
function compactPdf417(value, options = {}) {
|
|
8435
|
+
const mode = options.compaction ?? 'auto';
|
|
8436
|
+
if (mode === 'text') return compactPdf417Text(value);
|
|
8437
|
+
if (mode === 'byte') return compactPdf417Bytes(value);
|
|
8438
|
+
if (mode === 'numeric') return compactPdf417Numeric(value);
|
|
8439
|
+
if (mode !== 'auto') throw new EncodeError(`PDF417: unsupported compaction mode ${JSON.stringify(mode)}`);
|
|
8440
|
+
if (typeof value === 'string' && /^\d{13,}$/.test(value)) return compactPdf417Numeric(value);
|
|
8441
|
+
if (typeof value === 'string') {
|
|
8442
|
+
try { return compactPdf417Text(value); } catch (error) { if (!(error instanceof EncodeError)) throw error; }
|
|
8443
|
+
}
|
|
8444
|
+
return compactPdf417Bytes(value);
|
|
8445
|
+
}
|
|
8446
|
+
|
|
8447
|
+
function assertCodeword(codeword) {
|
|
8448
|
+
if (!Number.isInteger(codeword) || codeword < 0 || codeword > 928) throw new FormatError('PDF417: codeword is outside 0..928');
|
|
8449
|
+
}
|
|
8450
|
+
|
|
8451
|
+
function decodeUtf8(bytes, eci) {
|
|
8452
|
+
if (eci === 3) return Array.from(bytes, (byte) => String.fromCharCode(byte)).join('');
|
|
8453
|
+
if (eci !== 26) throw new FormatError(`PDF417 ECI: unsupported assignment number ${eci}`);
|
|
8454
|
+
try { return new TextDecoder('utf-8', { fatal: true }).decode(new Uint8Array(bytes)); }
|
|
8455
|
+
catch { throw new FormatError('PDF417 byte: invalid UTF-8 sequence'); }
|
|
8456
|
+
}
|
|
8457
|
+
|
|
8458
|
+
function decodeByteSegment(codewords, at, eci, sixOnly = false) {
|
|
8459
|
+
const values = [];
|
|
8460
|
+
while (at < codewords.length && codewords[at] < 900) values.push(codewords[at++]);
|
|
8461
|
+
if (sixOnly && values.length % 5) throw new FormatError('PDF417 byte: 924 segment must contain complete six-byte groups');
|
|
8462
|
+
const bytes = [];
|
|
8463
|
+
// In 901 mode an encoder can use five terminal literal codewords. The
|
|
8464
|
+
// unambiguous groups are therefore the ones followed by another codeword;
|
|
8465
|
+
// 924 is available whenever a segment consists exclusively of six-byte groups.
|
|
8466
|
+
const groupCount = sixOnly ? values.length / 5 : Math.max(0, Math.floor((values.length - 1) / 5));
|
|
8467
|
+
for (let groupAt = 0; groupAt < groupCount * 5; groupAt += 5) {
|
|
8468
|
+
let number = 0n;
|
|
8469
|
+
for (let i = 0; i < 5; i++) number = number * 900n + BigInt(values[groupAt + i]);
|
|
8470
|
+
const group = new Uint8Array(6);
|
|
8471
|
+
for (let i = 5; i >= 0; i--) { group[i] = Number(number & 255n); number >>= 8n; }
|
|
8472
|
+
if (number !== 0n) throw new FormatError('PDF417 byte: base-900 group exceeds six bytes');
|
|
8473
|
+
bytes.push(...group);
|
|
8474
|
+
}
|
|
8475
|
+
for (let i = groupCount * 5; i < values.length; i++) {
|
|
8476
|
+
if (values[i] > 255) throw new FormatError('PDF417 byte: literal tail is outside 0..255');
|
|
8477
|
+
bytes.push(values[i]);
|
|
8478
|
+
}
|
|
8479
|
+
return { at, text: decodeUtf8(bytes, eci), bytes: Uint8Array.from(bytes) };
|
|
8480
|
+
}
|
|
8481
|
+
|
|
8482
|
+
function decodeTextSegment(codewords, at, eci) {
|
|
8483
|
+
let mode = 'alpha';
|
|
8484
|
+
let output = '';
|
|
8485
|
+
let shift = null;
|
|
8486
|
+
let shiftedBytes = [];
|
|
8487
|
+
const bytes = [];
|
|
8488
|
+
const flushShiftedBytes = () => {
|
|
8489
|
+
if (shiftedBytes.length) {
|
|
8490
|
+
output += decodeUtf8(shiftedBytes, eci);
|
|
8491
|
+
bytes.push(...shiftedBytes);
|
|
8492
|
+
shiftedBytes = [];
|
|
8493
|
+
}
|
|
8494
|
+
};
|
|
8495
|
+
const emit = (alphabet, value) => {
|
|
8496
|
+
if (value < 0 || value >= alphabet.length) throw new FormatError('PDF417 text: invalid submode value');
|
|
8497
|
+
output += alphabet[value];
|
|
8498
|
+
};
|
|
8499
|
+
const process = (value) => {
|
|
8500
|
+
if (shift) { emit(shift === 'alpha' ? ALPHA : PUNCT, value); shift = null; return; }
|
|
8501
|
+
if (mode === 'alpha') {
|
|
8502
|
+
if (value < 26) emit(ALPHA, value);
|
|
8503
|
+
else if (value === 26) output += ' ';
|
|
8504
|
+
else if (value === 27) mode = 'lower';
|
|
8505
|
+
else if (value === 28) mode = 'mixed';
|
|
8506
|
+
else if (value === 29) shift = 'punct';
|
|
8507
|
+
} else if (mode === 'lower') {
|
|
8508
|
+
if (value < 26) emit(LOWER, value);
|
|
8509
|
+
else if (value === 26) output += ' ';
|
|
8510
|
+
else if (value === 27) shift = 'alpha';
|
|
8511
|
+
else if (value === 28) mode = 'mixed';
|
|
8512
|
+
else if (value === 29) shift = 'punct';
|
|
8513
|
+
} else if (mode === 'mixed') {
|
|
8514
|
+
if (value < 25) emit(MIXED, value);
|
|
8515
|
+
else if (value === 25) mode = 'punct';
|
|
8516
|
+
else if (value === 26) output += ' ';
|
|
8517
|
+
else if (value === 27) mode = 'lower';
|
|
8518
|
+
else if (value === 28) mode = 'alpha';
|
|
8519
|
+
else if (value === 29) shift = 'punct';
|
|
8520
|
+
} else {
|
|
8521
|
+
if (value < 29) emit(PUNCT, value);
|
|
8522
|
+
else if (value === 29) mode = 'alpha';
|
|
8523
|
+
}
|
|
8524
|
+
};
|
|
8525
|
+
while (at < codewords.length) {
|
|
8526
|
+
const codeword = codewords[at];
|
|
8527
|
+
if (codeword >= 900 && codeword !== 913) break;
|
|
8528
|
+
at++;
|
|
8529
|
+
if (codeword === 913) {
|
|
8530
|
+
if (at >= codewords.length || codewords[at] > 255) throw new FormatError('PDF417 text: invalid byte shift');
|
|
8531
|
+
shiftedBytes.push(codewords[at++]);
|
|
8532
|
+
continue;
|
|
8533
|
+
}
|
|
8534
|
+
flushShiftedBytes();
|
|
8535
|
+
process(Math.floor(codeword / 30));
|
|
8536
|
+
process(codeword % 30);
|
|
8537
|
+
}
|
|
8538
|
+
flushShiftedBytes();
|
|
8539
|
+
return { at, text: output, bytes: Uint8Array.from(bytes) };
|
|
8540
|
+
}
|
|
8541
|
+
|
|
8542
|
+
function decodeNumericSegment(codewords, at) {
|
|
8543
|
+
let output = '';
|
|
8544
|
+
while (at < codewords.length && codewords[at] < 900) {
|
|
8545
|
+
const end = Math.min(at + 15, codewords.length);
|
|
8546
|
+
let number = 0n;
|
|
8547
|
+
for (; at < end && codewords[at] < 900; at++) number = number * 900n + BigInt(codewords[at]);
|
|
8548
|
+
const decimal = number.toString();
|
|
8549
|
+
if (!decimal.startsWith('1')) throw new FormatError('PDF417 numeric: missing leading sentinel');
|
|
8550
|
+
output += decimal.slice(1);
|
|
8551
|
+
}
|
|
8552
|
+
return { at, text: output, bytes: new Uint8Array(0) };
|
|
8553
|
+
}
|
|
8554
|
+
|
|
8555
|
+
/**
|
|
8556
|
+
* Decode PDF417 compaction while preserving raw Byte Compaction and byte-shift
|
|
8557
|
+
* payloads. Text and Numeric Compaction do not manufacture bytes: their text
|
|
8558
|
+
* is available on each segment, while `bytes` contains only octets carried by
|
|
8559
|
+
* modes that encode octets explicitly.
|
|
8560
|
+
*/
|
|
8561
|
+
function decodePdf417CompactionDetailed(codewords) {
|
|
8562
|
+
if (!Array.isArray(codewords) && !ArrayBuffer.isView(codewords)) throw new FormatError('PDF417: codewords must be an array');
|
|
8563
|
+
for (const codeword of codewords) assertCodeword(codeword);
|
|
8564
|
+
let at = 0;
|
|
8565
|
+
// ISO/IEC 8859-1 is the PDF417 default; UTF-8 is selected explicitly with ECI 26.
|
|
8566
|
+
let eci = 3;
|
|
8567
|
+
let output = '';
|
|
8568
|
+
const bytes = [];
|
|
8569
|
+
const segments = [];
|
|
8570
|
+
while (at < codewords.length) {
|
|
8571
|
+
const codeword = codewords[at];
|
|
8572
|
+
if (codeword < 900 || codeword === 900 || codeword === 913) {
|
|
8573
|
+
const start = at;
|
|
8574
|
+
const latch = codeword === 900 ? codeword : null;
|
|
8575
|
+
if (latch !== null) at++;
|
|
8576
|
+
const segment = decodeTextSegment(codewords, at, eci);
|
|
8577
|
+
at = segment.at;
|
|
8578
|
+
output += segment.text;
|
|
8579
|
+
bytes.push(...segment.bytes);
|
|
8580
|
+
if (segment.text.length || segment.bytes.length) segments.push({ mode: 'text', text: segment.text, bytes: segment.bytes, eci, latch, codewordStart: start, codewordEnd: at });
|
|
8581
|
+
continue;
|
|
8582
|
+
}
|
|
8583
|
+
const start = at;
|
|
8584
|
+
at++;
|
|
8585
|
+
if (codeword === 901) {
|
|
8586
|
+
const segment = decodeByteSegment(codewords, at, eci);
|
|
8587
|
+
at = segment.at;
|
|
8588
|
+
output += segment.text;
|
|
8589
|
+
bytes.push(...segment.bytes);
|
|
8590
|
+
segments.push({ mode: 'byte', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
|
|
8591
|
+
} else if (codeword === 924) {
|
|
8592
|
+
const segment = decodeByteSegment(codewords, at, eci, true);
|
|
8593
|
+
at = segment.at;
|
|
8594
|
+
output += segment.text;
|
|
8595
|
+
bytes.push(...segment.bytes);
|
|
8596
|
+
segments.push({ mode: 'byte', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
|
|
8597
|
+
} else if (codeword === 902) {
|
|
8598
|
+
const segment = decodeNumericSegment(codewords, at);
|
|
8599
|
+
at = segment.at;
|
|
8600
|
+
output += segment.text;
|
|
8601
|
+
segments.push({ mode: 'numeric', text: segment.text, bytes: segment.bytes, eci, latch: codeword, codewordStart: start, codewordEnd: at });
|
|
8602
|
+
} else if (codeword === 927) {
|
|
8603
|
+
if (at >= codewords.length || codewords[at] > 899) throw new FormatError('PDF417 ECI: missing assignment number');
|
|
8604
|
+
eci = codewords[at++];
|
|
8605
|
+
} else {
|
|
8606
|
+
throw new FormatError(`PDF417: unsupported compaction codeword ${codeword}`);
|
|
8607
|
+
}
|
|
8608
|
+
}
|
|
8609
|
+
return { text: output, bytes: Uint8Array.from(bytes), segments };
|
|
8610
|
+
}
|
|
8611
|
+
|
|
8612
|
+
/** Decode PDF417 Text, Byte, Numeric and UTF-8 ECI compaction segments in source order. */
|
|
8613
|
+
function decodePdf417Compaction(codewords) {
|
|
8614
|
+
return decodePdf417CompactionDetailed(codewords).text;
|
|
8615
|
+
}
|
|
8616
|
+
|
|
8617
|
+
__exports.compactPdf417Text = compactPdf417Text;
|
|
8618
|
+
__exports.compactPdf417Bytes = compactPdf417Bytes;
|
|
8619
|
+
__exports.compactPdf417Numeric = compactPdf417Numeric;
|
|
8620
|
+
__exports.compactPdf417 = compactPdf417;
|
|
8621
|
+
__exports.decodePdf417CompactionDetailed = decodePdf417CompactionDetailed;
|
|
8622
|
+
__exports.decodePdf417Compaction = decodePdf417Compaction;
|
|
8623
|
+
};
|
|
8624
|
+
|
|
8625
|
+
__modules["pdf417/error-correction.js"] = function (__require, __exports) {
|
|
8626
|
+
const { EncodeError } = __require("core/errors.js");
|
|
8627
|
+
const { GF929 } = __require("core/galois-field.js");
|
|
8628
|
+
const { rsDecode, rsEncode } = __require("core/reed-solomon.js");
|
|
8629
|
+
function pdf417EccLength(level) {
|
|
8630
|
+
if (!Number.isInteger(level) || level < 0 || level > 8) throw new EncodeError('PDF417: error correction level must be in 0..8');
|
|
8631
|
+
return 1 << (level + 1);
|
|
8632
|
+
}
|
|
8633
|
+
function pdf417ErrorCorrection(data, level) {
|
|
8634
|
+
return rsEncode(data, pdf417EccLength(level), GF929, 1);
|
|
8635
|
+
}
|
|
8636
|
+
|
|
8637
|
+
/** Correct PDF417 codewords, optionally marking unreadable codewords as erasures. */
|
|
8638
|
+
function pdf417CorrectErrors(codewords, level, erasures = []) {
|
|
8639
|
+
return rsDecode(codewords, pdf417EccLength(level), GF929, 1, erasures);
|
|
8640
|
+
}
|
|
8641
|
+
|
|
8642
|
+
__exports.pdf417EccLength = pdf417EccLength;
|
|
8643
|
+
__exports.pdf417ErrorCorrection = pdf417ErrorCorrection;
|
|
8644
|
+
__exports.pdf417CorrectErrors = pdf417CorrectErrors;
|
|
8645
|
+
};
|
|
8646
|
+
|
|
8647
|
+
__modules["pdf417/tables.js"] = function (__require, __exports) {
|
|
8648
|
+
/** PDF417 symbol-character pattern table. @module pdf417/tables */
|
|
8649
|
+
const PDF417_CLUSTER_NUMBERS = Object.freeze([0, 3, 6]);
|
|
8650
|
+
const PDF417_CODEWORDS_PER_CLUSTER = 929;
|
|
8651
|
+
|
|
8652
|
+
// Transcribed from the normative AIM USS PDF417 specification, Appendix H,
|
|
8653
|
+
// Table H1 (Bar-Space Sequence Table), from a publicly accessible copy hosted
|
|
8654
|
+
// at https://expresscorp.com/wp-content/uploads/2023/02/USS-PDF-417.pdf.
|
|
8655
|
+
// ISO/IEC 15438:2015 is the current ISO specification for PDF417.
|
|
8656
|
+
// Each eight-digit sequence is ordered bar, space, bar, space, bar, space,
|
|
8657
|
+
// bar, space and is indexed by its codeword value from 0 through 928.
|
|
8658
|
+
const WIDTH_SEQUENCES = Object.freeze([
|
|
8659
|
+
'3111113641111144511111523111123541111243511112512111132631111334211114251111151621111524111116152111213631112144' +
|
|
8660
|
+
'4111215221112235311122434111225111112326211123341111242511113136211131443111315211113235211132433111325111113334' +
|
|
8661
|
+
'2111334211114144211141521111424321114251111151525111611131121135411211435112115121121226311212344112124221121325' +
|
|
8662
|
+
'3112133311121416211214243112143211121515211215231112161421122135311221434112215111122226211222343112224211122325' +
|
|
8663
|
+
'2112233331122341111224242112243211123135211231433112315111123234211232421112333321123341111241432112415111124242' +
|
|
8664
|
+
'1112434121131126311311344113114221131225311312334113124111131316211313243113133211131415211314231113151411131613' +
|
|
8665
|
+
'1113212621132134311321421113222521132233311322411113232421132332111324231113252211133134211331421113323321133241' +
|
|
8666
|
+
'1113333211134142211411253114113341141141111412162114122431141232111413152114132331141331111414142114142211141513' +
|
|
8667
|
+
'2114152111142125211421333114214111142224211422321114232321142331111424221114252121143141111433311115111621151124' +
|
|
8668
|
+
'3115113211151215211512233115123111151314211513221115141321151421111515121115212411152223111523221116111531161131' +
|
|
8669
|
+
'2116122221161321111615113211113542111143521111512211122632111234421112422211132532111333421113411211141622111424' +
|
|
8670
|
+
'1211151522112135321121434211215112112226221122343211224212112325221123331211242412112523121131352211314332113151' +
|
|
8671
|
+
'1211323422113242121133331211343212114143221141511211424212115151312111264121113451211142312112254121123351211241' +
|
|
8672
|
+
'2121131631211324412113322121141531211423412114312121151431211522221211263212113442121142212121262212122532121233' +
|
|
8673
|
+
'4212124121212225312122334121224111212316121214152212142332121431112124152121242311212514121221262212213432122142' +
|
|
8674
|
+
'1121312612122225221222333212224111213225212132333121324111213324121224231121342312123134221231421121413412123233' +
|
|
8675
|
+
'2212324111214233212142411121433212124142112151421212424111215241312211254122113351221141212212163122122441221232' +
|
|
8676
|
+
'2122131531221323412213312122141431221422212215132122161222131125321311334213114121222125221312243213123211222216' +
|
|
8677
|
+
'1213131531222232321313311122231512131414221314221122241421222422221315211213161212132125221321333213214111223125' +
|
|
8678
|
+
'1213222422132232112232242122323222132331112233231213242212132521121331332213314111224133121332321122423212133331' +
|
|
8679
|
+
'1122433111225141212311163123112441231132212312153123122341231231212313143123132221231413312314212123151221231611' +
|
|
8680
|
+
'1214111622141124321411321123211612141215221412233214123111232215212322233123223111232314121414132214142111232413' +
|
|
8681
|
+
'2123242111232512121421242214213211233124121422232214223111233223212332311123332212142421112334211123413211234231' +
|
|
8682
|
+
'2124111531241123412411312124121431241222212413133124132121241412212415111215111522151123321511311124211512151214' +
|
|
8683
|
+
'2215122211242214212422222215132111242313121514121124241212151511121521231124312311243222112433213125112231251221' +
|
|
8684
|
+
'2125141122161122121612131125221311252312112524112311112633111134431111422311122533111233131113162311132433111332' +
|
|
8685
|
+
'1311141523111423131115141311161313112126231121343311214213112225231122333311224113112324231123321311242313112522' +
|
|
8686
|
+
'1311313423113142131132332311324113113332131141421311424132211125422111335221114122211216322112244221123222211315' +
|
|
8687
|
+
'3221132342211331222114143221142222211513322115212312112533121133431211412221212523121224331212321221221613121315' +
|
|
8688
|
+
'3221223233121331122123152221232323121422122124141312151312212513131221252312213333122141122131251312222432213141' +
|
|
8689
|
+
'1221322422213232231223311221332313122422122134221312313323123141122141331312323212214232131233311312414112215141' +
|
|
8690
|
+
'3131111641311124513111323131121541311223513112313131131441311322313114134131142131311512222211163222112442221132' +
|
|
8691
|
+
'2131211622221215413121324222123121312215313122234131223121312314222214133222142121312413313124212222161113131116' +
|
|
8692
|
+
'2313112433131132122221161313121523131223331312311131311612222215222222233222223111313215213132233131323123131421' +
|
|
8693
|
+
'1131331412222413222224211131341313131611131321242313213212223124131322232313223111314124122232232222323111314223' +
|
|
8694
|
+
'2131423113132421122234211313313212224132131332311131513212224231313211154132112351321131313212144132122231321313' +
|
|
8695
|
+
'4132132131321412313215112223111532231123422311312132211522231214413221312132221431322222322313212132231322231412' +
|
|
8696
|
+
'2132241222231511213225111314111523141123331411311223211513141214231412221132311512232214222322222314132111323214' +
|
|
8697
|
+
'2132322213141412113233131223241213141511122325111314212323142131122331231314222211324123122332221314232111324222' +
|
|
8698
|
+
'1223332113143131113251313133111441331122313312134133122131331312313314112224111432241122213321142224121332241221' +
|
|
8699
|
+
'2133221331332221213323122224141121332411131511142315112212242114131512132315122111333114122422132224222111333213' +
|
|
8700
|
+
'2133322113151411113333121224241111333411122431221133412211334221413411213134131132251121222512122225131113161113' +
|
|
8701
|
+
'1225211311343113131613111225231124111125141112162411122414111315241113233411133114111414241114221411151324111521' +
|
|
8702
|
+
'1411212524112133341121411411222424112232141123232411233114112422141125211411313324113141141132321411333114114141' +
|
|
8703
|
+
'2321111633211124432111322321121533211223232113143321132223211413332114212321151214121116241211243412113213212116' +
|
|
8704
|
+
'1412121533212132341212311321221523212223332122311321231414121413241214211321241323212421141216111412212424122132' +
|
|
8705
|
+
'1321312414122223241222311321322323213231132133221412242114123132132141321412323113214231323111154231112352311131' +
|
|
8706
|
+
'3231121442311222323113134231132132311412323115112322111533221123223121152322121433221222223122143231222233221321' +
|
|
8707
|
+
'2231231323221412223124122322151122312511141311152413112313222115141312143322213112313115132222142322222224131321' +
|
|
8708
|
+
'1231321422313222141314121231331313222412141315111322251114132123241321311322312314132222123141231322322214132321' +
|
|
8709
|
+
'1231422213223321141331311322413112315131414111145141112241411213514112214141131241411411323211144232112231412114' +
|
|
8710
|
+
'4141212242321221314122134141222131412312323214113141241123231114332311222232211423231213332312212141311422322213' +
|
|
8711
|
+
'3232222121413213314132212323141121413312223224112141341114141114241411221323211414141213241412211232311413232213' +
|
|
8712
|
+
'2323222111414114123232132232322114141411114142132141422113232411114143121414212213233122141422211232412213233221' +
|
|
8713
|
+
'1141512212324221114152214142111351421121414212124142131132331113423311213142211341422121314222123233131131422311' +
|
|
8714
|
+
'2324111333241121223321132324121221423113223322122324131121423212223323112142331114151113241511211324211323242121' +
|
|
8715
|
+
'1233311313242212141513111142411312333212132423111142421212333311114243111324312111425121414312113143211231432211' +
|
|
8716
|
+
'2234211221433112214332111325211212343112114341121143421115111116151112152511122315111314151114131511151215112124' +
|
|
8717
|
+
'1511222315112322151124211511313215113231242111152421121434211222242113133421132124211412242115111512111525121123' +
|
|
8718
|
+
'1421211524212123251212221421221424212222142123132421232114212412151215111421251115122123251221311421312324213131' +
|
|
8719
|
+
'1421322215122321142133211512313114214131333111143331121333311312333114112422111423312114333121223422122123312213' +
|
|
8720
|
+
'3331222123312312242214112331241115131114142221141513121325131221133131141422221315131312133132131422231215131411' +
|
|
8721
|
+
'1331331214222411151321221422312215132221133141221422322113314221424111134241121242411311333211133241211342412121' +
|
|
8722
|
+
'3241221233321311324123112423111334231121233221133332212122413113233222122423131122413212233223112241331115141113' +
|
|
8723
|
+
'2514112114232113242321211332311314232212151413111241411313323212142323111241421213323311151421211423312113324121' +
|
|
8724
|
+
'1241512151511112515112114242111241512112424212114151221133331112324221123333121131513112324222113151321124241112' +
|
|
8725
|
+
'2333211224241211224231122333221121514112',
|
|
8726
|
+
'5111112561111133411112165111122461111232411113155111132361111331411114145111142241111513511115214111161241112125' +
|
|
8727
|
+
'5111213361112141311122164111222451112232311123154111232351112331311124144111242231112513411125213111261231113125' +
|
|
8728
|
+
'4111313351113141211132163111322441113232211133153111332341113331211134143111342221113513311135212111361221114125' +
|
|
8729
|
+
'3111413341114141111142162111422431114232111143152111432331114331111144142111442211114513211145211111512521115133' +
|
|
8730
|
+
'3111514111115224211152321111532321115331111154221111613321116141111162321111633141121116511211246112113241121215' +
|
|
8731
|
+
'5112122361121231411213145112132241121413511214214112151241121611311221164112212451122132311222154112222351122231' +
|
|
8732
|
+
'3112231441122322311224134112242131122512311226112112311631123124411231322112321531123223411232312112331431123322' +
|
|
8733
|
+
'2112341331123421211235122112361111124116211241243112413211124215211242233112423111124314211243221112441321124421' +
|
|
8734
|
+
'1112451211125124211251321112522321125231111253221112542111126132111262314113111551131123611311314113121451131222' +
|
|
8735
|
+
'4113131351131321411314124113151131132115411321235113213131132214411322223113231341132321311324123113251121133115' +
|
|
8736
|
+
'3113312341133131211332143113322221133313311333212113341221133511111341152113412331134131111342142113422211134313' +
|
|
8737
|
+
'2113432111134412111345111113512321135131111352221113532111136131411411145114112241141213511412214114131241141411' +
|
|
8738
|
+
'3114211441142122311422134114222131142312311424112114311431143122211432133114322121143312211434111114411421144122' +
|
|
8739
|
+
'1114421321144221111443121114441111145122111452214115111351151121411512124115131131152113411521213115221231152311' +
|
|
8740
|
+
'2115311331153121211532122115331111154113211541211115421211154311411611124116121131162112311622112116311221163211' +
|
|
8741
|
+
'4211111652111124621111324211121552111223621112314211131452111322421114135211142142111512421116113211211642112124' +
|
|
8742
|
+
'5211213232112215421122235211223132112314421123223211241342112421321125123211261122113116321131244211313222113215' +
|
|
8743
|
+
'3211322342113231221133143211332222113413321134212211351222113611121141162211412432114132121142152211422332114231' +
|
|
8744
|
+
'1211431422114322121144132211442112114512121151242211513212115223221152311211532212115421121161321211623151211115' +
|
|
8745
|
+
'6121112311211164512112146121122211211263512113136121132111211362512114125121151142121115521211236212113141212115' +
|
|
8746
|
+
'4212121461212131412122145121222252121321412123134212141241212412421215114121251132122115421221235212213131213115' +
|
|
8747
|
+
'3212221442122222312132144121322242122321312133133212241231213412321225113121351122123115321231234212313121214115' +
|
|
8748
|
+
'2212321432123222212142143121422232123321212143132212341221214412221235112121451112124115221241233212413111215115' +
|
|
8749
|
+
'1212421422124222112152142121522222124321112153131212441211215412121245111212512322125131112161231212522211216222' +
|
|
8750
|
+
'1212532111216321121261315122111461221122112211635122121361221221112212625122131211221361512214114213111452131122' +
|
|
8751
|
+
'4122211442131213521312214122221351222221412223124213141141222411321321144213212231223114321322134213222131223213' +
|
|
8752
|
+
'4122322131223312321324113122341122133114321331222122411422133213321332212122421331224221212243122213341121224411' +
|
|
8753
|
+
'1213411422134122112251141213421322134221112252132122522111225312121344111122541112135122112261221213522111226221' +
|
|
8754
|
+
'5123111361231121112311625123121211231261512313114214111352141121412321135123212141232212421413114123231132142113' +
|
|
8755
|
+
'4214212131233113321422123123321232142311312333112214311332143121212341133123412121234212221433112123431112144113' +
|
|
8756
|
+
'2214412111235113121442121123521212144311112353111214512111236121512411121124116151241211421511124124211242151211' +
|
|
8757
|
+
'4124221132152112312431123215221131243211221531122124411222153211212442111215411211245112121542111124521151251111' +
|
|
8758
|
+
'4216111141252111321621113125311122163111212541114311111553111123631111314311121453111222431113135311132143111412' +
|
|
8759
|
+
'4311151133112115431121235311213133112214431122223311231343112321331124123311251123113115331131234311313123113214' +
|
|
8760
|
+
'3311322223113313331133212311341223113511131141152311412333114131131142142311422213114313231143211311441213114511' +
|
|
8761
|
+
'1311512323115131131152221311532113116131522111146221112212211163522112136221122112211262522113121221136152211411' +
|
|
8762
|
+
'4312111453121122422121144312121353121221422122135221222142212312431214114221241133122114431221223221311433122213' +
|
|
8763
|
+
'4312222132213213422132213221331233122411322134112312311433123122222141142312321333123221222142133221422122214312' +
|
|
8764
|
+
'2312341122214411131241142312412212215114131242132312422112215213222152211221531213124411122154111312512212216122' +
|
|
8765
|
+
'1312522112216221613111131131115421311162613112121131125321311261613113111131135211311451522211136222112112221162' +
|
|
8766
|
+
'5131211361312121113121621222126151312212522213111131226151312311431311135313112142222113431312124131311351313121' +
|
|
8767
|
+
'4313131141313212422223114131331133132113431321213222311333132212313141133222321233132311313142123222331131314311' +
|
|
8768
|
+
'2313311333133121222241132313321221315113222242122313331121315212222243112131531113134113231341211222511313134212' +
|
|
8769
|
+
'1131611312225212131343111131621212225311113163111313512112226121613211121132115321321161613212111132125211321351' +
|
|
8770
|
+
'5223111212231161513221125223121111322161513222114314111242232112431412114132311242232211413232113314211232233112' +
|
|
8771
|
+
'3314221131324112322332113132421123143112222341122314321121325112222342112132521113144112122351121314421111326112' +
|
|
8772
|
+
'1223521111326211613311111133115211331251522411115133211143151111422421114133311133152111322431113133411123153111' +
|
|
8773
|
+
'2224411121335111131541111224511111336111113411514411111454111122441112135411122144111312441114113411211444112122' +
|
|
8774
|
+
'3411221344112221341123123411241124113114341131222411321334113221241133122411341114114114241141221411421324114221' +
|
|
8775
|
+
'1411431214114411141151221411522153211113632111211321116253211212132112615321131144121113541211214321211344121212' +
|
|
8776
|
+
'4321221244121311432123113412211344122121332131133412221233213212341223113321331124123113341231212321411324123212' +
|
|
8777
|
+
'2321421224123311232143111412411324124121132151131412421213215212141243111321531114125121132161216231111212311153' +
|
|
8778
|
+
'2231116162311211123112521231135153221112132211615231211253221211123121615231221144131112432221124413121142313112' +
|
|
8779
|
+
'4322221142313211341321123322311234132211323141123322321132314211241331122322411224133211223151122322421122315211' +
|
|
8780
|
+
'1413411213225112141342111231611213225211123162111141114421411152114112432141125111411342114114416232111112321152' +
|
|
8781
|
+
'6141211111412152123212511141225153231111523221115141311144141111432321114232311141414111341421113323311132324111' +
|
|
8782
|
+
'3141511124143111232341112232511121416111141441111323511112326111114211432142115111421242114213411233115111422151' +
|
|
8783
|
+
'1143114211431241114411414511111345111212451113113511211345112121351122123511231125113113351131212511321225113311' +
|
|
8784
|
+
'1511411325114121151142121511431115115121542111121421116154211211451211124421211245121211442122113512211234213112' +
|
|
8785
|
+
'3512221134213211251231122421411225123211242142111512411214215112151242111421521163311111133111521331125154221111' +
|
|
8786
|
+
'5331211145131111442221114331311135132111342231113331411125133111242241112331511115134111142251111331611112411143' +
|
|
8787
|
+
'2241115112411242124113411332115112412151115111342151114211511233215112411151133211511431124211421151214212421241' +
|
|
8788
|
+
'1151224111521133215211411152123211521331124311411152214111531132115312311154113136112112361122112611311226113211' +
|
|
8789
|
+
'1611411216114211452121113612211135213111261231112521411116124111152151111431115113411142134112411251113322511141' +
|
|
8790
|
+
'1251123212511331134211411251214111611124216111321161122321611231116113221161142112521132116121321252123111612231' +
|
|
8791
|
+
'1162112321621131116212221162132112531131116221311163112211631221144111411351113213511231126111232261113112611222' +
|
|
8792
|
+
'1261132113521131126121311262112212621221',
|
|
8793
|
+
'2111115531111163111112462111125431111262111113452111135331111361111114442111145211111543611121141111215521112163' +
|
|
8794
|
+
'6111221311112254211122626111231211112353211123616111241111112452511131146111312211113163511132136111322111113262' +
|
|
8795
|
+
'5111331211113361511134114111411451114122411142135111422141114312411144113111511441115122311152134111522131115312' +
|
|
8796
|
+
'3111541121116114311161222111621331116221211163121112114621121154311211621112124521121253311212611112134421121352' +
|
|
8797
|
+
'1112144321121451111215426112211311122154211221626112221211122253211222616112231111122352111224515112311361123121' +
|
|
8798
|
+
'1112316251123212111232615112331141124113511241214112421241124311311251134112512131125212311253112112611331126121' +
|
|
8799
|
+
'2112621221126311111311452113115331131161111312442113125211131343211313511113144211131541611321121113215321132161' +
|
|
8800
|
+
'6113221111132252111323515113311211133161511332114113411241134211311351123113521121136112211362111114114421141152' +
|
|
8801
|
+
'1114124321141251111413421114144161142111111421521114225151143111411441113114511111151143211511511115124211151341' +
|
|
8802
|
+
'1115215111161142111612411211114622111154321111621211124522111253321112611211134422111352121114432211145112111542' +
|
|
8803
|
+
'6211211312112154221121626211221212112253221122616211231112112352121124515211311362113121121131625211321212113261' +
|
|
8804
|
+
'5211331142114113521141214211421242114311321151134211512132115212321153112211611332116121221162122211631121211145' +
|
|
8805
|
+
'3121115341211161112112362121124431211252112113352121134331211351112114342121144211211533212115411121163212121145' +
|
|
8806
|
+
'2212115332121161112121451212124422121252112122442121225222121351112123431212144211212442121215411121254162122112' +
|
|
8807
|
+
'1212215322122161612131126212221111213153121222526121321111213252121223511121335152123112121231615121411252123211' +
|
|
8808
|
+
'1121416151214211421241124121511242124211412152113212511231216112321252113121621122126112221262111122113621221144' +
|
|
8809
|
+
'3122115211221235212212433122125111221334212213421122143321221441112215321122163112131144221311521122214412131243' +
|
|
8810
|
+
'2213125111222243212222511122234212131441112224416213211112132152612231111122315212132251112232515213311151224111' +
|
|
8811
|
+
'4213411141225111321351113122611122136111112311352123114331231151112312342123124211231333212313411123143211231531' +
|
|
8812
|
+
'1214114322141151112321431214124211232242121413411123234112142151112331511124113421241142112412332124124111241332' +
|
|
8813
|
+
'1124143112151142112421421215124111242241112511332125114111251232112513311216114111252141112611321126123113111145' +
|
|
8814
|
+
'2311115333111161131112442311125213111343231113511311144213111541631121121311215323112161631122111311225213112351' +
|
|
8815
|
+
'5311311213113161531132114311411243114211331151123311521123116112231162111221113622211144322111521221123522211243' +
|
|
8816
|
+
'3221125112211334222113421221143322211441122115321221163113121144231211521221214413121243231212511221224322212251' +
|
|
8817
|
+
'1221234213121441122124416312211113122152622131111221315213122251122132515312311152214111431241114221511133125111' +
|
|
8818
|
+
'3221611123126111213111353131114341311151113112262131123431311242113113252131133331311341113114242131143211311523' +
|
|
8819
|
+
'2131153111311622122211352222114332221151113121351222123422221242113122342131224222221341113123331222143211312432' +
|
|
8820
|
+
'1222153111312531131311432313115112222143131312421131314312222242131313411131324212222341113133411313215112223151' +
|
|
8821
|
+
'1131415111321126213211343132114211321225213212333132124111321324213213321132142321321431113215221132162112231134' +
|
|
8822
|
+
'2223114211322134122312332223124111322233213222411132233212231431113224311314114212232142131412411132314212232241' +
|
|
8823
|
+
'1132324111331125213311333133114111331224213312321133132321331331113314221133152112241133222411411133213312241232' +
|
|
8824
|
+
'1133223212241331113323311315114112242141113331411134112421341132113412232134123111341322113414211225113211342132' +
|
|
8825
|
+
'1225123111342231113511232135113111351222113513211226113111352131113611221136122114111144241111521411124324111251' +
|
|
8826
|
+
'1411134214111441141121521411225154113111441141113411511124116111132111352321114333211151132112342321124213211333' +
|
|
8827
|
+
'2321134113211432132115311412114324121151132121431412124213212242141213411321234114122151132131511231112622311134' +
|
|
8828
|
+
'3231114212311225223112333231124112311324223113321231142322311431123115221231162113221134232211421231213413221233' +
|
|
8829
|
+
'2322124112312233132213321231233213221431123124311413114213222142141312411231314213222241123132412141112531411133' +
|
|
8830
|
+
'4141114111411216214112243141123211411315214113233141133111411414214114221141151321411521114116121232112522321133' +
|
|
8831
|
+
'3232114111412125123212242232123211412224214122322232133111412323123214221141242212321521114125211323113323231141' +
|
|
8832
|
+
'1232213313231232114131331232223213231331114132321232233111413331141411411323214112323141114141411142111621421124' +
|
|
8833
|
+
'3142113211421215214212233142123111421314214213221142141321421421114215121142161112331124223311321142212412331223' +
|
|
8834
|
+
'2233123111422223214222311142232212331421114224211324113212332132132412311142313212332231114232311143111521431123' +
|
|
8835
|
+
'3143113111431214214312221143131321431321114314121143151112341123223411311143212312341222114322221234132111432321' +
|
|
8836
|
+
'1325113112342131114331311144111421441122114412132144122111441312114414111235112211442122123512211144222111451113' +
|
|
8837
|
+
'2145112111451212114513111236112111452121151111432511115115111242151113411511215114211134242111421421123324211241' +
|
|
8838
|
+
'1421133214211431151211421421214215121241142122411331112523311133333111411331122423311232133113232331133113311422' +
|
|
8839
|
+
'1331152114221133242211411331213314221232133122321422133113312331151311411422214113313141124111162241112432411132' +
|
|
8840
|
+
'1241121522411223324112311241131422411322124114132241142112411512124116111332112423321132124121241332122323321231' +
|
|
8841
|
+
'1241222322412231124123221332142112412421142311321332213214231231124131321332223112413231215111153151112341511131' +
|
|
8842
|
+
'2151121431511222215113133151132121511412215115111242111522421123324211311151211512421214224212221151221421512222' +
|
|
8843
|
+
'2242132111512313124214121151241212421511115125111333112323331131124221231333122211513123124222221333132111513222' +
|
|
8844
|
+
'1242232111513321142411311333213112423131115141312152111431521122215212133152122121521312215214111243111422431122' +
|
|
8845
|
+
'1152211412431213224312211152221321522221115223121243141111522411133411221243212213341221115231221243222111523221' +
|
|
8846
|
+
'2153111331531121215312122153131112441113224411211153211312441212115322121244131111532311133511211244212111533121' +
|
|
8847
|
+
'2154111221541211124511121154211212451211115422111611114216111241152111332521114115211232152113311612114115212141' +
|
|
8848
|
+
'1431112424311132143112232431123114311322143114211522113214312132152212311431223113411115234111233341113113411214' +
|
|
8849
|
+
'2341122213411313234113211341141213411511143211232432113113412123234121311341222214321321134123211523113114322131' +
|
|
8850
|
+
'1341313122511114325111222251121332511221225113122251141113421114234211221251211422512122234212211251221313421312' +
|
|
8851
|
+
'1251231213421411125124111433112213422122143312211251312213422221125132213161111341611121316112123161131122521113' +
|
|
8852
|
+
'3252112121612113225212122161221222521311216123111343111323431121125221131343121211613113125222121343131111613212' +
|
|
8853
|
+
'1252231111613311143411211343212112523121116141213162111231621211225311122162211222531211216222111344111212532112' +
|
|
8854
|
+
'1344121111623112125322111162321131631111225411112163211113451111125421111163311116211132162112311531112325311131' +
|
|
8855
|
+
'1531122215311321162211311531213114411114244111221441121324411221144113121441141115321122144121221532122114412221' +
|
|
8856
|
+
'2351111333511121235112122351131114421113244211211351211323512121135122121442131113512311153311211442212113513121' +
|
|
8857
|
+
'3261111232611211235211122261211223521211226122111443111213522112144312111261311213522211126132113262111123531111' +
|
|
8858
|
+
'2262211114441111135321111262311116311122163112211541111325411121154112121541131116321121154121212451111224511211' +
|
|
8859
|
+
'1542111214512112154212111451221133611111',
|
|
8860
|
+
]);
|
|
8861
|
+
|
|
8862
|
+
function patternFromWidths(sequence) {
|
|
8863
|
+
let pattern = 0;
|
|
8864
|
+
for (let element = 0; element < 8; element++) {
|
|
8865
|
+
const width = sequence.charCodeAt(element) - 48;
|
|
8866
|
+
const dark = (element & 1) === 0;
|
|
8867
|
+
for (let i = 0; i < width; i++) pattern = (pattern << 1) | (dark ? 1 : 0);
|
|
8868
|
+
}
|
|
8869
|
+
return pattern;
|
|
8870
|
+
}
|
|
8871
|
+
|
|
8872
|
+
/** Return the cluster discriminator for an eight-element bar/space sequence. */
|
|
8873
|
+
function pdf417ClusterForWidths(widths) {
|
|
8874
|
+
if (!widths || widths.length !== 8) throw new Error('PDF417: a character requires eight element widths');
|
|
8875
|
+
return ((widths[0] - widths[2] + widths[4] - widths[6]) % 9 + 9) % 9;
|
|
8876
|
+
}
|
|
8877
|
+
|
|
8878
|
+
function buildPatternTable() {
|
|
8879
|
+
const tables = WIDTH_SEQUENCES.map((source, tableIndex) => {
|
|
8880
|
+
if (source.length !== PDF417_CODEWORDS_PER_CLUSTER * 8) throw new Error('PDF417: corrupt pattern-table length');
|
|
8881
|
+
const expectedCluster = PDF417_CLUSTER_NUMBERS[tableIndex];
|
|
8882
|
+
const table = new Int32Array(PDF417_CODEWORDS_PER_CLUSTER);
|
|
8883
|
+
const seen = new Set();
|
|
8884
|
+
for (let codeword = 0; codeword < PDF417_CODEWORDS_PER_CLUSTER; codeword++) {
|
|
8885
|
+
const sequence = source.slice(codeword * 8, codeword * 8 + 8);
|
|
8886
|
+
const widths = Array.from(sequence, (digit) => digit.charCodeAt(0) - 48);
|
|
8887
|
+
if (widths.some((width) => width < 1 || width > 6) || widths.reduce((sum, width) => sum + width, 0) !== 17) {
|
|
8888
|
+
throw new Error('PDF417: corrupt pattern-table width');
|
|
8889
|
+
}
|
|
8890
|
+
if (pdf417ClusterForWidths(widths) !== expectedCluster) throw new Error('PDF417: corrupt pattern-table cluster');
|
|
8891
|
+
const pattern = patternFromWidths(sequence);
|
|
8892
|
+
if (seen.has(pattern)) throw new Error('PDF417: duplicate pattern in cluster');
|
|
8893
|
+
seen.add(pattern);
|
|
8894
|
+
table[codeword] = pattern;
|
|
8895
|
+
}
|
|
8896
|
+
return Object.freeze(Array.from(table));
|
|
8897
|
+
});
|
|
8898
|
+
return Object.freeze(tables);
|
|
8899
|
+
}
|
|
8900
|
+
|
|
8901
|
+
/** Pattern table indexed by cluster index (0, 1, 2) and codeword value. */
|
|
8902
|
+
const PDF417_PATTERN_TABLE = buildPatternTable();
|
|
8903
|
+
const PATTERN_TO_CODEWORD = new Map();
|
|
8904
|
+
for (let index = 0; index < PDF417_PATTERN_TABLE.length; index++) {
|
|
8905
|
+
for (let codeword = 0; codeword < PDF417_CODEWORDS_PER_CLUSTER; codeword++) {
|
|
8906
|
+
PATTERN_TO_CODEWORD.set(PDF417_PATTERN_TABLE[index][codeword], Object.freeze({
|
|
8907
|
+
codeword, cluster: PDF417_CLUSTER_NUMBERS[index],
|
|
8908
|
+
}));
|
|
8909
|
+
}
|
|
8910
|
+
}
|
|
8911
|
+
|
|
8912
|
+
/**
|
|
8913
|
+
* Return the 17-bit bar/space pattern for a codeword in a row cluster.
|
|
8914
|
+
* @param {number} codeword
|
|
8915
|
+
* @param {number} cluster Cluster number 0, 3 or 6.
|
|
8916
|
+
* @returns {number}
|
|
8917
|
+
*/
|
|
8918
|
+
function pdf417PatternForCodeword(codeword, cluster) {
|
|
8919
|
+
if (!Number.isInteger(codeword) || codeword < 0 || codeword >= PDF417_CODEWORDS_PER_CLUSTER) throw new Error('PDF417: codeword must be in 0..928');
|
|
8920
|
+
const index = PDF417_CLUSTER_NUMBERS.indexOf(cluster);
|
|
8921
|
+
if (index < 0) throw new Error('PDF417: cluster must be 0, 3 or 6');
|
|
8922
|
+
return PDF417_PATTERN_TABLE[index][codeword];
|
|
8923
|
+
}
|
|
8924
|
+
|
|
8925
|
+
/**
|
|
8926
|
+
* Decode an exact 17-bit symbol-character pattern to its codeword and cluster.
|
|
8927
|
+
* @param {number} pattern
|
|
8928
|
+
* @returns {{codeword: number, cluster: number} | null}
|
|
8929
|
+
*/
|
|
8930
|
+
function pdf417CodewordForPattern(pattern) {
|
|
8931
|
+
const result = PATTERN_TO_CODEWORD.get(pattern);
|
|
8932
|
+
return result ? { ...result } : null;
|
|
8933
|
+
}
|
|
8934
|
+
|
|
8935
|
+
__exports.PDF417_CLUSTER_NUMBERS = PDF417_CLUSTER_NUMBERS;
|
|
8936
|
+
__exports.PDF417_CODEWORDS_PER_CLUSTER = PDF417_CODEWORDS_PER_CLUSTER;
|
|
8937
|
+
__exports.pdf417ClusterForWidths = pdf417ClusterForWidths;
|
|
8938
|
+
__exports.PDF417_PATTERN_TABLE = PDF417_PATTERN_TABLE;
|
|
8939
|
+
__exports.pdf417PatternForCodeword = pdf417PatternForCodeword;
|
|
8940
|
+
__exports.pdf417CodewordForPattern = pdf417CodewordForPattern;
|
|
8941
|
+
};
|
|
8942
|
+
|
|
8943
|
+
__modules["pdf417/encoder.js"] = function (__require, __exports) {
|
|
8944
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
8945
|
+
const { EncodeError } = __require("core/errors.js");
|
|
8946
|
+
const { compactPdf417 } = __require("pdf417/compaction.js");
|
|
8947
|
+
const { pdf417ErrorCorrection, pdf417EccLength } = __require("pdf417/error-correction.js");
|
|
8948
|
+
const { pdf417PatternForCodeword } = __require("pdf417/tables.js");
|
|
8949
|
+
|
|
8950
|
+
const START = '81111113';
|
|
8951
|
+
const STOP = '711311121';
|
|
8952
|
+
|
|
8953
|
+
function append(matrix, y, x, sequence, height) {
|
|
8954
|
+
let dark = true;
|
|
8955
|
+
for (const digit of sequence) {
|
|
8956
|
+
const width = digit.charCodeAt(0) - 48;
|
|
8957
|
+
if (dark) matrix.setRegion(x, y, width, height);
|
|
8958
|
+
x += width; dark = !dark;
|
|
8959
|
+
}
|
|
8960
|
+
return x;
|
|
8961
|
+
}
|
|
8962
|
+
function patternSequence(pattern) { return pattern.toString(2).padStart(17, '0').replace(/0+|1+/g, (run) => String(run.length)); }
|
|
8963
|
+
function indicators(row, rows, cols, level) {
|
|
8964
|
+
const group = Math.floor(row / 3), y = Math.floor((rows - 1) / 3), z = level * 3 + (rows - 1) % 3, v = cols - 1;
|
|
8965
|
+
if (row % 3 === 0) return [30 * group + y, 30 * group + v];
|
|
8966
|
+
if (row % 3 === 1) return [30 * group + z, 30 * group + y];
|
|
8967
|
+
return [30 * group + v, 30 * group + z];
|
|
8968
|
+
}
|
|
8969
|
+
function dimensions(needed, level, options) {
|
|
8970
|
+
for (const [name, value, min, max] of [['rows', options.rows, 3, 90], ['columns', options.columns, 1, 30]]) {
|
|
8971
|
+
if (value !== undefined && (!Number.isInteger(value) || value < min || value > max)) throw new EncodeError(`PDF417: ${name} must be an integer in ${min}..${max}`);
|
|
8972
|
+
}
|
|
8973
|
+
if (options.aspectRatio !== undefined && (!Number.isFinite(options.aspectRatio) || options.aspectRatio <= 0)) throw new EncodeError('PDF417: aspectRatio must be positive');
|
|
8974
|
+
const ecc = pdf417EccLength(level); let best = null;
|
|
8975
|
+
for (let rows = options.rows ?? 3; rows <= (options.rows ?? 90); rows++) for (let cols = options.columns ?? 1; cols <= (options.columns ?? 30); cols++) {
|
|
8976
|
+
if (rows < 3 || rows * cols > 928 || rows * cols - ecc < needed) continue;
|
|
8977
|
+
const ratio = (69 + cols * 17) / (rows * (options.rowHeight ?? 3));
|
|
8978
|
+
const score = (rows * cols - ecc - needed) * 10 + Math.abs(ratio - (options.aspectRatio ?? 3));
|
|
8979
|
+
if (!best || score < best.score) best = { rows, cols, score };
|
|
8980
|
+
}
|
|
8981
|
+
if (!best) throw new EncodeError('PDF417: payload does not fit the requested dimensions and error correction level');
|
|
8982
|
+
return best;
|
|
8983
|
+
}
|
|
8984
|
+
function encodePDF417(value, options = {}) {
|
|
8985
|
+
const level = options.eccLevel ?? 2, rowHeight = options.rowHeight ?? 3;
|
|
8986
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 3) throw new EncodeError('PDF417: rowHeight must be an integer of at least 3');
|
|
8987
|
+
const payload = compactPdf417(value, { compaction: options.compaction });
|
|
8988
|
+
const { rows, cols } = dimensions(payload.length + 1, level, { ...options, rowHeight });
|
|
8989
|
+
const eccLength = pdf417EccLength(level), dataLength = rows * cols - eccLength;
|
|
8990
|
+
const data = [dataLength, ...payload]; while (data.length < dataLength) data.push(900);
|
|
8991
|
+
const codewords = data.concat(pdf417ErrorCorrection(data, level));
|
|
8992
|
+
const matrix = new BitMatrix(69 + cols * 17, rows * rowHeight);
|
|
8993
|
+
for (let row = 0; row < rows; row++) {
|
|
8994
|
+
const y = row * rowHeight, cluster = (row % 3) * 3, [left, right] = indicators(row, rows, cols, level);
|
|
8995
|
+
let x = append(matrix, y, 0, START, rowHeight);
|
|
8996
|
+
x = append(matrix, y, x, patternSequence(pdf417PatternForCodeword(left, cluster)), rowHeight);
|
|
8997
|
+
for (let col = 0; col < cols; col++) x = append(matrix, y, x, patternSequence(pdf417PatternForCodeword(codewords[row * cols + col], cluster)), rowHeight);
|
|
8998
|
+
x = append(matrix, y, x, patternSequence(pdf417PatternForCodeword(right, cluster)), rowHeight);
|
|
8999
|
+
append(matrix, y, x, STOP, rowHeight);
|
|
9000
|
+
}
|
|
9001
|
+
matrix.pdf417 = { rows, columns: cols, eccLevel: level, rowHeight, codewords };
|
|
9002
|
+
return matrix;
|
|
9003
|
+
}
|
|
9004
|
+
|
|
9005
|
+
__exports.encodePDF417 = encodePDF417;
|
|
9006
|
+
};
|
|
9007
|
+
|
|
9008
|
+
__modules["pdf417/decoder.js"] = function (__require, __exports) {
|
|
9009
|
+
const { FormatError } = __require("core/errors.js");
|
|
9010
|
+
const { decodePdf417CompactionDetailed } = __require("pdf417/compaction.js");
|
|
9011
|
+
const { pdf417CorrectErrors, pdf417EccLength } = __require("pdf417/error-correction.js");
|
|
9012
|
+
const { pdf417CodewordForPattern } = __require("pdf417/tables.js");
|
|
9013
|
+
|
|
9014
|
+
const START = '11111111010101000';
|
|
9015
|
+
const STOP = '111111101000101001';
|
|
9016
|
+
function bits(matrix, y, x, width) { let value = 0; for (let i = 0; i < width; i++) value = (value << 1) | (matrix.get(x + i, y) ? 1 : 0); return value; }
|
|
9017
|
+
function indicators(row, rows, cols, level) { const group = Math.floor(row / 3), y = Math.floor((rows - 1) / 3), z = level * 3 + (rows - 1) % 3, v = cols - 1; return row % 3 === 0 ? [30 * group + y, 30 * group + v] : row % 3 === 1 ? [30 * group + z, 30 * group + y] : [30 * group + v, 30 * group + z]; }
|
|
9018
|
+
function decodePDF417(matrix, options = {}) {
|
|
9019
|
+
if (!matrix?.width || !matrix?.height || (matrix.width - 69) % 17) throw new FormatError('PDF417: invalid matrix dimensions');
|
|
9020
|
+
const cols = (matrix.width - 69) / 17, rowHeight = options.rowHeight ?? matrix.pdf417?.rowHeight ?? 3;
|
|
9021
|
+
if (!Number.isInteger(rowHeight) || matrix.height % rowHeight) throw new FormatError('PDF417: invalid row height');
|
|
9022
|
+
const rows = matrix.height / rowHeight;
|
|
9023
|
+
if (rows < 3 || rows > 90 || cols < 1 || cols > 30) throw new FormatError('PDF417: dimensions outside the standard range');
|
|
9024
|
+
const all = [];
|
|
9025
|
+
const erasures = [];
|
|
9026
|
+
for (let row = 0; row < rows; row++) {
|
|
9027
|
+
const y = row * rowHeight, cluster = (row % 3) * 3;
|
|
9028
|
+
if (bits(matrix, y, 0, 17).toString(2).padStart(17, '0') !== START || bits(matrix, y, matrix.width - 18, 18).toString(2).padStart(18, '0') !== STOP) throw new FormatError('PDF417: missing start or stop pattern');
|
|
9029
|
+
const read = (x) => { const result = pdf417CodewordForPattern(bits(matrix, y, x, 17)); if (!result || result.cluster !== cluster) throw new FormatError('PDF417: invalid codeword pattern'); return result.codeword; };
|
|
9030
|
+
const left = read(17), right = read(34 + cols * 17);
|
|
9031
|
+
let matched = false; for (let level = 0; level <= 8; level++) { const expected = indicators(row, rows, cols, level); if (left === expected[0] && right === expected[1]) { matched = true; break; } }
|
|
9032
|
+
if (!matched) throw new FormatError('PDF417: row indicator mismatch');
|
|
9033
|
+
for (let col = 0; col < cols; col++) {
|
|
9034
|
+
try { all.push(read(34 + col * 17)); }
|
|
9035
|
+
catch {
|
|
9036
|
+
erasures.push(all.length);
|
|
9037
|
+
all.push(0);
|
|
9038
|
+
}
|
|
9039
|
+
}
|
|
9040
|
+
}
|
|
9041
|
+
let level = -1; for (let candidate = 0; candidate <= 8; candidate++) if (all.length > pdf417EccLength(candidate)) { level = candidate; break; }
|
|
9042
|
+
// The row indicators determine the level uniquely across the symbol.
|
|
9043
|
+
for (let candidate = 0; candidate <= 8; candidate++) {
|
|
9044
|
+
let ok = true; for (let row = 0; row < rows; row++) { const y = row * rowHeight, cluster = (row % 3) * 3, expected = indicators(row, rows, cols, candidate); const left = pdf417CodewordForPattern(bits(matrix, y, 17, 17)); const right = pdf417CodewordForPattern(bits(matrix, y, 34 + cols * 17, 17)); if (!left || !right || left.cluster !== cluster || right.cluster !== cluster || left.codeword !== expected[0] || right.codeword !== expected[1]) { ok = false; break; } } if (ok) { level = candidate; break; }
|
|
9045
|
+
}
|
|
9046
|
+
if (level < 0) throw new FormatError('PDF417: could not determine error correction level');
|
|
9047
|
+
const corrected = all.slice(); const corrections = pdf417CorrectErrors(corrected, level, erasures);
|
|
9048
|
+
const length = corrected[0]; if (length < 1 || length > corrected.length - pdf417EccLength(level)) throw new FormatError('PDF417: invalid symbol length descriptor');
|
|
9049
|
+
const payload = corrected.slice(1, length);
|
|
9050
|
+
const decoded = decodePdf417CompactionDetailed(payload);
|
|
9051
|
+
return { ...decoded, codewords: corrected, rows, columns: cols, eccLevel: level, corrections };
|
|
9052
|
+
}
|
|
9053
|
+
|
|
9054
|
+
__exports.decodePDF417 = decodePDF417;
|
|
9055
|
+
};
|
|
9056
|
+
|
|
9057
|
+
__modules["pdf417/detector.js"] = function (__require, __exports) {
|
|
9058
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
9059
|
+
const { sampleGrid, sampleGridVoting } = __require("image/grid-sampler.js");
|
|
9060
|
+
const { PerspectiveTransform } = __require("image/perspective.js");
|
|
9061
|
+
const { decodePDF417 } = __require("pdf417/decoder.js");
|
|
9062
|
+
|
|
9063
|
+
const START_PATTERN = [8, 1, 1, 1, 1, 1, 1, 3];
|
|
9064
|
+
const STOP_PATTERN = [7, 1, 1, 3, 1, 1, 1, 2, 1];
|
|
9065
|
+
const SCAN_ANGLES = [0, -4, 4, -8, 8, -14, 14, -22, 22, -32, 32]
|
|
9066
|
+
.map((degrees) => degrees * Math.PI / 180);
|
|
9067
|
+
|
|
9068
|
+
function rotateClockwise(source) {
|
|
9069
|
+
const rotated = new BitMatrix(source.height, source.width);
|
|
9070
|
+
for (let y = 0; y < source.height; y++) for (let x = 0; x < source.width; x++) {
|
|
9071
|
+
if (source.get(x, y)) rotated.set(source.height - 1 - y, x);
|
|
9072
|
+
}
|
|
9073
|
+
return rotated;
|
|
9074
|
+
}
|
|
9075
|
+
|
|
9076
|
+
function scanGeometry(angle) {
|
|
9077
|
+
return {
|
|
9078
|
+
along: { x: Math.cos(angle), y: Math.sin(angle) },
|
|
9079
|
+
across: { x: -Math.sin(angle), y: Math.cos(angle) },
|
|
9080
|
+
};
|
|
9081
|
+
}
|
|
9082
|
+
|
|
9083
|
+
function projectionRange(image, vector) {
|
|
9084
|
+
const points = [
|
|
9085
|
+
{ x: 0, y: 0 }, { x: image.width - 1, y: 0 },
|
|
9086
|
+
{ x: image.width - 1, y: image.height - 1 }, { x: 0, y: image.height - 1 },
|
|
9087
|
+
];
|
|
9088
|
+
const values = points.map((point) => point.x * vector.x + point.y * vector.y);
|
|
9089
|
+
return { min: Math.min(...values), max: Math.max(...values) };
|
|
9090
|
+
}
|
|
9091
|
+
|
|
9092
|
+
function lineRange(image, geometry, across) {
|
|
9093
|
+
const { along, across: normal } = geometry;
|
|
9094
|
+
let min = -Infinity, max = Infinity;
|
|
9095
|
+
const constrain = (low, high, step, offset) => {
|
|
9096
|
+
if (Math.abs(step) < 1e-9) return offset >= low && offset <= high;
|
|
9097
|
+
const first = (low - offset) / step, second = (high - offset) / step;
|
|
9098
|
+
min = Math.max(min, Math.min(first, second));
|
|
9099
|
+
max = Math.min(max, Math.max(first, second));
|
|
9100
|
+
return min <= max;
|
|
9101
|
+
};
|
|
9102
|
+
if (!constrain(0, image.width - 1, along.x, normal.x * across) ||
|
|
9103
|
+
!constrain(0, image.height - 1, along.y, normal.y * across)) return null;
|
|
9104
|
+
return { min: Math.ceil(min), max: Math.floor(max) };
|
|
9105
|
+
}
|
|
9106
|
+
|
|
9107
|
+
function runsInLine(image, geometry, across) {
|
|
9108
|
+
const range = lineRange(image, geometry, across);
|
|
9109
|
+
if (!range || range.max < range.min) return [];
|
|
9110
|
+
const { along, across: normal } = geometry;
|
|
9111
|
+
const runs = [];
|
|
9112
|
+
const valueAt = (position) => image.get(
|
|
9113
|
+
Math.round(along.x * position + normal.x * across),
|
|
9114
|
+
Math.round(along.y * position + normal.y * across),
|
|
9115
|
+
);
|
|
9116
|
+
let dark = valueAt(range.min), start = range.min;
|
|
9117
|
+
for (let position = range.min + 1; position <= range.max + 1; position++) {
|
|
9118
|
+
const value = position <= range.max ? valueAt(position) : !dark;
|
|
9119
|
+
if (value !== dark) {
|
|
9120
|
+
runs.push({ dark, start, end: position, length: position - start });
|
|
9121
|
+
start = position; dark = value;
|
|
9122
|
+
}
|
|
9123
|
+
}
|
|
9124
|
+
return runs;
|
|
9125
|
+
}
|
|
9126
|
+
|
|
9127
|
+
function removeSinglePixelSpecks(runs) {
|
|
9128
|
+
const clean = runs.map((run) => ({ ...run }));
|
|
9129
|
+
for (let index = 1; index < clean.length - 1;) {
|
|
9130
|
+
if (clean[index].length > 1) { index++; continue; }
|
|
9131
|
+
const merged = {
|
|
9132
|
+
dark: clean[index - 1].dark,
|
|
9133
|
+
start: clean[index - 1].start,
|
|
9134
|
+
end: clean[index + 1].end,
|
|
9135
|
+
length: clean[index - 1].length + clean[index].length + clean[index + 1].length,
|
|
9136
|
+
};
|
|
9137
|
+
clean.splice(index - 1, 3, merged);
|
|
9138
|
+
index = Math.max(1, index - 2);
|
|
9139
|
+
}
|
|
9140
|
+
return clean;
|
|
9141
|
+
}
|
|
9142
|
+
|
|
9143
|
+
function matchPattern(runs, at, expected) {
|
|
9144
|
+
if (at + expected.length > runs.length || !runs[at].dark) return null;
|
|
9145
|
+
let observed = 0, modules = 0;
|
|
9146
|
+
for (let i = 0; i < expected.length; i++) { observed += runs[at + i].length; modules += expected[i]; }
|
|
9147
|
+
const scale = observed / modules;
|
|
9148
|
+
if (scale < 0.65) return null;
|
|
9149
|
+
let error = 0;
|
|
9150
|
+
for (let i = 0; i < expected.length; i++) {
|
|
9151
|
+
const delta = Math.abs(runs[at + i].length - expected[i] * scale);
|
|
9152
|
+
if (delta > Math.max(1.15, scale * 0.62)) return null;
|
|
9153
|
+
error += delta / scale;
|
|
9154
|
+
}
|
|
9155
|
+
if (error / expected.length > 0.48) return null;
|
|
9156
|
+
return { start: runs[at].start, end: runs[at + expected.length - 1].end, scale, error, at };
|
|
9157
|
+
}
|
|
9158
|
+
|
|
9159
|
+
function quietPenalty(runs, start, stop) {
|
|
9160
|
+
const before = start.at > 0 ? runs[start.at - 1].length / start.scale : 0;
|
|
9161
|
+
const afterIndex = stop.at + STOP_PATTERN.length;
|
|
9162
|
+
const after = afterIndex < runs.length ? runs[afterIndex].length / stop.scale : 0;
|
|
9163
|
+
return Math.max(0, 2 - before) + Math.max(0, 2 - after);
|
|
9164
|
+
}
|
|
9165
|
+
|
|
9166
|
+
function patternPairs(runs) {
|
|
9167
|
+
const starts = [], stops = [];
|
|
9168
|
+
for (let at = 0; at < runs.length; at++) {
|
|
9169
|
+
const start = matchPattern(runs, at, START_PATTERN); if (start) starts.push(start);
|
|
9170
|
+
const stop = matchPattern(runs, at, STOP_PATTERN); if (stop) stops.push(stop);
|
|
9171
|
+
}
|
|
9172
|
+
const pairs = [];
|
|
9173
|
+
for (const start of starts) for (const stop of stops) {
|
|
9174
|
+
if (stop.start <= start.end) continue;
|
|
9175
|
+
const measured = stop.end - start.start;
|
|
9176
|
+
const localScale = Math.sqrt(start.scale * stop.scale);
|
|
9177
|
+
const roughColumns = Math.round((measured / localScale - 69) / 17);
|
|
9178
|
+
for (let columns = Math.max(1, roughColumns - 2); columns <= Math.min(30, roughColumns + 2); columns++) {
|
|
9179
|
+
const width = 69 + columns * 17;
|
|
9180
|
+
const globalScale = measured / width;
|
|
9181
|
+
const ratio = Math.max(start.scale, stop.scale, globalScale) /
|
|
9182
|
+
Math.min(start.scale, stop.scale, globalScale);
|
|
9183
|
+
if (ratio > 1.85) continue;
|
|
9184
|
+
const scaleError = Math.abs(Math.log(start.scale / globalScale)) +
|
|
9185
|
+
Math.abs(Math.log(stop.scale / globalScale));
|
|
9186
|
+
pairs.push({ start, stop, columns, width, scale: globalScale,
|
|
9187
|
+
startScale: start.scale, stopScale: stop.scale,
|
|
9188
|
+
error: start.error + stop.error + scaleError * 4 + quietPenalty(runs, start, stop) * 0.15 });
|
|
9189
|
+
}
|
|
9190
|
+
}
|
|
9191
|
+
pairs.sort((a, b) => a.error - b.error);
|
|
9192
|
+
const used = new Set();
|
|
9193
|
+
return pairs.filter((pair) => {
|
|
9194
|
+
if (used.has(pair.columns)) return false;
|
|
9195
|
+
used.add(pair.columns);
|
|
9196
|
+
return used.size <= 3;
|
|
9197
|
+
});
|
|
9198
|
+
}
|
|
9199
|
+
|
|
9200
|
+
function pointAt(geometry, along, across) {
|
|
9201
|
+
return {
|
|
9202
|
+
x: geometry.along.x * along + geometry.across.x * across,
|
|
9203
|
+
y: geometry.along.y * along + geometry.across.y * across,
|
|
9204
|
+
};
|
|
9205
|
+
}
|
|
9206
|
+
|
|
9207
|
+
function scanHits(image, angle) {
|
|
9208
|
+
const geometry = scanGeometry(angle);
|
|
9209
|
+
const range = projectionRange(image, geometry.across);
|
|
9210
|
+
const hits = [];
|
|
9211
|
+
for (let across = Math.ceil(range.min); across <= Math.floor(range.max); across++) {
|
|
9212
|
+
const raw = runsInLine(image, geometry, across);
|
|
9213
|
+
let pairs = patternPairs(raw);
|
|
9214
|
+
if (!pairs.length) pairs = patternPairs(removeSinglePixelSpecks(raw));
|
|
9215
|
+
for (const pair of pairs) {
|
|
9216
|
+
hits.push({ across, left: pair.start.start, right: pair.stop.end,
|
|
9217
|
+
leftPoint: pointAt(geometry, pair.start.start, across),
|
|
9218
|
+
rightPoint: pointAt(geometry, pair.stop.end, across),
|
|
9219
|
+
scale: pair.scale, startScale: pair.startScale, stopScale: pair.stopScale,
|
|
9220
|
+
columns: pair.columns, width: pair.width, error: pair.error,
|
|
9221
|
+
geometry });
|
|
9222
|
+
}
|
|
9223
|
+
}
|
|
9224
|
+
return hits;
|
|
9225
|
+
}
|
|
9226
|
+
|
|
9227
|
+
function fittedLine(hits, key) {
|
|
9228
|
+
const meanX = hits.reduce((sum, hit) => sum + hit.across, 0) / hits.length;
|
|
9229
|
+
const meanY = hits.reduce((sum, hit) => sum + hit[key], 0) / hits.length;
|
|
9230
|
+
let covariance = 0, variance = 0;
|
|
9231
|
+
for (const hit of hits) {
|
|
9232
|
+
const delta = hit.across - meanX;
|
|
9233
|
+
covariance += delta * (hit[key] - meanY);
|
|
9234
|
+
variance += delta * delta;
|
|
9235
|
+
}
|
|
9236
|
+
const slope = variance ? covariance / variance : 0;
|
|
9237
|
+
return { slope, intercept: meanY - slope * meanX };
|
|
9238
|
+
}
|
|
9239
|
+
|
|
9240
|
+
function lineValue(line, at) {
|
|
9241
|
+
return line.intercept + line.slope * at;
|
|
9242
|
+
}
|
|
9243
|
+
|
|
9244
|
+
function finderExtent(image, hits, edgeKey, scaleKey, centreModules, fallback) {
|
|
9245
|
+
const geometry = hits[0].geometry;
|
|
9246
|
+
const edge = fittedLine(hits, edgeKey), scale = fittedLine(hits, scaleKey);
|
|
9247
|
+
const span = fallback.bottom - fallback.top;
|
|
9248
|
+
const projection = projectionRange(image, geometry.across);
|
|
9249
|
+
const margin = Math.max(6, span * 0.35, hits[0].scale * 4);
|
|
9250
|
+
const start = Math.max(Math.ceil(projection.min), Math.floor(fallback.top - margin));
|
|
9251
|
+
const end = Math.min(Math.floor(projection.max), Math.ceil(fallback.bottom + margin));
|
|
9252
|
+
const values = [];
|
|
9253
|
+
for (let across = start; across <= end; across++) {
|
|
9254
|
+
const localScale = Math.max(0.5, lineValue(scale, across));
|
|
9255
|
+
const centre = lineValue(edge, across) + localScale * centreModules;
|
|
9256
|
+
let dark = 0;
|
|
9257
|
+
for (const offset of [-0.75, 0, 0.75]) {
|
|
9258
|
+
const point = pointAt(geometry, centre + localScale * offset, across);
|
|
9259
|
+
if (image.get(Math.round(point.x), Math.round(point.y))) dark++;
|
|
9260
|
+
}
|
|
9261
|
+
values.push({ across, dark: dark >= 2 });
|
|
9262
|
+
}
|
|
9263
|
+
const segments = [];
|
|
9264
|
+
let first = null, lastDark = null, gap = 0;
|
|
9265
|
+
for (const value of values) {
|
|
9266
|
+
if (value.dark) {
|
|
9267
|
+
if (first === null) first = value.across;
|
|
9268
|
+
lastDark = value.across; gap = 0;
|
|
9269
|
+
} else if (first !== null && ++gap > 2) {
|
|
9270
|
+
segments.push({ top: first, bottom: lastDark + 1 });
|
|
9271
|
+
first = null; lastDark = null; gap = 0;
|
|
9272
|
+
}
|
|
9273
|
+
}
|
|
9274
|
+
if (first !== null) segments.push({ top: first, bottom: lastDark + 1 });
|
|
9275
|
+
let best = null, bestScore = -Infinity;
|
|
9276
|
+
for (const segment of segments) {
|
|
9277
|
+
const overlap = Math.max(0, Math.min(segment.bottom, fallback.bottom) - Math.max(segment.top, fallback.top));
|
|
9278
|
+
const score = overlap * 4 + (segment.bottom - segment.top) -
|
|
9279
|
+
Math.abs((segment.top + segment.bottom) / 2 - (fallback.top + fallback.bottom) / 2);
|
|
9280
|
+
if (overlap >= span * 0.55 && score > bestScore) { best = segment; bestScore = score; }
|
|
9281
|
+
}
|
|
9282
|
+
return best ?? fallback;
|
|
9283
|
+
}
|
|
9284
|
+
|
|
9285
|
+
function intersectBoundary(leftAcross, rightAcross, leftCentre, rightCentre, leftEdge, rightEdge) {
|
|
9286
|
+
const delta = rightCentre - leftCentre;
|
|
9287
|
+
if (Math.abs(delta) < 1e-6) return { left: leftAcross, right: rightAcross };
|
|
9288
|
+
const slope = (rightAcross - leftAcross) / delta;
|
|
9289
|
+
const intercept = leftAcross - slope * leftCentre;
|
|
9290
|
+
const atEdge = (edge, fallback) => {
|
|
9291
|
+
const denominator = 1 - slope * edge.slope;
|
|
9292
|
+
return Math.abs(denominator) < 1e-6 ? fallback :
|
|
9293
|
+
(slope * edge.intercept + intercept) / denominator;
|
|
9294
|
+
};
|
|
9295
|
+
return { left: atEdge(leftEdge, leftAcross), right: atEdge(rightEdge, rightAcross) };
|
|
9296
|
+
}
|
|
9297
|
+
|
|
9298
|
+
function groupHits(hits, image) {
|
|
9299
|
+
const groups = [];
|
|
9300
|
+
for (const hit of hits.sort((a, b) => a.across - b.across || a.error - b.error)) {
|
|
9301
|
+
let best = null, bestDistance = Infinity;
|
|
9302
|
+
for (const group of groups) {
|
|
9303
|
+
const last = group.hits[group.hits.length - 1];
|
|
9304
|
+
const gap = hit.across - last.across;
|
|
9305
|
+
if (hit.columns !== last.columns || gap <= 0 || gap > Math.max(5, hit.scale * 3)) continue;
|
|
9306
|
+
const scaleRatio = Math.max(hit.scale, last.scale) / Math.min(hit.scale, last.scale);
|
|
9307
|
+
if (scaleRatio > 1.45) continue;
|
|
9308
|
+
const tolerance = Math.max(5, hit.scale * 4 + gap);
|
|
9309
|
+
const distance = Math.abs(hit.left - last.left) + Math.abs(hit.right - last.right);
|
|
9310
|
+
if (distance > tolerance * 2 || distance >= bestDistance) continue;
|
|
9311
|
+
best = group; bestDistance = distance;
|
|
9312
|
+
}
|
|
9313
|
+
if (best) best.hits.push(hit); else groups.push({ hits: [hit] });
|
|
9314
|
+
}
|
|
9315
|
+
const candidates = [];
|
|
9316
|
+
for (const group of groups) {
|
|
9317
|
+
const rows = group.hits;
|
|
9318
|
+
const scale = rows.reduce((sum, hit) => sum + hit.scale, 0) / rows.length;
|
|
9319
|
+
const top = rows[0].across, bottom = rows[rows.length - 1].across + 1;
|
|
9320
|
+
const span = bottom - top;
|
|
9321
|
+
if (rows.length < 4 || span < Math.max(6, scale * 4) || rows.length / span < 0.28) continue;
|
|
9322
|
+
const geometry = rows[0].geometry;
|
|
9323
|
+
const left = fittedLine(rows, 'left'), right = fittedLine(rows, 'right');
|
|
9324
|
+
const startScale = fittedLine(rows, 'startScale'), stopScale = fittedLine(rows, 'stopScale');
|
|
9325
|
+
const fallback = { top, bottom };
|
|
9326
|
+
const leftExtent = image ? finderExtent(image, rows, 'left', 'startScale', 4, fallback) : fallback;
|
|
9327
|
+
const rightExtent = image ? finderExtent(image, rows, 'right', 'stopScale', -14.5, fallback) : fallback;
|
|
9328
|
+
const boundary = (leftAcross, rightAcross) => intersectBoundary(
|
|
9329
|
+
leftAcross,
|
|
9330
|
+
rightAcross,
|
|
9331
|
+
lineValue(left, leftAcross) + lineValue(startScale, leftAcross) * 4,
|
|
9332
|
+
lineValue(right, rightAcross) - lineValue(stopScale, rightAcross) * 14.5,
|
|
9333
|
+
left,
|
|
9334
|
+
right,
|
|
9335
|
+
);
|
|
9336
|
+
const topBoundary = boundary(leftExtent.top, rightExtent.top);
|
|
9337
|
+
const bottomBoundary = boundary(leftExtent.bottom, rightExtent.bottom);
|
|
9338
|
+
candidates.push({
|
|
9339
|
+
width: rows[0].width, scale,
|
|
9340
|
+
corners: [
|
|
9341
|
+
pointAt(geometry, lineValue(left, topBoundary.left), topBoundary.left),
|
|
9342
|
+
pointAt(geometry, lineValue(right, topBoundary.right), topBoundary.right),
|
|
9343
|
+
pointAt(geometry, lineValue(right, bottomBoundary.right), bottomBoundary.right),
|
|
9344
|
+
pointAt(geometry, lineValue(left, bottomBoundary.left), bottomBoundary.left),
|
|
9345
|
+
],
|
|
9346
|
+
score: rows.length / span * 8 + Math.log2(rows.length + 1) * 2 -
|
|
9347
|
+
rows.reduce((sum, hit) => sum + hit.error, 0) / rows.length,
|
|
9348
|
+
});
|
|
9349
|
+
}
|
|
9350
|
+
return candidates.sort((a, b) => b.score - a.score);
|
|
9351
|
+
}
|
|
9352
|
+
|
|
9353
|
+
function validQuadrilateral(value) {
|
|
9354
|
+
return Array.isArray(value) && value.length === 4 &&
|
|
9355
|
+
value.every((point) => Number.isFinite(point?.x) && Number.isFinite(point?.y));
|
|
9356
|
+
}
|
|
9357
|
+
|
|
9358
|
+
function manualCandidate(corners) {
|
|
9359
|
+
const horizontal = (Math.hypot(corners[1].x - corners[0].x, corners[1].y - corners[0].y) +
|
|
9360
|
+
Math.hypot(corners[2].x - corners[3].x, corners[2].y - corners[3].y)) / 2;
|
|
9361
|
+
const vertical = (Math.hypot(corners[3].x - corners[0].x, corners[3].y - corners[0].y) +
|
|
9362
|
+
Math.hypot(corners[2].x - corners[1].x, corners[2].y - corners[1].y)) / 2;
|
|
9363
|
+
const out = [];
|
|
9364
|
+
for (let columns = 1; columns <= 30; columns++) {
|
|
9365
|
+
const width = 69 + columns * 17, scale = horizontal / width;
|
|
9366
|
+
if (scale < 0.65) continue;
|
|
9367
|
+
const moduleHeight = vertical / scale;
|
|
9368
|
+
let plausibility = Infinity;
|
|
9369
|
+
for (let rowHeight = 3; rowHeight <= 12; rowHeight++) {
|
|
9370
|
+
const rows = Math.round(moduleHeight / rowHeight);
|
|
9371
|
+
if (rows >= 3 && rows <= 90) plausibility = Math.min(plausibility,
|
|
9372
|
+
Math.abs(moduleHeight - rows * rowHeight) / rowHeight);
|
|
9373
|
+
}
|
|
9374
|
+
out.push({ width, scale, corners, score: Number.isFinite(plausibility) ? 2 - plausibility : 0 });
|
|
9375
|
+
}
|
|
9376
|
+
return out.sort((a, b) => b.score - a.score);
|
|
9377
|
+
}
|
|
9378
|
+
|
|
9379
|
+
function edgeLength(first, second) {
|
|
9380
|
+
return Math.hypot(second.x - first.x, second.y - first.y);
|
|
9381
|
+
}
|
|
9382
|
+
|
|
9383
|
+
function rowCandidates(candidate, options) {
|
|
9384
|
+
const vertical = (edgeLength(candidate.corners[0], candidate.corners[3]) +
|
|
9385
|
+
edgeLength(candidate.corners[1], candidate.corners[2])) / 2;
|
|
9386
|
+
const allowedHeights = Number.isInteger(options.rowHeight) ? [options.rowHeight] :
|
|
9387
|
+
Array.from({ length: 10 }, (_, index) => index + 3);
|
|
9388
|
+
const rows = [];
|
|
9389
|
+
for (let value = 3; value <= 90; value++) {
|
|
9390
|
+
let score = Infinity;
|
|
9391
|
+
for (const rowHeight of allowedHeights) {
|
|
9392
|
+
score = Math.min(score, Math.abs(Math.log(vertical / (candidate.scale * value * rowHeight))));
|
|
9393
|
+
}
|
|
9394
|
+
rows.push({ value, score });
|
|
9395
|
+
}
|
|
9396
|
+
return rows.sort((a, b) => a.score - b.score).map((entry) => entry.value);
|
|
9397
|
+
}
|
|
9398
|
+
|
|
9399
|
+
function shiftedCandidate(candidate, amount) {
|
|
9400
|
+
if (!amount) return candidate;
|
|
9401
|
+
const topDx = candidate.corners[3].x - candidate.corners[0].x;
|
|
9402
|
+
const topDy = candidate.corners[3].y - candidate.corners[0].y;
|
|
9403
|
+
const bottomDx = candidate.corners[2].x - candidate.corners[1].x;
|
|
9404
|
+
const bottomDy = candidate.corners[2].y - candidate.corners[1].y;
|
|
9405
|
+
const topLength = Math.hypot(topDx, topDy) || 1;
|
|
9406
|
+
const bottomLength = Math.hypot(bottomDx, bottomDy) || 1;
|
|
9407
|
+
return { ...candidate, corners: [
|
|
9408
|
+
{ x: candidate.corners[0].x - topDx / topLength * amount, y: candidate.corners[0].y - topDy / topLength * amount },
|
|
9409
|
+
{ x: candidate.corners[1].x - bottomDx / bottomLength * amount, y: candidate.corners[1].y - bottomDy / bottomLength * amount },
|
|
9410
|
+
{ x: candidate.corners[2].x + bottomDx / bottomLength * amount, y: candidate.corners[2].y + bottomDy / bottomLength * amount },
|
|
9411
|
+
{ x: candidate.corners[3].x + topDx / topLength * amount, y: candidate.corners[3].y + topDy / topLength * amount },
|
|
9412
|
+
] };
|
|
9413
|
+
}
|
|
9414
|
+
|
|
9415
|
+
function canonicalRows(matrix) {
|
|
9416
|
+
const rowHeight = 3;
|
|
9417
|
+
const out = new BitMatrix(matrix.width, matrix.height * rowHeight);
|
|
9418
|
+
for (let y = 0; y < matrix.height; y++) for (let x = 0; x < matrix.width; x++) {
|
|
9419
|
+
if (matrix.get(x, y)) out.setRegion(x, y * rowHeight, 1, rowHeight);
|
|
9420
|
+
}
|
|
9421
|
+
return out;
|
|
9422
|
+
}
|
|
9423
|
+
|
|
9424
|
+
function sampleCandidate(image, candidate, options) {
|
|
9425
|
+
for (const edgeShift of [0, candidate.scale * 0.35, -candidate.scale * 0.25]) {
|
|
9426
|
+
const geometry = shiftedCandidate(candidate, edgeShift);
|
|
9427
|
+
for (const rows of rowCandidates(geometry, options)) {
|
|
9428
|
+
const transform = PerspectiveTransform.quadToQuad(0, 0, geometry.width, 0, geometry.width, rows, 0, rows,
|
|
9429
|
+
geometry.corners[0].x, geometry.corners[0].y, geometry.corners[1].x, geometry.corners[1].y,
|
|
9430
|
+
geometry.corners[2].x, geometry.corners[2].y, geometry.corners[3].x, geometry.corners[3].y);
|
|
9431
|
+
for (const voting of [false, true]) {
|
|
9432
|
+
let matrix;
|
|
9433
|
+
try { matrix = voting ? sampleGridVoting(image, geometry.width, rows, transform) : sampleGrid(image, geometry.width, rows, transform); }
|
|
9434
|
+
catch { continue; }
|
|
9435
|
+
try {
|
|
9436
|
+
const result = decodePDF417(matrix, { ...options, rowHeight: 1 });
|
|
9437
|
+
return { matrix: canonicalRows(matrix), result, corners: geometry.corners };
|
|
9438
|
+
}
|
|
9439
|
+
catch { /* Try the next geometry. */ }
|
|
9440
|
+
}
|
|
9441
|
+
}
|
|
9442
|
+
}
|
|
9443
|
+
return null;
|
|
9444
|
+
}
|
|
9445
|
+
|
|
9446
|
+
function automaticCandidates(image) {
|
|
9447
|
+
const out = [];
|
|
9448
|
+
for (const angle of SCAN_ANGLES) {
|
|
9449
|
+
out.push(...groupHits(scanHits(image, angle), image));
|
|
9450
|
+
if (out.length) break;
|
|
9451
|
+
}
|
|
9452
|
+
return out;
|
|
9453
|
+
}
|
|
9454
|
+
|
|
9455
|
+
function detectInOrientation(image, options, supplied) {
|
|
9456
|
+
for (const candidate of [...supplied, ...automaticCandidates(image)]) {
|
|
9457
|
+
const decoded = sampleCandidate(image, candidate, options);
|
|
9458
|
+
if (decoded) return { candidate, decoded };
|
|
9459
|
+
}
|
|
9460
|
+
if (supplied.length) return null;
|
|
9461
|
+
for (const angle of SCAN_ANGLES.slice(1)) {
|
|
9462
|
+
const candidates = groupHits(scanHits(image, angle), image);
|
|
9463
|
+
for (const candidate of candidates) {
|
|
9464
|
+
const decoded = sampleCandidate(image, candidate, options);
|
|
9465
|
+
if (decoded) return { candidate, decoded };
|
|
9466
|
+
}
|
|
9467
|
+
}
|
|
9468
|
+
return null;
|
|
9469
|
+
}
|
|
9470
|
+
|
|
9471
|
+
/*
|
|
9472
|
+
* Locate a binarized raster symbol from its repeated start and stop patterns.
|
|
9473
|
+
* The detector estimates a projective quadrilateral; grayscale binarization
|
|
9474
|
+
* remains the caller's responsibility.
|
|
9475
|
+
*/
|
|
9476
|
+
function detectPDF417(binaryImage, options = {}) {
|
|
9477
|
+
if (!binaryImage?.width || !binaryImage?.height || typeof binaryImage.get !== 'function') return null;
|
|
9478
|
+
let oriented = binaryImage;
|
|
9479
|
+
let toOriginal = (point) => ({ x: point.x, y: point.y });
|
|
9480
|
+
for (let turns = 0; turns < 4; turns++) {
|
|
9481
|
+
const supplied = turns === 0 && validQuadrilateral(options.quadrilateral)
|
|
9482
|
+
? manualCandidate(options.quadrilateral.map(({ x, y }) => ({ x, y }))) : [];
|
|
9483
|
+
const found = detectInOrientation(oriented, options, supplied);
|
|
9484
|
+
if (found) {
|
|
9485
|
+
return { matrix: found.decoded.matrix, rotation: turns * 90,
|
|
9486
|
+
corners: found.decoded.corners.map(toOriginal), ...found.decoded.result };
|
|
9487
|
+
}
|
|
9488
|
+
const previous = oriented, previousToOriginal = toOriginal;
|
|
9489
|
+
oriented = rotateClockwise(previous);
|
|
9490
|
+
toOriginal = (point) => previousToOriginal({ x: point.y, y: previous.height - point.x });
|
|
9491
|
+
}
|
|
9492
|
+
return null;
|
|
9493
|
+
}
|
|
9494
|
+
function detectAndDecodePDF417(binaryImage, options = {}) { return detectPDF417(binaryImage, options); }
|
|
9495
|
+
|
|
9496
|
+
__exports.detectPDF417 = detectPDF417;
|
|
9497
|
+
__exports.detectAndDecodePDF417 = detectAndDecodePDF417;
|
|
9498
|
+
};
|
|
9499
|
+
|
|
9500
|
+
__modules["pdf417/index.js"] = function (__require, __exports) {
|
|
9501
|
+
const __reexport0 = __require("pdf417/compaction.js"); __exports.compactPdf417 = __reexport0.compactPdf417; __exports.compactPdf417Text = __reexport0.compactPdf417Text; __exports.compactPdf417Bytes = __reexport0.compactPdf417Bytes; __exports.compactPdf417Numeric = __reexport0.compactPdf417Numeric; __exports.decodePdf417Compaction = __reexport0.decodePdf417Compaction; __exports.decodePdf417CompactionDetailed = __reexport0.decodePdf417CompactionDetailed;
|
|
9502
|
+
const __reexport1 = __require("pdf417/encoder.js"); __exports.encodePDF417 = __reexport1.encodePDF417;
|
|
9503
|
+
const __reexport2 = __require("pdf417/decoder.js"); __exports.decodePDF417 = __reexport2.decodePDF417;
|
|
9504
|
+
const __reexport3 = __require("pdf417/detector.js"); __exports.detectPDF417 = __reexport3.detectPDF417; __exports.detectAndDecodePDF417 = __reexport3.detectAndDecodePDF417;
|
|
9505
|
+
const __reexport4 = __require("pdf417/error-correction.js"); __exports.pdf417EccLength = __reexport4.pdf417EccLength; __exports.pdf417ErrorCorrection = __reexport4.pdf417ErrorCorrection; __exports.pdf417CorrectErrors = __reexport4.pdf417CorrectErrors;
|
|
9506
|
+
const __reexport5 = __require("pdf417/tables.js"); __exports.PDF417_PATTERN_TABLE = __reexport5.PDF417_PATTERN_TABLE; __exports.PDF417_CLUSTER_NUMBERS = __reexport5.PDF417_CLUSTER_NUMBERS; __exports.pdf417PatternForCodeword = __reexport5.pdf417PatternForCodeword; __exports.pdf417CodewordForPattern = __reexport5.pdf417CodewordForPattern;
|
|
9507
|
+
|
|
9508
|
+
|
|
9509
|
+
};
|
|
9510
|
+
|
|
9511
|
+
__modules["micropdf417/tables.js"] = function (__require, __exports) {
|
|
9512
|
+
/**
|
|
9513
|
+
* MicroPDF417 format facts and Row Address Pattern (RAP) helpers.
|
|
9514
|
+
*
|
|
9515
|
+
* The tables are represented as compact, immutable data and are guarded by
|
|
9516
|
+
* {@link validateMicroPdf417Tables}. They are deliberately separate from the
|
|
9517
|
+
* PDF417 symbol-character table: MicroPDF417 has a fixed family of symbols and
|
|
9518
|
+
* its own row-address system.
|
|
9519
|
+
*
|
|
9520
|
+
* Values are derived from publicly available symbology documentation and
|
|
9521
|
+
* independently checked against black-box reference output. This module makes
|
|
9522
|
+
* no certification or conformance claim.
|
|
9523
|
+
*
|
|
9524
|
+
* @module micropdf417/tables
|
|
9525
|
+
*/
|
|
9526
|
+
|
|
9527
|
+
const variant = (id, columns, rows, eccCodewords, rapStart, rapRotation) => Object.freeze({
|
|
9528
|
+
id,
|
|
9529
|
+
columns,
|
|
9530
|
+
rows,
|
|
9531
|
+
totalCodewords: columns * rows,
|
|
9532
|
+
dataCodewords: columns * rows - eccCodewords,
|
|
9533
|
+
eccCodewords,
|
|
9534
|
+
rapStart,
|
|
9535
|
+
rapRotation,
|
|
9536
|
+
});
|
|
9537
|
+
|
|
9538
|
+
/** All 34 predefined MicroPDF417 symbol variants, in format-table order. */
|
|
9539
|
+
const MICROPDF417_VARIANTS = Object.freeze([
|
|
9540
|
+
variant(1, 1, 11, 7, 1, 8), variant(2, 1, 14, 7, 8, 0),
|
|
9541
|
+
variant(3, 1, 17, 7, 36, 0), variant(4, 1, 20, 8, 19, 0),
|
|
9542
|
+
variant(5, 1, 24, 8, 9, 8), variant(6, 1, 28, 8, 25, 8),
|
|
9543
|
+
variant(7, 2, 8, 8, 1, 0), variant(8, 2, 11, 9, 1, 8),
|
|
9544
|
+
variant(9, 2, 14, 9, 8, 0), variant(10, 2, 17, 10, 36, 0),
|
|
9545
|
+
variant(11, 2, 20, 11, 19, 0), variant(12, 2, 23, 13, 9, 8),
|
|
9546
|
+
variant(13, 2, 26, 15, 27, 8),
|
|
9547
|
+
variant(14, 3, 6, 12, 1, 0), variant(15, 3, 8, 14, 7, 0),
|
|
9548
|
+
variant(16, 3, 10, 16, 15, 0), variant(17, 3, 12, 18, 25, 0),
|
|
9549
|
+
variant(18, 3, 15, 21, 37, 0), variant(19, 3, 20, 26, 1, 16),
|
|
9550
|
+
variant(20, 3, 26, 32, 1, 8), variant(21, 3, 32, 38, 21, 8),
|
|
9551
|
+
variant(22, 3, 38, 44, 15, 16), variant(23, 3, 44, 50, 1, 24),
|
|
9552
|
+
variant(24, 4, 4, 8, 47, 24), variant(25, 4, 6, 12, 1, 0),
|
|
9553
|
+
variant(26, 4, 8, 14, 7, 0), variant(27, 4, 10, 16, 15, 0),
|
|
9554
|
+
variant(28, 4, 12, 18, 25, 0), variant(29, 4, 15, 21, 37, 0),
|
|
9555
|
+
variant(30, 4, 20, 26, 1, 16), variant(31, 4, 26, 32, 1, 8),
|
|
9556
|
+
variant(32, 4, 32, 38, 21, 8), variant(33, 4, 38, 44, 15, 16),
|
|
9557
|
+
variant(34, 4, 44, 50, 1, 24),
|
|
9558
|
+
]);
|
|
9559
|
+
|
|
9560
|
+
const byId = new Map(MICROPDF417_VARIANTS.map((entry) => [entry.id, entry]));
|
|
9561
|
+
|
|
9562
|
+
// Six run widths, ordered bar-space-bar-space-bar-space. A RAP is ten
|
|
9563
|
+
// modules wide; the right RAP has one additional one-module stop bar when
|
|
9564
|
+
// rendered. Keeping runs rather than bitmap literals makes each invariant
|
|
9565
|
+
// inspectable and avoids a rendering-specific representation here.
|
|
9566
|
+
const SIDE_RAP_RUNS = Object.freeze([
|
|
9567
|
+
'221311', '311311', '312211', '222211', '213211', '214111', '223111', '313111',
|
|
9568
|
+
'322111', '412111', '421111', '331111', '241111', '232111', '231211', '321211',
|
|
9569
|
+
'411211', '411121', '411112', '321112', '312112', '311212', '311221', '311131',
|
|
9570
|
+
'311122', '311113', '221113', '221122', '221131', '221221', '222121', '312121',
|
|
9571
|
+
'321121', '231121', '231112', '222112', '213112', '212212', '212221', '212131',
|
|
9572
|
+
'212122', '212113', '211213', '211123', '211132', '211141', '211231', '211222',
|
|
9573
|
+
'211312', '211321', '211411', '212311',
|
|
9574
|
+
]);
|
|
9575
|
+
|
|
9576
|
+
const CENTER_RAP_RUNS = Object.freeze([
|
|
9577
|
+
'112231', '121231', '122131', '131131', '131221', '132121', '141121', '141211',
|
|
9578
|
+
'142111', '133111', '132211', '131311', '122311', '123211', '124111', '115111',
|
|
9579
|
+
'114211', '114121', '123121', '123112', '122212', '122221', '121321', '121411',
|
|
9580
|
+
'112411', '113311', '113221', '113212', '113122', '122122', '131122', '131113',
|
|
9581
|
+
'122113', '113113', '112213', '112222', '112312', '112321', '111421', '111331',
|
|
9582
|
+
'111322', '111232', '111223', '111133', '111124', '111214', '112114', '121114',
|
|
9583
|
+
'121123', '121132', '112132', '112141',
|
|
9584
|
+
]);
|
|
9585
|
+
|
|
9586
|
+
/** @param {number} value @param {number} offset @returns {number} */
|
|
9587
|
+
function microPdf417NextRap(value, offset = 1) {
|
|
9588
|
+
if (!Number.isInteger(value) || value < 1 || value > 52) throw new RangeError('MicroPDF417: RAP number must be in 1..52');
|
|
9589
|
+
if (!Number.isInteger(offset)) throw new RangeError('MicroPDF417: RAP offset must be an integer');
|
|
9590
|
+
return ((value - 1 + offset) % 52 + 52) % 52 + 1;
|
|
9591
|
+
}
|
|
9592
|
+
|
|
9593
|
+
/** @param {number} id @returns {Readonly<typeof MICROPDF417_VARIANTS[number]>} */
|
|
9594
|
+
function microPdf417VariantByNumber(id) {
|
|
9595
|
+
const entry = byId.get(id);
|
|
9596
|
+
if (!entry) throw new RangeError('MicroPDF417: variant must be an integer in 1..34');
|
|
9597
|
+
return entry;
|
|
9598
|
+
}
|
|
9599
|
+
|
|
9600
|
+
/**
|
|
9601
|
+
* Return the smallest data-region candidate that fits `codewords`.
|
|
9602
|
+
* Ties are resolved by width, then height, so selection is deterministic.
|
|
9603
|
+
*/
|
|
9604
|
+
function microPdf417VariantForCapacity(codewords) {
|
|
9605
|
+
if (!Number.isInteger(codewords) || codewords < 1) throw new RangeError('MicroPDF417: codeword capacity must be a positive integer');
|
|
9606
|
+
const candidates = MICROPDF417_VARIANTS.filter((entry) => entry.dataCodewords >= codewords);
|
|
9607
|
+
if (!candidates.length) throw new RangeError('MicroPDF417: payload exceeds the largest symbol data region');
|
|
9608
|
+
return candidates.slice().sort((a, b) => a.totalCodewords - b.totalCodewords || a.columns - b.columns || a.rows - b.rows)[0];
|
|
9609
|
+
}
|
|
9610
|
+
|
|
9611
|
+
/** Return the six bar/space run widths for a numbered side or center RAP. */
|
|
9612
|
+
function microPdf417RapSequence(number, kind = 'side') {
|
|
9613
|
+
if (!Number.isInteger(number) || number < 1 || number > 52) throw new RangeError('MicroPDF417: RAP number must be in 1..52');
|
|
9614
|
+
if (kind === 'side') return SIDE_RAP_RUNS[number - 1];
|
|
9615
|
+
if (kind === 'center') return CENTER_RAP_RUNS[number - 1];
|
|
9616
|
+
throw new RangeError('MicroPDF417: RAP kind must be side or center');
|
|
9617
|
+
}
|
|
9618
|
+
|
|
9619
|
+
/**
|
|
9620
|
+
* Resolve all row-address data for a zero-based row within a variant.
|
|
9621
|
+
* @returns {{left: number, center: number|null, right: number, cluster: 0|3|6}}
|
|
9622
|
+
*/
|
|
9623
|
+
function microPdf417RowAddress(entry, row) {
|
|
9624
|
+
if (!entry || !Number.isInteger(entry.columns) || !Number.isInteger(entry.rows)) throw new TypeError('MicroPDF417: a variant entry is required');
|
|
9625
|
+
if (!Number.isInteger(row) || row < 0 || row >= entry.rows) throw new RangeError(`MicroPDF417: row must be in 0..${entry.rows - 1}`);
|
|
9626
|
+
const left = microPdf417NextRap(entry.rapStart, row);
|
|
9627
|
+
const cluster = /** @type {0|3|6} */ (((left - 1) % 3) * 3);
|
|
9628
|
+
if (entry.columns < 3) return { left, center: null, right: microPdf417NextRap(left, entry.rapRotation), cluster };
|
|
9629
|
+
const center = microPdf417NextRap(left, entry.rapRotation);
|
|
9630
|
+
return { left, center, right: microPdf417NextRap(center, entry.rapRotation), cluster };
|
|
9631
|
+
}
|
|
9632
|
+
|
|
9633
|
+
const validRuns = (runs) => runs.length === 6 && /^[1-9]{6}$/.test(runs) && [...runs].reduce((sum, digit) => sum + Number(digit), 0) === 10;
|
|
9634
|
+
const oneEdgeShift = (from, to) => [...from].reduce((sum, digit, index) => sum + Math.abs(Number(digit) - Number(to[index])), 0) === 2;
|
|
9635
|
+
|
|
9636
|
+
/** Return any table-invariant failures; an empty result means the table is coherent. */
|
|
9637
|
+
function validateMicroPdf417Tables() {
|
|
9638
|
+
const issues = [];
|
|
9639
|
+
if (MICROPDF417_VARIANTS.length !== 34) issues.push('expected 34 variants');
|
|
9640
|
+
const ids = new Set();
|
|
9641
|
+
const formats = new Set();
|
|
9642
|
+
for (const entry of MICROPDF417_VARIANTS) {
|
|
9643
|
+
if (ids.has(entry.id)) issues.push(`duplicate variant ${entry.id}`); ids.add(entry.id);
|
|
9644
|
+
const format = `${entry.columns}x${entry.rows}`;
|
|
9645
|
+
if (formats.has(format)) issues.push(`duplicate format ${format}`); formats.add(format);
|
|
9646
|
+
if (entry.totalCodewords !== entry.columns * entry.rows) issues.push(`${format}: total codeword geometry mismatch`);
|
|
9647
|
+
if (entry.dataCodewords + entry.eccCodewords !== entry.totalCodewords) issues.push(`${format}: data/ECC capacity mismatch`);
|
|
9648
|
+
if (entry.eccCodewords < 7 || entry.eccCodewords > 50) issues.push(`${format}: invalid ECC length`);
|
|
9649
|
+
if (entry.rapStart < 1 || entry.rapStart > 52 || entry.rapRotation < 0 || entry.rapRotation > 51) issues.push(`${format}: invalid RAP assignment`);
|
|
9650
|
+
for (let row = 0; row < entry.rows; row++) {
|
|
9651
|
+
const address = microPdf417RowAddress(entry, row);
|
|
9652
|
+
if (address.cluster !== ((address.left - 1) % 3) * 3) issues.push(`${format}: cluster mismatch at row ${row}`);
|
|
9653
|
+
if ((entry.columns < 3) !== (address.center === null)) issues.push(`${format}: center RAP layout mismatch`);
|
|
9654
|
+
}
|
|
9655
|
+
}
|
|
9656
|
+
for (const [kind, runs] of [['side', SIDE_RAP_RUNS], ['center', CENTER_RAP_RUNS]]) {
|
|
9657
|
+
if (runs.length !== 52) issues.push(`${kind}: expected 52 RAPs`);
|
|
9658
|
+
if (new Set(runs).size !== runs.length) issues.push(`${kind}: duplicate RAP`);
|
|
9659
|
+
for (let i = 0; i < runs.length; i++) {
|
|
9660
|
+
if (!validRuns(runs[i])) issues.push(`${kind}: invalid RAP ${i + 1}`);
|
|
9661
|
+
if (runs.length && !oneEdgeShift(runs[i], runs[(i + 1) % runs.length])) issues.push(`${kind}: RAP ${i + 1} is not adjacent to its successor`);
|
|
9662
|
+
}
|
|
9663
|
+
}
|
|
9664
|
+
return issues;
|
|
9665
|
+
}
|
|
9666
|
+
|
|
9667
|
+
__exports.MICROPDF417_VARIANTS = MICROPDF417_VARIANTS;
|
|
9668
|
+
__exports.microPdf417NextRap = microPdf417NextRap;
|
|
9669
|
+
__exports.microPdf417VariantByNumber = microPdf417VariantByNumber;
|
|
9670
|
+
__exports.microPdf417VariantForCapacity = microPdf417VariantForCapacity;
|
|
9671
|
+
__exports.microPdf417RapSequence = microPdf417RapSequence;
|
|
9672
|
+
__exports.microPdf417RowAddress = microPdf417RowAddress;
|
|
9673
|
+
__exports.validateMicroPdf417Tables = validateMicroPdf417Tables;
|
|
9674
|
+
};
|
|
9675
|
+
|
|
9676
|
+
__modules["micropdf417/error-correction.js"] = function (__require, __exports) {
|
|
9677
|
+
/** MicroPDF417 error correction over the existing GF(929) core. @module micropdf417/error-correction */
|
|
9678
|
+
const { EncodeError } = __require("core/errors.js");
|
|
9679
|
+
const { GF929 } = __require("core/galois-field.js");
|
|
9680
|
+
const { generatorPoly, rsDecode, rsEncode } = __require("core/reed-solomon.js");
|
|
9681
|
+
|
|
9682
|
+
function eccLength(entry) {
|
|
9683
|
+
if (!entry || !Number.isInteger(entry.eccCodewords)) throw new EncodeError('MicroPDF417: a variant with an ECC length is required');
|
|
9684
|
+
if (entry.eccCodewords < 1 || entry.eccCodewords >= GF929.size) throw new EncodeError('MicroPDF417: ECC length is outside GF(929) bounds');
|
|
9685
|
+
return entry.eccCodewords;
|
|
9686
|
+
}
|
|
9687
|
+
|
|
9688
|
+
/** Return the fixed number of parity codewords for a MicroPDF417 variant. */
|
|
9689
|
+
function microPdf417EccLength(entry) { return eccLength(entry); }
|
|
9690
|
+
|
|
9691
|
+
/** Build the MicroPDF417 generator polynomial for a variant's fixed ECC length. */
|
|
9692
|
+
function microPdf417Generator(entry) { return generatorPoly(eccLength(entry), GF929, 1); }
|
|
9693
|
+
|
|
9694
|
+
/** Compute systematic MicroPDF417 parity codewords. `data` must already include padding. */
|
|
9695
|
+
function microPdf417ErrorCorrection(data, entry) { return rsEncode(data, eccLength(entry), GF929, 1); }
|
|
9696
|
+
|
|
9697
|
+
/** Correct a complete MicroPDF417 codeword stream, optionally marking erasures. */
|
|
9698
|
+
function microPdf417CorrectErrors(codewords, entry, erasures = []) {
|
|
9699
|
+
return rsDecode(codewords, eccLength(entry), GF929, 1, erasures);
|
|
9700
|
+
}
|
|
9701
|
+
|
|
9702
|
+
__exports.microPdf417EccLength = microPdf417EccLength;
|
|
9703
|
+
__exports.microPdf417Generator = microPdf417Generator;
|
|
9704
|
+
__exports.microPdf417ErrorCorrection = microPdf417ErrorCorrection;
|
|
9705
|
+
__exports.microPdf417CorrectErrors = microPdf417CorrectErrors;
|
|
9706
|
+
};
|
|
9707
|
+
|
|
9708
|
+
__modules["micropdf417/compaction.js"] = function (__require, __exports) {
|
|
9709
|
+
/** MicroPDF417 high-level compaction adapter. @module micropdf417/compaction */
|
|
9710
|
+
const { EncodeError } = __require("core/errors.js");
|
|
9711
|
+
const { compactPdf417Bytes, compactPdf417Numeric, compactPdf417Text } = __require("pdf417/compaction.js");
|
|
9712
|
+
|
|
9713
|
+
function byteLength(value) {
|
|
9714
|
+
if (value instanceof Uint8Array) return value.byteLength;
|
|
9715
|
+
if (ArrayBuffer.isView(value)) return value.byteLength;
|
|
9716
|
+
return -1;
|
|
9717
|
+
}
|
|
9718
|
+
|
|
9719
|
+
function assertNotEmpty(value) {
|
|
9720
|
+
if ((typeof value === 'string' && value.length === 0) || byteLength(value) === 0) {
|
|
9721
|
+
throw new EncodeError('MicroPDF417: value must not be empty');
|
|
9722
|
+
}
|
|
9723
|
+
}
|
|
9724
|
+
|
|
9725
|
+
function latin1Bytes(value) {
|
|
9726
|
+
if (typeof value !== 'string') return value;
|
|
9727
|
+
const bytes = [];
|
|
9728
|
+
for (const character of value) {
|
|
9729
|
+
const codePoint = character.codePointAt(0);
|
|
9730
|
+
if (codePoint > 255) {
|
|
9731
|
+
throw new EncodeError('MicroPDF417 ECI 3: string contains a character outside ISO-8859-1');
|
|
9732
|
+
}
|
|
9733
|
+
bytes.push(codePoint);
|
|
9734
|
+
}
|
|
9735
|
+
return Uint8Array.from(bytes);
|
|
9736
|
+
}
|
|
9737
|
+
|
|
9738
|
+
function compactByte(value, eci) {
|
|
9739
|
+
if (eci === undefined) return compactPdf417Bytes(value);
|
|
9740
|
+
if (eci === 3) return compactPdf417Bytes(latin1Bytes(value));
|
|
9741
|
+
if (eci === 26) {
|
|
9742
|
+
if (typeof value !== 'string') {
|
|
9743
|
+
throw new EncodeError('MicroPDF417 ECI 26: value must be a string so UTF-8 validity is known');
|
|
9744
|
+
}
|
|
9745
|
+
const encoded = compactPdf417Bytes(value);
|
|
9746
|
+
return encoded[0] === 927 && encoded[1] === 26 ? encoded : [927, 26, ...encoded];
|
|
9747
|
+
}
|
|
9748
|
+
throw new EncodeError('MicroPDF417: supported ECI assignment numbers are 3 and 26');
|
|
9749
|
+
}
|
|
9750
|
+
|
|
9751
|
+
/**
|
|
9752
|
+
* Compact one MicroPDF417 value.
|
|
9753
|
+
*
|
|
9754
|
+
* Unlike PDF417, MicroPDF417 starts in Byte Compaction. Text therefore needs
|
|
9755
|
+
* an explicit 900 latch. Byte compaction always emits 901 or 924 so its start
|
|
9756
|
+
* state is unambiguous, including when an ECI designator precedes it.
|
|
9757
|
+
*/
|
|
9758
|
+
function compactMicroPDF417(value, options = {}) {
|
|
9759
|
+
assertNotEmpty(value);
|
|
9760
|
+
const mode = options.compaction ?? 'auto';
|
|
9761
|
+
const eci = options.eci;
|
|
9762
|
+
if (eci !== undefined && eci !== 3 && eci !== 26) {
|
|
9763
|
+
throw new EncodeError('MicroPDF417: supported ECI assignment numbers are 3 and 26');
|
|
9764
|
+
}
|
|
9765
|
+
|
|
9766
|
+
if (mode === 'text') {
|
|
9767
|
+
if (eci !== undefined) throw new EncodeError('MicroPDF417: explicit ECI is supported only with byte compaction');
|
|
9768
|
+
return [900, ...compactPdf417Text(value)];
|
|
9769
|
+
}
|
|
9770
|
+
if (mode === 'numeric') {
|
|
9771
|
+
if (eci !== undefined) throw new EncodeError('MicroPDF417: explicit ECI is supported only with byte compaction');
|
|
9772
|
+
return compactPdf417Numeric(value);
|
|
9773
|
+
}
|
|
9774
|
+
if (mode === 'byte') return compactByte(value, eci);
|
|
9775
|
+
if (mode !== 'auto') {
|
|
9776
|
+
throw new EncodeError(`MicroPDF417: unsupported compaction mode ${JSON.stringify(mode)}`);
|
|
9777
|
+
}
|
|
9778
|
+
|
|
9779
|
+
if (eci !== undefined) return compactByte(value, eci);
|
|
9780
|
+
if (typeof value === 'string' && /^\d{13,}$/.test(value)) return compactPdf417Numeric(value);
|
|
9781
|
+
if (typeof value === 'string') {
|
|
9782
|
+
try {
|
|
9783
|
+
return [900, ...compactPdf417Text(value)];
|
|
9784
|
+
} catch (error) {
|
|
9785
|
+
if (!(error instanceof EncodeError)) throw error;
|
|
9786
|
+
}
|
|
9787
|
+
}
|
|
9788
|
+
return compactPdf417Bytes(value);
|
|
9789
|
+
}
|
|
9790
|
+
|
|
9791
|
+
__exports.compactMicroPDF417 = compactMicroPDF417;
|
|
9792
|
+
};
|
|
9793
|
+
|
|
9794
|
+
__modules["micropdf417/encoder.js"] = function (__require, __exports) {
|
|
9795
|
+
/** MicroPDF417 encoder. @module micropdf417/encoder */
|
|
9796
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
9797
|
+
const { EncodeError } = __require("core/errors.js");
|
|
9798
|
+
const { pdf417PatternForCodeword } = __require("pdf417/tables.js");
|
|
9799
|
+
const { compactMicroPDF417 } = __require("micropdf417/compaction.js");
|
|
9800
|
+
const { microPdf417ErrorCorrection } = __require("micropdf417/error-correction.js");
|
|
9801
|
+
const { MICROPDF417_VARIANTS, microPdf417RapSequence, microPdf417RowAddress, microPdf417VariantByNumber, microPdf417VariantForCapacity } = __require("micropdf417/tables.js");
|
|
9802
|
+
|
|
9803
|
+
function appendWidths(matrix, y, x, sequence, height) {
|
|
9804
|
+
let dark = true;
|
|
9805
|
+
for (const digit of sequence) {
|
|
9806
|
+
const width = digit.charCodeAt(0) - 48;
|
|
9807
|
+
if (!Number.isInteger(width) || width < 1 || width > 6) {
|
|
9808
|
+
throw new EncodeError('MicroPDF417: invalid module-width sequence');
|
|
9809
|
+
}
|
|
9810
|
+
if (dark) matrix.setRegion(x, y, width, height);
|
|
9811
|
+
x += width;
|
|
9812
|
+
dark = !dark;
|
|
9813
|
+
}
|
|
9814
|
+
return x;
|
|
9815
|
+
}
|
|
9816
|
+
|
|
9817
|
+
function codewordSequence(codeword, cluster) {
|
|
9818
|
+
return pdf417PatternForCodeword(codeword, cluster)
|
|
9819
|
+
.toString(2)
|
|
9820
|
+
.padStart(17, '0')
|
|
9821
|
+
.replace(/0+|1+/g, (run) => String(run.length));
|
|
9822
|
+
}
|
|
9823
|
+
|
|
9824
|
+
function symbolWidth(columns) {
|
|
9825
|
+
return 21 + columns * 17 + (columns > 2 ? 10 : 0);
|
|
9826
|
+
}
|
|
9827
|
+
|
|
9828
|
+
function validateOptions(options) {
|
|
9829
|
+
const rowHeight = options.rowHeight ?? 2;
|
|
9830
|
+
if (!Number.isInteger(rowHeight) || rowHeight < 2) {
|
|
9831
|
+
throw new EncodeError('MicroPDF417: rowHeight must be an integer of at least 2');
|
|
9832
|
+
}
|
|
9833
|
+
if (options.columns !== undefined &&
|
|
9834
|
+
(!Number.isInteger(options.columns) || options.columns < 1 || options.columns > 4)) {
|
|
9835
|
+
throw new EncodeError('MicroPDF417: columns must be an integer in 1..4');
|
|
9836
|
+
}
|
|
9837
|
+
if (options.variant !== undefined &&
|
|
9838
|
+
(!Number.isInteger(options.variant) || options.variant < 1 || options.variant > 34)) {
|
|
9839
|
+
throw new EncodeError('MicroPDF417: variant must be an integer in 1..34');
|
|
9840
|
+
}
|
|
9841
|
+
if (options.aspectRatio !== undefined &&
|
|
9842
|
+
(!Number.isFinite(options.aspectRatio) || options.aspectRatio <= 0)) {
|
|
9843
|
+
throw new EncodeError('MicroPDF417: aspectRatio must be positive');
|
|
9844
|
+
}
|
|
9845
|
+
if (options.rows !== undefined) {
|
|
9846
|
+
throw new EncodeError('MicroPDF417: rows are fixed by the selected variant');
|
|
9847
|
+
}
|
|
9848
|
+
if (options.eccLevel !== undefined) {
|
|
9849
|
+
throw new EncodeError('MicroPDF417: error correction is fixed by the selected variant');
|
|
9850
|
+
}
|
|
9851
|
+
for (const feature of [
|
|
9852
|
+
'structuredAppend', 'macro', 'macroPdf417', 'macroControlBlock',
|
|
9853
|
+
'readerInit', 'gs1', 'hibc', 'linkage',
|
|
9854
|
+
]) {
|
|
9855
|
+
if (options[feature] !== undefined) {
|
|
9856
|
+
throw new EncodeError(`MicroPDF417: ${feature} is not implemented`);
|
|
9857
|
+
}
|
|
9858
|
+
}
|
|
9859
|
+
return rowHeight;
|
|
9860
|
+
}
|
|
9861
|
+
|
|
9862
|
+
function chooseVariant(codewordCount, rowHeight, options) {
|
|
9863
|
+
if (options.variant !== undefined) {
|
|
9864
|
+
const variant = microPdf417VariantByNumber(options.variant);
|
|
9865
|
+
if (!variant) throw new EncodeError(`MicroPDF417: unknown variant ${options.variant}`);
|
|
9866
|
+
if (options.columns !== undefined && variant.columns !== options.columns) {
|
|
9867
|
+
throw new EncodeError(`MicroPDF417: variant ${variant.id} has ${variant.columns} columns`);
|
|
9868
|
+
}
|
|
9869
|
+
if (codewordCount > variant.dataCodewords) {
|
|
9870
|
+
throw new EncodeError(
|
|
9871
|
+
`MicroPDF417: payload requires ${codewordCount} data codewords, variant ${variant.id} holds ${variant.dataCodewords}`
|
|
9872
|
+
);
|
|
9873
|
+
}
|
|
9874
|
+
return variant;
|
|
9875
|
+
}
|
|
9876
|
+
|
|
9877
|
+
if (options.columns === undefined && options.aspectRatio === undefined) {
|
|
9878
|
+
try {
|
|
9879
|
+
return microPdf417VariantForCapacity(codewordCount);
|
|
9880
|
+
} catch (error) {
|
|
9881
|
+
if (!(error instanceof RangeError)) throw error;
|
|
9882
|
+
throw new EncodeError(`MicroPDF417: payload requires ${codewordCount} data codewords and exceeds every variant`);
|
|
9883
|
+
}
|
|
9884
|
+
}
|
|
9885
|
+
|
|
9886
|
+
const candidates = MICROPDF417_VARIANTS.filter((variant) =>
|
|
9887
|
+
variant.dataCodewords >= codewordCount &&
|
|
9888
|
+
(options.columns === undefined || variant.columns === options.columns)
|
|
9889
|
+
);
|
|
9890
|
+
if (!candidates.length) {
|
|
9891
|
+
const columnText = options.columns === undefined ? '' : ` with ${options.columns} columns`;
|
|
9892
|
+
throw new EncodeError(`MicroPDF417: payload does not fit any supported variant${columnText}`);
|
|
9893
|
+
}
|
|
9894
|
+
if (options.aspectRatio === undefined) {
|
|
9895
|
+
return candidates.reduce((best, variant) =>
|
|
9896
|
+
variant.dataCodewords < best.dataCodewords ||
|
|
9897
|
+
(variant.dataCodewords === best.dataCodewords && variant.totalCodewords < best.totalCodewords)
|
|
9898
|
+
? variant : best
|
|
9899
|
+
);
|
|
9900
|
+
}
|
|
9901
|
+
|
|
9902
|
+
const target = options.aspectRatio;
|
|
9903
|
+
return candidates.reduce((best, variant) => {
|
|
9904
|
+
const ratio = symbolWidth(variant.columns) / (variant.rows * rowHeight);
|
|
9905
|
+
const score = Math.abs(Math.log(ratio / target)) +
|
|
9906
|
+
(variant.dataCodewords - codewordCount) / 10000;
|
|
9907
|
+
return !best || score < best.score ? { variant, score } : best;
|
|
9908
|
+
}, null).variant;
|
|
9909
|
+
}
|
|
9910
|
+
|
|
9911
|
+
/** Encode a value as one of the 34 fixed MicroPDF417 variants. */
|
|
9912
|
+
function encodeMicroPDF417(value, options = {}) {
|
|
9913
|
+
const rowHeight = validateOptions(options);
|
|
9914
|
+
const payload = compactMicroPDF417(value, options);
|
|
9915
|
+
const variant = chooseVariant(payload.length, rowHeight, options);
|
|
9916
|
+
const data = payload.slice();
|
|
9917
|
+
while (data.length < variant.dataCodewords) data.push(900);
|
|
9918
|
+
const ecc = microPdf417ErrorCorrection(data, variant);
|
|
9919
|
+
if (ecc.length !== variant.eccCodewords) {
|
|
9920
|
+
throw new EncodeError('MicroPDF417: error-correction length does not match the selected variant');
|
|
9921
|
+
}
|
|
9922
|
+
const codewords = data.concat(ecc);
|
|
9923
|
+
if (codewords.length !== variant.totalCodewords || codewords.length !== variant.rows * variant.columns) {
|
|
9924
|
+
throw new EncodeError('MicroPDF417: selected variant has inconsistent codeword dimensions');
|
|
9925
|
+
}
|
|
9926
|
+
|
|
9927
|
+
const matrix = new BitMatrix(symbolWidth(variant.columns), variant.rows * rowHeight);
|
|
9928
|
+
for (let row = 0; row < variant.rows; row++) {
|
|
9929
|
+
const y = row * rowHeight;
|
|
9930
|
+
const address = microPdf417RowAddress(variant, row);
|
|
9931
|
+
let x = appendWidths(matrix, y, 0, microPdf417RapSequence(address.left, 'side'), rowHeight);
|
|
9932
|
+
for (let column = 0; column < variant.columns; column++) {
|
|
9933
|
+
x = appendWidths(
|
|
9934
|
+
matrix,
|
|
9935
|
+
y,
|
|
9936
|
+
x,
|
|
9937
|
+
codewordSequence(codewords[row * variant.columns + column], address.cluster),
|
|
9938
|
+
rowHeight
|
|
9939
|
+
);
|
|
9940
|
+
const hasCentralRap = (variant.columns === 3 && column === 0) ||
|
|
9941
|
+
(variant.columns === 4 && column === 1);
|
|
9942
|
+
if (hasCentralRap) {
|
|
9943
|
+
if (address.center === null) {
|
|
9944
|
+
throw new EncodeError('MicroPDF417: selected variant is missing its centre row address');
|
|
9945
|
+
}
|
|
9946
|
+
x = appendWidths(matrix, y, x, microPdf417RapSequence(address.center, 'center'), rowHeight);
|
|
9947
|
+
}
|
|
9948
|
+
}
|
|
9949
|
+
x = appendWidths(matrix, y, x, microPdf417RapSequence(address.right, 'side'), rowHeight);
|
|
9950
|
+
matrix.setRegion(x, y, 1, rowHeight);
|
|
9951
|
+
x++;
|
|
9952
|
+
if (x !== matrix.width) throw new EncodeError('MicroPDF417: row width does not match the selected variant');
|
|
9953
|
+
}
|
|
9954
|
+
|
|
9955
|
+
matrix.micropdf417 = {
|
|
9956
|
+
variant: variant.id,
|
|
9957
|
+
rows: variant.rows,
|
|
9958
|
+
columns: variant.columns,
|
|
9959
|
+
eccCodewords: variant.eccCodewords,
|
|
9960
|
+
rowHeight,
|
|
9961
|
+
payloadCodewords: payload.length,
|
|
9962
|
+
dataCodewords: data,
|
|
9963
|
+
codewords,
|
|
9964
|
+
};
|
|
9965
|
+
return matrix;
|
|
9966
|
+
}
|
|
9967
|
+
|
|
9968
|
+
__exports.encodeMicroPDF417 = encodeMicroPDF417;
|
|
9969
|
+
};
|
|
9970
|
+
|
|
9971
|
+
__modules["micropdf417/decoder.js"] = function (__require, __exports) {
|
|
9972
|
+
/**
|
|
9973
|
+
* Direct-module MicroPDF417 decoder.
|
|
9974
|
+
*
|
|
9975
|
+
* This module reads an already sampled, axis-aligned `BitMatrix`. Image finding,
|
|
9976
|
+
* perspective correction, and recognition from photographic pixels are deliberately
|
|
9977
|
+
* outside this first decoder boundary. The RAP sequence is authoritative for format
|
|
9978
|
+
* detection; matrix metadata is used only as an optional row-height hint.
|
|
9979
|
+
*
|
|
9980
|
+
* @module micropdf417/decoder
|
|
9981
|
+
*/
|
|
9982
|
+
const { FormatError } = __require("core/errors.js");
|
|
9983
|
+
const { decodePdf417CompactionDetailed } = __require("pdf417/compaction.js");
|
|
9984
|
+
const { pdf417CodewordForPattern } = __require("pdf417/tables.js");
|
|
9985
|
+
const { microPdf417CorrectErrors } = __require("micropdf417/error-correction.js");
|
|
9986
|
+
const { MICROPDF417_VARIANTS, microPdf417RapSequence, microPdf417RowAddress, microPdf417VariantByNumber } = __require("micropdf417/tables.js");
|
|
9987
|
+
|
|
9988
|
+
function symbolWidth(columns) {
|
|
9989
|
+
return 21 + columns * 17 + (columns > 2 ? 10 : 0);
|
|
9990
|
+
}
|
|
9991
|
+
|
|
9992
|
+
function bits(matrix, y, x, width) {
|
|
9993
|
+
let value = 0;
|
|
9994
|
+
for (let i = 0; i < width; i++) value = (value << 1) | (matrix.get(x + i, y) ? 1 : 0);
|
|
9995
|
+
return value;
|
|
9996
|
+
}
|
|
9997
|
+
|
|
9998
|
+
function widthsToBits(widths) {
|
|
9999
|
+
let dark = true;
|
|
10000
|
+
let out = '';
|
|
10001
|
+
for (const digit of widths) {
|
|
10002
|
+
out += (dark ? '1' : '0').repeat(digit.charCodeAt(0) - 48);
|
|
10003
|
+
dark = !dark;
|
|
10004
|
+
}
|
|
10005
|
+
return out;
|
|
10006
|
+
}
|
|
10007
|
+
|
|
10008
|
+
function hasExpectedBits(matrix, y, x, sequence) {
|
|
10009
|
+
const expected = widthsToBits(sequence);
|
|
10010
|
+
for (let i = 0; i < expected.length; i++) {
|
|
10011
|
+
if ((matrix.get(x + i, y) ? '1' : '0') !== expected[i]) return false;
|
|
10012
|
+
}
|
|
10013
|
+
return true;
|
|
10014
|
+
}
|
|
10015
|
+
|
|
10016
|
+
function centralRapAfter(entry, column) {
|
|
10017
|
+
return (entry.columns === 3 && column === 0) ||
|
|
10018
|
+
(entry.columns === 4 && column === 1);
|
|
10019
|
+
}
|
|
10020
|
+
|
|
10021
|
+
/** Return true when all address patterns for this format candidate agree. */
|
|
10022
|
+
function hasValidRowAddresses(matrix, entry, rowHeight) {
|
|
10023
|
+
for (let row = 0; row < entry.rows; row++) {
|
|
10024
|
+
const y = row * rowHeight;
|
|
10025
|
+
const address = microPdf417RowAddress(entry, row);
|
|
10026
|
+
let x = 0;
|
|
10027
|
+
if (!hasExpectedBits(matrix, y, x, microPdf417RapSequence(address.left, 'side'))) return false;
|
|
10028
|
+
x += 10;
|
|
10029
|
+
for (let column = 0; column < entry.columns; column++) {
|
|
10030
|
+
x += 17;
|
|
10031
|
+
if (centralRapAfter(entry, column)) {
|
|
10032
|
+
if (address.center === null ||
|
|
10033
|
+
!hasExpectedBits(matrix, y, x, microPdf417RapSequence(address.center, 'center'))) return false;
|
|
10034
|
+
x += 10;
|
|
10035
|
+
}
|
|
10036
|
+
}
|
|
10037
|
+
if (!hasExpectedBits(matrix, y, x, microPdf417RapSequence(address.right, 'side'))) return false;
|
|
10038
|
+
x += 10;
|
|
10039
|
+
if (!matrix.get(x, y) || x + 1 !== matrix.width) return false;
|
|
10040
|
+
}
|
|
10041
|
+
return true;
|
|
10042
|
+
}
|
|
10043
|
+
|
|
10044
|
+
function candidateFormats(matrix, options) {
|
|
10045
|
+
const metadataHeight = matrix.micropdf417?.rowHeight;
|
|
10046
|
+
const requestedHeight = options.rowHeight ?? metadataHeight;
|
|
10047
|
+
if (requestedHeight !== undefined && (!Number.isInteger(requestedHeight) || requestedHeight < 1)) {
|
|
10048
|
+
throw new FormatError('MicroPDF417: rowHeight must be a positive integer');
|
|
10049
|
+
}
|
|
10050
|
+
const requestedVariant = options.variant === undefined ? null : microPdf417VariantByNumber(options.variant);
|
|
10051
|
+
const pool = requestedVariant ? [requestedVariant] : MICROPDF417_VARIANTS;
|
|
10052
|
+
const candidates = [];
|
|
10053
|
+
for (const entry of pool) {
|
|
10054
|
+
if (matrix.width !== symbolWidth(entry.columns)) continue;
|
|
10055
|
+
if (matrix.height % entry.rows) continue;
|
|
10056
|
+
const rowHeight = matrix.height / entry.rows;
|
|
10057
|
+
if (requestedHeight !== undefined && rowHeight !== requestedHeight) continue;
|
|
10058
|
+
if (hasValidRowAddresses(matrix, entry, rowHeight)) candidates.push({ entry, rowHeight });
|
|
10059
|
+
}
|
|
10060
|
+
return candidates;
|
|
10061
|
+
}
|
|
10062
|
+
|
|
10063
|
+
function resolveFormat(matrix, options) {
|
|
10064
|
+
if (!matrix?.width || !matrix?.height || typeof matrix.get !== 'function') {
|
|
10065
|
+
throw new FormatError('MicroPDF417: matrix with width, height and get() is required');
|
|
10066
|
+
}
|
|
10067
|
+
const candidates = candidateFormats(matrix, options);
|
|
10068
|
+
if (!candidates.length) throw new FormatError('MicroPDF417: no variant matches matrix geometry and row-address patterns');
|
|
10069
|
+
if (candidates.length > 1) throw new FormatError('MicroPDF417: row-address patterns do not identify a unique variant');
|
|
10070
|
+
return candidates[0];
|
|
10071
|
+
}
|
|
10072
|
+
|
|
10073
|
+
function readCodewords(matrix, entry, rowHeight) {
|
|
10074
|
+
const codewords = [];
|
|
10075
|
+
const erasures = [];
|
|
10076
|
+
for (let row = 0; row < entry.rows; row++) {
|
|
10077
|
+
const y = row * rowHeight;
|
|
10078
|
+
const address = microPdf417RowAddress(entry, row);
|
|
10079
|
+
let x = 10;
|
|
10080
|
+
for (let column = 0; column < entry.columns; column++) {
|
|
10081
|
+
const decoded = pdf417CodewordForPattern(bits(matrix, y, x, 17));
|
|
10082
|
+
if (!decoded || decoded.cluster !== address.cluster) {
|
|
10083
|
+
erasures.push(codewords.length);
|
|
10084
|
+
codewords.push(0);
|
|
10085
|
+
} else {
|
|
10086
|
+
codewords.push(decoded.codeword);
|
|
10087
|
+
}
|
|
10088
|
+
x += 17;
|
|
10089
|
+
if (centralRapAfter(entry, column)) x += 10;
|
|
10090
|
+
}
|
|
10091
|
+
}
|
|
10092
|
+
return { codewords, erasures };
|
|
10093
|
+
}
|
|
10094
|
+
|
|
10095
|
+
/**
|
|
10096
|
+
* Decode a sampled MicroPDF417 matrix.
|
|
10097
|
+
*
|
|
10098
|
+
* The complete fixed data region is compacted after correction. Encoder padding
|
|
10099
|
+
* is PDF417 Text latch 900, which contributes no characters at the end of the
|
|
10100
|
+
* payload. This avoids relying on non-symbol metadata for payload length.
|
|
10101
|
+
*/
|
|
10102
|
+
function decodeMicroPDF417(matrix, options = {}) {
|
|
10103
|
+
const { entry, rowHeight } = resolveFormat(matrix, options);
|
|
10104
|
+
const { codewords, erasures } = readCodewords(matrix, entry, rowHeight);
|
|
10105
|
+
const corrections = microPdf417CorrectErrors(codewords, entry, erasures);
|
|
10106
|
+
const data = codewords.slice(0, entry.dataCodewords);
|
|
10107
|
+
const decoded = decodePdf417CompactionDetailed(data);
|
|
10108
|
+
return {
|
|
10109
|
+
...decoded,
|
|
10110
|
+
codewords,
|
|
10111
|
+
rows: entry.rows,
|
|
10112
|
+
columns: entry.columns,
|
|
10113
|
+
variant: entry.id,
|
|
10114
|
+
eccCodewords: entry.eccCodewords,
|
|
10115
|
+
rowHeight,
|
|
10116
|
+
corrections,
|
|
10117
|
+
};
|
|
10118
|
+
}
|
|
10119
|
+
|
|
10120
|
+
__exports.decodeMicroPDF417 = decodeMicroPDF417;
|
|
10121
|
+
};
|
|
10122
|
+
|
|
10123
|
+
__modules["micropdf417/detector.js"] = function (__require, __exports) {
|
|
10124
|
+
/**
|
|
10125
|
+
* Axis-aligned MicroPDF417 raster detection.
|
|
10126
|
+
*
|
|
10127
|
+
* A MicroPDF417 symbol has a fixed module width for each column count and a
|
|
10128
|
+
* dark leading and trailing module in every row. Consequently the bounding
|
|
10129
|
+
* rectangle of dark pixels identifies the complete symbol even when a light
|
|
10130
|
+
* quiet zone surrounds it. Its width determines the integer raster scale;
|
|
10131
|
+
* the existing direct-module decoder then verifies every row-address pattern
|
|
10132
|
+
* and selects the exact variant. This is intentionally narrower than the
|
|
10133
|
+
* PDF417 photo detector: it handles clean binarized rasters only, not skew or
|
|
10134
|
+
* projective camera images.
|
|
10135
|
+
*
|
|
10136
|
+
* @module micropdf417/detector
|
|
10137
|
+
*/
|
|
10138
|
+
const { BitMatrix } = __require("core/bit-matrix.js");
|
|
10139
|
+
const { decodeMicroPDF417 } = __require("micropdf417/decoder.js");
|
|
10140
|
+
|
|
10141
|
+
/** @typedef {{x:number, y:number}} Point */
|
|
10142
|
+
|
|
10143
|
+
// Each row has two 10-module side RAPs, a final separator, and 17 modules for
|
|
10144
|
+
// each data column. Three and four columns also contain one central RAP.
|
|
10145
|
+
function symbolWidth(columns) { return 21 + columns * 17 + (columns > 2 ? 10 : 0); }
|
|
10146
|
+
const WIDTHS = [1, 2, 3, 4].map(symbolWidth);
|
|
10147
|
+
|
|
10148
|
+
function rotateClockwise(source) {
|
|
10149
|
+
const rotated = new BitMatrix(source.height, source.width);
|
|
10150
|
+
for (let y = 0; y < source.height; y++) for (let x = 0; x < source.width; x++) {
|
|
10151
|
+
if (source.get(x, y)) rotated.set(source.height - 1 - y, x);
|
|
10152
|
+
}
|
|
10153
|
+
return rotated;
|
|
10154
|
+
}
|
|
10155
|
+
|
|
10156
|
+
function integerScale(width, modules) {
|
|
10157
|
+
if (width % modules) return 0;
|
|
10158
|
+
const scale = width / modules;
|
|
10159
|
+
return Number.isInteger(scale) && scale > 0 ? scale : 0;
|
|
10160
|
+
}
|
|
10161
|
+
|
|
10162
|
+
/** Collapse exact integer scale blocks using a majority vote. */
|
|
10163
|
+
function sampleRaster(image, bounds, modulesWide, scale) {
|
|
10164
|
+
const modulesHigh = bounds.height / scale;
|
|
10165
|
+
if (!Number.isInteger(modulesHigh) || modulesHigh < 1) return null;
|
|
10166
|
+
const matrix = new BitMatrix(modulesWide, modulesHigh);
|
|
10167
|
+
for (let y = 0; y < modulesHigh; y++) for (let x = 0; x < modulesWide; x++) {
|
|
10168
|
+
let dark = 0;
|
|
10169
|
+
for (let py = 0; py < scale; py++) for (let px = 0; px < scale; px++) {
|
|
10170
|
+
if (image.get(bounds.x + x * scale + px, bounds.y + y * scale + py)) dark++;
|
|
10171
|
+
}
|
|
10172
|
+
if (dark * 2 >= scale * scale) matrix.set(x, y);
|
|
10173
|
+
}
|
|
10174
|
+
return matrix;
|
|
10175
|
+
}
|
|
10176
|
+
|
|
10177
|
+
function rectangle(bounds) {
|
|
10178
|
+
return [
|
|
10179
|
+
{ x: bounds.x, y: bounds.y },
|
|
10180
|
+
{ x: bounds.x + bounds.width, y: bounds.y },
|
|
10181
|
+
{ x: bounds.x + bounds.width, y: bounds.y + bounds.height },
|
|
10182
|
+
{ x: bounds.x, y: bounds.y + bounds.height },
|
|
10183
|
+
];
|
|
10184
|
+
}
|
|
10185
|
+
|
|
10186
|
+
function detectAxisAligned(image, options) {
|
|
10187
|
+
const bounds = image.getBounds();
|
|
10188
|
+
if (!bounds) return null;
|
|
10189
|
+
for (const width of WIDTHS) {
|
|
10190
|
+
const scale = integerScale(bounds.width, width);
|
|
10191
|
+
if (!scale || bounds.height % scale) continue;
|
|
10192
|
+
const matrix = sampleRaster(image, bounds, width, scale);
|
|
10193
|
+
if (!matrix) continue;
|
|
10194
|
+
try {
|
|
10195
|
+
const decoded = decodeMicroPDF417(matrix, options);
|
|
10196
|
+
return { matrix, corners: rectangle(bounds), moduleSize: scale, ...decoded };
|
|
10197
|
+
} catch { /* The RAP sequence is not a MicroPDF417 symbol of this width. */ }
|
|
10198
|
+
}
|
|
10199
|
+
return null;
|
|
10200
|
+
}
|
|
10201
|
+
|
|
10202
|
+
/**
|
|
10203
|
+
* Detect and decode one clean, binarized MicroPDF417 raster.
|
|
10204
|
+
*
|
|
10205
|
+
* Integer upscaling and quiet zones are accepted. The image is retried at all
|
|
10206
|
+
* quarter-turns, but arbitrary angles and perspective require caller-side
|
|
10207
|
+
* rectification before this function is used. `rotation` reports the clockwise
|
|
10208
|
+
* orientation of the supplied input relative to a normally oriented symbol;
|
|
10209
|
+
* it is not the inverse correction applied internally while searching.
|
|
10210
|
+
*
|
|
10211
|
+
* @param {import('../core/bit-matrix.js').BitMatrix} binaryImage Set bit = dark.
|
|
10212
|
+
* @param {object} [options] Passed to {@link decodeMicroPDF417}.
|
|
10213
|
+
* @returns {(ReturnType<typeof decodeMicroPDF417> & {matrix: BitMatrix, corners: Point[], moduleSize: number, rotation: number}) | null}
|
|
10214
|
+
*/
|
|
10215
|
+
function detectMicroPDF417(binaryImage, options = {}) {
|
|
10216
|
+
if (!binaryImage?.width || !binaryImage?.height || typeof binaryImage.get !== 'function') return null;
|
|
10217
|
+
let oriented = binaryImage;
|
|
10218
|
+
let toOriginal = (point) => ({ x: point.x, y: point.y });
|
|
10219
|
+
for (let turns = 0; turns < 4; turns++) {
|
|
10220
|
+
const found = detectAxisAligned(oriented, options);
|
|
10221
|
+
// Search rotates clockwise to normalize the input. Public rotation has the
|
|
10222
|
+
// opposite meaning: it describes how the input itself was rotated.
|
|
10223
|
+
if (found) return {
|
|
10224
|
+
...found,
|
|
10225
|
+
rotation: (360 - turns * 90) % 360,
|
|
10226
|
+
corners: found.corners.map(toOriginal),
|
|
10227
|
+
};
|
|
10228
|
+
const previous = oriented;
|
|
10229
|
+
const previousToOriginal = toOriginal;
|
|
10230
|
+
oriented = rotateClockwise(previous);
|
|
10231
|
+
// Boundary coordinates (rather than just pixel centres) are transformed
|
|
10232
|
+
// here, so callers can draw the returned rectangle directly on the input.
|
|
10233
|
+
toOriginal = (point) => previousToOriginal({ x: point.y, y: previous.height - point.x });
|
|
10234
|
+
}
|
|
10235
|
+
return null;
|
|
10236
|
+
}
|
|
10237
|
+
|
|
10238
|
+
/** Alias kept symmetric with the other 2D readers. */
|
|
10239
|
+
function detectAndDecodeMicroPDF417(binaryImage, options = {}) {
|
|
10240
|
+
return detectMicroPDF417(binaryImage, options);
|
|
10241
|
+
}
|
|
10242
|
+
|
|
10243
|
+
__exports.detectMicroPDF417 = detectMicroPDF417;
|
|
10244
|
+
__exports.detectAndDecodeMicroPDF417 = detectAndDecodeMicroPDF417;
|
|
10245
|
+
};
|
|
10246
|
+
|
|
10247
|
+
__modules["micropdf417/index.js"] = function (__require, __exports) {
|
|
10248
|
+
const __reexport0 = __require("micropdf417/tables.js"); __exports.MICROPDF417_VARIANTS = __reexport0.MICROPDF417_VARIANTS; __exports.microPdf417NextRap = __reexport0.microPdf417NextRap; __exports.microPdf417VariantByNumber = __reexport0.microPdf417VariantByNumber; __exports.microPdf417VariantForCapacity = __reexport0.microPdf417VariantForCapacity; __exports.microPdf417RapSequence = __reexport0.microPdf417RapSequence; __exports.microPdf417RowAddress = __reexport0.microPdf417RowAddress; __exports.validateMicroPdf417Tables = __reexport0.validateMicroPdf417Tables;
|
|
10249
|
+
const __reexport1 = __require("micropdf417/error-correction.js"); __exports.microPdf417EccLength = __reexport1.microPdf417EccLength; __exports.microPdf417Generator = __reexport1.microPdf417Generator; __exports.microPdf417ErrorCorrection = __reexport1.microPdf417ErrorCorrection; __exports.microPdf417CorrectErrors = __reexport1.microPdf417CorrectErrors;
|
|
10250
|
+
const __reexport2 = __require("micropdf417/compaction.js"); __exports.compactMicroPDF417 = __reexport2.compactMicroPDF417;
|
|
10251
|
+
const __reexport3 = __require("micropdf417/encoder.js"); __exports.encodeMicroPDF417 = __reexport3.encodeMicroPDF417;
|
|
10252
|
+
const __reexport4 = __require("micropdf417/decoder.js"); __exports.decodeMicroPDF417 = __reexport4.decodeMicroPDF417;
|
|
10253
|
+
const __reexport5 = __require("micropdf417/detector.js"); __exports.detectMicroPDF417 = __reexport5.detectMicroPDF417; __exports.detectAndDecodeMicroPDF417 = __reexport5.detectAndDecodeMicroPDF417;
|
|
10254
|
+
|
|
10255
|
+
|
|
8332
10256
|
};
|
|
8333
10257
|
|
|
8334
10258
|
__modules["render/options.js"] = function (__require, __exports) {
|
|
@@ -9587,6 +11511,8 @@ const { decodeOneD } = __require("oned/reader.js");
|
|
|
9587
11511
|
const datamatrix = __require("datamatrix/index.js");
|
|
9588
11512
|
const qr = __require("qr/index.js");
|
|
9589
11513
|
const aztec = __require("aztec/index.js");
|
|
11514
|
+
const pdf417 = __require("pdf417/index.js");
|
|
11515
|
+
const micropdf417 = __require("micropdf417/index.js");
|
|
9590
11516
|
__exports.BitMatrix = BitMatrix;
|
|
9591
11517
|
const __reexport0 = __require("core/errors.js"); __exports.BarcodeError = __reexport0.BarcodeError; __exports.EncodeError = __reexport0.EncodeError; __exports.NotFoundError = __reexport0.NotFoundError; __exports.FormatError = __reexport0.FormatError; __exports.ChecksumError = __reexport0.ChecksumError;
|
|
9592
11518
|
const __reexport1 = __require("image/luminance.js"); __exports.LuminanceSource = __reexport1.LuminanceSource;
|
|
@@ -9600,6 +11526,8 @@ const __reexport7 = __require("render/index.js"); __exports.renderToCanvasAutoAs
|
|
|
9600
11526
|
const __reexport8 = __require("qr/index.js"); __exports.encodeQR = __reexport8.encodeQR; __exports.decodeQR = __reexport8.decodeQR; __exports.detectQR = __reexport8.detectQR; __exports.detectAndDecodeQR = __reexport8.detectAndDecodeQR;
|
|
9601
11527
|
const __reexport9 = __require("datamatrix/index.js"); __exports.encodeDataMatrix = __reexport9.encodeDataMatrix; __exports.decodeDataMatrix = __reexport9.decodeDataMatrix; __exports.detectDataMatrix = __reexport9.detectDataMatrix; __exports.detectAndDecodeDataMatrix = __reexport9.detectAndDecodeDataMatrix;
|
|
9602
11528
|
const __reexport10 = __require("aztec/index.js"); __exports.encodeAztec = __reexport10.encodeAztec; __exports.decodeAztec = __reexport10.decodeAztec; __exports.detectAztec = __reexport10.detectAztec; __exports.detectAndDecodeAztec = __reexport10.detectAndDecodeAztec;
|
|
11529
|
+
const __reexport11 = __require("pdf417/index.js"); __exports.encodePDF417 = __reexport11.encodePDF417; __exports.decodePDF417 = __reexport11.decodePDF417; __exports.detectPDF417 = __reexport11.detectPDF417; __exports.detectAndDecodePDF417 = __reexport11.detectAndDecodePDF417;
|
|
11530
|
+
const __reexport12 = __require("micropdf417/index.js"); __exports.encodeMicroPDF417 = __reexport12.encodeMicroPDF417; __exports.decodeMicroPDF417 = __reexport12.decodeMicroPDF417; __exports.detectMicroPDF417 = __reexport12.detectMicroPDF417; __exports.detectAndDecodeMicroPDF417 = __reexport12.detectAndDecodeMicroPDF417;
|
|
9603
11531
|
|
|
9604
11532
|
/**
|
|
9605
11533
|
* @typedef {object} FormatInfo
|
|
@@ -9627,6 +11555,14 @@ const dataMatrixCanEncode = typeof datamatrix.encodeDataMatrix === 'function';
|
|
|
9627
11555
|
const dataMatrixCanDecode = typeof datamatrix.detectAndDecodeDataMatrix === 'function';
|
|
9628
11556
|
const aztecCanEncode = typeof aztec.encodeAztec === 'function';
|
|
9629
11557
|
const aztecCanDecode = typeof aztec.detectAndDecodeAztec === 'function';
|
|
11558
|
+
const pdf417CanEncode = typeof pdf417.encodePDF417 === 'function';
|
|
11559
|
+
// The matrix decoder is complete, but automatic image localization is still
|
|
11560
|
+
// limited to clean module-aligned symbols or an application-supplied
|
|
11561
|
+
// quadrilateral. Keep the generic scanner capability opt-in until a
|
|
11562
|
+
// perspective/noise corpus is passed.
|
|
11563
|
+
const pdf417CanDecode = typeof pdf417.detectAndDecodePDF417 === 'function';
|
|
11564
|
+
const microPdf417CanEncode = typeof micropdf417.encodeMicroPDF417 === 'function';
|
|
11565
|
+
const microPdf417CanDecode = typeof micropdf417.detectAndDecodeMicroPDF417 === 'function';
|
|
9630
11566
|
|
|
9631
11567
|
/**
|
|
9632
11568
|
* Every format this build supports.
|
|
@@ -9668,6 +11604,20 @@ function listFormats() {
|
|
|
9668
11604
|
canRead: aztecCanDecode,
|
|
9669
11605
|
kind: /** @type {'2D'} */ ('2D'),
|
|
9670
11606
|
});
|
|
11607
|
+
formats.push({
|
|
11608
|
+
id: 'pdf417',
|
|
11609
|
+
label: 'PDF417',
|
|
11610
|
+
canWrite: pdf417CanEncode,
|
|
11611
|
+
canRead: pdf417CanDecode,
|
|
11612
|
+
kind: /** @type {'2D'} */ ('2D'),
|
|
11613
|
+
});
|
|
11614
|
+
formats.push({
|
|
11615
|
+
id: 'micropdf417',
|
|
11616
|
+
label: 'MicroPDF417',
|
|
11617
|
+
canWrite: microPdf417CanEncode,
|
|
11618
|
+
canRead: microPdf417CanDecode,
|
|
11619
|
+
kind: /** @type {'2D'} */ ('2D'),
|
|
11620
|
+
});
|
|
9671
11621
|
|
|
9672
11622
|
return formats;
|
|
9673
11623
|
}
|
|
@@ -9691,6 +11641,13 @@ function listFormats() {
|
|
|
9691
11641
|
* @param {number} [options.layers] Aztec layer count; automatic if omitted.
|
|
9692
11642
|
* @param {boolean} [options.compact] Force an Aztec Compact or Full symbol.
|
|
9693
11643
|
* @param {number} [options.eccPercent] Requested Aztec error-correction percentage.
|
|
11644
|
+
* @param {number} [options.eccLevel] PDF417 error-correction level, 0-8.
|
|
11645
|
+
* @param {number} [options.columns] PDF417 columns, 1-30.
|
|
11646
|
+
* @param {number} [options.rows] PDF417 rows, 3-90.
|
|
11647
|
+
* @param {number} [options.rowHeight] PDF417 row height in modules.
|
|
11648
|
+
* @param {'auto'|'text'|'byte'|'numeric'} [options.compaction] PDF417 compaction mode.
|
|
11649
|
+
* @param {number} [options.eci] MicroPDF417 byte-compaction ECI assignment (3 or 26).
|
|
11650
|
+
* @param {number} [options.aspectRatio] Preferred MicroPDF417 symbol aspect ratio.
|
|
9694
11651
|
* @returns {BitMatrix}
|
|
9695
11652
|
*/
|
|
9696
11653
|
function encode(text, options = {}) {
|
|
@@ -9706,10 +11663,16 @@ function encode(text, options = {}) {
|
|
|
9706
11663
|
if (format === 'aztec' || format === 'aztec-code') {
|
|
9707
11664
|
return aztec.encodeAztec(value, options);
|
|
9708
11665
|
}
|
|
11666
|
+
if (format === 'pdf417' || format === 'pdf-417') {
|
|
11667
|
+
return pdf417.encodePDF417(value, options);
|
|
11668
|
+
}
|
|
11669
|
+
if (format === 'micropdf417' || format === 'micro-pdf417' || format === 'micro-pdf-417') {
|
|
11670
|
+
return micropdf417.encodeMicroPDF417(value, options);
|
|
11671
|
+
}
|
|
9709
11672
|
|
|
9710
11673
|
const entry = ONED_FORMATS[format];
|
|
9711
11674
|
if (!entry) {
|
|
9712
|
-
const known = [...Object.keys(ONED_FORMATS), 'qr', 'datamatrix', 'aztec'].join(', ');
|
|
11675
|
+
const known = [...Object.keys(ONED_FORMATS), 'qr', 'datamatrix', 'aztec', 'pdf417', 'micropdf417'].join(', ');
|
|
9713
11676
|
throw new EncodeError(`Unknown format "${format}". Known formats: ${known}`);
|
|
9714
11677
|
}
|
|
9715
11678
|
return entry.encode(value, options);
|
|
@@ -9719,12 +11682,19 @@ function encode(text, options = {}) {
|
|
|
9719
11682
|
* @typedef {object} DecodeResult
|
|
9720
11683
|
* @property {string} text
|
|
9721
11684
|
* @property {string} format
|
|
9722
|
-
* @property {Uint8Array} [bytes] Raw payload, before text decoding.
|
|
11685
|
+
* @property {Uint8Array} [bytes] Raw octets exposed by byte-oriented payload modes, before text decoding.
|
|
11686
|
+
* @property {{mode: 'text'|'byte'|'numeric', text: string, bytes: Uint8Array, eci: number, latch: number|null, codewordStart: number, codewordEnd: number}[]} [segments] PDF417 compaction segments in source order.
|
|
9723
11687
|
* @property {number} [version] QR version.
|
|
9724
11688
|
* @property {string} [ecc] QR error-correction level.
|
|
9725
11689
|
* @property {number} [layers] Aztec layer count.
|
|
9726
11690
|
* @property {boolean} [compact] Whether an Aztec symbol is Compact.
|
|
9727
11691
|
* @property {number} [corrections] Reed–Solomon corrections applied by an Aztec decode.
|
|
11692
|
+
* @property {number} [rows] PDF417 row count.
|
|
11693
|
+
* @property {number} [columns] PDF417 column count.
|
|
11694
|
+
* @property {number} [eccLevel] PDF417 error-correction level.
|
|
11695
|
+
* @property {number} [rowHeight] PDF417 row height in modules.
|
|
11696
|
+
* @property {number} [variant] MicroPDF417 predefined variant number.
|
|
11697
|
+
* @property {number} [eccCodewords] MicroPDF417 fixed error-correction codewords.
|
|
9728
11698
|
*/
|
|
9729
11699
|
|
|
9730
11700
|
/**
|
|
@@ -9747,6 +11717,8 @@ function decode(image, options = {}) {
|
|
|
9747
11717
|
const wantQR = !want || want.has('qr') || want.has('qrcode');
|
|
9748
11718
|
const wantDataMatrix = !want || want.has('datamatrix') || want.has('data-matrix');
|
|
9749
11719
|
const wantAztec = !want || want.has('aztec') || want.has('aztec-code');
|
|
11720
|
+
const wantPDF417 = !want || want.has('pdf417') || want.has('pdf-417');
|
|
11721
|
+
const wantMicroPDF417 = !want || want.has('micropdf417') || want.has('micro-pdf417') || want.has('micro-pdf-417');
|
|
9750
11722
|
const wantOneD = !want || [...want].some((f) => f in ONED_FORMATS);
|
|
9751
11723
|
|
|
9752
11724
|
const source = LuminanceSource.fromImageData(image);
|
|
@@ -9799,6 +11771,30 @@ function decode(image, options = {}) {
|
|
|
9799
11771
|
}
|
|
9800
11772
|
}
|
|
9801
11773
|
|
|
11774
|
+
if (wantPDF417 && pdf417CanDecode) {
|
|
11775
|
+
try {
|
|
11776
|
+
const found = pdf417.detectAndDecodePDF417(bits);
|
|
11777
|
+
if (found) results.push({ ...found, format: 'pdf417' });
|
|
11778
|
+
} catch {
|
|
11779
|
+
/* no PDF417 in this pass */
|
|
11780
|
+
}
|
|
11781
|
+
}
|
|
11782
|
+
|
|
11783
|
+
if (wantMicroPDF417 && microPdf417CanDecode) {
|
|
11784
|
+
// MicroPDF417 detection measures runs across the whole raster. Hybrid
|
|
11785
|
+
// thresholding can alter uniform modules near local-window boundaries,
|
|
11786
|
+
// so retry the global threshold in auto mode as for the other 2D codes.
|
|
11787
|
+
const microPdf417Bits = binarizer === 'auto' ? [bits, binarize(pass, 'global')] : [bits];
|
|
11788
|
+
for (const candidateBits of microPdf417Bits) {
|
|
11789
|
+
try {
|
|
11790
|
+
const found = micropdf417.detectAndDecodeMicroPDF417(candidateBits);
|
|
11791
|
+
if (found) { results.push({ ...found, format: 'micropdf417' }); break; }
|
|
11792
|
+
} catch {
|
|
11793
|
+
/* no MicroPDF417 with this threshold */
|
|
11794
|
+
}
|
|
11795
|
+
}
|
|
11796
|
+
}
|
|
11797
|
+
|
|
9802
11798
|
if (wantOneD) {
|
|
9803
11799
|
const oneDFormats = want ? [...want].filter((f) => f in ONED_FORMATS) : null;
|
|
9804
11800
|
for (const found of decodeOneD(bits, { formats: oneDFormats, tryHarder })) {
|
|
@@ -9833,7 +11829,7 @@ function decodeStrict(image, options) {
|
|
|
9833
11829
|
}
|
|
9834
11830
|
|
|
9835
11831
|
/** Library version, matching package.json. */
|
|
9836
|
-
const VERSION = '1.
|
|
11832
|
+
const VERSION = '1.2.5';
|
|
9837
11833
|
|
|
9838
11834
|
__exports.listFormats = listFormats;
|
|
9839
11835
|
__exports.encode = encode;
|