tapirscan 1.0.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.
Files changed (44) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +241 -0
  3. package/THIRD_PARTY_NOTICES.md +656 -0
  4. package/dist/detail-20260914/continuity.d.mts +2 -0
  5. package/dist/detail-20260914/continuity.mjs +62 -0
  6. package/dist/detail-20260914/detail-proposals-rich.d.mts +13 -0
  7. package/dist/detail-20260914/detail-proposals-rich.mjs +53 -0
  8. package/dist/detail-20260914/direct-recovery.d.mts +28 -0
  9. package/dist/detail-20260914/direct-recovery.mjs +139 -0
  10. package/dist/detail-20260914/host.d.mts +40 -0
  11. package/dist/detail-20260914/host.mjs +280 -0
  12. package/dist/detail-20260914/scanner.d.mts +12 -0
  13. package/dist/detail-20260914/scanner.mjs +64 -0
  14. package/dist/detail-20260914/source-evidence.d.mts +10 -0
  15. package/dist/detail-20260914/source-evidence.mjs +94 -0
  16. package/dist/detail-canvas.d.ts +35 -0
  17. package/dist/detail-canvas.js +73 -0
  18. package/dist/detail.d.ts +19 -0
  19. package/dist/detail.js +87 -0
  20. package/dist/host.d.ts +112 -0
  21. package/dist/host.js +184 -0
  22. package/dist/host64.d.ts +112 -0
  23. package/dist/host64.js +184 -0
  24. package/dist/index.d.ts +92 -0
  25. package/dist/index.js +199 -0
  26. package/dist/multiformat/formats.d.ts +26 -0
  27. package/dist/multiformat/formats.js +59 -0
  28. package/dist/multiformat/geometry.d.ts +32 -0
  29. package/dist/multiformat/geometry.js +122 -0
  30. package/dist/multiformat/pixels.d.ts +3 -0
  31. package/dist/multiformat/pixels.js +36 -0
  32. package/dist/multiformat/scanner.d.ts +51 -0
  33. package/dist/multiformat/scanner.js +258 -0
  34. package/dist/multiformat-host.d.ts +121 -0
  35. package/dist/multiformat-host.js +207 -0
  36. package/dist/policy.d.ts +12 -0
  37. package/dist/policy.js +12 -0
  38. package/package.json +52 -0
  39. package/wasm/high-release-20260915.wasm +0 -0
  40. package/wasm/low-release-20260915.wasm +0 -0
  41. package/wasm/medium-release-20260915.wasm +0 -0
  42. package/wasm/multiformat.json +6 -0
  43. package/wasm/multiformat.wasm +0 -0
  44. package/wasm/very-high-release-20260915.wasm +0 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Florian Nick
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,241 @@
1
+ # Tapirscan for JavaScript and TypeScript
2
+
3
+ Scan image pixels in a browser or Node with the same Rust/WASM core.
4
+ [Quick start](#quick-start) · [WASM loading](#wasm-loading) · [Functions](#functions) · [All options](#all-options) · [Results](#results)
5
+
6
+ ## Quick start
7
+
8
+ ```sh
9
+ npm install tapirscan
10
+ ```
11
+
12
+ Registry publication is pending; until then, install a tarball from the
13
+ [local build guide](../../docs/DEVELOPMENT.md). TypeScript declarations and WASM
14
+ binaries are included. Your runtime must support WebAssembly SIMD.
15
+
16
+ Pass a canvas's `ImageData` directly:
17
+
18
+ ```js
19
+ import { scan } from "tapirscan";
20
+
21
+ // Using an existing canvas and its 2D context:
22
+ const image = context.getImageData(0, 0, canvas.width, canvas.height);
23
+ const result = await scan(image);
24
+ console.log(result.values); // e.g. ["4006381333931"]
25
+ ```
26
+
27
+ Defaults are Medium effort, EAN13, multiple results, and debug disabled.
28
+ `result.barcodes` also gives each read's text, format, polygon and rectangle.
29
+ The helper creates and disposes a scanner automatically. Browser apps need to
30
+ serve its [WASM assets](#wasm-loading); Node loads the packaged files automatically.
31
+
32
+ For more control or repeated images, reuse a scanner:
33
+
34
+ ```js
35
+ import { Scanner } from "tapirscan";
36
+
37
+ const scanner = await Scanner.create({ mode: "high", formats: "1D" });
38
+ try {
39
+ const result = scanner.scan(image);
40
+ for (const barcode of result.barcodes) {
41
+ console.log(barcode.text, barcode.format, barcode.polygon);
42
+ }
43
+ } finally {
44
+ scanner.dispose();
45
+ }
46
+ ```
47
+
48
+ Here `image` is the `ImageData` above. `formats: "1D"` enables all supported linear
49
+ formats; additional readers are experimental. Settings also work with the helper:
50
+ `await scan(image, { mode: "high", formats: "1D" })`.
51
+
52
+ ## WASM loading
53
+
54
+ In Node, the default loader reads assets from the installed package. Decode your
55
+ image with an image library first, then pass grayscale, RGB or RGBA bytes:
56
+
57
+ ```js
58
+ const result = await scan({ data: pixels, width, height, channels: 1, stride: width });
59
+ ```
60
+
61
+ Here `pixels` is a Uint8Array of decoded grayscale pixels. Image codecs are not
62
+ included; filenames, URLs and encoded JPEG/PNG bytes are not scan inputs.
63
+
64
+ In a browser, the default loader fetches assets relative to the module. If your
65
+ bundler relocates modules, copy the WASMs into your public directory:
66
+
67
+ ```sh
68
+ mkdir -p public/tapirscan
69
+ cp node_modules/tapirscan/wasm/*.wasm public/tapirscan/
70
+ ```
71
+
72
+ Then supply a loader pointing at those files:
73
+
74
+ ```js
75
+ const scanner = await Scanner.create({
76
+ loadWasm: async (url) => {
77
+ const filename = url.pathname.split("/").pop();
78
+ const response = await fetch(`/tapirscan/${filename}`);
79
+ if (!response.ok) throw new Error(`Could not load scanner: ${response.status}`);
80
+ return response.arrayBuffer();
81
+ },
82
+ });
83
+ try {
84
+ console.log(scanner.scan(image).values);
85
+ } finally {
86
+ scanner.dispose();
87
+ }
88
+ ```
89
+
90
+ Use the deployed base path if your app is hosted below a subpath. Copy all current
91
+ WASMs: Medium/High/Very high also load the Low recovery decoder. The demo and its
92
+ comparison engines are not needed in your app.
93
+
94
+ ## Camera and worker use
95
+
96
+ Initialization is asynchronous; scanning is synchronous. For a responsive browser
97
+ UI, initialize one scanner inside a Web Worker and transfer an owned frame buffer.
98
+ Capture the next frame after the previous result arrives. Avoid racing scanner
99
+ initialization or modifying pixels during scanning. The [demo worker](../../demo/src/lib/scan.worker.ts)
100
+ shows a complete integration. Camera capture belongs to your app and requires
101
+ HTTPS (localhost works for development).
102
+
103
+ ## Moving from ZXing
104
+
105
+ For [`zxing-wasm`](https://github.com/Sec-ant/zxing-wasm), you can keep your
106
+ existing ImageData and replace the decoding call:
107
+
108
+ ```js
109
+ // Before:
110
+ import { readBarcodes } from "zxing-wasm/reader";
111
+ const reads = await readBarcodes(image, { formats: ["EAN13"] });
112
+ const oldValues = reads.filter((read) => read.isValid).map((read) => read.text);
113
+
114
+ // After:
115
+ import { scan } from "tapirscan";
116
+ const result = await scan(image, { formats: ["EAN13"] });
117
+ const values = result.values;
118
+ ```
119
+
120
+ Here `image` is decoded ImageData. Keep an explicit format selection during
121
+ migration; Tapirscan defaults to EAN13. For successive frames, initialize a
122
+ `Scanner` once and scan inside a worker, as shown above.
123
+
124
+ | Existing ZXing integration | Tapirscan equivalent or difference |
125
+ | ---------------------------------------- | ------------------------------------------------------------------------------------------- |
126
+ | Array of reads | `result.barcodes`, or `result.values` for strings. |
127
+ | `read.text` | `barcode.text`. |
128
+ | `read.position` | `barcode.polygon` as four [x, y] corners, or `barcode.rect`. |
129
+ | `tryHarder`, `tryRotate`, `tryDownscale` | No direct option mapping. Select an effort mode and measure your images. |
130
+ | `maxNumberOfSymbols` | No arbitrary count limit; `multiple: false` selects one after the scan, without early exit. |
131
+ | Blob or encoded image input | Decode to ImageData or a supported byte buffer before scanning. |
132
+ | WASM overrides/asset paths | Use Tapirscan's `loadWasm` and packaged assets. |
133
+
134
+ [`@zxing/browser`](https://github.com/zxing-js/browser) also manages browser image
135
+ and video acquisition. Tapirscan's scanner accepts pixels; it does not replace
136
+ camera-device helpers or continuous-scan callbacks. Keep your capture loop,
137
+ draw frames to a canvas, and pass ImageData to a reusable scanner. Stop media
138
+ tracks when capture ends, and dispose the scanner when finished. See the
139
+ [demo](../../demo/README.md) for capture behavior.
140
+
141
+ Check supported formats and reader-specific metadata before switching. Additional
142
+ formats are experimental, and Tapirscan is not a drop-in replacement for every
143
+ ZXing package. Run both readers on representative inputs before replacing one.
144
+
145
+ ## Functions
146
+
147
+ | Function | Return type | Behavior |
148
+ | ----------------------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------------- |
149
+ | `scan(image, options = {})` | `Promise<ScanResult>` | One image with automatic scanner creation and disposal, including on failure. Accepts creation and scan options together. |
150
+ | `Scanner.create(options = {})` | `Promise<Scanner>` | Initialize a reusable scanner. Mode and formats are fixed for its lifetime. |
151
+ | `scanner.scan(image, options = {})` | `ScanResult` | Synchronously scan pixels. Accepts scan options only. |
152
+ | `scanner.best(result)` | `Barcode \| undefined` | Convenience alias for `result.best`. |
153
+ | `scanner.dispose()` | `void` | Release WASM sessions. Repeated disposal is safe; do not scan after disposal. |
154
+
155
+ `image` is required for either scan function. All options are optional. Reuse a
156
+ scanner for successive frames to avoid repeated initialization; create another
157
+ to change effort or formats. Previously returned results survive disposal.
158
+
159
+ ## All options
160
+
161
+ | Option | Where | Default | Meaning |
162
+ | ---------------- | -------- | ---------------------- | ---------------------------------------------------------------------------------------------------------- |
163
+ | `mode` | Creation | `"medium"` | `"low"`, `"medium"`, `"high"`, `"very-high"`. |
164
+ | `formats` | Creation | `["EAN13"]` | `"1D"`, `"2D"`, `"all"`, or a nonempty array of exact identifiers. |
165
+ | `loadWasm` | Creation | Module-relative loader | `(url: URL) => Promise<ArrayBuffer>`. Uses HTTP fetch in browsers and filesystem reads for Node file URLs. |
166
+ | `multiple` | Scan | `true` | False keeps at most the highest-support read after scanning; it does not provide an early exit. |
167
+ | `debug` | Scan | `false` | Include search evidence under `result.debug`. Decoded polygons are always returned. |
168
+ | `includeRegions` | Scan | Unset | Compatibility alias for `debug`; prefer `debug` in new code. Conflicting values are rejected. |
169
+
170
+ Format presets cover supported symbologies. Exports `linearFormats`, `matrixFormats`
171
+ and `retailFormats` let you compose custom selections; `formatBits` provides their
172
+ native bit mapping. See [identifiers and coverage](../../docs/FORMATS.md).
173
+ The four effort modes tune EAN13/UPCA; additional readers use fixed effort.
174
+
175
+ Resolution, camera capture, preprocessing rotation, ROI, confidence thresholds,
176
+ timeouts and exact work budgets are not public scan options. Demo capture and
177
+ resize settings belong to the application.
178
+
179
+ ## Image input
180
+
181
+ `PixelImage` accepts `ImageData` (or its data/width/height fields) or an explicit
182
+ `Image` buffer:
183
+
184
+ | Field | Type | Meaning |
185
+ | ----------------- | ------------- | ------------------------------------------------------------------------------------------------------- |
186
+ | `data` | `Uint8Array` | Decoded pixels. ImageData instead uses `Uint8ClampedArray` and implies tightly packed RGBA. |
187
+ | `width`, `height` | `number` | Integer input dimensions, at least 3 pixels each. |
188
+ | `channels` | `1 \| 3 \| 4` | Grayscale, RGB or RGBA. Alpha is ignored. Required for explicit buffers. |
189
+ | `stride` | `number` | Bytes between row starts, at least width × channels. Required for explicit buffers; padding is allowed. |
190
+
191
+ Input is limited to 128 MiB of addressed pixels. Keep the buffer stable during the
192
+ call. Convert DOM image elements or encoded images to pixels before scanning.
193
+
194
+ ## Results
195
+
196
+ | Field | Type | Meaning |
197
+ | ------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------- |
198
+ | `result.values` | `string[]` | Decoded strings. |
199
+ | `result.barcodes` | `Barcode[]` | Decoded values with format and geometry. |
200
+ | `result.best` | `Barcode \| undefined` | Highest-support read, or undefined when empty. |
201
+ | `result.image` | `{ width: number, height: number }` | Dimensions of supplied pixels. |
202
+ | `result.mode` | `Mode` | Selected effort. |
203
+ | `result.elapsedMs` | `number` | Host scan time in milliseconds; excludes file loading and scanner initialization. |
204
+ | `result.unfinished` | `boolean` | Incomplete work; returned reads may still be useful. |
205
+ | `result.debug` | `Diagnostics \| undefined` | Requested diagnostic evidence; absent by default. |
206
+ | `barcode.text` | `string` | Decoded text. |
207
+ | `barcode.format` | `Format \| "Unknown"` | Symbology identifier. |
208
+ | `barcode.polygon` | `Quad` | Four `[x, y]` corners in input-image coordinates. |
209
+ | `barcode.rect` | `{ left: number, top: number, width: number, height: number }` | Enclosing integer rectangle. |
210
+
211
+ Both result arrays are empty when nothing is decoded. Coordinates start at the
212
+ top left, x rightward and y downward. Geometry is returned, not a cropped bitmap.
213
+ Map coordinates back yourself if you resize/rotate before scanning. Support is a
214
+ ranking heuristic, not a probability.
215
+
216
+ The package exports `ScannerOptions`, `ScanOptions`, `ScanResult`, `Barcode`,
217
+ `PixelImage`, `Image`, `Quad`, `Mode`, `Format`, `FormatSelection`, `Diagnostics`
218
+ and `DiagnosticBarcode` types. TypeScript infers results from calls; runtime
219
+ checks still validate pixel buffers and dimensions.
220
+
221
+ ## Diagnostics and errors
222
+
223
+ ```js
224
+ const result = scanner.scan(image, { debug: true });
225
+ if (result.debug) {
226
+ console.log(result.debug.localization, result.debug.searchWindows);
227
+ console.log(result.debug.scan.barcodes);
228
+ }
229
+ ```
230
+
231
+ Diagnostics retain the raw schema-2 result: `scan` includes support and candidate
232
+ evidence, and `localizationLimited` reports localization limits. Depending on the
233
+ reader, `localization`, `searchWindows`, `recovery` and `detailRegions` may be
234
+ present. Raw metadata includes GS1 and structured append where supported.
235
+ Candidate indices inside recovery crops are local to the crop and are not
236
+ identifiers for tracking between frames.
237
+
238
+ Invalid options can raise TypeError. Scanner validation and engine failures can
239
+ raise the exported `ScannerError` with a `.code` and `.message`. Loader/fetch
240
+ errors propagate to the caller; creation and the one-shot helper reject their
241
+ promises on failure. Always dispose reusable scanners with `finally`.