image-barcode-identifier 0.0.0-stage → 0.1.1

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/README.md CHANGED
@@ -1,3 +1,124 @@
1
- # Temporary Holding Version
1
+ # image-barcode-identifier
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Reads barcodes from photos in the browser (or Node): you give it an image, it gives you the value.
4
+
5
+ It is built for difficult labels - blur, skew, perspective, uneven light, long thin Code 128 - and is tested against
6
+ photos of real labels. Everything ZXing reads works (Code 128/39/93, EAN/UPC, ITF, QR, DataMatrix, PDF417, Aztec, ...) plus a
7
+ tolerant, checksum-validated Code 128 decoder, barcode localisation, perspective rectification, tiles and a rotation sweep.
8
+
9
+ Nothing leaves the device. No server, no CDN: the ZXing WASM is embedded in the package.
10
+
11
+ ## Install
12
+
13
+ ```bash
14
+ npm install image-barcode-identifier
15
+ ```
16
+
17
+ ## Use
18
+
19
+ ```ts
20
+ import { readBarcode } from 'image-barcode-identifier';
21
+
22
+ const value = await readBarcode(photo); // photo: File | Blob | ImageBitmap | <img> | <canvas> | ImageData | bytes
23
+ // "BCMSY03E38AA4FD00AA41", or null when there is no barcode
24
+ ```
25
+
26
+ Details (format, which stage found it, corner positions) and several barcodes per image:
27
+
28
+ ```ts
29
+ import { readBarcodes } from 'image-barcode-identifier';
30
+
31
+ const results = await readBarcodes(photo, { all: true, timeoutMs: 8000 });
32
+ // [{ text, format, strategy, position }] - [] when nothing was found
33
+ ```
34
+
35
+ ### Keep the UI responsive: use a Web Worker
36
+
37
+ Decoding is CPU heavy (a fraction of a second to a few seconds on a phone). On the main thread it freezes the
38
+ page, so in a UI run it in a worker. Two small steps:
39
+
40
+ ```ts
41
+ // barcode.worker.ts (a file in your app)
42
+ import 'image-barcode-identifier/worker';
43
+ ```
44
+
45
+ ```ts
46
+ import { createWorkerReader } from 'image-barcode-identifier/client';
47
+
48
+ const reader = createWorkerReader(new Worker(new URL('./barcode.worker.ts', import.meta.url), { type: 'module' }));
49
+ void reader.warmup(); // optional: load the engine in the background before the first photo
50
+
51
+ const value = await reader.readBarcode(photo, { timeoutMs: 8000 });
52
+ ```
53
+
54
+ `reader.terminate()` stops the worker and frees its memory (the engine uses a lot of it).
55
+
56
+ ### Vite
57
+
58
+ Add this to `vite.config.ts`, otherwise `npm run dev` discovers the packages when you first read a barcode and reloads
59
+ the whole page (production builds are not affected):
60
+
61
+ ```ts
62
+ export default defineConfig({
63
+ worker: { format: 'es' },
64
+ optimizeDeps: {
65
+ include: [
66
+ 'image-barcode-identifier',
67
+ 'image-barcode-identifier/client',
68
+ 'image-barcode-identifier/worker',
69
+ '@techstark/opencv-js',
70
+ 'zxing-wasm/reader',
71
+ ],
72
+ },
73
+ });
74
+ ```
75
+
76
+ If you set `build.rollupOptions.output.manualChunks`, keep `@techstark/opencv-js` out of your eager vendor chunk.
77
+ It is ~13 MB (about 4 MB gzipped) and is only downloaded when the first image is read.
78
+
79
+ ### Webpack / other bundlers
80
+
81
+ Anything that supports `new Worker(new URL('./x.js', import.meta.url))` and dynamic `import()` works (webpack 5,
82
+ Parcel, Rollup + plugins).
83
+
84
+ ## Options
85
+
86
+ | option | default | meaning |
87
+ | ----------- | ------- | -------------------------------------------------------------------------------------------- |
88
+ | `all` | false | find every barcode instead of stopping at the first |
89
+ | `thorough` | false | run the rotation sweep even when something was found |
90
+ | `timeoutMs` | none | stop searching and return what was found so far (checked between attempts). Set one for a UI |
91
+ | `maxEdge` | 4096 | downscale so the longest edge is at most this. Normal phone photos are left untouched |
92
+
93
+ ## Node
94
+
95
+ Node has no image decoder, so pass raw RGBA pixels (from `sharp`, `pngjs`, `jpeg-js`, ...):
96
+
97
+ ```ts
98
+ import { readBarcode } from 'image-barcode-identifier';
99
+ const value = await readBarcode({ data: rgba, width, height });
100
+ ```
101
+
102
+ ## Notes
103
+
104
+ - Results for a given image can depend on its resolution. Prefer sending the full-resolution photo to downscaling it.
105
+ - A checksum-valid Code 128 read of a very blurry label can still be wrong; the reader keeps the lowest-error candidate
106
+ across several row bands, strips and widths, which fixed every misread seen so far. Validate values against your own
107
+ format (for example a fixed prefix and length) if a wrong read would be costly.
108
+ - `zxing-wasm` and `@techstark/opencv-js` are pinned to exact versions on purpose: the embedded WASM binary must match
109
+ the JS that loads it.
110
+
111
+ ## Develop
112
+
113
+ ```bash
114
+ npm install
115
+ npm test # reference barcode images + two real label photos, in Node
116
+ npm run build # embeds the wasm, compiles to dist/
117
+ ```
118
+
119
+ ## Publish
120
+
121
+ ```bash
122
+ npm login
123
+ npm publish # prepublishOnly runs the typecheck, build and tests first
124
+ ```
@@ -0,0 +1,13 @@
1
+ import type { BarcodeResult, ImageInput, ReadOptions } from './types.js';
2
+ export type { BarcodeResult, ImageInput, Point, RawImage, ReadOptions } from './types.js';
3
+ export interface WorkerReader {
4
+ /** Resolves with [] when nothing was found; rejects when decoding itself failed. */
5
+ readBarcodes(image: ImageInput, options?: ReadOptions): Promise<BarcodeResult[]>;
6
+ /** The value of the first barcode found, or `null`. */
7
+ readBarcode(image: ImageInput, options?: ReadOptions): Promise<string | null>;
8
+ /** Start loading OpenCV + ZXing in the worker so the first read is fast. */
9
+ warmup(): Promise<void>;
10
+ /** Terminate the worker (frees its memory) and reject everything in flight. */
11
+ terminate(): void;
12
+ }
13
+ export declare function createWorkerReader(worker: Worker): WorkerReader;
package/dist/client.js ADDED
@@ -0,0 +1,56 @@
1
+ export function createWorkerReader(worker) {
2
+ let nextId = 1;
3
+ const pending = new Map();
4
+ worker.onmessage = ({ data }) => {
5
+ const entry = pending.get(data.id);
6
+ if (!entry)
7
+ return;
8
+ pending.delete(data.id);
9
+ if (data.type === 'error')
10
+ entry.reject(new Error(data.message));
11
+ else
12
+ entry.resolve(data);
13
+ };
14
+ worker.onerror = (event) => {
15
+ const error = new Error(event.message || 'Barcode worker failed to load');
16
+ for (const entry of pending.values())
17
+ entry.reject(error);
18
+ pending.clear();
19
+ };
20
+ const send = (request, transfer = []) => new Promise((resolve, reject) => {
21
+ pending.set(request.id, { resolve, reject });
22
+ worker.postMessage(request, transfer);
23
+ });
24
+ // Canvases and <img> elements can't be posted to a worker; bitmaps can, and are transferred (no copy).
25
+ const postable = async (image) => {
26
+ const isElement = (typeof HTMLImageElement !== 'undefined' && image instanceof HTMLImageElement) ||
27
+ (typeof HTMLCanvasElement !== 'undefined' && image instanceof HTMLCanvasElement) ||
28
+ (typeof OffscreenCanvas !== 'undefined' && image instanceof OffscreenCanvas);
29
+ const value = isElement ? await createImageBitmap(image) : image;
30
+ const transfer = typeof ImageBitmap !== 'undefined' && value instanceof ImageBitmap ? [value] : [];
31
+ return { image: value, transfer };
32
+ };
33
+ const readBarcodes = async (image, options) => {
34
+ const { image: value, transfer } = await postable(image);
35
+ const res = await send({ id: nextId++, type: 'read', image: value, options }, transfer);
36
+ return res.type === 'read' ? res.results : [];
37
+ };
38
+ return {
39
+ readBarcodes,
40
+ async readBarcode(image, options) {
41
+ const [first] = await readBarcodes(image, { ...options, all: false });
42
+ return first ? first.text : null;
43
+ },
44
+ async warmup() {
45
+ await send({ id: nextId++, type: 'warmup' });
46
+ },
47
+ terminate() {
48
+ worker.terminate();
49
+ const error = new Error('Barcode worker terminated');
50
+ for (const entry of pending.values())
51
+ entry.reject(error);
52
+ pending.clear();
53
+ },
54
+ };
55
+ }
56
+ //# sourceMappingURL=client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import type { Gray } from './ops.js';
2
+ /** A decode with at most this mean error is trusted without checking the remaining row bands. */
3
+ export declare const CONFIDENT_ERROR = 0.04;
4
+ /**
5
+ * A checksum-valid decode with a larger mean error is rejected outright: correct reads of very blurry photos
6
+ * measured up to about 0.10, while misreads of a wrong region or heavy blur measured 0.125 and more. Returning
7
+ * nothing is better than returning a wrong barcode value.
8
+ */
9
+ export declare const MAX_ERROR = 0.11;
10
+ export interface Decoded {
11
+ text: string;
12
+ /** Mean per-module squared error (lower is better). */
13
+ error: number;
14
+ }
15
+ /**
16
+ * Decode a Code 128 barcode from a 1D intensity profile (dark bars on light ground, left-to-right).
17
+ * Returns the best checksum-valid decode or null.
18
+ */
19
+ export declare function decodeProfile(profile: Float64Array): Decoded | null;
20
+ /**
21
+ * strip: grayscale image of an upright barcode (bars vertical), with quiet zones. Tries several row bands and
22
+ * both reading directions.
23
+ *
24
+ * The checksum alone is a weak check (about 1 in 103 random misreads passes it) and different row bands of the
25
+ * same strip can disagree: on real photos a band over a smudge or the caption can produce a checksum-valid but
26
+ * wrong text. The match error tells them apart (correct decodes measured 0.03-0.05, wrong ones 0.07-0.09), so
27
+ * the lowest-error decode over all bands wins. Bands are only skipped once a decode is confident
28
+ * (error <= CONFIDENT_ERROR).
29
+ */
30
+ export declare function decodeRectified(strip: Gray): Decoded | null;
@@ -0,0 +1,338 @@
1
+ const CODE128_PATTERNS = [
2
+ '11011001100', '11001101100', '11001100110', '10010011000', '10010001100', '10001001100',
3
+ '10011001000', '10011000100', '10001100100', '11001001000', '11001000100', '11000100100',
4
+ '10110011100', '10011011100', '10011001110', '10111001100', '10011101100', '10011100110',
5
+ '11001110010', '11001011100', '11001001110', '11011100100', '11001110100', '11101101110',
6
+ '11101001100', '11100101100', '11100100110', '11101100100', '11100110100', '11100110010',
7
+ '11011011000', '11011000110', '11000110110', '10100011000', '10001011000', '10001000110',
8
+ '10110001000', '10001101000', '10001100010', '11010001000', '11000101000', '11000100010',
9
+ '10110111000', '10110001110', '10001101110', '10111011000', '10111000110', '10001110110',
10
+ '11101110110', '11010001110', '11000101110', '11011101000', '11011100010', '11011101110',
11
+ '11101011000', '11101000110', '11100010110', '11101101000', '11101100010', '11100011010',
12
+ '11101111010', '11001000010', '11110001010', '10100110000', '10100001100', '10010110000',
13
+ '10010000110', '10000101100', '10000100110', '10110010000', '10110000100', '10011010000',
14
+ '10011000010', '10000110100', '10000110010', '11000010010', '11001010000', '11110111010',
15
+ '11000010100', '10001111010', '10100111100', '10010111100', '10010011110', '10111100100',
16
+ '10011110100', '10011110010', '11110100100', '11110010100', '11110010010', '11011011110',
17
+ '11011110110', '11110110110', '10101111000', '10100011110', '10001011110', '10111101000',
18
+ '10111100010', '11110101000', '11110100010', '10111011110', '10111101110', '11101011110',
19
+ '11110101110', '11010000100', '11010010000', '11010011100',
20
+ ];
21
+ const STOP_PATTERN = '1100011101011'; // 13 modules incl. final termination bar
22
+ const P = new Float64Array(CODE128_PATTERNS.length * 11); // (106, 11) flattened
23
+ CODE128_PATTERNS.forEach((p, v) => {
24
+ for (let i = 0; i < 11; i++)
25
+ P[v * 11 + i] = p.charCodeAt(i) - 48;
26
+ });
27
+ const STOP = Float64Array.from(STOP_PATTERN, (c) => c.charCodeAt(0) - 48);
28
+ const N_PATTERNS = CODE128_PATTERNS.length;
29
+ const START_A = 103;
30
+ const START_B = 104;
31
+ const START_C = 105;
32
+ /** A decode with at most this mean error is trusted without checking the remaining row bands. */
33
+ export const CONFIDENT_ERROR = 0.04;
34
+ /**
35
+ * A checksum-valid decode with a larger mean error is rejected outright: correct reads of very blurry photos
36
+ * measured up to about 0.10, while misreads of a wrong region or heavy blur measured 0.125 and more. Returning
37
+ * nothing is better than returning a wrong barcode value.
38
+ */
39
+ export const MAX_ERROR = 0.11;
40
+ /** values: start, data... (without checksum). */
41
+ function translate(values) {
42
+ let mode = values[0] === START_A ? 'A' : values[0] === START_B ? 'B' : 'C';
43
+ let out = '';
44
+ let shiftOnce = false;
45
+ for (let k = 1; k < values.length; k++) {
46
+ const v = values[k];
47
+ let cur = mode;
48
+ if (shiftOnce) {
49
+ cur = mode === 'A' ? 'B' : 'A';
50
+ shiftOnce = false;
51
+ }
52
+ if (cur === 'C') {
53
+ if (v < 100)
54
+ out += String(v).padStart(2, '0');
55
+ else if (v === 100)
56
+ mode = 'B';
57
+ else if (v === 101)
58
+ mode = 'A';
59
+ continue;
60
+ }
61
+ if (v < 96) {
62
+ if (cur === 'A')
63
+ out += String.fromCharCode(v < 64 ? 32 + v : v - 64);
64
+ else
65
+ out += String.fromCharCode(32 + v);
66
+ }
67
+ else if (v === 98)
68
+ shiftOnce = true;
69
+ else if (v === 99)
70
+ mode = 'C';
71
+ else if (v === 100 && cur === 'A')
72
+ mode = 'B';
73
+ else if (v === 101 && cur === 'B')
74
+ mode = 'A';
75
+ // FNC1-4 are ignored
76
+ }
77
+ return out;
78
+ }
79
+ function sampler(darkness) {
80
+ const n = darkness.length;
81
+ const cum = new Float64Array(n + 1);
82
+ for (let i = 0; i < n; i++)
83
+ cum[i + 1] = cum[i] + darkness[i];
84
+ const interp = (x) => {
85
+ const i = Math.floor(x);
86
+ return i >= n ? cum[n] : cum[i] + (x - i) * darkness[i];
87
+ };
88
+ return (a, b) => {
89
+ a = Math.min(Math.max(a, 0), n);
90
+ b = Math.min(Math.max(b, 0), n);
91
+ return (interp(b) - interp(a)) / Math.max(b - a, 1e-6);
92
+ };
93
+ }
94
+ function linspace(a, b, n) {
95
+ return Array.from({ length: n }, (_, i) => a + ((b - a) * i) / (n - 1));
96
+ }
97
+ /** Decode `nChars` symbol characters (start..checksum) followed by the stop pattern. */
98
+ function tryDecode(avg, start, m, nChars) {
99
+ const shifts = linspace(-0.45 * m, 0.45 * m, 10);
100
+ const samples = new Float64Array(11);
101
+ let pos = start;
102
+ const values = [];
103
+ let totalErr = 0;
104
+ for (let c = 0; c < nChars; c++) {
105
+ let bestErr = Infinity;
106
+ let bestS = 0;
107
+ let bestV = 0;
108
+ for (let s = 0; s < shifts.length; s++) {
109
+ for (let i = 0; i < 11; i++) {
110
+ const center = pos + shifts[s] + (i + 0.5) * m;
111
+ samples[i] = avg(center - 0.3 * m, center + 0.3 * m);
112
+ }
113
+ for (let v = 0; v < N_PATTERNS; v++) {
114
+ let err = 0;
115
+ for (let i = 0; i < 11; i++) {
116
+ const d = samples[i] - P[v * 11 + i];
117
+ err += d * d;
118
+ }
119
+ if (err < bestErr) {
120
+ bestErr = err;
121
+ bestS = s;
122
+ bestV = v;
123
+ }
124
+ }
125
+ }
126
+ const e = bestErr / 11;
127
+ if (e > 0.2)
128
+ return null;
129
+ if (c === 0 && bestV !== START_A && bestV !== START_B && bestV !== START_C)
130
+ return null;
131
+ totalErr += e;
132
+ values.push(bestV);
133
+ pos += shifts[bestS] + 11 * m;
134
+ }
135
+ // stop pattern
136
+ let stopErr = Infinity;
137
+ const stopSamples = new Float64Array(13);
138
+ for (const shift of shifts) {
139
+ for (let i = 0; i < 13; i++) {
140
+ const center = pos + shift + (i + 0.5) * m;
141
+ stopSamples[i] = avg(center - 0.3 * m, center + 0.3 * m);
142
+ }
143
+ let err = 0;
144
+ for (let i = 0; i < 13; i++) {
145
+ const d = stopSamples[i] - STOP[i];
146
+ err += d * d;
147
+ }
148
+ if (err < stopErr)
149
+ stopErr = err;
150
+ }
151
+ if (stopErr / 13 > 0.2)
152
+ return null;
153
+ // checksum
154
+ const data = values.slice(0, -1);
155
+ const check = values[values.length - 1];
156
+ let sum = data[0];
157
+ for (let i = 1; i < data.length; i++)
158
+ sum += i * data[i];
159
+ if (sum % 103 !== check)
160
+ return null;
161
+ const text = translate(data);
162
+ if (!text)
163
+ return null;
164
+ return { text, error: totalErr / nChars };
165
+ }
166
+ /** Cheap prefilter: does the first 11 modules look like a Start A/B/C pattern? */
167
+ function startCharOk(avg, start, m) {
168
+ const shifts = linspace(-0.45 * m, 0.45 * m, 7);
169
+ const samples = new Float64Array(11);
170
+ for (const shift of shifts) {
171
+ for (let i = 0; i < 11; i++) {
172
+ const center = start + shift + (i + 0.5) * m;
173
+ samples[i] = avg(center - 0.3 * m, center + 0.3 * m);
174
+ }
175
+ for (let v = START_A; v <= START_C; v++) {
176
+ let err = 0;
177
+ for (let i = 0; i < 11; i++) {
178
+ const d = samples[i] - P[v * 11 + i];
179
+ err += d * d;
180
+ }
181
+ if (err / 11 < 0.25)
182
+ return true;
183
+ }
184
+ }
185
+ return false;
186
+ }
187
+ function percentile(values, q) {
188
+ const sorted = Float64Array.from(values).sort();
189
+ const idx = (q / 100) * (sorted.length - 1);
190
+ const lo = Math.floor(idx);
191
+ const hi = Math.min(lo + 1, sorted.length - 1);
192
+ return sorted[lo] + (sorted[hi] - sorted[lo]) * (idx - lo);
193
+ }
194
+ /** Sliding max/min over a window of width k (odd), window truncated at the borders. */
195
+ function slidingExtreme(row, k, pickMax) {
196
+ const n = row.length;
197
+ const r = k >> 1;
198
+ const out = new Float64Array(n);
199
+ for (let i = 0; i < n; i++) {
200
+ let best = row[i];
201
+ for (let j = Math.max(0, i - r); j <= Math.min(n - 1, i + r); j++) {
202
+ if (pickMax ? row[j] > best : row[j] < best)
203
+ best = row[j];
204
+ }
205
+ out[i] = best;
206
+ }
207
+ return out;
208
+ }
209
+ /** Normalised box blur with BORDER_REFLECT_101 (like cv2.blur on a single row). */
210
+ function boxBlur(row, k) {
211
+ const n = row.length;
212
+ const r = k >> 1;
213
+ const reflect = (i) => {
214
+ if (n === 1)
215
+ return 0;
216
+ while (i < 0 || i >= n)
217
+ i = i < 0 ? -i : 2 * (n - 1) - i;
218
+ return i;
219
+ };
220
+ const out = new Float64Array(n);
221
+ let acc = 0;
222
+ for (let j = -r; j <= r; j++)
223
+ acc += row[reflect(j)];
224
+ out[0] = acc / k;
225
+ for (let i = 1; i < n; i++) {
226
+ acc += row[reflect(i + r)] - row[reflect(i - 1 - r)];
227
+ out[i] = acc / k;
228
+ }
229
+ return out;
230
+ }
231
+ const clip01 = (x) => (x < 0 ? 0 : x > 1 ? 1 : x);
232
+ /** 0..1 darkness: one with global normalisation, one with local (uneven lighting). */
233
+ function* darknessMaps(p) {
234
+ const n = p.length;
235
+ const lo = percentile(p, 2);
236
+ const hi = percentile(p, 98);
237
+ if (hi - lo >= 25) {
238
+ const out = new Float64Array(n);
239
+ for (let i = 0; i < n; i++)
240
+ out[i] = clip01((hi - p[i]) / (hi - lo));
241
+ yield out;
242
+ }
243
+ const k = Math.max(31, Math.floor(n / 6) | 1);
244
+ const mx = boxBlur(slidingExtreme(p, k, true), k);
245
+ const mn = boxBlur(slidingExtreme(p, k, false), k);
246
+ const out = new Float64Array(n);
247
+ for (let i = 0; i < n; i++)
248
+ out[i] = clip01((mx[i] - p[i]) / Math.max(mx[i] - mn[i], 25));
249
+ yield out;
250
+ }
251
+ function decodeDark(dark) {
252
+ let count = 0;
253
+ let first = -1;
254
+ let last = -1;
255
+ for (let i = 0; i < dark.length; i++) {
256
+ if (dark[i] > 0.5) {
257
+ count++;
258
+ if (first < 0)
259
+ first = i;
260
+ last = i;
261
+ }
262
+ }
263
+ if (count < 50)
264
+ return null;
265
+ const start = first;
266
+ const width = last + 1 - first;
267
+ const avg = sampler(dark);
268
+ let best = null;
269
+ for (let nChars = 3; nChars < 80; nChars++) {
270
+ // start + data + checksum
271
+ const m = width / (11 * nChars + 13);
272
+ if (m < 1.2)
273
+ break;
274
+ if (!startCharOk(avg, start, m))
275
+ continue;
276
+ for (const dm of [1.0, 0.99, 1.01, 0.98, 1.02]) {
277
+ for (const ds of [0.0, -0.3 * m, 0.3 * m]) {
278
+ const res = tryDecode(avg, start + ds, m * dm, nChars);
279
+ if (res && (best === null || res.error < best.error))
280
+ best = res;
281
+ }
282
+ }
283
+ if (best)
284
+ return best;
285
+ }
286
+ return best;
287
+ }
288
+ /**
289
+ * Decode a Code 128 barcode from a 1D intensity profile (dark bars on light ground, left-to-right).
290
+ * Returns the best checksum-valid decode or null.
291
+ */
292
+ export function decodeProfile(profile) {
293
+ for (const dark of darknessMaps(profile)) {
294
+ const res = decodeDark(dark);
295
+ if (res)
296
+ return res;
297
+ }
298
+ return null;
299
+ }
300
+ /**
301
+ * strip: grayscale image of an upright barcode (bars vertical), with quiet zones. Tries several row bands and
302
+ * both reading directions.
303
+ *
304
+ * The checksum alone is a weak check (about 1 in 103 random misreads passes it) and different row bands of the
305
+ * same strip can disagree: on real photos a band over a smudge or the caption can produce a checksum-valid but
306
+ * wrong text. The match error tells them apart (correct decodes measured 0.03-0.05, wrong ones 0.07-0.09), so
307
+ * the lowest-error decode over all bands wins. Bands are only skipped once a decode is confident
308
+ * (error <= CONFIDENT_ERROR).
309
+ */
310
+ export function decodeRectified(strip) {
311
+ const { width: w, height: h, data } = strip;
312
+ const bands = [[0.2, 0.8], [0.1, 0.4], [0.3, 0.6], [0.5, 0.9], [0.0, 1.0]];
313
+ let best = null;
314
+ for (const [a, b] of bands) {
315
+ const r0 = Math.trunc(h * a);
316
+ const r1 = Math.max(Math.trunc(h * b), r0 + 1);
317
+ const profile = new Float64Array(w);
318
+ for (let y = r0; y < r1; y++) {
319
+ const row = y * w;
320
+ for (let x = 0; x < w; x++)
321
+ profile[x] += data[row + x];
322
+ }
323
+ for (let x = 0; x < w; x++)
324
+ profile[x] /= r1 - r0;
325
+ const reversed = Float64Array.from(profile).reverse();
326
+ const inverted = profile.map((v) => 255 - v);
327
+ const invertedReversed = reversed.map((v) => 255 - v);
328
+ for (const prof of [profile, reversed, inverted, invertedReversed]) {
329
+ const res = decodeProfile(prof);
330
+ if (res && (best === null || res.error < best.error))
331
+ best = res;
332
+ }
333
+ if (best && best.error <= CONFIDENT_ERROR)
334
+ break;
335
+ }
336
+ return best;
337
+ }
338
+ //# sourceMappingURL=code128.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"code128.js","sourceRoot":"","sources":["../src/code128.ts"],"names":[],"mappings":"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"}
package/dist/cv.d.ts ADDED
@@ -0,0 +1,8 @@
1
+ export declare function setOpencvLoader(loader: (() => Promise<unknown>) | undefined): void;
2
+ /** The loaded OpenCV.js module. Only valid after `loadCv()` resolved. */
3
+ export declare function getCv(): any;
4
+ /**
5
+ * Loads OpenCV.js once. The module is ~13 MB of JS with the WASM inlined, so it is imported lazily and only
6
+ * when the first image is processed.
7
+ */
8
+ export declare function loadCv(): Promise<void>;
package/dist/cv.js ADDED
@@ -0,0 +1,38 @@
1
+ /* eslint-disable @typescript-eslint/no-explicit-any */
2
+ let cvInstance;
3
+ let cvPromise;
4
+ let opencvLoader;
5
+ export function setOpencvLoader(loader) {
6
+ opencvLoader = loader;
7
+ }
8
+ /** The loaded OpenCV.js module. Only valid after `loadCv()` resolved. */
9
+ export function getCv() {
10
+ if (!cvInstance)
11
+ throw new Error('OpenCV is not loaded yet; await loadCv() first');
12
+ return cvInstance;
13
+ }
14
+ /**
15
+ * Loads OpenCV.js once. The module is ~13 MB of JS with the WASM inlined, so it is imported lazily and only
16
+ * when the first image is processed.
17
+ */
18
+ export function loadCv() {
19
+ if (!cvPromise) {
20
+ cvPromise = (async () => {
21
+ const mod = await (opencvLoader ? opencvLoader() : import('@techstark/opencv-js'));
22
+ let cv = mod && mod.default ? mod.default : mod;
23
+ // Depending on the build, the export is a Promise, an already initialised module, or a module that
24
+ // signals readiness through a callback. Never return `cv` from this async function: the Emscripten
25
+ // module is a thenable and would be awaited recursively.
26
+ if (cv instanceof Promise)
27
+ cv = await cv;
28
+ else if (!cv.Mat)
29
+ await new Promise((resolve) => { cv.onRuntimeInitialized = () => resolve(); });
30
+ cvInstance = cv;
31
+ })();
32
+ cvPromise.catch(() => {
33
+ cvPromise = undefined; // a failed load (offline, blocked chunk) must not be cached
34
+ });
35
+ }
36
+ return cvPromise;
37
+ }
38
+ //# sourceMappingURL=cv.js.map
package/dist/cv.js.map ADDED
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cv.js","sourceRoot":"","sources":["../src/cv.ts"],"names":[],"mappings":"AAAA,uDAAuD;AACvD,IAAI,UAAe,CAAC;AACpB,IAAI,SAAoC,CAAC;AACzC,IAAI,YAAkD,CAAC;AAEvD,MAAM,UAAU,eAAe,CAAC,MAA4C;IAC1E,YAAY,GAAG,MAAM,CAAC;AACxB,CAAC;AAED,yEAAyE;AACzE,MAAM,UAAU,KAAK;IACnB,IAAI,CAAC,UAAU;QAAE,MAAM,IAAI,KAAK,CAAC,gDAAgD,CAAC,CAAC;IACnF,OAAO,UAAU,CAAC;AACpB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,MAAM;IACpB,IAAI,CAAC,SAAS,EAAE,CAAC;QACf,SAAS,GAAG,CAAC,KAAK,IAAI,EAAE;YACtB,MAAM,GAAG,GAAQ,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,sBAAsB,CAAC,CAAC,CAAC;YACxF,IAAI,EAAE,GAAQ,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC;YACrD,mGAAmG;YACnG,mGAAmG;YACnG,yDAAyD;YACzD,IAAI,EAAE,YAAY,OAAO;gBAAE,EAAE,GAAG,MAAM,EAAE,CAAC;iBACpC,IAAI,CAAC,EAAE,CAAC,GAAG;gBAAE,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE,GAAG,EAAE,CAAC,oBAAoB,GAAG,GAAG,EAAE,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;YACvG,UAAU,GAAG,EAAE,CAAC;QAClB,CAAC,CAAC,EAAE,CAAC;QACL,SAAS,CAAC,KAAK,CAAC,GAAG,EAAE;YACnB,SAAS,GAAG,SAAS,CAAC,CAAC,4DAA4D;QACrF,CAAC,CAAC,CAAC;IACL,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC"}