@sythos/js_barcode_universal 1.5.8 → 1.5.9
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 +17 -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
|
* Decoder for the Sythos Canvas QR profile.
|
|
33
32
|
*
|
|
@@ -42,21 +41,13 @@
|
|
|
42
41
|
*
|
|
43
42
|
* @module frameqr/decoder
|
|
44
43
|
*/
|
|
45
|
-
|
|
46
44
|
import { FormatError } from '../core/errors.js';
|
|
47
45
|
import { decodeQR } from '../qr/decoder.js';
|
|
48
|
-
import {
|
|
49
|
-
FRAMEQR_PROFILE,
|
|
50
|
-
normalizeCanvasSpec,
|
|
51
|
-
validateCanvasSpec,
|
|
52
|
-
analyzeCanvasDamage,
|
|
53
|
-
} from './tables.js';
|
|
54
|
-
|
|
46
|
+
import { FRAMEQR_PROFILE, normalizeCanvasSpec, validateCanvasSpec, analyzeCanvasDamage, } from './tables.js';
|
|
55
47
|
/** @param {unknown} value @returns {boolean} */
|
|
56
48
|
function isObject(value) {
|
|
57
|
-
|
|
49
|
+
return value !== null && typeof value === 'object';
|
|
58
50
|
}
|
|
59
|
-
|
|
60
51
|
/**
|
|
61
52
|
* Return the profile marker attached by the encoder. Older callers sometimes
|
|
62
53
|
* use camel case, so accepting it here is harmless while the emitted marker
|
|
@@ -66,16 +57,15 @@ function isObject(value) {
|
|
|
66
57
|
* @returns {object|null}
|
|
67
58
|
*/
|
|
68
59
|
function markerOf(matrix) {
|
|
69
|
-
|
|
70
|
-
|
|
60
|
+
const marker = matrix && (matrix.frameqr ?? matrix.frameQR);
|
|
61
|
+
return isObject(marker) ? marker : null;
|
|
71
62
|
}
|
|
72
|
-
|
|
73
63
|
/** @param {unknown} profile @returns {boolean} */
|
|
74
64
|
function isExpectedProfile(profile) {
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
if (profile === FRAMEQR_PROFILE.id)
|
|
66
|
+
return true;
|
|
67
|
+
return isObject(profile) && profile.id === FRAMEQR_PROFILE.id;
|
|
77
68
|
}
|
|
78
|
-
|
|
79
69
|
/**
|
|
80
70
|
* Normalize and validate the canvas metadata. Validation functions in the
|
|
81
71
|
* table module throw on invalid input; a few consumers also return `false` or
|
|
@@ -87,34 +77,33 @@ function isExpectedProfile(profile) {
|
|
|
87
77
|
* @returns {{canvas: object, damage: object}}
|
|
88
78
|
*/
|
|
89
79
|
function validateCanvas(symbolSize, version, canvas) {
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
80
|
+
if (!isObject(canvas))
|
|
81
|
+
throw new FormatError('Sythos Canvas QR: canvas metadata is missing');
|
|
82
|
+
let normalized;
|
|
83
|
+
try {
|
|
84
|
+
normalized = normalizeCanvasSpec(symbolSize, canvas);
|
|
85
|
+
const validation = validateCanvasSpec(version, normalized);
|
|
86
|
+
if (validation === false ||
|
|
87
|
+
(Array.isArray(validation) && validation.length > 0) ||
|
|
88
|
+
(isObject(validation) && validation.valid === false) ||
|
|
89
|
+
(isObject(validation) && validation.safe === false)) {
|
|
90
|
+
throw new Error('canvas geometry is outside the profile limits');
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
if (error instanceof FormatError)
|
|
95
|
+
throw error;
|
|
96
|
+
throw new FormatError(`Sythos Canvas QR: invalid canvas metadata: ${error.message}`);
|
|
97
|
+
}
|
|
98
|
+
let damage;
|
|
99
|
+
try {
|
|
100
|
+
damage = analyzeCanvasDamage(version, normalized);
|
|
103
101
|
}
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
let damage;
|
|
110
|
-
try {
|
|
111
|
-
damage = analyzeCanvasDamage(version, normalized);
|
|
112
|
-
} catch (error) {
|
|
113
|
-
throw new FormatError(`Sythos Canvas QR: cannot analyse canvas damage: ${error.message}`);
|
|
114
|
-
}
|
|
115
|
-
return { canvas: normalized, damage };
|
|
102
|
+
catch (error) {
|
|
103
|
+
throw new FormatError(`Sythos Canvas QR: cannot analyse canvas damage: ${error.message}`);
|
|
104
|
+
}
|
|
105
|
+
return { canvas: normalized, damage };
|
|
116
106
|
}
|
|
117
|
-
|
|
118
107
|
/**
|
|
119
108
|
* Resolve the profile marker and canvas from the matrix/options pair.
|
|
120
109
|
*
|
|
@@ -128,61 +117,53 @@ function validateCanvas(symbolSize, version, canvas) {
|
|
|
128
117
|
* @returns {{profile: string, canvas: object, damage: object, certified: false}}
|
|
129
118
|
*/
|
|
130
119
|
function resolveProfile(matrix, options) {
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
120
|
+
const marker = markerOf(matrix);
|
|
121
|
+
const suppliedProfile = options.profile;
|
|
122
|
+
const markerProfile = marker ? marker.profile : undefined;
|
|
123
|
+
if (markerProfile !== undefined && suppliedProfile !== undefined) {
|
|
124
|
+
const markerId = isObject(markerProfile) ? markerProfile.id : markerProfile;
|
|
125
|
+
const suppliedId = isObject(suppliedProfile) ? suppliedProfile.id : suppliedProfile;
|
|
126
|
+
if (markerId !== suppliedId) {
|
|
127
|
+
throw new FormatError('Sythos Canvas QR: matrix and requested profile markers disagree');
|
|
128
|
+
}
|
|
139
129
|
}
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
);
|
|
147
|
-
}
|
|
148
|
-
if (marker && marker.certified === true) {
|
|
149
|
-
throw new FormatError(
|
|
150
|
-
'Sythos Canvas QR: certified FrameQR input is not supported by this profile decoder'
|
|
151
|
-
);
|
|
152
|
-
}
|
|
153
|
-
if (!marker && !options.allowUnmarked) {
|
|
154
|
-
throw new FormatError(
|
|
155
|
-
'Sythos Canvas QR: unmarked QR matrix rejected; provide a verified profile marker'
|
|
156
|
-
);
|
|
157
|
-
}
|
|
158
|
-
|
|
159
|
-
const markerCanvas = marker ? marker.canvas : undefined;
|
|
160
|
-
const canvas = options.canvas ?? markerCanvas;
|
|
161
|
-
const version = (matrix.width - 17) / 4;
|
|
162
|
-
if (!Number.isInteger(version) || version < 1 || version > 40) {
|
|
163
|
-
throw new FormatError(`Sythos Canvas QR: invalid QR symbol size ${matrix.width}`);
|
|
164
|
-
}
|
|
165
|
-
const checked = validateCanvas(matrix.width, version, canvas);
|
|
166
|
-
if (markerCanvas && options.canvas) {
|
|
167
|
-
let marked;
|
|
168
|
-
try {
|
|
169
|
-
marked = normalizeCanvasSpec(matrix.width, markerCanvas);
|
|
170
|
-
} catch (error) {
|
|
171
|
-
throw new FormatError(`Sythos Canvas QR: invalid marker canvas: ${error.message}`);
|
|
130
|
+
const profile = markerProfile ?? suppliedProfile;
|
|
131
|
+
if (!isExpectedProfile(profile)) {
|
|
132
|
+
throw new FormatError('Sythos Canvas QR: profile marker is missing or is not the Sythos Canvas QR profile');
|
|
133
|
+
}
|
|
134
|
+
if (marker && marker.certified === true) {
|
|
135
|
+
throw new FormatError('Sythos Canvas QR: certified FrameQR input is not supported by this profile decoder');
|
|
172
136
|
}
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
throw new FormatError('Sythos Canvas QR: matrix and requested canvas metadata disagree');
|
|
137
|
+
if (!marker && !options.allowUnmarked) {
|
|
138
|
+
throw new FormatError('Sythos Canvas QR: unmarked QR matrix rejected; provide a verified profile marker');
|
|
176
139
|
}
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
140
|
+
const markerCanvas = marker ? marker.canvas : undefined;
|
|
141
|
+
const canvas = options.canvas ?? markerCanvas;
|
|
142
|
+
const version = (matrix.width - 17) / 4;
|
|
143
|
+
if (!Number.isInteger(version) || version < 1 || version > 40) {
|
|
144
|
+
throw new FormatError(`Sythos Canvas QR: invalid QR symbol size ${matrix.width}`);
|
|
145
|
+
}
|
|
146
|
+
const checked = validateCanvas(matrix.width, version, canvas);
|
|
147
|
+
if (markerCanvas && options.canvas) {
|
|
148
|
+
let marked;
|
|
149
|
+
try {
|
|
150
|
+
marked = normalizeCanvasSpec(matrix.width, markerCanvas);
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
throw new FormatError(`Sythos Canvas QR: invalid marker canvas: ${error.message}`);
|
|
154
|
+
}
|
|
155
|
+
const fields = ['shape', 'centerX', 'centerY', 'width', 'height', 'angle'];
|
|
156
|
+
if (fields.some((field) => marked[field] !== checked.canvas[field])) {
|
|
157
|
+
throw new FormatError('Sythos Canvas QR: matrix and requested canvas metadata disagree');
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
profile: FRAMEQR_PROFILE.id,
|
|
162
|
+
canvas: checked.canvas,
|
|
163
|
+
damage: checked.damage,
|
|
164
|
+
certified: false,
|
|
165
|
+
};
|
|
184
166
|
}
|
|
185
|
-
|
|
186
167
|
/**
|
|
187
168
|
* Decode a Sythos Canvas QR matrix.
|
|
188
169
|
*
|
|
@@ -203,37 +184,33 @@ function resolveProfile(matrix, options) {
|
|
|
203
184
|
* is an ordinary QR Code.
|
|
204
185
|
*/
|
|
205
186
|
export function decodeFrameQR(matrix, options = {}) {
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
);
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
187
|
+
if (!matrix || !Number.isInteger(matrix.width) || !Number.isInteger(matrix.height)) {
|
|
188
|
+
throw new FormatError('Sythos Canvas QR: no matrix supplied');
|
|
189
|
+
}
|
|
190
|
+
if (matrix.width !== matrix.height) {
|
|
191
|
+
throw new FormatError(`Sythos Canvas QR: symbol must be square, got ${matrix.width}x${matrix.height}`);
|
|
192
|
+
}
|
|
193
|
+
const profile = resolveProfile(matrix, options);
|
|
194
|
+
let decoded;
|
|
195
|
+
try {
|
|
196
|
+
decoded = decodeQR(matrix);
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
// Preserve the original QR/RS error when possible, but give callers a
|
|
200
|
+
// profile-specific context without exposing implementation details.
|
|
201
|
+
if (error instanceof FormatError) {
|
|
202
|
+
throw new FormatError(`Sythos Canvas QR: payload is not recoverable: ${error.message}`);
|
|
203
|
+
}
|
|
204
|
+
throw error;
|
|
224
205
|
}
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
canvas: profile.canvas,
|
|
235
|
-
canvasDamage: profile.damage,
|
|
236
|
-
};
|
|
206
|
+
return {
|
|
207
|
+
...decoded,
|
|
208
|
+
format: 'frameqr',
|
|
209
|
+
profile: profile.profile,
|
|
210
|
+
certified: profile.certified,
|
|
211
|
+
frame: profile.canvas,
|
|
212
|
+
canvas: profile.canvas,
|
|
213
|
+
canvasDamage: profile.damage,
|
|
214
|
+
};
|
|
237
215
|
}
|
|
238
|
-
|
|
239
216
|
export { isExpectedProfile };
|
|
@@ -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 the non-certified Sythos Canvas QR profile.
|
|
33
32
|
*
|
|
@@ -45,19 +44,12 @@
|
|
|
45
44
|
*
|
|
46
45
|
* @module frameqr/detector
|
|
47
46
|
*/
|
|
48
|
-
|
|
49
47
|
import { NotFoundError } from '../core/errors.js';
|
|
50
48
|
import { sampleQuad } from '../image/grid-sampler.js';
|
|
51
49
|
import { detectQR } from '../qr/detector.js';
|
|
52
50
|
import { decodeFrameQR } from './decoder.js';
|
|
53
|
-
import {
|
|
54
|
-
FRAMEQR_PROFILE,
|
|
55
|
-
canvasModules,
|
|
56
|
-
normalizeCanvasSpec,
|
|
57
|
-
} from './tables.js';
|
|
58
|
-
|
|
51
|
+
import { FRAMEQR_PROFILE, canvasModules, normalizeCanvasSpec, } from './tables.js';
|
|
59
52
|
/** @typedef {{x:number, y:number}} Point */
|
|
60
|
-
|
|
61
53
|
/** @typedef {object} FrameQRDetection
|
|
62
54
|
* @property {Point[]} corners Outer corners in reading order.
|
|
63
55
|
* @property {number} dimension QR modules per side.
|
|
@@ -69,11 +61,10 @@ import {
|
|
|
69
61
|
* @property {string} profile Profile identifier.
|
|
70
62
|
* @property {false} certified Always false for this implementation.
|
|
71
63
|
*/
|
|
72
|
-
|
|
73
64
|
function orientationDegrees(corners) {
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
65
|
+
const [tl, tr] = corners;
|
|
66
|
+
const angle = Math.atan2(tr.y - tl.y, tr.x - tl.x) * 180 / Math.PI;
|
|
67
|
+
return ((Math.round(angle / 90) * 90) % 360 + 360) % 360;
|
|
77
68
|
}
|
|
78
69
|
/**
|
|
79
70
|
* Return the number of canvas modules that are dark in a sampled matrix.
|
|
@@ -83,20 +74,20 @@ function orientationDegrees(corners) {
|
|
|
83
74
|
* artwork; both are rejected because decoding that image would be speculative.
|
|
84
75
|
*/
|
|
85
76
|
function canvasDarkCount(matrix, canvas) {
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
77
|
+
let dark = 0;
|
|
78
|
+
for (const [x, y] of canvasModules(matrix.width, canvas)) {
|
|
79
|
+
if (matrix.get(x, y))
|
|
80
|
+
dark++;
|
|
81
|
+
}
|
|
82
|
+
return dark;
|
|
91
83
|
}
|
|
92
|
-
|
|
93
84
|
function sameCandidate(left, right) {
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
85
|
+
if (left.dimension !== right.dimension)
|
|
86
|
+
return false;
|
|
87
|
+
const a = left.corners[0];
|
|
88
|
+
const b = right.corners[0];
|
|
89
|
+
return Math.hypot(a.x - b.x, a.y - b.y) <= Math.max(left.moduleSize, right.moduleSize) * 2;
|
|
98
90
|
}
|
|
99
|
-
|
|
100
91
|
/**
|
|
101
92
|
* Detect Sythos Canvas QR symbols in a binarized raster.
|
|
102
93
|
*
|
|
@@ -109,66 +100,76 @@ function sameCandidate(left, right) {
|
|
|
109
100
|
* profile signature is found.
|
|
110
101
|
*/
|
|
111
102
|
export function detectFrameQR(binaryImage, options = {}) {
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
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
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
103
|
+
if (!binaryImage || !binaryImage.width || !binaryImage.height) {
|
|
104
|
+
throw new NotFoundError('detectFrameQR: no image supplied');
|
|
105
|
+
}
|
|
106
|
+
let candidates;
|
|
107
|
+
try {
|
|
108
|
+
candidates = detectQR(binaryImage);
|
|
109
|
+
}
|
|
110
|
+
catch {
|
|
111
|
+
return [];
|
|
112
|
+
}
|
|
113
|
+
const detections = [];
|
|
114
|
+
for (const candidate of candidates) {
|
|
115
|
+
// QR detector dimensions are already constrained to legal Model 2 sizes.
|
|
116
|
+
let canvas;
|
|
117
|
+
try {
|
|
118
|
+
canvas = normalizeCanvasSpec(candidate.dimension, options.canvas);
|
|
119
|
+
}
|
|
120
|
+
catch {
|
|
121
|
+
continue;
|
|
122
|
+
}
|
|
123
|
+
for (const voting of [Boolean(options.voting), !Boolean(options.voting)]) {
|
|
124
|
+
let matrix;
|
|
125
|
+
try {
|
|
126
|
+
matrix = sampleQuad(binaryImage, candidate.dimension, candidate.corners, voting);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
continue;
|
|
130
|
+
}
|
|
131
|
+
// The signature check is intentionally strict. It prevents an ordinary
|
|
132
|
+
// QR symbol from being relabelled as Canvas QR by the decoder's explicit
|
|
133
|
+
// allowUnmarked escape hatch.
|
|
134
|
+
if (canvasDarkCount(matrix, canvas) !== 0)
|
|
135
|
+
continue;
|
|
136
|
+
const marked = matrix;
|
|
137
|
+
marked.frameqr = {
|
|
138
|
+
profile: FRAMEQR_PROFILE.id,
|
|
139
|
+
certified: false,
|
|
140
|
+
canvas,
|
|
141
|
+
};
|
|
142
|
+
let decoded;
|
|
143
|
+
try {
|
|
144
|
+
decoded = decodeFrameQR(marked, {
|
|
145
|
+
profile: FRAMEQR_PROFILE.id,
|
|
146
|
+
canvas,
|
|
147
|
+
allowUnmarked: true,
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
catch {
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
const detection = {
|
|
154
|
+
corners: candidate.corners,
|
|
155
|
+
dimension: candidate.dimension,
|
|
156
|
+
version: candidate.version,
|
|
157
|
+
moduleSize: candidate.moduleSize,
|
|
158
|
+
rotation: orientationDegrees(candidate.corners),
|
|
159
|
+
matrix: marked,
|
|
160
|
+
canvas,
|
|
161
|
+
profile: FRAMEQR_PROFILE.id,
|
|
162
|
+
certified: false,
|
|
163
|
+
result: decoded,
|
|
164
|
+
};
|
|
165
|
+
if (!detections.some((entry) => sameCandidate(entry, detection)))
|
|
166
|
+
detections.push(detection);
|
|
167
|
+
break;
|
|
168
|
+
}
|
|
165
169
|
}
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
detections.sort((a, b) => b.moduleSize - a.moduleSize);
|
|
169
|
-
return detections;
|
|
170
|
+
detections.sort((a, b) => b.moduleSize - a.moduleSize);
|
|
171
|
+
return detections;
|
|
170
172
|
}
|
|
171
|
-
|
|
172
173
|
/**
|
|
173
174
|
* Detect and decode all verified Canvas QR symbols in one call.
|
|
174
175
|
*
|
|
@@ -177,16 +178,22 @@ export function detectFrameQR(binaryImage, options = {}) {
|
|
|
177
178
|
* @returns {Array<object>}
|
|
178
179
|
*/
|
|
179
180
|
export function detectAndDecodeFrameQR(binaryImage, options = {}) {
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
seen
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
181
|
+
let detections;
|
|
182
|
+
try {
|
|
183
|
+
detections = detectFrameQR(binaryImage, options);
|
|
184
|
+
}
|
|
185
|
+
catch {
|
|
186
|
+
return [];
|
|
187
|
+
}
|
|
188
|
+
const results = [];
|
|
189
|
+
const seen = new Set();
|
|
190
|
+
for (const detection of detections) {
|
|
191
|
+
const result = detection.result;
|
|
192
|
+
const key = `${result.version}|${result.text}`;
|
|
193
|
+
if (seen.has(key))
|
|
194
|
+
continue;
|
|
195
|
+
seen.add(key);
|
|
196
|
+
results.push({ ...result, corners: detection.corners, rotation: detection.rotation });
|
|
197
|
+
}
|
|
198
|
+
return results;
|
|
192
199
|
}
|