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/README.md +1068 -1057
- package/dist/esm/quadqr.js +1270 -99
- package/dist/esm/vision.js +597 -52
- package/dist/quadqr.js +1865 -153
- package/dist/quadqr.min.js +1881 -153
- package/docs/API.md +329 -309
- package/docs/BROWSER_CDN.md +142 -137
- package/docs/GETTING_STARTED.md +174 -173
- package/docs/WASM.md +67 -67
- package/package.json +95 -95
- package/types/index.d.ts +123 -1
- package/docs/PUBLISHING.md +0 -109
package/docs/BROWSER_CDN.md
CHANGED
|
@@ -1,137 +1,142 @@
|
|
|
1
|
-
# Browser and CDN Usage
|
|
2
|
-
|
|
3
|
-
## Browser ESM
|
|
4
|
-
|
|
5
|
-
With Vite, webpack, Rollup, Next.js client code, or another browser bundler:
|
|
6
|
-
|
|
7
|
-
```js
|
|
8
|
-
import {
|
|
9
|
-
encodeText,
|
|
10
|
-
renderToCanvas,
|
|
11
|
-
scanFile,
|
|
12
|
-
startCameraScanner
|
|
13
|
-
} from "quadqr-js/browser";
|
|
14
|
-
```
|
|
15
|
-
|
|
16
|
-
The main `quadqr-js` entry also works in modern browser bundlers for runtime-neutral APIs.
|
|
17
|
-
|
|
18
|
-
## Render to canvas
|
|
19
|
-
|
|
20
|
-
```js
|
|
21
|
-
const code = encodeText("Hello browser");
|
|
22
|
-
|
|
23
|
-
renderToCanvas(code, document.querySelector("#qr"), {
|
|
24
|
-
moduleSize: 12,
|
|
25
|
-
quietZone: 4,
|
|
26
|
-
style: "classic"
|
|
27
|
-
});
|
|
28
|
-
```
|
|
29
|
-
|
|
30
|
-
Available styles are `classic`, `depth`, `soft`, and `inset`.
|
|
31
|
-
|
|
32
|
-
## Scan an uploaded image
|
|
33
|
-
|
|
34
|
-
```js
|
|
35
|
-
const input = document.querySelector("#image");
|
|
36
|
-
const result = await scanFile(input.files[0]);
|
|
37
|
-
|
|
38
|
-
console.log(result.text);
|
|
39
|
-
```
|
|
40
|
-
|
|
41
|
-
If the symbol uses Secure Payload, the scan result has `secure: true` and `requiresDecryption: true` until it is successfully unlocked.
|
|
42
|
-
|
|
43
|
-
## Live camera scanning
|
|
44
|
-
|
|
45
|
-
```js
|
|
46
|
-
const video = document.querySelector("#camera");
|
|
47
|
-
|
|
48
|
-
const scanner = await startCameraScanner(video, {
|
|
49
|
-
scanInterval: 120,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
1
|
+
# Browser and CDN Usage
|
|
2
|
+
|
|
3
|
+
## Browser ESM
|
|
4
|
+
|
|
5
|
+
With Vite, webpack, Rollup, Next.js client code, or another browser bundler:
|
|
6
|
+
|
|
7
|
+
```js
|
|
8
|
+
import {
|
|
9
|
+
encodeText,
|
|
10
|
+
renderToCanvas,
|
|
11
|
+
scanFile,
|
|
12
|
+
startCameraScanner
|
|
13
|
+
} from "quadqr-js/browser";
|
|
14
|
+
```
|
|
15
|
+
|
|
16
|
+
The main `quadqr-js` entry also works in modern browser bundlers for runtime-neutral APIs.
|
|
17
|
+
|
|
18
|
+
## Render to canvas
|
|
19
|
+
|
|
20
|
+
```js
|
|
21
|
+
const code = encodeText("Hello browser");
|
|
22
|
+
|
|
23
|
+
renderToCanvas(code, document.querySelector("#qr"), {
|
|
24
|
+
moduleSize: 12,
|
|
25
|
+
quietZone: 4,
|
|
26
|
+
style: "classic"
|
|
27
|
+
});
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Available styles are `classic`, `depth`, `soft`, and `inset`.
|
|
31
|
+
|
|
32
|
+
## Scan an uploaded image
|
|
33
|
+
|
|
34
|
+
```js
|
|
35
|
+
const input = document.querySelector("#image");
|
|
36
|
+
const result = await scanFile(input.files[0]);
|
|
37
|
+
|
|
38
|
+
console.log(result.text);
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
If the symbol uses Secure Payload, the scan result has `secure: true` and `requiresDecryption: true` until it is successfully unlocked.
|
|
42
|
+
|
|
43
|
+
## Live camera scanning
|
|
44
|
+
|
|
45
|
+
```js
|
|
46
|
+
const video = document.querySelector("#camera");
|
|
47
|
+
|
|
48
|
+
const scanner = await startCameraScanner(video, {
|
|
49
|
+
scanInterval: 120,
|
|
50
|
+
cameraFinderRecoveryEvery: 2,
|
|
51
|
+
async onResult(result) {
|
|
52
|
+
console.log(result);
|
|
53
|
+
scanner.stop();
|
|
54
|
+
},
|
|
55
|
+
onScanMiss() {
|
|
56
|
+
// Keep searching.
|
|
57
|
+
},
|
|
58
|
+
onDiagnostic(event) {
|
|
59
|
+
// Useful for live finder overlays and scanner debug logs.
|
|
60
|
+
console.log(event.method, event.finderMethod, event.finderCount, event.geometry?.version);
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
Camera access requires HTTPS or localhost. QuadQR scans the part of an `object-fit: cover` video that is actually visible to the user. The fast finder pass uses the RGB value channel (`max(R,G,B)`) so saturated data colors are less likely to be mistaken for structural black. After misses, throttled recovery frames can try alternate finder thresholds before stronger color correction. `onDiagnostic` exposes the finder method and geometry work already performed by the scanner.
|
|
66
|
+
|
|
67
|
+
## Decrypt a secure scan
|
|
68
|
+
|
|
69
|
+
```js
|
|
70
|
+
import { decryptDecoded } from "quadqr-js/browser";
|
|
71
|
+
|
|
72
|
+
const locked = await scanFile(file);
|
|
73
|
+
|
|
74
|
+
if (locked.secure) {
|
|
75
|
+
const unlocked = await decryptDecoded(locked, {
|
|
76
|
+
password: "my-password"
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
console.log(unlocked.text);
|
|
80
|
+
}
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
Raw-key mode uses `{ key }` instead of `{ password }`.
|
|
84
|
+
|
|
85
|
+
## Classic script tag
|
|
86
|
+
|
|
87
|
+
The global browser build exposes `window.QuadQR` / `globalThis.QuadQR`.
|
|
88
|
+
|
|
89
|
+
```html
|
|
90
|
+
<canvas id="qr"></canvas>
|
|
91
|
+
<script src="https://cdn.jsdelivr.net/npm/quadqr-js@1.0.1/dist/quadqr.min.js"></script>
|
|
92
|
+
<script>
|
|
93
|
+
const code = QuadQR.encodeText("Hello CDN");
|
|
94
|
+
|
|
95
|
+
QuadQR.renderToCanvas(code, document.querySelector("#qr"), {
|
|
96
|
+
moduleSize: 12,
|
|
97
|
+
quietZone: 4
|
|
98
|
+
});
|
|
99
|
+
</script>
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
## unpkg
|
|
103
|
+
|
|
104
|
+
```html
|
|
105
|
+
<script src="https://unpkg.com/quadqr-js@1.0.1/dist/quadqr.min.js"></script>
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Direct CDN ESM
|
|
109
|
+
|
|
110
|
+
```html
|
|
111
|
+
<script type="module">
|
|
112
|
+
import {
|
|
113
|
+
encodeText,
|
|
114
|
+
renderToCanvas
|
|
115
|
+
} from "https://cdn.jsdelivr.net/npm/quadqr-js@1.0.1/dist/browser.js";
|
|
116
|
+
|
|
117
|
+
const code = encodeText("ES module CDN");
|
|
118
|
+
renderToCanvas(code, document.querySelector("#qr"));
|
|
119
|
+
</script>
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Optional WASM from a CDN
|
|
123
|
+
|
|
124
|
+
The classic global build can resolve the bundled WASM asset relative to its own script URL:
|
|
125
|
+
|
|
126
|
+
```js
|
|
127
|
+
await QuadQR.initWasm();
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
You can also provide a custom URL:
|
|
131
|
+
|
|
132
|
+
```js
|
|
133
|
+
await QuadQR.initWasm({
|
|
134
|
+
url: "https://example.com/assets/quadqr-core.wasm"
|
|
135
|
+
});
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
WASM is optional. The normal JavaScript implementation remains available if it cannot load.
|
|
139
|
+
|
|
140
|
+
## Production recommendation
|
|
141
|
+
|
|
142
|
+
Pin a concrete package version such as `@1.0.1` in CDN URLs so an existing site does not silently change when a newer package version becomes available.
|
package/docs/GETTING_STARTED.md
CHANGED
|
@@ -1,173 +1,174 @@
|
|
|
1
|
-
# Getting Started
|
|
2
|
-
|
|
3
|
-
## Install
|
|
4
|
-
|
|
5
|
-
```bash
|
|
6
|
-
npm install quadqr-js
|
|
7
|
-
```
|
|
8
|
-
|
|
9
|
-
Node.js usage targets Node.js 20.19 or newer. Browser use works through a bundler, direct ESM, or the prebuilt CDN/global bundle.
|
|
10
|
-
|
|
11
|
-
## Encode and decode text
|
|
12
|
-
|
|
13
|
-
```js
|
|
14
|
-
import { encodeText, decodeMatrix } from "quadqr-js";
|
|
15
|
-
|
|
16
|
-
const code = encodeText("Hello from QuadQR", {
|
|
17
|
-
ecc: "M"
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
const result = decodeMatrix(code.matrix);
|
|
21
|
-
console.log(result.text);
|
|
22
|
-
```
|
|
23
|
-
|
|
24
|
-
If no version is supplied, QuadQR automatically chooses the smallest version that fits the payload.
|
|
25
|
-
|
|
26
|
-
## Render in the browser
|
|
27
|
-
|
|
28
|
-
```js
|
|
29
|
-
import {
|
|
30
|
-
encodeText,
|
|
31
|
-
renderToCanvas
|
|
32
|
-
} from "quadqr-js/browser";
|
|
33
|
-
|
|
34
|
-
const code = encodeText("Rendered in the browser");
|
|
35
|
-
|
|
36
|
-
renderToCanvas(code, document.querySelector("#qr"), {
|
|
37
|
-
moduleSize: 12,
|
|
38
|
-
quietZone: 4,
|
|
39
|
-
style: "classic"
|
|
40
|
-
});
|
|
41
|
-
```
|
|
42
|
-
|
|
43
|
-
Available presentation styles are `classic`, `depth`, `soft`, and `inset`. Styling does not change the encoded matrix.
|
|
44
|
-
|
|
45
|
-
## Scan an uploaded image
|
|
46
|
-
|
|
47
|
-
```js
|
|
48
|
-
import { scanFile } from "quadqr-js/browser";
|
|
49
|
-
|
|
50
|
-
const file = document.querySelector("#image").files[0];
|
|
51
|
-
const result = await scanFile(file);
|
|
52
|
-
|
|
53
|
-
console.log(result.text);
|
|
54
|
-
```
|
|
55
|
-
|
|
56
|
-
## Scan from the camera
|
|
57
|
-
|
|
58
|
-
```js
|
|
59
|
-
import { startCameraScanner } from "quadqr-js/browser";
|
|
60
|
-
|
|
61
|
-
let scanner;
|
|
62
|
-
scanner = await startCameraScanner(
|
|
63
|
-
document.querySelector("#video"),
|
|
64
|
-
{
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
}
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
key
|
|
121
|
-
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
import {
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
<
|
|
151
|
-
<script>
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
npx quadqr-js
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
npx quadqr-js
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
1
|
+
# Getting Started
|
|
2
|
+
|
|
3
|
+
## Install
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npm install quadqr-js
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
Node.js usage targets Node.js 20.19 or newer. Browser use works through a bundler, direct ESM, or the prebuilt CDN/global bundle.
|
|
10
|
+
|
|
11
|
+
## Encode and decode text
|
|
12
|
+
|
|
13
|
+
```js
|
|
14
|
+
import { encodeText, decodeMatrix } from "quadqr-js";
|
|
15
|
+
|
|
16
|
+
const code = encodeText("Hello from QuadQR", {
|
|
17
|
+
ecc: "M"
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const result = decodeMatrix(code.matrix);
|
|
21
|
+
console.log(result.text);
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
If no version is supplied, QuadQR automatically chooses the smallest version that fits the payload.
|
|
25
|
+
|
|
26
|
+
## Render in the browser
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
import {
|
|
30
|
+
encodeText,
|
|
31
|
+
renderToCanvas
|
|
32
|
+
} from "quadqr-js/browser";
|
|
33
|
+
|
|
34
|
+
const code = encodeText("Rendered in the browser");
|
|
35
|
+
|
|
36
|
+
renderToCanvas(code, document.querySelector("#qr"), {
|
|
37
|
+
moduleSize: 12,
|
|
38
|
+
quietZone: 4,
|
|
39
|
+
style: "classic"
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
Available presentation styles are `classic`, `depth`, `soft`, and `inset`. Styling does not change the encoded matrix.
|
|
44
|
+
|
|
45
|
+
## Scan an uploaded image
|
|
46
|
+
|
|
47
|
+
```js
|
|
48
|
+
import { scanFile } from "quadqr-js/browser";
|
|
49
|
+
|
|
50
|
+
const file = document.querySelector("#image").files[0];
|
|
51
|
+
const result = await scanFile(file);
|
|
52
|
+
|
|
53
|
+
console.log(result.text);
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
## Scan from the camera
|
|
57
|
+
|
|
58
|
+
```js
|
|
59
|
+
import { startCameraScanner } from "quadqr-js/browser";
|
|
60
|
+
|
|
61
|
+
let scanner;
|
|
62
|
+
scanner = await startCameraScanner(
|
|
63
|
+
document.querySelector("#video"),
|
|
64
|
+
{
|
|
65
|
+
cameraFinderRecoveryEvery: 2,
|
|
66
|
+
onResult(result) {
|
|
67
|
+
console.log(result);
|
|
68
|
+
scanner.stop();
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
);
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Camera access requires HTTPS or localhost. Finder detection uses a QuadQR-specific RGB value pass first, then throttled threshold recovery when the fast pass cannot lock onto all three finder patterns.
|
|
75
|
+
|
|
76
|
+
## Secure password mode
|
|
77
|
+
|
|
78
|
+
Secure payloads are optional. Password mode is the simplest choice when a person will provide the secret during decryption.
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
import {
|
|
82
|
+
encodeSecureText,
|
|
83
|
+
decodeMatrix,
|
|
84
|
+
decryptDecoded
|
|
85
|
+
} from "quadqr-js";
|
|
86
|
+
|
|
87
|
+
const code = await encodeSecureText("Private payload", {
|
|
88
|
+
ecc: "M",
|
|
89
|
+
security: {
|
|
90
|
+
mode: "password",
|
|
91
|
+
password: "correct horse battery staple"
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
|
|
95
|
+
const locked = decodeMatrix(code.matrix);
|
|
96
|
+
|
|
97
|
+
const unlocked = await decryptDecoded(locked, {
|
|
98
|
+
password: "correct horse battery staple"
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
console.log(unlocked.text);
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
A secure image or camera scan follows the same pattern: scanning returns a locked result, then `decryptDecoded()` reveals plaintext only after successful authentication.
|
|
105
|
+
|
|
106
|
+
## Secure raw-key mode
|
|
107
|
+
|
|
108
|
+
Use raw-key mode when an application already manages its own cryptographic keys.
|
|
109
|
+
|
|
110
|
+
```js
|
|
111
|
+
import {
|
|
112
|
+
encodeSecureText,
|
|
113
|
+
generateRaw256Key
|
|
114
|
+
} from "quadqr-js";
|
|
115
|
+
|
|
116
|
+
const key = generateRaw256Key();
|
|
117
|
+
|
|
118
|
+
const code = await encodeSecureText("Application-managed secret", {
|
|
119
|
+
security: {
|
|
120
|
+
mode: "raw-key",
|
|
121
|
+
key
|
|
122
|
+
}
|
|
123
|
+
});
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
The key must be exactly 32 bytes. Never embed the secret key inside the same QuadQR payload.
|
|
127
|
+
|
|
128
|
+
## Generate and scan PNG files in Node.js
|
|
129
|
+
|
|
130
|
+
```js
|
|
131
|
+
import { encodeText } from "quadqr-js";
|
|
132
|
+
import { savePNG, scanFile } from "quadqr-js/node";
|
|
133
|
+
|
|
134
|
+
const code = encodeText("Generated on Node.js");
|
|
135
|
+
|
|
136
|
+
await savePNG(code, "quadqr.png", {
|
|
137
|
+
moduleSize: 12,
|
|
138
|
+
quietZone: 4
|
|
139
|
+
});
|
|
140
|
+
|
|
141
|
+
const result = await scanFile("quadqr.png");
|
|
142
|
+
console.log(result.text);
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
PNG generation and decoding are built into the Node.js adapter.
|
|
146
|
+
|
|
147
|
+
## Use a script tag
|
|
148
|
+
|
|
149
|
+
```html
|
|
150
|
+
<canvas id="qr"></canvas>
|
|
151
|
+
<script src="https://cdn.jsdelivr.net/npm/quadqr-js@1.0.1/dist/quadqr.min.js"></script>
|
|
152
|
+
<script>
|
|
153
|
+
const code = QuadQR.encodeText("No build step");
|
|
154
|
+
QuadQR.renderToCanvas(code, document.querySelector("#qr"));
|
|
155
|
+
</script>
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
Pin an exact package version in production.
|
|
159
|
+
|
|
160
|
+
## Use the CLI
|
|
161
|
+
|
|
162
|
+
```bash
|
|
163
|
+
npx quadqr-js encode "Hello QuadQR" -o hello.png
|
|
164
|
+
npx quadqr-js decode hello.png
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
Password-protected CLI workflow:
|
|
168
|
+
|
|
169
|
+
```bash
|
|
170
|
+
npx quadqr-js encode "Private data" --password "my-password" -o secure.png
|
|
171
|
+
npx quadqr-js decode secure.png --password "my-password"
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
See [CLI.md](./CLI.md) for the full command reference.
|