A pure JavaScript QR code reading library that processes raw images to locate, extract and parse QR codes.
npx @tessl/cli install tessl/npm-jsqr@1.4.00
# jsQR
1
2
jsQR is a pure JavaScript QR code reading library that processes raw image data to locate, extract and parse QR codes. It operates entirely in JavaScript without external dependencies, making it suitable for both browser and Node.js environments.
3
4
## Package Information
5
6
- **Package Name**: jsqr
7
- **Package Type**: npm
8
- **Language**: TypeScript/JavaScript
9
- **Installation**: `npm install jsqr`
10
11
## Core Imports
12
13
```javascript
14
// ES6 import
15
import jsQR from "jsqr";
16
17
// CommonJS require
18
const jsQR = require("jsqr");
19
```
20
21
For browser usage with script tag:
22
```html
23
<script src="jsQR.js"></script>
24
<script>
25
// jsQR is available globally
26
</script>
27
```
28
29
## Basic Usage
30
31
```javascript
32
import jsQR from "jsqr";
33
34
// Get RGBA image data from canvas, image, or other source
35
const imageData = canvas.getContext('2d').getImageData(0, 0, width, height);
36
37
// Process the image data
38
const code = jsQR(imageData.data, imageData.width, imageData.height);
39
40
if (code) {
41
console.log("Found QR code:", code.data);
42
console.log("Location:", code.location);
43
} else {
44
console.log("No QR code found");
45
}
46
```
47
48
## Capabilities
49
50
### QR Code Detection and Decoding
51
52
Processes raw RGBA image data to find and decode QR codes, returning comprehensive information about the decoded content and location.
53
54
```javascript { .api }
55
/**
56
* Scans image data for QR codes and returns decoded information
57
* @param data - RGBA pixel data as Uint8ClampedArray [r0,g0,b0,a0,r1,g1,b1,a1,...]
58
* @param width - Image width in pixels
59
* @param height - Image height in pixels
60
* @param providedOptions - Optional scanning configuration
61
* @returns Decoded QR code data or null if no valid QR code found
62
*/
63
function jsQR(
64
data: Uint8ClampedArray,
65
width: number,
66
height: number,
67
providedOptions?: Options
68
): QRCode | null;
69
```
70
71
**Parameters:**
72
- `data` - An `Uint8ClampedArray` of RGBA pixel values in the form `[r0, g0, b0, a0, r1, g1, b1, a1, ...]`. The length should be `4 * width * height`. This matches the format of browser `ImageData` interface and common Node.js image processing libraries.
73
- `width` - The width of the image in pixels
74
- `height` - The height of the image in pixels
75
- `providedOptions` (optional) - Configuration options for scanning behavior
76
77
**Returns:**
78
- `QRCode` object if a valid QR code is found and successfully decoded
79
- `null` if no QR code is found or decoding fails
80
81
## Types
82
83
```javascript { .api }
84
interface Options {
85
/**
86
* Image inversion strategy for finding QR codes on different backgrounds
87
* - "attemptBoth": Try both normal and inverted (default, ~50% performance hit)
88
* - "dontInvert": Only scan normal image
89
* - "onlyInvert": Only scan inverted image
90
* - "invertFirst": Try inverted first, then normal if no result
91
*/
92
inversionAttempts?: "dontInvert" | "onlyInvert" | "attemptBoth" | "invertFirst";
93
}
94
95
interface QRCode {
96
/** Raw bytes of the QR code as numeric array */
97
binaryData: number[];
98
/** Decoded string content of the QR code */
99
data: string;
100
/** Array of decoded data chunks with encoding information */
101
chunks: Chunks;
102
/** QR code version number (1-40, indicating size and capacity) */
103
version: number;
104
/** Precise pixel coordinates of key QR code features */
105
location: {
106
/** Corner coordinates of the decoded QR code area */
107
topRightCorner: Point;
108
topLeftCorner: Point;
109
bottomRightCorner: Point;
110
bottomLeftCorner: Point;
111
/** Finder pattern centers (the square detection patterns) */
112
topRightFinderPattern: Point;
113
topLeftFinderPattern: Point;
114
bottomLeftFinderPattern: Point;
115
/** Alignment pattern center (may not exist for smaller QR codes) */
116
bottomRightAlignmentPattern?: Point;
117
};
118
}
119
120
interface Point {
121
/** X coordinate in pixels */
122
x: number;
123
/** Y coordinate in pixels */
124
y: number;
125
}
126
127
type Chunks = Array<Chunk | ByteChunk | ECIChunk>;
128
129
interface Chunk {
130
/** Data encoding mode used for this chunk */
131
type: Mode;
132
/** Decoded text content */
133
text: string;
134
}
135
136
interface ByteChunk {
137
/** Binary data encoding mode */
138
type: Mode.Byte | Mode.Kanji;
139
/** Raw byte data as numeric array */
140
bytes: number[];
141
/** Decoded text content (may be empty string if decoding fails) */
142
text: string;
143
}
144
145
interface ECIChunk {
146
/** Extended Channel Interpretation mode */
147
type: Mode.ECI;
148
/** ECI assignment number for character encoding */
149
assignmentNumber: number;
150
}
151
152
enum Mode {
153
/** Numeric digits 0-9 */
154
Numeric = "numeric",
155
/** Alphanumeric characters (0-9, A-Z, space, $, %, *, +, -, ., /, :) */
156
Alphanumeric = "alphanumeric",
157
/** 8-bit byte data */
158
Byte = "byte",
159
/** Kanji characters (Shift JIS encoding) */
160
Kanji = "kanji",
161
/** Extended Channel Interpretation for character encoding */
162
ECI = "eci"
163
}
164
```
165
166
## Usage Examples
167
168
### Basic QR Code Scanning
169
170
```javascript
171
import jsQR from "jsqr";
172
173
// From canvas element
174
const canvas = document.getElementById('canvas');
175
const context = canvas.getContext('2d');
176
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
177
178
const code = jsQR(imageData.data, imageData.width, imageData.height);
179
if (code) {
180
console.log("QR Code found:", code.data);
181
}
182
```
183
184
### Webcam QR Code Scanning
185
186
```javascript
187
import jsQR from "jsqr";
188
189
// In a video frame processing loop
190
function tick() {
191
if (video.readyState === video.HAVE_ENOUGH_DATA) {
192
canvas.width = video.videoWidth;
193
canvas.height = video.videoHeight;
194
context.drawImage(video, 0, 0, canvas.width, canvas.height);
195
196
const imageData = context.getImageData(0, 0, canvas.width, canvas.height);
197
const code = jsQR(imageData.data, imageData.width, imageData.height);
198
199
if (code) {
200
console.log("Found QR code:", code.data);
201
// Access location information
202
console.log("Top-left corner:", code.location.topLeftCorner);
203
}
204
}
205
requestAnimationFrame(tick);
206
}
207
```
208
209
### Performance Optimization
210
211
```javascript
212
import jsQR from "jsqr";
213
214
// For better performance, skip inversion attempts if you know your QR codes
215
// are standard black-on-white
216
const code = jsQR(imageData.data, width, height, {
217
inversionAttempts: "dontInvert"
218
});
219
220
// For white-on-dark QR codes, only try inverted
221
const code2 = jsQR(imageData.data, width, height, {
222
inversionAttempts: "onlyInvert"
223
});
224
```
225
226
### Accessing Detailed Information
227
228
```javascript
229
import jsQR from "jsqr";
230
231
const code = jsQR(imageData.data, width, height);
232
if (code) {
233
console.log("Decoded text:", code.data);
234
console.log("Raw bytes:", code.binaryData);
235
console.log("QR version:", code.version);
236
237
// Access encoding chunks
238
code.chunks.forEach((chunk, index) => {
239
console.log(`Chunk ${index}:`, chunk.type);
240
if (chunk.type === "byte" || chunk.type === "kanji") {
241
console.log("Raw bytes:", chunk.bytes);
242
console.log("Decoded text:", chunk.text);
243
} else if (chunk.type === "eci") {
244
console.log("ECI assignment:", chunk.assignmentNumber);
245
} else {
246
console.log("Text:", chunk.text);
247
}
248
});
249
250
// Draw detection outline on canvas
251
const corners = [
252
code.location.topLeftCorner,
253
code.location.topRightCorner,
254
code.location.bottomRightCorner,
255
code.location.bottomLeftCorner
256
];
257
258
context.strokeStyle = "red";
259
context.beginPath();
260
corners.forEach((corner, index) => {
261
if (index === 0) {
262
context.moveTo(corner.x, corner.y);
263
} else {
264
context.lineTo(corner.x, corner.y);
265
}
266
});
267
context.closePath();
268
context.stroke();
269
}
270
```