quadqr-js 1.0.0 → 1.0.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/docs/WASM.md CHANGED
@@ -1,67 +1,67 @@
1
- # WebAssembly
2
-
3
- QuadQR includes an optional prebuilt WebAssembly module at:
4
-
5
- ```text
6
- dist/wasm/quadqr-core.wasm
7
- ```
8
-
9
- The normal JavaScript implementation works without WASM. Applications can opt in when they want to use the bundled accelerator.
10
-
11
- ## Enable WASM
12
-
13
- ```js
14
- import { initWasm } from "quadqr-js";
15
-
16
- const state = await initWasm();
17
- console.log(state);
18
- ```
19
-
20
- In QuadQR 0.7.x, the WASM module accelerates CRC-32. Once initialized, normal encode/decode operations automatically use the installed accelerator.
21
-
22
- ## Check the current state
23
-
24
- ```js
25
- import { getWasmState } from "quadqr-js";
26
-
27
- console.log(getWasmState());
28
- ```
29
-
30
- Before initialization, or after disabling WASM, the result is `null`.
31
-
32
- ## Disable WASM
33
-
34
- ```js
35
- import { disableWasm } from "quadqr-js";
36
-
37
- disableWasm();
38
- ```
39
-
40
- QuadQR immediately returns to the JavaScript implementation.
41
-
42
- ## Custom WASM URL
43
-
44
- Browser and CDN applications can override the asset location:
45
-
46
- ```js
47
- await initWasm({
48
- url: "https://example.com/assets/quadqr-core.wasm"
49
- });
50
- ```
51
-
52
- You can also provide WASM bytes directly through the `bytes` option.
53
-
54
- ## CDN behavior
55
-
56
- When the classic `quadqr.min.js` global build is loaded from a CDN, `QuadQR.initWasm()` resolves the bundled sibling WASM asset from the same package/version location.
57
-
58
- ```html
59
- <script src="https://cdn.jsdelivr.net/npm/quadqr-js@1.0.0/dist/quadqr.min.js"></script>
60
- <script>
61
- await QuadQR.initWasm();
62
- </script>
63
- ```
64
-
65
- ## Fallback behavior
66
-
67
- WASM is never required for the QuadQR wire format. If your environment cannot load WebAssembly, simply do not call `initWasm()` and continue using the JavaScript implementation.
1
+ # WebAssembly
2
+
3
+ QuadQR includes an optional prebuilt WebAssembly module at:
4
+
5
+ ```text
6
+ dist/wasm/quadqr-core.wasm
7
+ ```
8
+
9
+ The normal JavaScript implementation works without WASM. Applications can opt in when they want to use the bundled accelerator.
10
+
11
+ ## Enable WASM
12
+
13
+ ```js
14
+ import { initWasm } from "quadqr-js";
15
+
16
+ const state = await initWasm();
17
+ console.log(state);
18
+ ```
19
+
20
+ In QuadQR 0.7.x, the WASM module accelerates CRC-32. Once initialized, normal encode/decode operations automatically use the installed accelerator.
21
+
22
+ ## Check the current state
23
+
24
+ ```js
25
+ import { getWasmState } from "quadqr-js";
26
+
27
+ console.log(getWasmState());
28
+ ```
29
+
30
+ Before initialization, or after disabling WASM, the result is `null`.
31
+
32
+ ## Disable WASM
33
+
34
+ ```js
35
+ import { disableWasm } from "quadqr-js";
36
+
37
+ disableWasm();
38
+ ```
39
+
40
+ QuadQR immediately returns to the JavaScript implementation.
41
+
42
+ ## Custom WASM URL
43
+
44
+ Browser and CDN applications can override the asset location:
45
+
46
+ ```js
47
+ await initWasm({
48
+ url: "https://example.com/assets/quadqr-core.wasm"
49
+ });
50
+ ```
51
+
52
+ You can also provide WASM bytes directly through the `bytes` option.
53
+
54
+ ## CDN behavior
55
+
56
+ When the classic `quadqr.min.js` global build is loaded from a CDN, `QuadQR.initWasm()` resolves the bundled sibling WASM asset from the same package/version location.
57
+
58
+ ```html
59
+ <script src="https://cdn.jsdelivr.net/npm/quadqr-js@1.0.1/dist/quadqr.min.js"></script>
60
+ <script>
61
+ await QuadQR.initWasm();
62
+ </script>
63
+ ```
64
+
65
+ ## Fallback behavior
66
+
67
+ WASM is never required for the QuadQR wire format. If your environment cannot load WebAssembly, simply do not call `initWasm()` and continue using the JavaScript implementation.
package/package.json CHANGED
@@ -1,95 +1,95 @@
1
- {
2
- "name": "quadqr-js",
3
- "version": "1.0.0",
4
- "description": "QuadQR: experimental four-state RGBW matrix code with Spectrum ECC, browser/Node scanning, CDN builds, and optional AES-256-GCM secure payloads.",
5
- "type": "module",
6
- "main": "./dist/index.cjs",
7
- "module": "./dist/index.js",
8
- "browser": "./dist/browser.js",
9
- "types": "./types/index.d.ts",
10
- "unpkg": "./dist/quadqr.min.js",
11
- "jsdelivr": "./dist/quadqr.min.js",
12
- "exports": {
13
- ".": {
14
- "types": "./types/index.d.ts",
15
- "import": "./dist/index.js",
16
- "require": "./dist/index.cjs",
17
- "default": "./dist/index.js"
18
- },
19
- "./browser": {
20
- "types": "./types/index.d.ts",
21
- "import": "./dist/browser.js",
22
- "default": "./dist/browser.js"
23
- },
24
- "./node": {
25
- "types": "./types/node.d.ts",
26
- "import": "./dist/node.js",
27
- "require": "./dist/node.cjs",
28
- "default": "./dist/node.js"
29
- },
30
- "./benchmark": {
31
- "types": "./types/benchmark.d.ts",
32
- "import": "./dist/benchmark.js",
33
- "require": "./dist/benchmark.cjs",
34
- "default": "./dist/benchmark.js"
35
- },
36
- "./quadqr.js": "./dist/quadqr.js",
37
- "./quadqr.min.js": "./dist/quadqr.min.js",
38
- "./wasm/quadqr-core.wasm": "./dist/wasm/quadqr-core.wasm",
39
- "./package.json": "./package.json"
40
- },
41
- "files": [
42
- "dist",
43
- "types",
44
- "bin",
45
- "docs",
46
- "FORMAT.md",
47
- "README.md",
48
- "LICENSE"
49
- ],
50
- "bin": {
51
- "quadqr": "./bin/quadqr.js"
52
- },
53
- "scripts": {
54
- "build": "node scripts/build.js",
55
- "start": "node scripts/serve.js",
56
- "demo": "node scripts/serve.js",
57
- "docs": "node scripts/serve.js --docs",
58
- "test": "node tests/self-test.js && node tests/package-test.js",
59
- "benchmark": "node scripts/benchmark.js",
60
- "pack:check": "npm run build && npm pack --dry-run",
61
- "prepublishOnly": "npm run build && npm test"
62
- },
63
- "engines": {
64
- "node": ">=20.19"
65
- },
66
- "publishConfig": {
67
- "access": "public"
68
- },
69
- "repository": {
70
- "type": "git",
71
- "url": "git+https://github.com/akanshsirohi/QuadQR.git"
72
- },
73
- "bugs": {
74
- "url": "https://github.com/akanshsirohi/QuadQR/issues"
75
- },
76
- "homepage": "https://github.com/akanshsirohi/QuadQR#readme",
77
- "author": "Akansh Sirohi",
78
- "license": "AGPL-3.0-only",
79
- "keywords": [
80
- "quadqr",
81
- "qr",
82
- "rgb",
83
- "rgbw",
84
- "matrix-code",
85
- "barcode",
86
- "reed-solomon",
87
- "ecc",
88
- "scanner",
89
- "camera-scanner",
90
- "encryption",
91
- "aes-gcm",
92
- "wasm"
93
- ],
94
- "sideEffects": false
95
- }
1
+ {
2
+ "name": "quadqr-js",
3
+ "version": "1.0.2",
4
+ "description": "QuadQR: experimental four-state RGBW matrix code with Spectrum ECC, browser/Node scanning, CDN builds, and optional AES-256-GCM secure payloads.",
5
+ "type": "module",
6
+ "main": "./dist/index.cjs",
7
+ "module": "./dist/index.js",
8
+ "browser": "./dist/browser.js",
9
+ "types": "./types/index.d.ts",
10
+ "unpkg": "./dist/quadqr.min.js",
11
+ "jsdelivr": "./dist/quadqr.min.js",
12
+ "exports": {
13
+ ".": {
14
+ "types": "./types/index.d.ts",
15
+ "import": "./dist/index.js",
16
+ "require": "./dist/index.cjs",
17
+ "default": "./dist/index.js"
18
+ },
19
+ "./browser": {
20
+ "types": "./types/index.d.ts",
21
+ "import": "./dist/browser.js",
22
+ "default": "./dist/browser.js"
23
+ },
24
+ "./node": {
25
+ "types": "./types/node.d.ts",
26
+ "import": "./dist/node.js",
27
+ "require": "./dist/node.cjs",
28
+ "default": "./dist/node.js"
29
+ },
30
+ "./benchmark": {
31
+ "types": "./types/benchmark.d.ts",
32
+ "import": "./dist/benchmark.js",
33
+ "require": "./dist/benchmark.cjs",
34
+ "default": "./dist/benchmark.js"
35
+ },
36
+ "./quadqr.js": "./dist/quadqr.js",
37
+ "./quadqr.min.js": "./dist/quadqr.min.js",
38
+ "./wasm/quadqr-core.wasm": "./dist/wasm/quadqr-core.wasm",
39
+ "./package.json": "./package.json"
40
+ },
41
+ "files": [
42
+ "dist",
43
+ "types",
44
+ "bin",
45
+ "docs",
46
+ "FORMAT.md",
47
+ "README.md",
48
+ "LICENSE"
49
+ ],
50
+ "bin": {
51
+ "quadqr": "./bin/quadqr.js"
52
+ },
53
+ "scripts": {
54
+ "build": "node scripts/build.js",
55
+ "start": "node scripts/serve.js",
56
+ "demo": "node scripts/serve.js",
57
+ "docs": "node scripts/serve.js --docs",
58
+ "test": "node tests/self-test.js && node tests/package-test.js",
59
+ "benchmark": "node scripts/benchmark.js",
60
+ "pack:check": "npm run build && npm pack --dry-run",
61
+ "prepublishOnly": "npm run build && npm test"
62
+ },
63
+ "engines": {
64
+ "node": ">=20.19"
65
+ },
66
+ "publishConfig": {
67
+ "access": "public"
68
+ },
69
+ "repository": {
70
+ "type": "git",
71
+ "url": "git+https://github.com/akanshsirohi/QuadQR.git"
72
+ },
73
+ "bugs": {
74
+ "url": "https://github.com/akanshsirohi/QuadQR/issues"
75
+ },
76
+ "homepage": "https://github.com/akanshsirohi/QuadQR#readme",
77
+ "author": "Akansh Sirohi",
78
+ "license": "AGPL-3.0-only",
79
+ "keywords": [
80
+ "quadqr",
81
+ "qr",
82
+ "rgb",
83
+ "rgbw",
84
+ "matrix-code",
85
+ "barcode",
86
+ "reed-solomon",
87
+ "ecc",
88
+ "scanner",
89
+ "camera-scanner",
90
+ "encryption",
91
+ "aes-gcm",
92
+ "wasm"
93
+ ],
94
+ "sideEffects": false
95
+ }
package/types/index.d.ts CHANGED
@@ -82,6 +82,51 @@ export interface ImageDataLike {
82
82
  data: Uint8ClampedArray | Uint8Array;
83
83
  }
84
84
 
85
+ export interface CameraFinderDiagnostic {
86
+ x: number;
87
+ y: number;
88
+ moduleSize: number;
89
+ confirmations?: number;
90
+ score?: number;
91
+ }
92
+
93
+ export interface CameraGeometryDiagnostic {
94
+ version: number;
95
+ size: number;
96
+ score: number;
97
+ estimatedSize?: number;
98
+ alignmentScore?: number;
99
+ alignmentGridScore?: number;
100
+ finders?: {
101
+ topLeft: CameraFinderDiagnostic;
102
+ topRight: CameraFinderDiagnostic;
103
+ bottomLeft: CameraFinderDiagnostic;
104
+ };
105
+ [key: string]: unknown;
106
+ }
107
+
108
+ export interface CameraDiagnosticEvent {
109
+ type: "camera-ready" | "frame" | "method" | "success" | string;
110
+ timestamp: number;
111
+ frame: number;
112
+ state?: "trying" | "miss" | "failed" | "decoded" | string;
113
+ method?: string;
114
+ message?: string;
115
+ elapsedMs?: number;
116
+ missStreak?: number;
117
+ scanWidth?: number;
118
+ scanHeight?: number;
119
+ frameWidth?: number;
120
+ frameHeight?: number;
121
+ scanRect?: { x: number; y: number; width: number; height: number };
122
+ finderCount?: number;
123
+ finders?: CameraFinderDiagnostic[];
124
+ finderMethod?: string | null;
125
+ finderPasses?: Array<{ method: string; finderCount: number; threshold?: number; geometryCount?: number }>;
126
+ geometry?: CameraGeometryDiagnostic | null;
127
+ [key: string]: unknown;
128
+ }
129
+
85
130
  export interface RenderOptions {
86
131
  moduleSize?: number;
87
132
  quietZone?: number;
@@ -95,9 +140,86 @@ export interface ScanOptions {
95
140
  maxVersion?: number;
96
141
  perspective?: boolean;
97
142
  axisAlignedFallback?: boolean;
143
+ maxDimension?: number;
144
+ sampleRadius?: number;
145
+ robustSampleRadius?: number;
146
+ adaptiveSampling?: boolean;
147
+ spatialColorNormalization?: boolean;
148
+ structureTolerance?: number;
149
+ maxErasureConfidence?: number;
150
+ geometryRefinement?: boolean;
151
+ finderRecovery?: boolean;
152
+ finderAutoColorBlackClip?: number;
153
+ finderAutoColorWhiteClip?: number;
154
+ finderAutoColorHighlightPercentile?: number;
155
+ finderAutoColorOutputHighlight?: number;
156
+ finderAutoColorAnalysisInset?: number;
157
+ finderAutoColorAnalysisInsets?: number[];
158
+ finderAutoColorMinimumInputRange?: number;
159
+ finderAutoColorTargetSamples?: number;
160
+ autoEnhanceRecovery?: boolean;
161
+ autoEnhanceWhenNoGeometry?: boolean;
162
+ autoEnhanceBlackClip?: number;
163
+ autoEnhanceWhiteClip?: number;
164
+ autoEnhanceSaturation?: number;
165
+ autoEnhanceTargetSamples?: number;
166
+ fullFrameAutoEnhanceRecovery?: boolean;
167
+ rectifiedAutoEnhanceRecovery?: boolean;
168
+ rectifiedRecoveryModuleSize?: number;
169
+ rectifiedRecoveryRadiusRatio?: number;
170
+ rectifiedAutoEnhanceBlackClip?: number;
171
+ rectifiedAutoEnhanceWhiteClip?: number;
172
+ rectifiedAutoEnhanceSaturation?: number;
173
+ rectifiedAutoEnhanceHighlightFraction?: number;
174
+ videoCropMode?: "visible" | "full";
175
+ videoObjectFit?: string;
176
+ videoObjectPosition?: string;
177
+ videoCropInset?: number;
178
+ refinementOffset?: number;
179
+ refinementStructureThreshold?: number;
180
+ refinementDecodeThreshold?: number;
181
+ refinementDecodeCandidates?: number;
98
182
  [key: string]: unknown;
99
183
  }
100
184
 
185
+ export interface CameraFrameMeta {
186
+ frame: number;
187
+ imageData: ImageDataLike;
188
+ scanWidth: number;
189
+ scanHeight: number;
190
+ sourceRect?: { x: number; y: number; width: number; height: number; cropped?: boolean } | null;
191
+ enhancedImageData?: ImageDataLike | null;
192
+ enhancedRect?: { x: number; y: number; width: number; height: number } | null;
193
+ enhancement?: { method?: string; cropInset?: number; analysisInset?: number; [key: string]: unknown } | null;
194
+ diagnostic?: Record<string, unknown> | null;
195
+ }
196
+
197
+ export interface CameraScanOptions extends ScanOptions {
198
+ scanInterval?: number;
199
+ stopOnResult?: boolean;
200
+ multiFrame?: boolean;
201
+ multiFrameWindow?: number;
202
+ multiFrameMinFrames?: number;
203
+ cameraAutoColorRecovery?: boolean;
204
+ cameraAutoColorEvery?: number;
205
+ cameraAutoColorBlackClip?: number;
206
+ cameraAutoColorWhiteClip?: number;
207
+ cameraAutoColorHighlightPercentile?: number;
208
+ cameraAutoColorOutputHighlight?: number;
209
+ cameraAutoColorAnalysisInset?: number;
210
+ cameraAutoColorAnalysisInsets?: number[];
211
+ cameraAutoColorCropInsets?: number[];
212
+ cameraAutoColorMinimumInputRange?: number;
213
+ cameraAutoColorTargetSamples?: number;
214
+ cameraAutoEnhanceEvery?: number;
215
+ cameraFinderRecoveryEvery?: number;
216
+ constraints?: MediaStreamConstraints;
217
+ onResult?: (result: DecodeResult, frame?: CameraFrameMeta | null) => void | Promise<void>;
218
+ onDecode?: (result: DecodeResult, frame?: CameraFrameMeta | null) => void | Promise<void>;
219
+ onScanMiss?: (error: Error) => void;
220
+ onDiagnostic?: (event: CameraDiagnosticEvent) => void;
221
+ }
222
+
101
223
  export const FORMAT_VERSION: number;
102
224
  export const MIN_VERSION: number;
103
225
  export const MAX_VERSION: number;
@@ -122,7 +244,7 @@ export function renderToImageData(codeOrMatrix: QuadQRCode | number[][], options
122
244
  export function scanImageData(imageData: ImageDataLike, options?: ScanOptions): DecodeResult;
123
245
  export function scanFile(file: Blob, options?: ScanOptions): Promise<DecodeResult>;
124
246
  export function scanVideoFrame(video: HTMLVideoElement, options?: ScanOptions): DecodeResult;
125
- export function startCameraScanner(video: HTMLVideoElement, options?: ScanOptions & { onDecode?: (result: DecodeResult) => void | Promise<void>; onError?: (error: Error) => void; scanInterval?: number; constraints?: MediaStreamConstraints }): Promise<{ stop(): void; scanNow(): DecodeResult; stream: MediaStream }>;
247
+ export function startCameraScanner(video: HTMLVideoElement, options?: CameraScanOptions): Promise<{ stop(): void; scanNow(): DecodeResult; stream: MediaStream; video: HTMLVideoElement }>;
126
248
  export function rectifyDetectedCode(imageData: ImageDataLike, options?: Record<string, unknown>): ImageDataLike;
127
249
  export function rotateMatrix(matrix: number[][], quarterTurns?: number): number[][];
128
250
  export function getVersionInfo(version: number, options?: { ecc?: EccLevel }): Record<string, unknown>;
@@ -1,109 +0,0 @@
1
- # Publishing QuadQR to npm
2
-
3
- QuadQR is published on npm as [`quadqr-js`](https://www.npmjs.com/package/quadqr-js). The repository package name is `quadqr-js`.
4
-
5
- The QuadQR project/brand, browser global (`QuadQR`), CLI executable (`quadqr`), and generated filenames remain unchanged. Only the npm package identifier is `quadqr-js`.
6
-
7
- ## 1. Create/sign in to npm
8
-
9
- Create an account at https://www.npmjs.com/ and enable two-factor authentication.
10
-
11
- Then authenticate the CLI:
12
-
13
- ```bash
14
- npm login
15
- ```
16
-
17
- Check the active account:
18
-
19
- ```bash
20
- npm whoami
21
- ```
22
-
23
- ## 2. Install repository dependencies
24
-
25
- QuadQR currently has no runtime dependencies, but run:
26
-
27
- ```bash
28
- npm install
29
- ```
30
-
31
- so your local package lock and npm metadata are synchronized.
32
-
33
- ## 3. Verify the package metadata
34
-
35
- ```bash
36
- npm view quadqr-js
37
- ```
38
-
39
- Confirm the published package and current version before releasing an update.
40
-
41
- ## 4. Run the full release checks
42
-
43
- ```bash
44
- npm test
45
- npm run benchmark
46
- npm run pack:check
47
- ```
48
-
49
- `pack:check` rebuilds `dist/` and displays exactly what npm will include.
50
-
51
- You can inspect the final tarball too:
52
-
53
- ```bash
54
- npm pack
55
- ```
56
-
57
- ## 5. Publish
58
-
59
- The package is an unscoped public package and `publishConfig.access` is already set to `public`, so publish with:
60
-
61
- ```bash
62
- npm publish
63
- ```
64
-
65
- npm publishing requires an account that satisfies npm's current 2FA/authentication requirements.
66
-
67
- ## 6. Verify installation from a clean directory
68
-
69
- ```bash
70
- mkdir quadqr-consumer-test
71
- cd quadqr-consumer-test
72
- npm init -y
73
- npm install quadqr-js
74
- ```
75
-
76
- Then test ESM, Node PNG, and the CLI.
77
-
78
- ```bash
79
- npx quadqr-js keygen
80
- npx quadqr-js encode "Hello from npm" -o hello.png
81
- npx quadqr-js decode hello.png
82
- ```
83
-
84
- ## 7. Verify CDN availability
85
-
86
- After npm and CDN caches update, test:
87
-
88
- ```text
89
- https://cdn.jsdelivr.net/npm/quadqr-js@1.0.0/dist/quadqr.min.js
90
- https://unpkg.com/quadqr-js@1.0.0/dist/quadqr.min.js
91
- ```
92
-
93
- Then call `QuadQR.encodeText(...)` from a plain HTML page.
94
-
95
- ## Releasing the next version
96
-
97
- Use semantic versioning:
98
-
99
- ```bash
100
- npm version patch
101
- # or
102
- npm version minor
103
- # or
104
- npm version major
105
- ```
106
-
107
- Then run the release checks again and publish.
108
-
109
- Never reuse an npm version that has already been published. Published package versions are immutable.