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/dist/esm/wasm.js CHANGED
@@ -1,12 +1,14 @@
1
1
  /**
2
2
  * Optional QuadQR WASM acceleration.
3
3
  *
4
- * The library does not require WASM. Calling initWasm() installs the bundled
5
- * CRC-32 helper into the normal synchronous codec path; failure leaves the
6
- * JavaScript fallback untouched.
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 rawHeapBase = instance.exports.__heap_base;
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
- if (required > memory.buffer.byteLength) {
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(["crc32"]),
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
  }