tapirscan 1.2.1 → 1.3.0
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 +220 -0
- package/README.md +384 -226
- package/dist/browser-worker.d.ts +33 -0
- package/dist/browser-worker.js +83 -0
- package/dist/browser.d.ts +44 -0
- package/dist/browser.js +211 -0
- package/dist/freeze.d.ts +6 -0
- package/dist/freeze.js +7 -0
- package/dist/index.d.ts +53 -46
- package/dist/index.js +168 -209
- package/dist/layout.d.ts +19 -0
- package/dist/layout.js +27 -0
- package/dist/multiformat/format-registry.d.ts +26 -0
- package/dist/multiformat/format-registry.js +63 -0
- package/dist/multiformat/formats.d.ts +4 -24
- package/dist/multiformat/formats.js +15 -46
- package/dist/rust-session.d.ts +19 -0
- package/dist/rust-session.js +102 -0
- package/examples/camera.html +28 -29
- package/examples/vite/README.md +31 -0
- package/examples/vite/index.html +14 -0
- package/examples/vite/main.js +33 -0
- package/examples/vite/package.json +16 -0
- package/examples/vite/vite.config.js +6 -0
- package/package.json +28 -11
- package/wasm/build.json +295 -0
- package/wasm/experimental-turbo16.wasm +0 -0
- package/wasm/experimental-turbo2.wasm +0 -0
- package/wasm/experimental-turbo4.wasm +0 -0
- package/wasm/experimental-turbo8.wasm +0 -0
- package/wasm/high.wasm +0 -0
- package/wasm/low.wasm +0 -0
- package/wasm/medium.wasm +0 -0
- package/wasm/very-high.wasm +0 -0
- package/dist/completion-host.d.mts +0 -40
- package/dist/completion-host.mjs +0 -188
- package/dist/detail-20260914/continuity.d.mts +0 -2
- package/dist/detail-20260914/continuity.mjs +0 -62
- package/dist/detail-20260914/detail-proposals-rich.d.mts +0 -13
- package/dist/detail-20260914/detail-proposals-rich.mjs +0 -53
- package/dist/detail-20260914/direct-recovery.d.mts +0 -28
- package/dist/detail-20260914/direct-recovery.mjs +0 -139
- package/dist/detail-20260914/host.d.mts +0 -40
- package/dist/detail-20260914/host.mjs +0 -280
- package/dist/detail-20260914/scanner.d.mts +0 -12
- package/dist/detail-20260914/scanner.mjs +0 -64
- package/dist/detail-20260914/source-evidence.d.mts +0 -10
- package/dist/detail-20260914/source-evidence.mjs +0 -94
- package/dist/detail-canvas.d.ts +0 -35
- package/dist/detail-canvas.js +0 -73
- package/dist/detail-runtime/direct-recovery.d.mts +0 -28
- package/dist/detail-runtime/direct-recovery.mjs +0 -142
- package/dist/detail-runtime/host.d.mts +0 -40
- package/dist/detail-runtime/host.mjs +0 -284
- package/dist/detail-runtime/scanner.d.mts +0 -12
- package/dist/detail-runtime/scanner.mjs +0 -70
- package/dist/detail.d.ts +0 -20
- package/dist/detail.js +0 -84
- package/dist/host.d.ts +0 -112
- package/dist/host.js +0 -184
- package/dist/host64.d.ts +0 -112
- package/dist/host64.js +0 -184
- package/dist/multiformat/coverage.d.ts +0 -7
- package/dist/multiformat/coverage.js +0 -26
- package/dist/multiformat/geometry.d.ts +0 -37
- package/dist/multiformat/geometry.js +0 -132
- package/dist/multiformat/linear-duplicates.d.ts +0 -16
- package/dist/multiformat/linear-duplicates.js +0 -163
- package/dist/multiformat/pixels.d.ts +0 -3
- package/dist/multiformat/pixels.js +0 -36
- package/dist/multiformat/scanner.d.ts +0 -60
- package/dist/multiformat/scanner.js +0 -382
- package/dist/multiformat-host.d.ts +0 -121
- package/dist/multiformat-host.js +0 -207
- package/dist/policy.d.ts +0 -12
- package/dist/policy.js +0 -12
- package/examples/scan-worker.mjs +0 -20
- package/examples/worker-client.mjs +0 -63
- package/wasm/high-shared-retail-portable-20260919.wasm +0 -0
- package/wasm/low-shared-retail-portable-20260919.wasm +0 -0
- package/wasm/medium-shared-retail-portable-20260919.wasm +0 -0
- package/wasm/multiformat.json +0 -7
- package/wasm/multiformat.wasm +0 -0
- package/wasm/very-high-shared-retail-portable-20260919.wasm +0 -0
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
export function project(t, x, y) {
|
|
2
|
-
const z = t[6] * x + t[7] * y + 1;
|
|
3
|
-
return [(t[0] * x + t[1] * y + t[2]) / z, (t[3] * x + t[4] * y + t[5]) / z];
|
|
4
|
-
}
|
|
5
|
-
export function transformFor(quad, width, height) {
|
|
6
|
-
const source = [
|
|
7
|
-
[0, 0],
|
|
8
|
-
[width, 0],
|
|
9
|
-
[width, height],
|
|
10
|
-
[0, height],
|
|
11
|
-
];
|
|
12
|
-
const a = [];
|
|
13
|
-
for (let i = 0; i < 4; i++) {
|
|
14
|
-
const [x, y] = source[i], [u, v] = quad[i];
|
|
15
|
-
a.push([x, y, 1, 0, 0, 0, -u * x, -u * y, u], [0, 0, 0, x, y, 1, -v * x, -v * y, v]);
|
|
16
|
-
}
|
|
17
|
-
for (let col = 0; col < 8; col++) {
|
|
18
|
-
let pivot = col;
|
|
19
|
-
for (let i = col + 1; i < 8; i++)
|
|
20
|
-
if (Math.abs(a[i][col]) > Math.abs(a[pivot][col]))
|
|
21
|
-
pivot = i;
|
|
22
|
-
if (Math.abs(a[pivot][col]) < 1e-9)
|
|
23
|
-
throw Error("Degenerate barcode region.");
|
|
24
|
-
[a[col], a[pivot]] = [a[pivot], a[col]];
|
|
25
|
-
const divisor = a[col][col];
|
|
26
|
-
for (let j = col; j <= 8; j++)
|
|
27
|
-
a[col][j] /= divisor;
|
|
28
|
-
for (let i = 0; i < 8; i++) {
|
|
29
|
-
if (i === col)
|
|
30
|
-
continue;
|
|
31
|
-
const scale = a[i][col];
|
|
32
|
-
for (let j = col; j <= 8; j++)
|
|
33
|
-
a[i][j] -= scale * a[col][j];
|
|
34
|
-
}
|
|
35
|
-
}
|
|
36
|
-
return a.map((row) => row[8]);
|
|
37
|
-
}
|
|
38
|
-
export function rectificationPlan(quad) {
|
|
39
|
-
const distance = (a, b) => Math.hypot(a[0] - b[0], a[1] - b[1]);
|
|
40
|
-
const w = Math.max(8, Math.ceil(Math.max(distance(quad[0], quad[1]), distance(quad[3], quad[2]))));
|
|
41
|
-
const h = Math.max(8, Math.ceil(Math.max(distance(quad[0], quad[3]), distance(quad[1], quad[2]))));
|
|
42
|
-
if (w * h > 8 * 1024 * 1024)
|
|
43
|
-
throw Error("Barcode region exceeds rectification budget.");
|
|
44
|
-
const base = transformFor(quad, w, h);
|
|
45
|
-
const pad = 8, divisor = 1 - pad * (base[6] + base[7]);
|
|
46
|
-
const t = [
|
|
47
|
-
base[0] / divisor,
|
|
48
|
-
base[1] / divisor,
|
|
49
|
-
(base[2] - pad * (base[0] + base[1])) / divisor,
|
|
50
|
-
base[3] / divisor,
|
|
51
|
-
base[4] / divisor,
|
|
52
|
-
(base[5] - pad * (base[3] + base[4])) / divisor,
|
|
53
|
-
base[6] / divisor,
|
|
54
|
-
base[7] / divisor,
|
|
55
|
-
];
|
|
56
|
-
const paddedWidth = w + 2 * pad, paddedHeight = h + 2 * pad;
|
|
57
|
-
return { width: paddedWidth, height: paddedHeight, transform: t };
|
|
58
|
-
}
|
|
59
|
-
export function rectify(gray, width, height, quad) {
|
|
60
|
-
const { width: paddedWidth, height: paddedHeight, transform: t } = rectificationPlan(quad);
|
|
61
|
-
const data = new Uint8Array(paddedWidth * paddedHeight);
|
|
62
|
-
for (let y = 0; y < paddedHeight; y++) {
|
|
63
|
-
const cy = y + 0.5;
|
|
64
|
-
const yX = t[1] * cy, yY = t[4] * cy, yZ = t[7] * cy;
|
|
65
|
-
for (let x = 0; x < paddedWidth; x++) {
|
|
66
|
-
const cx = x + 0.5;
|
|
67
|
-
const z = t[6] * cx + yZ + 1;
|
|
68
|
-
const xx = (t[0] * cx + yX + t[2]) / z;
|
|
69
|
-
const yy = (t[3] * cx + yY + t[5]) / z;
|
|
70
|
-
if (xx < 0 || yy < 0 || xx > width - 1 || yy > height - 1) {
|
|
71
|
-
data[y * paddedWidth + x] = 255;
|
|
72
|
-
continue;
|
|
73
|
-
}
|
|
74
|
-
const x0 = Math.floor(xx), y0 = Math.floor(yy), fx = xx - x0, fy = yy - y0;
|
|
75
|
-
const x1 = Math.min(width - 1, x0 + 1), y1 = Math.min(height - 1, y0 + 1);
|
|
76
|
-
data[y * paddedWidth + x] = Math.round((gray[y0 * width + x0] * (1 - fx) + gray[y0 * width + x1] * fx) * (1 - fy) +
|
|
77
|
-
(gray[y1 * width + x0] * (1 - fx) + gray[y1 * width + x1] * fx) * fy);
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
return { data, width: paddedWidth, height: paddedHeight, transform: t };
|
|
81
|
-
}
|
|
82
|
-
/** Convex intersection, including opposite winding and projective quadrilaterals. */
|
|
83
|
-
export function polygonOverlap(a, b) {
|
|
84
|
-
const signedArea = (p) => p.reduce((sum, q, i) => {
|
|
85
|
-
const r = p[(i + 1) % p.length];
|
|
86
|
-
return sum + q[0] * r[1] - q[1] * r[0];
|
|
87
|
-
}, 0) / 2;
|
|
88
|
-
const aa = Math.abs(signedArea(a)), bb = Math.abs(signedArea(b));
|
|
89
|
-
if (Math.min(aa, bb) < 1e-6)
|
|
90
|
-
return { iou: 0, smaller: 0, a: 0, b: 0 };
|
|
91
|
-
const winding = Math.sign(signedArea(b));
|
|
92
|
-
let points = [...a];
|
|
93
|
-
for (let i = 0; i < 4 && points.length; i++) {
|
|
94
|
-
const p = b[i], q = b[(i + 1) % 4];
|
|
95
|
-
const side = (r) => winding * ((q[0] - p[0]) * (r[1] - p[1]) - (q[1] - p[1]) * (r[0] - p[0]));
|
|
96
|
-
const clipped = [];
|
|
97
|
-
for (let j = 0; j < points.length; j++) {
|
|
98
|
-
const u = points[j], v = points[(j + 1) % points.length], su = side(u), sv = side(v);
|
|
99
|
-
if (su >= 0)
|
|
100
|
-
clipped.push(u);
|
|
101
|
-
if (su >= 0 !== sv >= 0) {
|
|
102
|
-
const t = su / (su - sv);
|
|
103
|
-
clipped.push([u[0] + t * (v[0] - u[0]), u[1] + t * (v[1] - u[1])]);
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
points = clipped;
|
|
107
|
-
}
|
|
108
|
-
const intersection = Math.min(aa, bb, Math.abs(signedArea(points)));
|
|
109
|
-
return {
|
|
110
|
-
iou: intersection / (aa + bb - intersection),
|
|
111
|
-
smaller: intersection / Math.min(aa, bb),
|
|
112
|
-
a: intersection / aa,
|
|
113
|
-
b: intersection / bb,
|
|
114
|
-
};
|
|
115
|
-
}
|
|
116
|
-
/** Suppress overlapping reads of the same physical symbol, never by text alone. */
|
|
117
|
-
export function distinctReads(reads) {
|
|
118
|
-
const result = [];
|
|
119
|
-
for (const read of [...reads].sort((a, b) => b.support - a.support)) {
|
|
120
|
-
if (!result.some((r) => r.text === read.text &&
|
|
121
|
-
r.format === read.format &&
|
|
122
|
-
r.eanAddOn === read.eanAddOn &&
|
|
123
|
-
Boolean(r.readerInitialization) === Boolean(read.readerInitialization) &&
|
|
124
|
-
r.structuredAppend?.index === read.structuredAppend?.index &&
|
|
125
|
-
r.structuredAppend?.count === read.structuredAppend?.count &&
|
|
126
|
-
r.structuredAppend?.id === read.structuredAppend?.id &&
|
|
127
|
-
r.structuredAppend?.parity === read.structuredAppend?.parity &&
|
|
128
|
-
polygonOverlap(r.polygon, read.polygon).smaller >= 0.65))
|
|
129
|
-
result.push(read);
|
|
130
|
-
}
|
|
131
|
-
return result;
|
|
132
|
-
}
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
import type { Image, Quad } from "../host.js";
|
|
2
|
-
type Read = {
|
|
3
|
-
text: string;
|
|
4
|
-
format: string;
|
|
5
|
-
polygon: Quad;
|
|
6
|
-
support: number;
|
|
7
|
-
eanAddOn?: string;
|
|
8
|
-
gs1?: boolean;
|
|
9
|
-
readerInitialization?: boolean;
|
|
10
|
-
};
|
|
11
|
-
/** Only merge equal-value, aligned bands when source pixels connect their bars.
|
|
12
|
-
* This does not change search coverage or retry budgets. Exhausting the small
|
|
13
|
-
* evidence budget leaves detections separate, never drops an unchecked read.
|
|
14
|
-
*/
|
|
15
|
-
export declare function mergeLinearDuplicates<T extends Read>(reads: readonly T[], image: Image): T[];
|
|
16
|
-
export {};
|
|
@@ -1,163 +0,0 @@
|
|
|
1
|
-
import { polygonOverlap } from "./geometry.js";
|
|
2
|
-
const formats = new Set(["EAN13", "UPCA", "EAN8", "UPCE", "Code128", "Code39", "ITF"]);
|
|
3
|
-
function bitCount(value) {
|
|
4
|
-
let bits = value - ((value >>> 1) & 0x55555555);
|
|
5
|
-
bits = (bits & 0x33333333) + ((bits >>> 2) & 0x33333333);
|
|
6
|
-
return (((bits + (bits >>> 4)) & 0x0f0f0f0f) * 0x01010101) >>> 24;
|
|
7
|
-
}
|
|
8
|
-
const midpoint = (a, b) => [
|
|
9
|
-
(a[0] + b[0]) / 2,
|
|
10
|
-
(a[1] + b[1]) / 2,
|
|
11
|
-
];
|
|
12
|
-
const line = (q) => [midpoint(q[0], q[3]), midpoint(q[1], q[2])];
|
|
13
|
-
/** Only merge equal-value, aligned bands when source pixels connect their bars.
|
|
14
|
-
* This does not change search coverage or retry budgets. Exhausting the small
|
|
15
|
-
* evidence budget leaves detections separate, never drops an unchecked read.
|
|
16
|
-
*/
|
|
17
|
-
export function mergeLinearDuplicates(reads, image) {
|
|
18
|
-
if (reads.length < 2)
|
|
19
|
-
return [...reads];
|
|
20
|
-
const seen = new Set();
|
|
21
|
-
let repeated = false;
|
|
22
|
-
for (const read of reads) {
|
|
23
|
-
if (!read.text || !formats.has(read.format))
|
|
24
|
-
continue;
|
|
25
|
-
const key = `${read.format}:${read.text}`;
|
|
26
|
-
if (seen.has(key)) {
|
|
27
|
-
repeated = true;
|
|
28
|
-
break;
|
|
29
|
-
}
|
|
30
|
-
seen.add(key);
|
|
31
|
-
}
|
|
32
|
-
if (!repeated)
|
|
33
|
-
return [...reads];
|
|
34
|
-
let remaining = 32768;
|
|
35
|
-
const result = [];
|
|
36
|
-
let values;
|
|
37
|
-
const profile = (left, right) => {
|
|
38
|
-
if (remaining < 64)
|
|
39
|
-
return undefined;
|
|
40
|
-
remaining -= 64;
|
|
41
|
-
values ??= new Float64Array(64);
|
|
42
|
-
let lo = 255, hi = 0;
|
|
43
|
-
for (let i = 0; i < 64; i++) {
|
|
44
|
-
const f = (i + 0.5) / 64;
|
|
45
|
-
const x = Math.round(left[0] + (right[0] - left[0]) * f);
|
|
46
|
-
const y = Math.round(left[1] + (right[1] - left[1]) * f);
|
|
47
|
-
if (x < 0 || y < 0 || x >= image.width || y >= image.height)
|
|
48
|
-
return undefined;
|
|
49
|
-
const p = y * image.stride + x * image.channels;
|
|
50
|
-
const value = image.channels === 1
|
|
51
|
-
? image.data[p]
|
|
52
|
-
: (77 * image.data[p] + 150 * image.data[p + 1] + 29 * image.data[p + 2]) / 256;
|
|
53
|
-
values[i] = value;
|
|
54
|
-
lo = Math.min(lo, value);
|
|
55
|
-
hi = Math.max(hi, value);
|
|
56
|
-
}
|
|
57
|
-
if (hi - lo < 24)
|
|
58
|
-
return undefined;
|
|
59
|
-
const threshold = (lo + hi) / 2;
|
|
60
|
-
let first = 0, second = 0;
|
|
61
|
-
for (let i = 0; i < 32; i++) {
|
|
62
|
-
if (values[i] < threshold)
|
|
63
|
-
first |= 1 << i;
|
|
64
|
-
if (values[i + 32] < threshold)
|
|
65
|
-
second |= 1 << i;
|
|
66
|
-
}
|
|
67
|
-
return [first, second];
|
|
68
|
-
};
|
|
69
|
-
const connected = (a, inputB) => {
|
|
70
|
-
if (!a.every((p) => p.every(Number.isFinite)) || !inputB.every((p) => p.every(Number.isFinite)))
|
|
71
|
-
return undefined;
|
|
72
|
-
const al = line(a), bl = line(inputB);
|
|
73
|
-
const ax = al[1][0] - al[0][0], ay = al[1][1] - al[0][1];
|
|
74
|
-
let bx = bl[1][0] - bl[0][0], by = bl[1][1] - bl[0][1];
|
|
75
|
-
const aw = Math.hypot(ax, ay), bw = Math.hypot(bx, by);
|
|
76
|
-
if (aw < 24 || bw / aw < 0.9 || bw / aw > 1.1)
|
|
77
|
-
return undefined;
|
|
78
|
-
let b = inputB;
|
|
79
|
-
if (ax * bx + ay * by < 0) {
|
|
80
|
-
b = [inputB[2], inputB[3], inputB[0], inputB[1]];
|
|
81
|
-
bx = -bx;
|
|
82
|
-
by = -by;
|
|
83
|
-
}
|
|
84
|
-
if ((ax * bx + ay * by) / (aw * bw) < 0.996)
|
|
85
|
-
return undefined;
|
|
86
|
-
const ac = midpoint(al[0], al[1]), bline = line(b), bc = midpoint(bline[0], bline[1]);
|
|
87
|
-
const dx = bc[0] - ac[0], dy = bc[1] - ac[1];
|
|
88
|
-
if (Math.abs(dx * ax + dy * ay) / aw > aw * 0.06)
|
|
89
|
-
return undefined;
|
|
90
|
-
// Bound endpoint movement too: rotation/perspective can move an edge farther
|
|
91
|
-
// than the centers. Every interpolated sample then moves at most one pixel.
|
|
92
|
-
const distance = Math.max(Math.hypot(bline[0][0] - al[0][0], bline[0][1] - al[0][1]), Math.hypot(bline[1][0] - al[1][0], bline[1][1] - al[1][1]));
|
|
93
|
-
const steps = Math.ceil(distance);
|
|
94
|
-
if (steps < 1 || steps > 384 || (steps + 2) * 64 > remaining)
|
|
95
|
-
return undefined;
|
|
96
|
-
const reference = profile(al[0], al[1]);
|
|
97
|
-
if (!reference)
|
|
98
|
-
return undefined;
|
|
99
|
-
let dark0 = reference[0], dark1 = reference[1];
|
|
100
|
-
let light0 = ~dark0, light1 = ~dark1;
|
|
101
|
-
const minimumDark = Math.max(4, Math.ceil((bitCount(dark0) + bitCount(dark1)) / 4));
|
|
102
|
-
const minimumLight = Math.max(4, Math.ceil((bitCount(light0) + bitCount(light1)) / 4));
|
|
103
|
-
for (let step = 1; step <= steps; step++) {
|
|
104
|
-
const f = step / steps;
|
|
105
|
-
const l = [
|
|
106
|
-
al[0][0] + (bline[0][0] - al[0][0]) * f,
|
|
107
|
-
al[0][1] + (bline[0][1] - al[0][1]) * f,
|
|
108
|
-
];
|
|
109
|
-
const r = [
|
|
110
|
-
al[1][0] + (bline[1][0] - al[1][0]) * f,
|
|
111
|
-
al[1][1] + (bline[1][1] - al[1][1]) * f,
|
|
112
|
-
];
|
|
113
|
-
const sample = profile(l, r);
|
|
114
|
-
if (!sample)
|
|
115
|
-
return undefined;
|
|
116
|
-
const disagreement = bitCount(reference[0] ^ sample[0]) + bitCount(reference[1] ^ sample[1]);
|
|
117
|
-
if (disagreement > 12)
|
|
118
|
-
return undefined;
|
|
119
|
-
dark0 &= sample[0];
|
|
120
|
-
dark1 &= sample[1];
|
|
121
|
-
light0 &= ~sample[0];
|
|
122
|
-
light1 &= ~sample[1];
|
|
123
|
-
// A skewed separator may cross columns at different heights. Require
|
|
124
|
-
// individual bars AND spaces to survive the entire bridge, not just rows.
|
|
125
|
-
if (bitCount(dark0) + bitCount(dark1) < minimumDark ||
|
|
126
|
-
bitCount(light0) + bitCount(light1) < minimumLight)
|
|
127
|
-
return undefined;
|
|
128
|
-
}
|
|
129
|
-
const along = (p) => (-ay * p[0] + ax * p[1]) / aw;
|
|
130
|
-
const top = along(midpoint(a[0], a[1])) < along(midpoint(b[0], b[1])) ? a : b;
|
|
131
|
-
const bottom = along(midpoint(a[2], a[3])) > along(midpoint(b[2], b[3])) ? a : b;
|
|
132
|
-
return [top[0], top[1], bottom[2], bottom[3]];
|
|
133
|
-
};
|
|
134
|
-
for (const read of [...reads].sort((a, b) => b.support - a.support)) {
|
|
135
|
-
if (!formats.has(read.format) || !read.text || remaining < 192) {
|
|
136
|
-
result.push(read);
|
|
137
|
-
continue;
|
|
138
|
-
}
|
|
139
|
-
let merged = false;
|
|
140
|
-
for (let i = 0; i < result.length; i++) {
|
|
141
|
-
const other = result[i];
|
|
142
|
-
if (read.format !== other.format ||
|
|
143
|
-
read.text !== other.text ||
|
|
144
|
-
read.eanAddOn !== other.eanAddOn ||
|
|
145
|
-
Boolean(read.gs1) !== Boolean(other.gs1) ||
|
|
146
|
-
Boolean(read.readerInitialization) !== Boolean(other.readerInitialization))
|
|
147
|
-
continue;
|
|
148
|
-
if (polygonOverlap(other.polygon, read.polygon).smaller >= 0.65) {
|
|
149
|
-
merged = true;
|
|
150
|
-
break;
|
|
151
|
-
}
|
|
152
|
-
const polygon = connected(other.polygon, read.polygon);
|
|
153
|
-
if (!polygon)
|
|
154
|
-
continue;
|
|
155
|
-
result[i] = { ...other, polygon }; // Keep strongest support; observations may overlap.
|
|
156
|
-
merged = true;
|
|
157
|
-
break;
|
|
158
|
-
}
|
|
159
|
-
if (!merged)
|
|
160
|
-
result.push(read);
|
|
161
|
-
}
|
|
162
|
-
return result;
|
|
163
|
-
}
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const littleEndian = new Uint8Array(new Uint32Array([1]).buffer)[0] === 1;
|
|
2
|
-
/** Input dimensions are validated by the scanner. Preserve its integer luma rule. */
|
|
3
|
-
export function toGray({ data, width, height, channels, stride }) {
|
|
4
|
-
const count = width * height;
|
|
5
|
-
if (channels === 1 && stride === width)
|
|
6
|
-
return data.slice(0, count);
|
|
7
|
-
const gray = new Uint8Array(count);
|
|
8
|
-
if (channels === 4 && stride === width * 4 && littleEndian && data.byteOffset % 4 === 0) {
|
|
9
|
-
const words = new Uint32Array(data.buffer, data.byteOffset, count);
|
|
10
|
-
for (let i = 0; i < count; i++) {
|
|
11
|
-
const value = words[i];
|
|
12
|
-
gray[i] =
|
|
13
|
-
((value & 255) * 77 + ((value >>> 8) & 255) * 150 + ((value >>> 16) & 255) * 29 + 128) >>>
|
|
14
|
-
8;
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
else if (channels === 4 && stride === width * 4) {
|
|
18
|
-
for (let i = 0, j = 0; j < count; i += 4, j++)
|
|
19
|
-
gray[j] = (data[i] * 77 + data[i + 1] * 150 + data[i + 2] * 29 + 128) >> 8;
|
|
20
|
-
}
|
|
21
|
-
else if (channels === 3 && stride === width * 3) {
|
|
22
|
-
for (let i = 0, j = 0; j < count; i += 3, j++)
|
|
23
|
-
gray[j] = (data[i] * 77 + data[i + 1] * 150 + data[i + 2] * 29 + 128) >> 8;
|
|
24
|
-
}
|
|
25
|
-
else if (channels === 1) {
|
|
26
|
-
for (let y = 0; y < height; y++)
|
|
27
|
-
gray.set(data.subarray(y * stride, y * stride + width), y * width);
|
|
28
|
-
}
|
|
29
|
-
else {
|
|
30
|
-
for (let y = 0; y < height; y++) {
|
|
31
|
-
for (let x = 0, i = y * stride, j = y * width; x < width; x++, i += channels, j++)
|
|
32
|
-
gray[j] = (data[i] * 77 + data[i + 1] * 150 + data[i + 2] * 29 + 128) >> 8;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return gray;
|
|
36
|
-
}
|
|
@@ -1,60 +0,0 @@
|
|
|
1
|
-
import { ReleaseDetailScanner } from "../detail.js";
|
|
2
|
-
import { IndependentScanner, type Image, type Quad } from "../completion-host.mjs";
|
|
3
|
-
import type { Mode } from "../index.js";
|
|
4
|
-
import { type Format } from "./formats.js";
|
|
5
|
-
export interface Barcode {
|
|
6
|
-
bytes?: number[];
|
|
7
|
-
format: Format | "Unknown";
|
|
8
|
-
text: string;
|
|
9
|
-
polygon: Quad;
|
|
10
|
-
support: number;
|
|
11
|
-
localizationScore?: number;
|
|
12
|
-
gs1?: boolean;
|
|
13
|
-
readerInitialization?: boolean;
|
|
14
|
-
structuredAppend?: {
|
|
15
|
-
index: number;
|
|
16
|
-
count: number;
|
|
17
|
-
id?: string;
|
|
18
|
-
parity?: number;
|
|
19
|
-
};
|
|
20
|
-
eanAddOn?: string;
|
|
21
|
-
error?: number;
|
|
22
|
-
rank?: number;
|
|
23
|
-
}
|
|
24
|
-
export type EanAddOnSymbol = "Ignore" | "Read" | "Require";
|
|
25
|
-
export interface Frame {
|
|
26
|
-
primary?: ReturnType<ReleaseDetailScanner["scanLocalized"]> | ReturnType<IndependentScanner["scanLocalized"]>;
|
|
27
|
-
eanAddOnSymbol: EanAddOnSymbol;
|
|
28
|
-
barcodes: Barcode[];
|
|
29
|
-
regions: Barcode[];
|
|
30
|
-
formats: Format[];
|
|
31
|
-
unfinished: boolean;
|
|
32
|
-
scanMs: number;
|
|
33
|
-
mediumMs: number;
|
|
34
|
-
additionalMs: number;
|
|
35
|
-
preparationMs: number;
|
|
36
|
-
localizationMs: number;
|
|
37
|
-
linearStrategy: "scanlines" | "medium-localized";
|
|
38
|
-
}
|
|
39
|
-
/** Shared retail evidence over primary profiles, plus independent additional readers. */
|
|
40
|
-
export declare class MediumMultiformatScanner {
|
|
41
|
-
private medium?;
|
|
42
|
-
private mode;
|
|
43
|
-
private extra?;
|
|
44
|
-
private handle;
|
|
45
|
-
private rgba;
|
|
46
|
-
private crop;
|
|
47
|
-
private effort;
|
|
48
|
-
private qrEffort;
|
|
49
|
-
private disposed;
|
|
50
|
-
private constructor();
|
|
51
|
-
static create(mediumBytes: ArrayBuffer | undefined, extraBytes?: ArrayBuffer, mode?: Mode, recoveryBytes?: ArrayBuffer): Promise<MediumMultiformatScanner>;
|
|
52
|
-
scan(image: Image, inputFormats?: readonly string[], options?: {
|
|
53
|
-
linearStrategy?: "scanlines" | "medium-localized";
|
|
54
|
-
eanAddOnSymbol?: EanAddOnSymbol;
|
|
55
|
-
finishCandidates?: boolean;
|
|
56
|
-
}): Frame;
|
|
57
|
-
private scanExtra;
|
|
58
|
-
private scanPrepared;
|
|
59
|
-
dispose(): void;
|
|
60
|
-
}
|