@sythos/js_barcode_universal 1.5.8 → 1.5.10
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 +5 -4
- package/NOTICE.md +2 -2
- package/README.md +61 -13
- package/bundle/sythos-barcode.esm.js +11658 -11244
- package/bundle/sythos-barcode.js +11658 -11244
- package/package.json +10 -3
- package/src/index.d.ts +1 -1
- package/src/index.js +508 -516
- package/src/js/aztec/decoder.js +208 -199
- package/src/js/aztec/detector.js +153 -126
- package/src/js/aztec/encoder.js +172 -153
- package/src/js/aztec/high-level.js +106 -101
- package/src/js/aztec/index.js +1 -12
- package/src/js/aztec/tables.js +106 -120
- package/src/js/aztecrune/decoder.js +76 -85
- package/src/js/aztecrune/detector.js +107 -93
- package/src/js/aztecrune/encoder.js +50 -68
- package/src/js/aztecrune/index.js +1 -16
- package/src/js/aztecrune/tables.js +59 -54
- package/src/js/compactpdf417/decoder.js +69 -74
- package/src/js/compactpdf417/detector.js +74 -75
- package/src/js/compactpdf417/encoder.js +68 -81
- package/src/js/compactpdf417/index.js +1 -13
- package/src/js/compactpdf417/tables.js +71 -80
- package/src/js/core/bit-buffer.js +106 -122
- package/src/js/core/bit-matrix.js +196 -194
- package/src/js/core/errors.js +13 -15
- package/src/js/core/galois-field.js +119 -133
- package/src/js/core/index.js +2 -19
- package/src/js/core/reed-solomon.js +195 -204
- package/src/js/databar/codec.js +93 -108
- package/src/js/databar/decoder.js +149 -140
- package/src/js/databar/encoder.js +47 -55
- package/src/js/databar/gs1.js +122 -123
- package/src/js/databar/index.js +4 -36
- package/src/js/databar/patterns.js +81 -85
- package/src/js/databar/tables.js +51 -52
- package/src/js/datamatrix/decoder.js +216 -182
- package/src/js/datamatrix/detector.js +161 -132
- package/src/js/datamatrix/encoder.js +192 -133
- package/src/js/datamatrix/index.js +1 -9
- package/src/js/datamatrix/tables.js +68 -69
- package/src/js/frameqr/decoder.js +102 -125
- package/src/js/frameqr/detector.js +101 -94
- package/src/js/frameqr/encoder.js +67 -80
- package/src/js/frameqr/index.js +1 -10
- package/src/js/frameqr/tables.js +145 -163
- package/src/js/image/binarizer.js +146 -162
- package/src/js/image/grid-sampler.js +63 -79
- package/src/js/image/index.js +0 -2
- package/src/js/image/luminance.js +129 -140
- package/src/js/image/perspective.js +112 -149
- package/src/js/micropdf417/compaction.js +64 -65
- package/src/js/micropdf417/decoder.js +106 -109
- package/src/js/micropdf417/detector.js +73 -70
- package/src/js/micropdf417/encoder.js +129 -154
- package/src/js/micropdf417/error-correction.js +6 -11
- package/src/js/micropdf417/index.js +2 -16
- package/src/js/micropdf417/tables.js +112 -99
- package/src/js/microqr/decoder.js +177 -182
- package/src/js/microqr/detector.js +240 -256
- package/src/js/microqr/encoder.js +239 -194
- package/src/js/microqr/index.js +0 -2
- package/src/js/microqr/tables.js +208 -200
- package/src/js/oned/addons.js +167 -191
- package/src/js/oned/index.js +27 -58
- package/src/js/oned/patterns.js +194 -213
- package/src/js/oned/reader.js +1003 -984
- package/src/js/oned/writers.js +411 -466
- package/src/js/pdf417/compaction.js +315 -222
- package/src/js/pdf417/decoder.js +71 -36
- package/src/js/pdf417/detector.js +377 -361
- package/src/js/pdf417/encoder.js +57 -46
- package/src/js/pdf417/error-correction.js +5 -8
- package/src/js/pdf417/tables.js +248 -250
- package/src/js/qr/decoder.js +311 -347
- package/src/js/qr/detector.js +378 -395
- package/src/js/qr/encoder.js +514 -599
- package/src/js/qr/index.js +0 -2
- package/src/js/qr/tables.js +375 -422
- package/src/js/render/image-data.js +57 -62
- package/src/js/render/index.js +21 -23
- package/src/js/render/options.js +82 -90
- package/src/js/render/png.js +144 -169
- package/src/js/render/svg.js +41 -44
- package/src/js/render/webgl.js +103 -109
- package/src/js/render/webgpu.js +205 -217
- package/src/js/rmqr/decoder.js +161 -53
- package/src/js/rmqr/detector.js +73 -41
- package/src/js/rmqr/encoder.js +253 -104
- package/src/js/rmqr/index.js +1 -5
- package/src/js/rmqr/tables.js +108 -85
- package/src/ts/aztec/decoder.ts +317 -0
- package/src/ts/aztec/detector.ts +224 -0
- package/src/ts/aztec/encoder.ts +257 -0
- package/src/ts/aztec/high-level.ts +211 -0
- package/src/ts/aztec/index.ts +45 -0
- package/src/ts/aztec/tables.ts +210 -0
- package/src/ts/aztecrune/decoder.ts +155 -0
- package/src/ts/aztecrune/detector.ts +166 -0
- package/src/ts/aztecrune/encoder.ts +121 -0
- package/src/ts/aztecrune/index.ts +49 -0
- package/src/ts/aztecrune/tables.ts +137 -0
- package/src/ts/compactpdf417/decoder.ts +128 -0
- package/src/ts/compactpdf417/detector.ts +139 -0
- package/src/ts/compactpdf417/encoder.ts +140 -0
- package/src/ts/compactpdf417/index.ts +17 -0
- package/src/ts/compactpdf417/tables.ts +173 -0
- package/src/ts/core/bit-buffer.ts +174 -0
- package/src/ts/core/bit-matrix.ts +241 -0
- package/src/ts/core/errors.ts +61 -0
- package/src/ts/core/galois-field.ts +207 -0
- package/src/ts/core/index.ts +56 -0
- package/src/ts/core/reed-solomon.ts +327 -0
- package/src/ts/databar/codec.ts +181 -0
- package/src/ts/databar/decoder.ts +215 -0
- package/src/ts/databar/encoder.ts +96 -0
- package/src/ts/databar/gs1.ts +177 -0
- package/src/ts/databar/index.ts +68 -0
- package/src/ts/databar/patterns.ts +143 -0
- package/src/ts/databar/tables.ts +124 -0
- package/src/ts/datamatrix/decoder.ts +262 -0
- package/src/ts/datamatrix/detector.ts +225 -0
- package/src/ts/datamatrix/encoder.ts +191 -0
- package/src/ts/datamatrix/index.ts +42 -0
- package/src/ts/datamatrix/tables.ts +123 -0
- package/src/ts/frameqr/decoder.ts +239 -0
- package/src/ts/frameqr/detector.ts +192 -0
- package/src/ts/frameqr/encoder.ts +156 -0
- package/src/ts/frameqr/index.ts +42 -0
- package/src/ts/frameqr/tables.ts +270 -0
- package/src/ts/image/binarizer.ts +270 -0
- package/src/ts/image/grid-sampler.ts +164 -0
- package/src/ts/image/index.ts +40 -0
- package/src/ts/image/luminance.ts +196 -0
- package/src/ts/image/perspective.ts +195 -0
- package/src/ts/index.d.ts +1 -1
- package/src/ts/index.ts +790 -0
- package/src/ts/micropdf417/compaction.ts +116 -0
- package/src/ts/micropdf417/decoder.ts +183 -0
- package/src/ts/micropdf417/detector.ts +149 -0
- package/src/ts/micropdf417/encoder.ts +209 -0
- package/src/ts/micropdf417/error-correction.ts +55 -0
- package/src/ts/micropdf417/index.ts +49 -0
- package/src/ts/micropdf417/tables.ts +184 -0
- package/src/ts/microqr/decoder.ts +245 -0
- package/src/ts/microqr/detector.ts +355 -0
- package/src/ts/microqr/encoder.ts +269 -0
- package/src/ts/microqr/index.ts +36 -0
- package/src/ts/microqr/tables.ts +316 -0
- package/src/ts/oned/addons.ts +420 -0
- package/src/ts/oned/index.ts +106 -0
- package/src/ts/oned/patterns.ts +384 -0
- package/src/ts/oned/reader.ts +1364 -0
- package/src/ts/oned/writers.ts +746 -0
- package/src/ts/pdf417/compaction.ts +298 -0
- package/src/ts/pdf417/decoder.ts +75 -0
- package/src/ts/pdf417/detector.ts +468 -0
- package/src/ts/pdf417/encoder.ts +91 -0
- package/src/ts/pdf417/error-correction.ts +47 -0
- package/src/ts/pdf417/index.ts +6 -0
- package/src/ts/pdf417/tables.ts +317 -0
- package/src/ts/qr/decoder.ts +575 -0
- package/src/ts/qr/detector.ts +630 -0
- package/src/ts/qr/encoder.ts +958 -0
- package/src/ts/qr/index.ts +44 -0
- package/src/ts/qr/tables.ts +737 -0
- package/src/ts/render/image-data.ts +125 -0
- package/src/ts/render/index.ts +130 -0
- package/src/ts/render/options.ts +160 -0
- package/src/ts/render/png.ts +295 -0
- package/src/ts/render/svg.ts +120 -0
- package/src/ts/render/webgl.ts +206 -0
- package/src/ts/render/webgpu.ts +369 -0
- package/src/ts/rmqr/decoder.ts +101 -0
- package/src/ts/rmqr/detector.ts +90 -0
- package/src/ts/rmqr/encoder.ts +172 -0
- package/src/ts/rmqr/index.ts +37 -0
- package/src/ts/rmqr/tables.ts +154 -0
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Aztec Rune decoder.
|
|
33
32
|
*
|
|
@@ -39,74 +38,66 @@
|
|
|
39
38
|
*
|
|
40
39
|
* @module aztecrune/decoder
|
|
41
40
|
*/
|
|
42
|
-
|
|
43
41
|
import { FormatError } from '../core/errors.js';
|
|
44
42
|
import { rsDecode } from '../core/reed-solomon.js';
|
|
45
|
-
import {
|
|
46
|
-
AZTEC_RUNE_DATA_CODEWORDS,
|
|
47
|
-
AZTEC_RUNE_DATA_POSITIONS,
|
|
48
|
-
AZTEC_RUNE_ECC_CODEWORDS,
|
|
49
|
-
AZTEC_RUNE_MASK,
|
|
50
|
-
AZTEC_RUNE_SIZE,
|
|
51
|
-
aztecRuneField,
|
|
52
|
-
aztecRuneStructuralValue,
|
|
53
|
-
} from './tables.js';
|
|
54
|
-
|
|
43
|
+
import { AZTEC_RUNE_DATA_POSITIONS, AZTEC_RUNE_ECC_CODEWORDS, AZTEC_RUNE_MASK, AZTEC_RUNE_SIZE, aztecRuneField, aztecRuneStructuralValue, } from './tables.js';
|
|
55
44
|
/** @param {import('../core/bit-matrix.js').BitMatrix} source @param {number} turns */
|
|
56
45
|
function rotateClockwise(source, turns) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
46
|
+
let current = source.clone();
|
|
47
|
+
for (let turn = 0; turn < turns; turn++) {
|
|
48
|
+
const out = new source.constructor(current.height, current.width);
|
|
49
|
+
for (let y = 0; y < current.height; y++)
|
|
50
|
+
for (let x = 0; x < current.width; x++) {
|
|
51
|
+
if (current.get(x, y))
|
|
52
|
+
out.set(current.height - 1 - y, x);
|
|
53
|
+
}
|
|
54
|
+
current = out;
|
|
62
55
|
}
|
|
63
|
-
current
|
|
64
|
-
}
|
|
65
|
-
return current;
|
|
56
|
+
return current;
|
|
66
57
|
}
|
|
67
|
-
|
|
68
58
|
/** @param {import('../core/bit-matrix.js').BitMatrix} matrix */
|
|
69
59
|
function invert(matrix) {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
60
|
+
const out = matrix.clone();
|
|
61
|
+
for (let y = 0; y < out.height; y++)
|
|
62
|
+
for (let x = 0; x < out.width; x++)
|
|
63
|
+
out.flip(x, y);
|
|
64
|
+
return out;
|
|
73
65
|
}
|
|
74
|
-
|
|
75
66
|
/** @param {import('../core/bit-matrix.js').BitMatrix} matrix @param {boolean} inverted */
|
|
76
67
|
function structureMatches(matrix, inverted) {
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
68
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++)
|
|
69
|
+
for (let x = 0; x < AZTEC_RUNE_SIZE; x++) {
|
|
70
|
+
const expected = aztecRuneStructuralValue(x, y);
|
|
71
|
+
if (expected === null)
|
|
72
|
+
continue;
|
|
73
|
+
if (matrix.get(x, y) !== (inverted ? !expected : expected))
|
|
74
|
+
return false;
|
|
75
|
+
}
|
|
76
|
+
return true;
|
|
83
77
|
}
|
|
84
|
-
|
|
85
78
|
/** @param {import('../core/bit-matrix.js').BitMatrix} matrix @param {boolean} inverted */
|
|
86
79
|
function readCodewords(matrix, inverted) {
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
const words = new Array(2 + AZTEC_RUNE_ECC_CODEWORDS).fill(0);
|
|
81
|
+
for (let at = 0; at < AZTEC_RUNE_DATA_POSITIONS.length; at++) {
|
|
82
|
+
const [x, y] = AZTEC_RUNE_DATA_POSITIONS[at];
|
|
83
|
+
const bit = matrix.get(x, y) !== inverted;
|
|
84
|
+
words[at >>> 2] = (words[at >>> 2] << 1) | (bit ? 1 : 0);
|
|
85
|
+
}
|
|
86
|
+
return words.map((word) => word ^ AZTEC_RUNE_MASK);
|
|
94
87
|
}
|
|
95
|
-
|
|
96
88
|
/** @param {number} value @param {boolean} inverted @param {number} rotation @param {number} corrections */
|
|
97
89
|
function result(value, inverted, rotation, corrections) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
90
|
+
return {
|
|
91
|
+
format: 'aztecrune',
|
|
92
|
+
value,
|
|
93
|
+
text: String(value).padStart(3, '0'),
|
|
94
|
+
bytes: Uint8Array.of(value),
|
|
95
|
+
dimension: AZTEC_RUNE_SIZE,
|
|
96
|
+
inverted,
|
|
97
|
+
rotation,
|
|
98
|
+
corrections,
|
|
99
|
+
};
|
|
108
100
|
}
|
|
109
|
-
|
|
110
101
|
/**
|
|
111
102
|
* Decode a square Aztec Rune matrix.
|
|
112
103
|
*
|
|
@@ -116,40 +107,40 @@ function result(value, inverted, rotation, corrections) {
|
|
|
116
107
|
* @throws {FormatError} For non-Rune geometry, structure or uncorrectable data.
|
|
117
108
|
*/
|
|
118
109
|
export function decodeAztecRune(matrix, options = {}) {
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
110
|
+
if (!matrix || matrix.width !== AZTEC_RUNE_SIZE || matrix.height !== AZTEC_RUNE_SIZE) {
|
|
111
|
+
throw new FormatError(`Aztec Rune: expected an ${AZTEC_RUNE_SIZE}x${AZTEC_RUNE_SIZE} module matrix`);
|
|
112
|
+
}
|
|
113
|
+
const invertedModes = options.inverted === true ? [true] : options.inverted === false ? [false] : [false, true];
|
|
114
|
+
const rotations = Number.isInteger(options.rotation)
|
|
115
|
+
? [((options.rotation % 360) + 360) % 360]
|
|
116
|
+
: [0, 90, 180, 270];
|
|
117
|
+
let checksumError = null;
|
|
118
|
+
for (const requestedRotation of rotations) {
|
|
119
|
+
if (requestedRotation % 90 !== 0)
|
|
120
|
+
continue;
|
|
121
|
+
// To canonicalize an input rotated clockwise by k degrees, rotate it
|
|
122
|
+
// counter-clockwise by k. `turns` is the clockwise operation we apply.
|
|
123
|
+
const turns = (4 - requestedRotation / 90) % 4;
|
|
124
|
+
const canonicalRotation = requestedRotation;
|
|
125
|
+
const rotated = turns === 0 ? matrix.clone() : rotateClockwise(matrix, turns);
|
|
126
|
+
for (const inverted of invertedModes) {
|
|
127
|
+
const canonical = inverted ? invert(rotated) : rotated;
|
|
128
|
+
if (!structureMatches(canonical, false))
|
|
129
|
+
continue;
|
|
130
|
+
const words = readCodewords(canonical, false);
|
|
131
|
+
try {
|
|
132
|
+
const corrections = rsDecode(words, AZTEC_RUNE_ECC_CODEWORDS, aztecRuneField(), 1);
|
|
133
|
+
const value = (words[0] << 4) | words[1];
|
|
134
|
+
return result(value, inverted, canonicalRotation, corrections);
|
|
135
|
+
}
|
|
136
|
+
catch (error) {
|
|
137
|
+
checksumError = error;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
if (checksumError) {
|
|
142
|
+
throw new FormatError(`Aztec Rune: Reed-Solomon check failed: ${checksumError.message}`);
|
|
146
143
|
}
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
if (checksumError) {
|
|
150
|
-
throw new FormatError(`Aztec Rune: Reed-Solomon check failed: ${checksumError.message}`);
|
|
151
|
-
}
|
|
152
|
-
throw new FormatError('Aztec Rune: structural pattern or orientation is invalid');
|
|
144
|
+
throw new FormatError('Aztec Rune: structural pattern or orientation is invalid');
|
|
153
145
|
}
|
|
154
|
-
|
|
155
146
|
export { readCodewords, structureMatches };
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Detector for Aztec Rune symbols.
|
|
33
32
|
*
|
|
@@ -39,14 +38,11 @@
|
|
|
39
38
|
*
|
|
40
39
|
* @module aztecrune/detector
|
|
41
40
|
*/
|
|
42
|
-
|
|
43
41
|
import { NotFoundError } from '../core/errors.js';
|
|
44
42
|
import { BitMatrix } from '../core/bit-matrix.js';
|
|
45
43
|
import { decodeAztecRune } from './decoder.js';
|
|
46
44
|
import { AZTEC_RUNE_SIZE } from './tables.js';
|
|
47
|
-
|
|
48
45
|
/** @typedef {{x:number,y:number}} Point */
|
|
49
|
-
|
|
50
46
|
/**
|
|
51
47
|
* Find connected components of a polarity. Components touching the image
|
|
52
48
|
* border are ignored when they exceed the plausible module area; this avoids
|
|
@@ -54,73 +50,78 @@ import { AZTEC_RUNE_SIZE } from './tables.js';
|
|
|
54
50
|
* Rune's isolated light centre module.
|
|
55
51
|
*/
|
|
56
52
|
function components(image, value) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
53
|
+
const width = image.width;
|
|
54
|
+
const height = image.height;
|
|
55
|
+
const seen = new Uint8Array(width * height);
|
|
56
|
+
const limit = Math.max(64, Math.floor(width * height * 0.04));
|
|
57
|
+
const found = [];
|
|
58
|
+
for (let y = 0; y < height; y++)
|
|
59
|
+
for (let x = 0; x < width; x++) {
|
|
60
|
+
const start = y * width + x;
|
|
61
|
+
if (seen[start] || image.get(x, y) !== value)
|
|
62
|
+
continue;
|
|
63
|
+
const queue = [[x, y]];
|
|
64
|
+
seen[start] = 1;
|
|
65
|
+
let head = 0;
|
|
66
|
+
let minX = x;
|
|
67
|
+
let maxX = x;
|
|
68
|
+
let minY = y;
|
|
69
|
+
let maxY = y;
|
|
70
|
+
let count = 0;
|
|
71
|
+
let touchesBorder = false;
|
|
72
|
+
while (head < queue.length) {
|
|
73
|
+
const [px, py] = queue[head++];
|
|
74
|
+
count++;
|
|
75
|
+
minX = Math.min(minX, px);
|
|
76
|
+
maxX = Math.max(maxX, px);
|
|
77
|
+
minY = Math.min(minY, py);
|
|
78
|
+
maxY = Math.max(maxY, py);
|
|
79
|
+
if (px === 0 || py === 0 || px === width - 1 || py === height - 1)
|
|
80
|
+
touchesBorder = true;
|
|
81
|
+
for (const [nx, ny] of [[px - 1, py], [px + 1, py], [px, py - 1], [px, py + 1]]) {
|
|
82
|
+
if (nx < 0 || ny < 0 || nx >= width || ny >= height)
|
|
83
|
+
continue;
|
|
84
|
+
const at = ny * width + nx;
|
|
85
|
+
if (!seen[at] && image.get(nx, ny) === value) {
|
|
86
|
+
seen[at] = 1;
|
|
87
|
+
queue.push([nx, ny]);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
const boxWidth = maxX - minX + 1;
|
|
92
|
+
const boxHeight = maxY - minY + 1;
|
|
93
|
+
if (count <= limit && !touchesBorder &&
|
|
94
|
+
Math.abs(boxWidth - boxHeight) <= Math.max(1, Math.ceil(Math.max(boxWidth, boxHeight) * 0.35)) &&
|
|
95
|
+
count >= boxWidth * boxHeight * 0.45) {
|
|
96
|
+
found.push({ x: (minX + maxX) / 2, y: (minY + maxY) / 2, width: boxWidth, height: boxHeight, count });
|
|
97
|
+
}
|
|
85
98
|
}
|
|
86
|
-
|
|
87
|
-
}
|
|
88
|
-
|
|
89
|
-
const boxWidth = maxX - minX + 1;
|
|
90
|
-
const boxHeight = maxY - minY + 1;
|
|
91
|
-
if (count <= limit && !touchesBorder &&
|
|
92
|
-
Math.abs(boxWidth - boxHeight) <= Math.max(1, Math.ceil(Math.max(boxWidth, boxHeight) * 0.35)) &&
|
|
93
|
-
count >= boxWidth * boxHeight * 0.45) {
|
|
94
|
-
found.push({ x: (minX + maxX) / 2, y: (minY + maxY) / 2, width: boxWidth, height: boxHeight, count });
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return found.sort((a, b) => b.count - a.count);
|
|
99
|
+
return found.sort((a, b) => b.count - a.count);
|
|
98
100
|
}
|
|
99
101
|
/** @param {import('../core/bit-matrix.js').BitMatrix} image @param {Point} center @param {number} pitch */
|
|
100
102
|
function sample(image, center, pitch) {
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
103
|
+
const matrix = new BitMatrix(AZTEC_RUNE_SIZE);
|
|
104
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++)
|
|
105
|
+
for (let x = 0; x < AZTEC_RUNE_SIZE; x++) {
|
|
106
|
+
const px = Math.round(center.x + (x - 5) * pitch);
|
|
107
|
+
const py = Math.round(center.y + (y - 5) * pitch);
|
|
108
|
+
if (px >= 0 && py >= 0 && px < image.width && py < image.height && image.get(px, py))
|
|
109
|
+
matrix.set(x, y);
|
|
110
|
+
}
|
|
111
|
+
return matrix;
|
|
108
112
|
}
|
|
109
|
-
|
|
110
113
|
function corners(center, pitch) {
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
114
|
+
const half = AZTEC_RUNE_SIZE * pitch / 2;
|
|
115
|
+
return [
|
|
116
|
+
{ x: center.x - half, y: center.y - half },
|
|
117
|
+
{ x: center.x + half, y: center.y - half },
|
|
118
|
+
{ x: center.x + half, y: center.y + half },
|
|
119
|
+
{ x: center.x - half, y: center.y + half },
|
|
120
|
+
];
|
|
118
121
|
}
|
|
119
|
-
|
|
120
122
|
function sameCandidate(left, right) {
|
|
121
|
-
|
|
123
|
+
return Math.hypot(left.center.x - right.center.x, left.center.y - right.center.y) <= Math.max(left.moduleSize, right.moduleSize) * 2;
|
|
122
124
|
}
|
|
123
|
-
|
|
124
125
|
/**
|
|
125
126
|
* Detect the most prominent Aztec Rune in a binarized image.
|
|
126
127
|
*
|
|
@@ -128,39 +129,52 @@ function sameCandidate(left, right) {
|
|
|
128
129
|
* @returns {{corners:Point[],dimension:11,moduleSize:number,matrix:BitMatrix,result:object}|null}
|
|
129
130
|
*/
|
|
130
131
|
export function detectAztecRune(binaryImage) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
}
|
|
134
|
-
const candidates = [];
|
|
135
|
-
for (const value of [true, false]) {
|
|
136
|
-
for (const component of components(binaryImage, value)) {
|
|
137
|
-
const pitch = (component.width + component.height) / 2;
|
|
138
|
-
if (pitch < 0.8) continue;
|
|
139
|
-
const matrix = sample(binaryImage, component, pitch);
|
|
140
|
-
let decoded;
|
|
141
|
-
try { decoded = decodeAztecRune(matrix); } catch { continue; }
|
|
142
|
-
const candidate = {
|
|
143
|
-
center: component,
|
|
144
|
-
corners: corners(component, pitch),
|
|
145
|
-
dimension: AZTEC_RUNE_SIZE,
|
|
146
|
-
moduleSize: pitch,
|
|
147
|
-
matrix,
|
|
148
|
-
result: decoded,
|
|
149
|
-
};
|
|
150
|
-
if (!candidates.some((entry) => sameCandidate(entry, candidate))) candidates.push(candidate);
|
|
132
|
+
if (!binaryImage || !binaryImage.width || !binaryImage.height) {
|
|
133
|
+
throw new NotFoundError('detectAztecRune: no image supplied');
|
|
151
134
|
}
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
135
|
+
const candidates = [];
|
|
136
|
+
for (const value of [true, false]) {
|
|
137
|
+
for (const component of components(binaryImage, value)) {
|
|
138
|
+
const pitch = (component.width + component.height) / 2;
|
|
139
|
+
if (pitch < 0.8)
|
|
140
|
+
continue;
|
|
141
|
+
const matrix = sample(binaryImage, component, pitch);
|
|
142
|
+
let decoded;
|
|
143
|
+
try {
|
|
144
|
+
decoded = decodeAztecRune(matrix);
|
|
145
|
+
}
|
|
146
|
+
catch {
|
|
147
|
+
continue;
|
|
148
|
+
}
|
|
149
|
+
const candidate = {
|
|
150
|
+
center: component,
|
|
151
|
+
corners: corners(component, pitch),
|
|
152
|
+
dimension: AZTEC_RUNE_SIZE,
|
|
153
|
+
moduleSize: pitch,
|
|
154
|
+
matrix,
|
|
155
|
+
result: decoded,
|
|
156
|
+
};
|
|
157
|
+
if (!candidates.some((entry) => sameCandidate(entry, candidate)))
|
|
158
|
+
candidates.push(candidate);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
candidates.sort((a, b) => b.moduleSize - a.moduleSize);
|
|
162
|
+
const best = candidates[0];
|
|
163
|
+
if (!best)
|
|
164
|
+
return null;
|
|
165
|
+
delete best.center;
|
|
166
|
+
return best;
|
|
158
167
|
}
|
|
159
|
-
|
|
160
168
|
/** Detect and decode one Aztec Rune, or return `null` when none is verified. */
|
|
161
169
|
export function detectAndDecodeAztecRune(binaryImage) {
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
170
|
+
let detection;
|
|
171
|
+
try {
|
|
172
|
+
detection = detectAztecRune(binaryImage);
|
|
173
|
+
}
|
|
174
|
+
catch {
|
|
175
|
+
return null;
|
|
176
|
+
}
|
|
177
|
+
if (!detection)
|
|
178
|
+
return null;
|
|
179
|
+
return { ...detection.result, corners: detection.corners, moduleSize: detection.moduleSize };
|
|
166
180
|
}
|
|
@@ -27,71 +27,52 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
|
-
/**
|
|
32
|
-
* Aztec Rune encoder.
|
|
33
|
-
*
|
|
34
|
-
* A Rune carries exactly one byte. Numeric strings are accepted for convenient
|
|
35
|
-
* human-readable input and are normalized to the canonical three-digit text;
|
|
36
|
-
* binary callers can pass one byte in an ArrayBuffer or typed-array view.
|
|
37
|
-
*
|
|
38
|
-
* @module aztecrune/encoder
|
|
39
|
-
*/
|
|
40
|
-
|
|
41
|
-
import { BitMatrix } from '../core/bit-matrix.js';
|
|
42
30
|
import { EncodeError } from '../core/errors.js';
|
|
43
31
|
import { rsEncode } from '../core/reed-solomon.js';
|
|
44
|
-
import {
|
|
45
|
-
AZTEC_RUNE_DATA_POSITIONS,
|
|
46
|
-
AZTEC_RUNE_ECC_CODEWORDS,
|
|
47
|
-
AZTEC_RUNE_MASK,
|
|
48
|
-
AZTEC_RUNE_SIZE,
|
|
49
|
-
aztecRuneField,
|
|
50
|
-
buildAztecRuneStructure,
|
|
51
|
-
} from './tables.js';
|
|
52
|
-
|
|
32
|
+
import { AZTEC_RUNE_DATA_POSITIONS, AZTEC_RUNE_ECC_CODEWORDS, AZTEC_RUNE_MASK, AZTEC_RUNE_SIZE, aztecRuneField, buildAztecRuneStructure, } from './tables.js';
|
|
53
33
|
/** @param {unknown} value @returns {number} */
|
|
54
34
|
export function normalizeAztecRuneValue(value) {
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
if (
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
35
|
+
if (typeof value === 'number') {
|
|
36
|
+
if (Number.isInteger(value) && value >= 0 && value <= 255)
|
|
37
|
+
return value;
|
|
38
|
+
throw new EncodeError('Aztec Rune: numeric value must be an integer from 0 to 255');
|
|
39
|
+
}
|
|
40
|
+
if (typeof value === 'string') {
|
|
41
|
+
if (!/^\d{1,3}$/.test(value))
|
|
42
|
+
throw new EncodeError('Aztec Rune: text input must contain one to three decimal digits');
|
|
43
|
+
const numeric = Number(value);
|
|
44
|
+
if (numeric > 255)
|
|
45
|
+
throw new EncodeError('Aztec Rune: decimal value must be from 000 to 255');
|
|
46
|
+
return numeric;
|
|
47
|
+
}
|
|
48
|
+
let bytes = null;
|
|
49
|
+
if (value instanceof ArrayBuffer)
|
|
50
|
+
bytes = new Uint8Array(value);
|
|
51
|
+
else if (ArrayBuffer.isView(value))
|
|
52
|
+
bytes = new Uint8Array(value.buffer, value.byteOffset, value.byteLength);
|
|
53
|
+
if (bytes) {
|
|
54
|
+
if (bytes.length !== 1)
|
|
55
|
+
throw new EncodeError('Aztec Rune: binary input must contain exactly one byte');
|
|
56
|
+
return bytes[0];
|
|
57
|
+
}
|
|
58
|
+
throw new EncodeError('Aztec Rune: expected a number, decimal string or one-byte binary value');
|
|
75
59
|
}
|
|
76
|
-
|
|
77
60
|
/** @param {number} value @returns {number[]} */
|
|
78
61
|
function codewordsForValue(value) {
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
62
|
+
const data = [value >>> 4, value & 0x0f];
|
|
63
|
+
const parity = rsEncode(data, AZTEC_RUNE_ECC_CODEWORDS, aztecRuneField(), 1);
|
|
64
|
+
return data.concat(parity).map((word) => word ^ AZTEC_RUNE_MASK);
|
|
82
65
|
}
|
|
83
|
-
|
|
84
66
|
/** @param {BitMatrix} matrix @param {number[]} codewords */
|
|
85
67
|
function writeDataRing(matrix, codewords) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
68
|
+
for (let word = 0; word < codewords.length; word++) {
|
|
69
|
+
for (let bit = 0; bit < 4; bit++) {
|
|
70
|
+
const at = word * 4 + bit;
|
|
71
|
+
const [x, y] = AZTEC_RUNE_DATA_POSITIONS[at];
|
|
72
|
+
matrix.setValue(x, y, ((codewords[word] >>> (3 - bit)) & 1) !== 0);
|
|
73
|
+
}
|
|
91
74
|
}
|
|
92
|
-
}
|
|
93
75
|
}
|
|
94
|
-
|
|
95
76
|
/**
|
|
96
77
|
* Encode one byte as an Aztec Rune.
|
|
97
78
|
*
|
|
@@ -102,20 +83,21 @@ function writeDataRing(matrix, codewords) {
|
|
|
102
83
|
* }}
|
|
103
84
|
*/
|
|
104
85
|
export function encodeAztecRune(value, options = {}) {
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
86
|
+
const numeric = normalizeAztecRuneValue(value);
|
|
87
|
+
if (options.inverted !== undefined && typeof options.inverted !== 'boolean') {
|
|
88
|
+
throw new EncodeError('Aztec Rune: inverted must be boolean');
|
|
89
|
+
}
|
|
90
|
+
const inverted = options.inverted === true;
|
|
91
|
+
const matrix = buildAztecRuneStructure();
|
|
92
|
+
writeDataRing(matrix, codewordsForValue(numeric));
|
|
93
|
+
if (inverted) {
|
|
94
|
+
for (let y = 0; y < AZTEC_RUNE_SIZE; y++)
|
|
95
|
+
for (let x = 0; x < AZTEC_RUNE_SIZE; x++)
|
|
96
|
+
matrix.flip(x, y);
|
|
97
|
+
}
|
|
98
|
+
matrix.format = 'aztecrune';
|
|
99
|
+
matrix.value = numeric;
|
|
100
|
+
matrix.inverted = inverted;
|
|
101
|
+
return matrix;
|
|
119
102
|
}
|
|
120
|
-
|
|
121
103
|
export { codewordsForValue };
|
|
@@ -27,23 +27,8 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/** Aztec Rune entry points. @module aztecrune */
|
|
32
|
-
|
|
33
31
|
export { encodeAztecRune, normalizeAztecRuneValue } from './encoder.js';
|
|
34
32
|
export { decodeAztecRune } from './decoder.js';
|
|
35
33
|
export { detectAztecRune, detectAndDecodeAztecRune } from './detector.js';
|
|
36
|
-
export {
|
|
37
|
-
AZTEC_RUNE_SIZE,
|
|
38
|
-
AZTEC_RUNE_DATA_BITS,
|
|
39
|
-
AZTEC_RUNE_WORD_SIZE,
|
|
40
|
-
AZTEC_RUNE_DATA_CODEWORDS,
|
|
41
|
-
AZTEC_RUNE_ECC_CODEWORDS,
|
|
42
|
-
AZTEC_RUNE_TOTAL_CODEWORDS,
|
|
43
|
-
AZTEC_RUNE_MASK,
|
|
44
|
-
AZTEC_RUNE_DATA_POSITIONS,
|
|
45
|
-
aztecRuneStructuralValue,
|
|
46
|
-
buildAztecRuneStructure,
|
|
47
|
-
aztecRuneField,
|
|
48
|
-
validateAztecRuneTables,
|
|
49
|
-
} from './tables.js';
|
|
34
|
+
export { AZTEC_RUNE_SIZE, AZTEC_RUNE_DATA_BITS, AZTEC_RUNE_WORD_SIZE, AZTEC_RUNE_DATA_CODEWORDS, AZTEC_RUNE_ECC_CODEWORDS, AZTEC_RUNE_TOTAL_CODEWORDS, AZTEC_RUNE_MASK, AZTEC_RUNE_DATA_POSITIONS, aztecRuneStructuralValue, buildAztecRuneStructure, aztecRuneField, validateAztecRuneTables, } from './tables.js';
|