quadqr-js 1.4.2 → 1.5.2
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/FORMAT.md +5 -5
- package/README.md +19 -8
- package/SPECIFICATION.md +12 -12
- package/dist/camera-scanner-worker.js +793 -0
- package/dist/esm/camera-scanner-worker.js +793 -0
- package/dist/esm/geometry.js +25 -10
- package/dist/esm/quadqr.js +843 -62
- package/dist/esm/vision.js +887 -122
- package/dist/esm/wasm.js +85 -12
- package/dist/quadqr.js +1803 -198
- package/dist/quadqr.min.js +2032 -274
- package/dist/wasm/quadqr-core.wasm +0 -0
- package/docs/API.md +13 -5
- package/docs/BROWSER_CDN.md +5 -5
- package/docs/CLI.md +167 -167
- package/docs/COMPRESSION.md +170 -170
- package/docs/GETTING_STARTED.md +1 -1
- package/docs/HIGH_DENSITY_MODE.md +100 -100
- package/docs/NODE.md +159 -159
- package/docs/README.md +62 -62
- package/docs/RELIABILITY_LAB.md +64 -64
- package/docs/TRIANGLE16.md +98 -98
- package/docs/WASM.md +30 -4
- package/package.json +5 -3
package/dist/esm/wasm.js
CHANGED
|
@@ -1,12 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Optional QuadQR WASM acceleration.
|
|
3
3
|
*
|
|
4
|
-
* The library
|
|
5
|
-
* CRC-32
|
|
6
|
-
*
|
|
4
|
+
* The library never requires WASM. Calling initWasm() installs the bundled
|
|
5
|
+
* CRC-32 and scanner pixel-preprocessing accelerators into the normal
|
|
6
|
+
* synchronous codec/scanner paths. Any load/runtime failure leaves the
|
|
7
|
+
* JavaScript fallbacks available.
|
|
7
8
|
*/
|
|
8
9
|
|
|
9
10
|
import { installCrc32Accelerator } from "./quadqr.js";
|
|
11
|
+
import { installVisionAccelerator } from "./vision.js";
|
|
10
12
|
|
|
11
13
|
let state = null;
|
|
12
14
|
let loading = null;
|
|
@@ -32,29 +34,93 @@ async function loadBytes(url) {
|
|
|
32
34
|
return new Uint8Array(await response.arrayBuffer());
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
function heapBaseOf(instance) {
|
|
38
|
+
const rawHeapBase = instance.exports.__heap_base;
|
|
39
|
+
return Number(rawHeapBase?.value ?? rawHeapBase ?? 65536);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function ensureMemory(memory, required) {
|
|
43
|
+
if (required <= memory.buffer.byteLength) return;
|
|
44
|
+
const pages = Math.ceil((required - memory.buffer.byteLength) / 65536);
|
|
45
|
+
memory.grow(pages);
|
|
46
|
+
}
|
|
47
|
+
|
|
35
48
|
function makeCrc32(instance) {
|
|
36
49
|
const { memory, crc32_bytes: crc32Bytes } = instance.exports;
|
|
37
50
|
if (!(memory instanceof WebAssembly.Memory) || typeof crc32Bytes !== "function") {
|
|
38
51
|
throw new Error("QuadQR WASM exports are invalid.");
|
|
39
52
|
}
|
|
40
53
|
|
|
41
|
-
const
|
|
42
|
-
const heapBase = Number(rawHeapBase?.value ?? rawHeapBase ?? 65536);
|
|
43
|
-
|
|
54
|
+
const heapBase = heapBaseOf(instance);
|
|
44
55
|
return (input) => {
|
|
45
56
|
const bytes = toUint8Array(input);
|
|
46
57
|
const required = heapBase + bytes.length;
|
|
47
|
-
|
|
48
|
-
const pages = Math.ceil((required - memory.buffer.byteLength) / 65536);
|
|
49
|
-
memory.grow(pages);
|
|
50
|
-
}
|
|
58
|
+
ensureMemory(memory, required);
|
|
51
59
|
new Uint8Array(memory.buffer, heapBase, bytes.length).set(bytes);
|
|
52
60
|
return crc32Bytes(heapBase, bytes.length) >>> 0;
|
|
53
61
|
};
|
|
54
62
|
}
|
|
55
63
|
|
|
64
|
+
function makeVisionAccelerator(instance) {
|
|
65
|
+
const { memory, build_binary_rgba: buildBinaryRgba } = instance.exports;
|
|
66
|
+
if (!(memory instanceof WebAssembly.Memory) || typeof buildBinaryRgba !== "function") return null;
|
|
67
|
+
|
|
68
|
+
const heapBase = heapBaseOf(instance);
|
|
69
|
+
const align16 = (value) => (value + 15) & ~15;
|
|
70
|
+
|
|
71
|
+
return Object.freeze({
|
|
72
|
+
buildBinary(imageData, options = {}) {
|
|
73
|
+
const width = Number(imageData?.width) || 0;
|
|
74
|
+
const height = Number(imageData?.height) || 0;
|
|
75
|
+
const pixels = width * height;
|
|
76
|
+
if (!pixels || !imageData?.data || imageData.data.length < pixels * 4) {
|
|
77
|
+
throw new Error("Valid ImageData is required for WASM preprocessing.");
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
const rgba = toUint8Array(imageData.data);
|
|
81
|
+
const rgbaBytes = pixels * 4;
|
|
82
|
+
const inputPtr = align16(heapBase);
|
|
83
|
+
const grayPtr = align16(inputPtr + rgbaBytes);
|
|
84
|
+
const binaryPtr = align16(grayPtr + pixels);
|
|
85
|
+
const required = binaryPtr + pixels;
|
|
86
|
+
ensureMemory(memory, required);
|
|
87
|
+
|
|
88
|
+
new Uint8Array(memory.buffer, inputPtr, rgbaBytes).set(rgba.subarray(0, rgbaBytes));
|
|
89
|
+
const grayMode = options.grayMode === "value" ? 0 : 1;
|
|
90
|
+
const thresholdOffset = Math.round(Number(options.thresholdOffset) || 0);
|
|
91
|
+
const packed = buildBinaryRgba(
|
|
92
|
+
inputPtr,
|
|
93
|
+
pixels,
|
|
94
|
+
grayMode,
|
|
95
|
+
thresholdOffset,
|
|
96
|
+
grayPtr,
|
|
97
|
+
binaryPtr
|
|
98
|
+
) >>> 0;
|
|
99
|
+
|
|
100
|
+
const threshold = packed & 0xff;
|
|
101
|
+
const baseThreshold = (packed >>> 8) & 0xff;
|
|
102
|
+
// Copy results out of WASM memory because a later memory.grow() can detach
|
|
103
|
+
// previously-created views. Scanner callers expect stable Uint8Arrays.
|
|
104
|
+
const gray = new Uint8Array(pixels);
|
|
105
|
+
const binary = new Uint8Array(pixels);
|
|
106
|
+
gray.set(new Uint8Array(memory.buffer, grayPtr, pixels));
|
|
107
|
+
binary.set(new Uint8Array(memory.buffer, binaryPtr, pixels));
|
|
108
|
+
return {
|
|
109
|
+
gray,
|
|
110
|
+
binary,
|
|
111
|
+
threshold,
|
|
112
|
+
baseThreshold,
|
|
113
|
+
grayMode: options.grayMode ?? "luminance",
|
|
114
|
+
accelerated: "wasm"
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
|
|
56
120
|
/**
|
|
57
|
-
* Load QuadQR's bundled WebAssembly helper and install it into the codec
|
|
121
|
+
* Load QuadQR's bundled WebAssembly helper and install it into the codec and
|
|
122
|
+
* scanner. Calling this once accelerates subsequent synchronous scanImageData()
|
|
123
|
+
* and camera-scanner work without changing their return values or API shape.
|
|
58
124
|
* @param {{url?: string|URL, bytes?: Uint8Array|ArrayBuffer}} options
|
|
59
125
|
*/
|
|
60
126
|
export async function initWasm(options = {}) {
|
|
@@ -68,12 +134,16 @@ export async function initWasm(options = {}) {
|
|
|
68
134
|
|
|
69
135
|
const { instance } = await WebAssembly.instantiate(bytes, {});
|
|
70
136
|
const crc32 = makeCrc32(instance);
|
|
137
|
+
const vision = makeVisionAccelerator(instance);
|
|
71
138
|
installCrc32Accelerator(crc32);
|
|
139
|
+
if (vision) installVisionAccelerator(vision);
|
|
72
140
|
|
|
141
|
+
const accelerators = ["crc32"];
|
|
142
|
+
if (vision) accelerators.push("scanner-preprocess");
|
|
73
143
|
state = Object.freeze({
|
|
74
144
|
enabled: true,
|
|
75
145
|
module: "quadqr-core",
|
|
76
|
-
accelerators: Object.freeze(
|
|
146
|
+
accelerators: Object.freeze(accelerators),
|
|
77
147
|
bytes: bytes.length
|
|
78
148
|
});
|
|
79
149
|
return state;
|
|
@@ -83,6 +153,8 @@ export async function initWasm(options = {}) {
|
|
|
83
153
|
return await loading;
|
|
84
154
|
} catch (error) {
|
|
85
155
|
loading = null;
|
|
156
|
+
installCrc32Accelerator(null);
|
|
157
|
+
installVisionAccelerator(null);
|
|
86
158
|
throw error;
|
|
87
159
|
}
|
|
88
160
|
}
|
|
@@ -93,6 +165,7 @@ export function getWasmState() {
|
|
|
93
165
|
|
|
94
166
|
export function disableWasm() {
|
|
95
167
|
installCrc32Accelerator(null);
|
|
168
|
+
installVisionAccelerator(null);
|
|
96
169
|
state = null;
|
|
97
170
|
loading = null;
|
|
98
171
|
}
|