@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
|
* Greyscale to black-and-white.
|
|
33
32
|
*
|
|
@@ -46,17 +45,13 @@
|
|
|
46
45
|
*
|
|
47
46
|
* @module image/binarizer
|
|
48
47
|
*/
|
|
49
|
-
|
|
50
48
|
import { BitMatrix } from '../core/bit-matrix.js';
|
|
51
49
|
import { NotFoundError } from '../core/errors.js';
|
|
52
|
-
|
|
53
50
|
/** Side of a block, in pixels. */
|
|
54
51
|
const BLOCK = 8;
|
|
55
52
|
const BLOCK_SHIFT = 3;
|
|
56
|
-
|
|
57
53
|
/** Below this spread, a block is treated as uniform rather than as edges. */
|
|
58
54
|
const MIN_DYNAMIC_RANGE = 24;
|
|
59
|
-
|
|
60
55
|
/**
|
|
61
56
|
* One threshold for the entire image, chosen from the luminance histogram.
|
|
62
57
|
*
|
|
@@ -68,74 +63,70 @@ const MIN_DYNAMIC_RANGE = 24;
|
|
|
68
63
|
* @returns {BitMatrix} Set bit = dark module.
|
|
69
64
|
*/
|
|
70
65
|
export function binarizeGlobal(source) {
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
66
|
+
const { grey, width, height } = source;
|
|
67
|
+
const buckets = new Int32Array(32);
|
|
68
|
+
for (let i = 0; i < grey.length; i++)
|
|
69
|
+
buckets[grey[i] >> 3]++;
|
|
70
|
+
const threshold = pickThreshold(buckets);
|
|
71
|
+
const out = new BitMatrix(width, height);
|
|
72
|
+
for (let y = 0; y < height; y++) {
|
|
73
|
+
const base = y * width;
|
|
74
|
+
for (let x = 0; x < width; x++) {
|
|
75
|
+
if (grey[base + x] < threshold)
|
|
76
|
+
out.set(x, y);
|
|
77
|
+
}
|
|
81
78
|
}
|
|
82
|
-
|
|
83
|
-
return out;
|
|
79
|
+
return out;
|
|
84
80
|
}
|
|
85
|
-
|
|
86
81
|
/**
|
|
87
82
|
* @param {Int32Array} buckets
|
|
88
83
|
* @returns {number} Threshold in 0-255.
|
|
89
84
|
*/
|
|
90
85
|
function pickThreshold(buckets) {
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
86
|
+
const n = buckets.length;
|
|
87
|
+
let firstPeak = 0, firstPeakSize = 0;
|
|
88
|
+
for (let i = 0; i < n; i++) {
|
|
89
|
+
if (buckets[i] > firstPeakSize) {
|
|
90
|
+
firstPeakSize = buckets[i];
|
|
91
|
+
firstPeak = i;
|
|
92
|
+
}
|
|
98
93
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
94
|
+
// Score candidates by population scaled by squared distance from the first
|
|
95
|
+
// peak: the second peak must be both populous and clearly separated.
|
|
96
|
+
let secondPeak = 0, secondScore = 0;
|
|
97
|
+
for (let i = 0; i < n; i++) {
|
|
98
|
+
const d = i - firstPeak;
|
|
99
|
+
const score = buckets[i] * d * d;
|
|
100
|
+
if (score > secondScore) {
|
|
101
|
+
secondScore = score;
|
|
102
|
+
secondPeak = i;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
let low = Math.min(firstPeak, secondPeak);
|
|
106
|
+
let high = Math.max(firstPeak, secondPeak);
|
|
107
|
+
if (high - low <= n >> 4) {
|
|
108
|
+
// Effectively unimodal — a blank region, or an image with no ink. Fall
|
|
109
|
+
// back to the midpoint of the occupied range rather than inventing edges.
|
|
110
|
+
let lo = 0, hi = n - 1;
|
|
111
|
+
while (lo < n && buckets[lo] === 0)
|
|
112
|
+
lo++;
|
|
113
|
+
while (hi > 0 && buckets[hi] === 0)
|
|
114
|
+
hi--;
|
|
115
|
+
return (((lo + hi) >> 1) << 3) + 4;
|
|
110
116
|
}
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
while (hi > 0 && buckets[hi] === 0) hi--;
|
|
122
|
-
return (((lo + hi) >> 1) << 3) + 4;
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
// Deepest valley between the peaks, biased toward the middle.
|
|
126
|
-
let valley = low, valleyScore = -1;
|
|
127
|
-
for (let i = low + 1; i < high; i++) {
|
|
128
|
-
const fromLow = i - low;
|
|
129
|
-
const fromHigh = high - i;
|
|
130
|
-
const score = fromLow * fromHigh * (firstPeakSize - buckets[i]);
|
|
131
|
-
if (score > valleyScore) {
|
|
132
|
-
valleyScore = score;
|
|
133
|
-
valley = i;
|
|
117
|
+
// Deepest valley between the peaks, biased toward the middle.
|
|
118
|
+
let valley = low, valleyScore = -1;
|
|
119
|
+
for (let i = low + 1; i < high; i++) {
|
|
120
|
+
const fromLow = i - low;
|
|
121
|
+
const fromHigh = high - i;
|
|
122
|
+
const score = fromLow * fromHigh * (firstPeakSize - buckets[i]);
|
|
123
|
+
if (score > valleyScore) {
|
|
124
|
+
valleyScore = score;
|
|
125
|
+
valley = i;
|
|
126
|
+
}
|
|
134
127
|
}
|
|
135
|
-
|
|
136
|
-
return (valley << 3) + 4;
|
|
128
|
+
return (valley << 3) + 4;
|
|
137
129
|
}
|
|
138
|
-
|
|
139
130
|
/**
|
|
140
131
|
* Locally adaptive thresholding.
|
|
141
132
|
*
|
|
@@ -153,100 +144,92 @@ function pickThreshold(buckets) {
|
|
|
153
144
|
* @returns {BitMatrix}
|
|
154
145
|
*/
|
|
155
146
|
export function binarizeHybrid(source) {
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
147
|
+
const { grey, width, height } = source;
|
|
148
|
+
// Too small to block up meaningfully; the global pass is strictly better.
|
|
149
|
+
if (width < BLOCK * 5 || height < BLOCK * 5)
|
|
150
|
+
return binarizeGlobal(source);
|
|
151
|
+
const bw = (width + BLOCK - 1) >> BLOCK_SHIFT;
|
|
152
|
+
const bh = (height + BLOCK - 1) >> BLOCK_SHIFT;
|
|
153
|
+
const means = new Int32Array(bw * bh);
|
|
154
|
+
const ranges = new Int32Array(bw * bh);
|
|
155
|
+
for (let by = 0; by < bh; by++) {
|
|
156
|
+
const y0 = by << BLOCK_SHIFT;
|
|
157
|
+
const y1 = Math.min(y0 + BLOCK, height);
|
|
158
|
+
for (let bx = 0; bx < bw; bx++) {
|
|
159
|
+
const x0 = bx << BLOCK_SHIFT;
|
|
160
|
+
const x1 = Math.min(x0 + BLOCK, width);
|
|
161
|
+
let sum = 0, min = 255, max = 0, count = 0;
|
|
162
|
+
for (let y = y0; y < y1; y++) {
|
|
163
|
+
const base = y * width;
|
|
164
|
+
for (let x = x0; x < x1; x++) {
|
|
165
|
+
const v = grey[base + x];
|
|
166
|
+
sum += v;
|
|
167
|
+
if (v < min)
|
|
168
|
+
min = v;
|
|
169
|
+
if (v > max)
|
|
170
|
+
max = v;
|
|
171
|
+
count++;
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
const idx = by * bw + bx;
|
|
175
|
+
means[idx] = count ? (sum / count) | 0 : 128;
|
|
176
|
+
ranges[idx] = max - min;
|
|
182
177
|
}
|
|
183
|
-
}
|
|
184
|
-
const idx = by * bw + bx;
|
|
185
|
-
means[idx] = count ? (sum / count) | 0 : 128;
|
|
186
|
-
ranges[idx] = max - min;
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
// Flat blocks adopt a threshold from context. Looking left and up is enough
|
|
191
|
-
// because those neighbours are already resolved, and it makes the pass
|
|
192
|
-
// single-shot rather than iterative.
|
|
193
|
-
for (let by = 0; by < bh; by++) {
|
|
194
|
-
for (let bx = 0; bx < bw; bx++) {
|
|
195
|
-
const idx = by * bw + bx;
|
|
196
|
-
if (ranges[idx] >= MIN_DYNAMIC_RANGE) continue;
|
|
197
|
-
|
|
198
|
-
let inherited = means[idx];
|
|
199
|
-
if (bx > 0 && by > 0) {
|
|
200
|
-
const neighbours = [
|
|
201
|
-
means[idx - 1],
|
|
202
|
-
means[idx - bw],
|
|
203
|
-
means[idx - bw - 1],
|
|
204
|
-
];
|
|
205
|
-
const avg = (neighbours[0] + neighbours[1] + neighbours[2]) / 3;
|
|
206
|
-
// A flat block darker than its surroundings is ink; lighter is paper.
|
|
207
|
-
// Either way the local minimum is the safer threshold than the mean.
|
|
208
|
-
inherited = Math.min(avg, means[idx]);
|
|
209
|
-
}
|
|
210
|
-
means[idx] = inherited | 0;
|
|
211
178
|
}
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
179
|
+
// Flat blocks adopt a threshold from context. Looking left and up is enough
|
|
180
|
+
// because those neighbours are already resolved, and it makes the pass
|
|
181
|
+
// single-shot rather than iterative.
|
|
182
|
+
for (let by = 0; by < bh; by++) {
|
|
183
|
+
for (let bx = 0; bx < bw; bx++) {
|
|
184
|
+
const idx = by * bw + bx;
|
|
185
|
+
if (ranges[idx] >= MIN_DYNAMIC_RANGE)
|
|
186
|
+
continue;
|
|
187
|
+
let inherited = means[idx];
|
|
188
|
+
if (bx > 0 && by > 0) {
|
|
189
|
+
const neighbours = [
|
|
190
|
+
means[idx - 1],
|
|
191
|
+
means[idx - bw],
|
|
192
|
+
means[idx - bw - 1],
|
|
193
|
+
];
|
|
194
|
+
const avg = (neighbours[0] + neighbours[1] + neighbours[2]) / 3;
|
|
195
|
+
// A flat block darker than its surroundings is ink; lighter is paper.
|
|
196
|
+
// Either way the local minimum is the safer threshold than the mean.
|
|
197
|
+
inherited = Math.min(avg, means[idx]);
|
|
198
|
+
}
|
|
199
|
+
means[idx] = inherited | 0;
|
|
232
200
|
}
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
201
|
+
}
|
|
202
|
+
const out = new BitMatrix(width, height);
|
|
203
|
+
const R = 2; // 5x5 block window
|
|
204
|
+
for (let by = 0; by < bh; by++) {
|
|
205
|
+
const y0 = by << BLOCK_SHIFT;
|
|
206
|
+
const y1 = Math.min(y0 + BLOCK, height);
|
|
207
|
+
const byLo = Math.max(0, by - R);
|
|
208
|
+
const byHi = Math.min(bh - 1, by + R);
|
|
209
|
+
for (let bx = 0; bx < bw; bx++) {
|
|
210
|
+
const bxLo = Math.max(0, bx - R);
|
|
211
|
+
const bxHi = Math.min(bw - 1, bx + R);
|
|
212
|
+
let sum = 0, count = 0;
|
|
213
|
+
for (let ny = byLo; ny <= byHi; ny++) {
|
|
214
|
+
for (let nx = bxLo; nx <= bxHi; nx++) {
|
|
215
|
+
sum += means[ny * bw + nx];
|
|
216
|
+
count++;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
const threshold = sum / count;
|
|
220
|
+
const x0 = bx << BLOCK_SHIFT;
|
|
221
|
+
const x1 = Math.min(x0 + BLOCK, width);
|
|
222
|
+
for (let y = y0; y < y1; y++) {
|
|
223
|
+
const base = y * width;
|
|
224
|
+
for (let x = x0; x < x1; x++) {
|
|
225
|
+
if (grey[base + x] < threshold)
|
|
226
|
+
out.set(x, y);
|
|
227
|
+
}
|
|
228
|
+
}
|
|
242
229
|
}
|
|
243
|
-
}
|
|
244
230
|
}
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
return out;
|
|
231
|
+
return out;
|
|
248
232
|
}
|
|
249
|
-
|
|
250
233
|
/**
|
|
251
234
|
* Binarize with the named strategy.
|
|
252
235
|
*
|
|
@@ -255,16 +238,17 @@ export function binarizeHybrid(source) {
|
|
|
255
238
|
* @returns {BitMatrix}
|
|
256
239
|
*/
|
|
257
240
|
export function binarize(source, strategy = 'auto') {
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
241
|
+
if (!source || !source.grey)
|
|
242
|
+
throw new NotFoundError('binarize: no luminance source');
|
|
243
|
+
switch (strategy) {
|
|
244
|
+
case 'global': return binarizeGlobal(source);
|
|
245
|
+
case 'hybrid': return binarizeHybrid(source);
|
|
246
|
+
case 'auto':
|
|
247
|
+
// Small images are almost always generated rather than photographed.
|
|
248
|
+
return source.width * source.height < 200 * 200
|
|
249
|
+
? binarizeGlobal(source)
|
|
250
|
+
: binarizeHybrid(source);
|
|
251
|
+
default:
|
|
252
|
+
throw new NotFoundError(`Unknown binarizer strategy: ${strategy}`);
|
|
253
|
+
}
|
|
270
254
|
}
|
|
@@ -27,7 +27,6 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Resample a distorted symbol in the image into an upright module grid.
|
|
33
32
|
*
|
|
@@ -38,11 +37,9 @@
|
|
|
38
37
|
*
|
|
39
38
|
* @module image/grid-sampler
|
|
40
39
|
*/
|
|
41
|
-
|
|
42
40
|
import { BitMatrix } from '../core/bit-matrix.js';
|
|
43
41
|
import { NotFoundError } from '../core/errors.js';
|
|
44
42
|
import { PerspectiveTransform } from './perspective.js';
|
|
45
|
-
|
|
46
43
|
/**
|
|
47
44
|
* Sample a `dimension` x `dimension` grid (or `width` x `height`).
|
|
48
45
|
*
|
|
@@ -54,33 +51,28 @@ import { PerspectiveTransform } from './perspective.js';
|
|
|
54
51
|
* @throws {NotFoundError} If the grid falls outside the image.
|
|
55
52
|
*/
|
|
56
53
|
export function sampleGrid(image, width, height, transform) {
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
}
|
|
77
|
-
if (image.get(px, py)) out.set(x, y);
|
|
54
|
+
const out = new BitMatrix(width, height);
|
|
55
|
+
const points = new Float32Array(width * 2);
|
|
56
|
+
for (let y = 0; y < height; y++) {
|
|
57
|
+
// Module centres: offset by half a module in both axes.
|
|
58
|
+
const gridY = y + 0.5;
|
|
59
|
+
for (let x = 0; x < width; x++) {
|
|
60
|
+
points[x * 2] = x + 0.5;
|
|
61
|
+
points[x * 2 + 1] = gridY;
|
|
62
|
+
}
|
|
63
|
+
transform.transform(points);
|
|
64
|
+
for (let x = 0; x < width; x++) {
|
|
65
|
+
const px = points[x * 2] | 0;
|
|
66
|
+
const py = points[x * 2 + 1] | 0;
|
|
67
|
+
if (px < 0 || py < 0 || px >= image.width || py >= image.height) {
|
|
68
|
+
throw new NotFoundError(`Sampling grid escapes the image at module (${x}, ${y})`);
|
|
69
|
+
}
|
|
70
|
+
if (image.get(px, py))
|
|
71
|
+
out.set(x, y);
|
|
72
|
+
}
|
|
78
73
|
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
return out;
|
|
74
|
+
return out;
|
|
82
75
|
}
|
|
83
|
-
|
|
84
76
|
/**
|
|
85
77
|
* Sample with a 3x3 majority vote per module.
|
|
86
78
|
*
|
|
@@ -95,48 +87,44 @@ export function sampleGrid(image, width, height, transform) {
|
|
|
95
87
|
* @returns {BitMatrix}
|
|
96
88
|
*/
|
|
97
89
|
export function sampleGridVoting(image, width, height, transform) {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
90
|
+
const out = new BitMatrix(width, height);
|
|
91
|
+
// Spacing between module centres, measured in image pixels, so the vote
|
|
92
|
+
// spreads across the module rather than a fixed pixel radius that would be
|
|
93
|
+
// meaningless at a different scale.
|
|
94
|
+
const p0 = transform.transformPoint(0.5, 0.5);
|
|
95
|
+
const p1 = transform.transformPoint(1.5, 0.5);
|
|
96
|
+
const p2 = transform.transformPoint(0.5, 1.5);
|
|
97
|
+
const stepX = Math.hypot(p1.x - p0.x, p1.y - p0.y);
|
|
98
|
+
const stepY = Math.hypot(p2.x - p0.x, p2.y - p0.y);
|
|
99
|
+
const rx = Math.max(1, Math.round(stepX / 4));
|
|
100
|
+
const ry = Math.max(1, Math.round(stepY / 4));
|
|
101
|
+
for (let y = 0; y < height; y++) {
|
|
102
|
+
for (let x = 0; x < width; x++) {
|
|
103
|
+
const c = transform.transformPoint(x + 0.5, y + 0.5);
|
|
104
|
+
const cx = c.x | 0;
|
|
105
|
+
const cy = c.y | 0;
|
|
106
|
+
if (cx < 0 || cy < 0 || cx >= image.width || cy >= image.height) {
|
|
107
|
+
throw new NotFoundError(`Sampling grid escapes the image at module (${x}, ${y})`);
|
|
108
|
+
}
|
|
109
|
+
let dark = 0;
|
|
110
|
+
let total = 0;
|
|
111
|
+
for (let dy = -1; dy <= 1; dy++) {
|
|
112
|
+
for (let dx = -1; dx <= 1; dx++) {
|
|
113
|
+
const sx = cx + dx * rx;
|
|
114
|
+
const sy = cy + dy * ry;
|
|
115
|
+
if (sx < 0 || sy < 0 || sx >= image.width || sy >= image.height)
|
|
116
|
+
continue;
|
|
117
|
+
total++;
|
|
118
|
+
if (image.get(sx, sy))
|
|
119
|
+
dark++;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (total > 0 && dark * 2 > total)
|
|
123
|
+
out.set(x, y);
|
|
131
124
|
}
|
|
132
|
-
}
|
|
133
|
-
if (total > 0 && dark * 2 > total) out.set(x, y);
|
|
134
125
|
}
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
return out;
|
|
126
|
+
return out;
|
|
138
127
|
}
|
|
139
|
-
|
|
140
128
|
/**
|
|
141
129
|
* Build the transform for a symbol whose four corners are known, and sample it.
|
|
142
130
|
*
|
|
@@ -149,16 +137,12 @@ export function sampleGridVoting(image, width, height, transform) {
|
|
|
149
137
|
* @returns {BitMatrix}
|
|
150
138
|
*/
|
|
151
139
|
export function sampleQuad(image, dimension, corners, voting = false) {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
return voting
|
|
162
|
-
? sampleGridVoting(image, d, d, transform)
|
|
163
|
-
: sampleGrid(image, d, d, transform);
|
|
140
|
+
if (corners.length !== 4)
|
|
141
|
+
throw new NotFoundError('sampleQuad needs exactly 4 corners');
|
|
142
|
+
const [tl, tr, br, bl] = corners;
|
|
143
|
+
const d = dimension;
|
|
144
|
+
const transform = PerspectiveTransform.quadToQuad(0, 0, d, 0, d, d, 0, d, tl.x, tl.y, tr.x, tr.y, br.x, br.y, bl.x, bl.y);
|
|
145
|
+
return voting
|
|
146
|
+
? sampleGridVoting(image, d, d, transform)
|
|
147
|
+
: sampleGrid(image, d, d, transform);
|
|
164
148
|
}
|
package/src/js/image/index.js
CHANGED
|
@@ -27,13 +27,11 @@
|
|
|
27
27
|
*
|
|
28
28
|
* Original work. No code from any other barcode implementation.
|
|
29
29
|
*/
|
|
30
|
-
|
|
31
30
|
/**
|
|
32
31
|
* Image pipeline, re-exported.
|
|
33
32
|
*
|
|
34
33
|
* @module image
|
|
35
34
|
*/
|
|
36
|
-
|
|
37
35
|
export { LuminanceSource } from './luminance.js';
|
|
38
36
|
export { binarize, binarizeGlobal, binarizeHybrid } from './binarizer.js';
|
|
39
37
|
export { PerspectiveTransform } from './perspective.js';
|