@qr-styled/browser 1.0.0
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/LICENSE +21 -0
- package/README.md +341 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/lib/QRGenerator.d.ts +59 -0
- package/dist/lib/QRGenerator.js +184 -0
- package/dist/lib/renderers/BackgroundRenderer.d.ts +21 -0
- package/dist/lib/renderers/BackgroundRenderer.js +47 -0
- package/dist/lib/renderers/GradientRenderer.d.ts +17 -0
- package/dist/lib/renderers/GradientRenderer.js +43 -0
- package/dist/lib/renderers/LogoRenderer.d.ts +25 -0
- package/dist/lib/renderers/LogoRenderer.js +89 -0
- package/dist/lib/renderers/ModuleRenderer.d.ts +43 -0
- package/dist/lib/renderers/ModuleRenderer.js +161 -0
- package/dist/lib/renderers/SVGRenderer.d.ts +22 -0
- package/dist/lib/renderers/SVGRenderer.js +73 -0
- package/dist/lib/utils/formatters.d.ts +25 -0
- package/dist/lib/utils/formatters.js +106 -0
- package/dist/lib/utils/types.d.ts +119 -0
- package/dist/lib/utils/types.js +34 -0
- package/dist/lib/utils/validators.d.ts +10 -0
- package/dist/lib/utils/validators.js +126 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Luis Manuel Yerena Sosa
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,341 @@
|
|
|
1
|
+
# @qr-styled/browser
|
|
2
|
+
|
|
3
|
+
[](https://www.npmjs.com/package/@qr-styled/browser)
|
|
4
|
+
[](https://opensource.org/licenses/MIT)
|
|
5
|
+
|
|
6
|
+
A professional browser QR code generator library with advanced styling options including **gradients**, **rounded modules**, **logo support**, **specialized QR types** (vCard, WiFi, Email, SMS, Geo), and **eye customization**.
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
✅ **Browser-native** - Uses HTML5 Canvas API
|
|
11
|
+
✅ **PNG/JPEG export** - Download or convert to Blob/DataURL
|
|
12
|
+
✅ **SVG support** - Vector graphics export
|
|
13
|
+
✅ **Custom colors & gradients** - Multi-color linear gradients
|
|
14
|
+
✅ **Logo integration** - Circle/square shapes, customizable size
|
|
15
|
+
✅ **Eye customization** - Custom colors and corner radius
|
|
16
|
+
✅ **Rounded modules** - Smooth, professional appearance
|
|
17
|
+
✅ **Specialized QR types** - vCard, WiFi, Email, SMS, Geo
|
|
18
|
+
✅ **TypeScript** - Full type safety
|
|
19
|
+
✅ **Zero dependencies** - Only `qrcode` library
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm install @qr-styled/browser
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Quick Start
|
|
28
|
+
|
|
29
|
+
```typescript
|
|
30
|
+
import { QRGenerator } from '@qr-styled/browser';
|
|
31
|
+
|
|
32
|
+
const qr = new QRGenerator({
|
|
33
|
+
url: 'https://example.com',
|
|
34
|
+
size: 400,
|
|
35
|
+
foregroundColor: '#1a73e8',
|
|
36
|
+
backgroundColor: '#ffffff',
|
|
37
|
+
rounded: true
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
// Append to DOM
|
|
41
|
+
await qr.appendTo(document.body);
|
|
42
|
+
|
|
43
|
+
// Download as PNG
|
|
44
|
+
await qr.download('qrcode.png');
|
|
45
|
+
|
|
46
|
+
// Get as Blob
|
|
47
|
+
const blob = await qr.generateToBlob();
|
|
48
|
+
|
|
49
|
+
// Get as Data URL
|
|
50
|
+
const dataURL = await qr.generateToDataURL();
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## API Reference
|
|
54
|
+
|
|
55
|
+
### Constructor
|
|
56
|
+
|
|
57
|
+
```typescript
|
|
58
|
+
new QRGenerator(options: QROptions)
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Methods
|
|
62
|
+
|
|
63
|
+
#### `generate(): Promise<HTMLCanvasElement>`
|
|
64
|
+
Generates and returns the QR code canvas element.
|
|
65
|
+
|
|
66
|
+
#### `appendTo(element: HTMLElement): Promise<HTMLCanvasElement>`
|
|
67
|
+
Generates the QR code and appends it to the specified DOM element.
|
|
68
|
+
|
|
69
|
+
#### `generateToDataURL(format?: 'png' | 'jpeg'): Promise<string>`
|
|
70
|
+
Generates a data URL of the QR code.
|
|
71
|
+
|
|
72
|
+
#### `generateToBlob(format?: 'png' | 'jpeg'): Promise<Blob>`
|
|
73
|
+
Generates a Blob of the QR code image.
|
|
74
|
+
|
|
75
|
+
#### `download(filename?: string): Promise<void>`
|
|
76
|
+
Generates and downloads the QR code as an image file.
|
|
77
|
+
|
|
78
|
+
#### `generateToSVG(): Promise<string>`
|
|
79
|
+
Generates an SVG string of the QR code.
|
|
80
|
+
|
|
81
|
+
#### `downloadSVG(filename?: string): Promise<void>`
|
|
82
|
+
Generates and downloads the QR code as an SVG file.
|
|
83
|
+
|
|
84
|
+
#### `updateOptions(options: Partial<QROptions>): void`
|
|
85
|
+
Updates the generator options.
|
|
86
|
+
|
|
87
|
+
### Helper Functions
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
// Quick generation
|
|
91
|
+
import { generateQR, generateQRToElement, generateQRAndDownload } from '@qr-styled/browser';
|
|
92
|
+
|
|
93
|
+
// Generate canvas
|
|
94
|
+
const canvas = await generateQR({ url: 'https://example.com' });
|
|
95
|
+
|
|
96
|
+
// Generate and append to DOM
|
|
97
|
+
const canvas = await generateQRToElement({ url: 'https://example.com' }, document.body);
|
|
98
|
+
|
|
99
|
+
// Generate and download
|
|
100
|
+
await generateQRAndDownload({ url: 'https://example.com' }, 'qrcode.png');
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
## Options
|
|
104
|
+
|
|
105
|
+
### Basic Options
|
|
106
|
+
|
|
107
|
+
| Option | Type | Default | Description |
|
|
108
|
+
|--------|------|---------|-------------|
|
|
109
|
+
| `url` | `string` | - | URL or text content |
|
|
110
|
+
| `type` | `QRDataType` | `'url'` | Type of QR data |
|
|
111
|
+
| `size` | `number` | `400` | Canvas size in pixels |
|
|
112
|
+
| `foregroundColor` | `string` | `'#000000'` | QR code color |
|
|
113
|
+
| `backgroundColor` | `string` | `'#ffffff'` | Background color |
|
|
114
|
+
| `padding` | `number` | `20` | Canvas padding |
|
|
115
|
+
| `margin` | `number` | `4` | QR quiet zone (modules) |
|
|
116
|
+
| `errorCorrectionLevel` | `'L'\|'M'\|'Q'\|'H'` | `'M'` | Error correction |
|
|
117
|
+
|
|
118
|
+
### Styling Options
|
|
119
|
+
|
|
120
|
+
| Option | Type | Default | Description |
|
|
121
|
+
|--------|------|---------|-------------|
|
|
122
|
+
| `rounded` | `boolean` | `false` | Use rounded corners |
|
|
123
|
+
| `moduleRadius` | `number` | `0.5` | Module corner radius (0-0.5) |
|
|
124
|
+
| `cornerRadius` | `number` | `30` | Background corner radius |
|
|
125
|
+
| `gradient` | `boolean` | `false` | Enable gradient |
|
|
126
|
+
| `gradientColors` | `string` | - | Comma-separated colors |
|
|
127
|
+
| `gradientAngle` | `number` | `45` | Gradient angle |
|
|
128
|
+
|
|
129
|
+
### Logo Options
|
|
130
|
+
|
|
131
|
+
| Option | Type | Default | Description |
|
|
132
|
+
|--------|------|---------|-------------|
|
|
133
|
+
| `logo` | `string\|HTMLImageElement` | - | Logo path/URL or image element |
|
|
134
|
+
| `logoSize` | `number` | - | Logo size override |
|
|
135
|
+
| `logoPadding` | `number` | `20` | Padding around logo |
|
|
136
|
+
| `logoShape` | `'circle'\|'square'` | `'circle'` | Logo background shape |
|
|
137
|
+
| `logoRadius` | `number` | `10` | Square logo corner radius |
|
|
138
|
+
|
|
139
|
+
### Eye Customization
|
|
140
|
+
|
|
141
|
+
| Option | Type | Default | Description |
|
|
142
|
+
|--------|------|---------|-------------|
|
|
143
|
+
| `eyeColor` | `string` | - | Custom eye (finder) color |
|
|
144
|
+
| `eyeRadius` | `number` | - | Custom eye corner radius |
|
|
145
|
+
|
|
146
|
+
## Examples
|
|
147
|
+
|
|
148
|
+
### Basic QR Code
|
|
149
|
+
|
|
150
|
+
```typescript
|
|
151
|
+
const qr = new QRGenerator({
|
|
152
|
+
url: 'https://example.com',
|
|
153
|
+
size: 400
|
|
154
|
+
});
|
|
155
|
+
|
|
156
|
+
await qr.appendTo(document.getElementById('qr-container'));
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Gradient QR Code
|
|
160
|
+
|
|
161
|
+
```typescript
|
|
162
|
+
const qr = new QRGenerator({
|
|
163
|
+
url: 'https://example.com',
|
|
164
|
+
size: 400,
|
|
165
|
+
gradient: true,
|
|
166
|
+
gradientColors: '#667eea, #764ba2, #f093fb',
|
|
167
|
+
gradientAngle: 135,
|
|
168
|
+
rounded: true
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
await qr.download('gradient-qr.png');
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
### QR Code with Logo
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const qr = new QRGenerator({
|
|
178
|
+
url: 'https://example.com',
|
|
179
|
+
size: 400,
|
|
180
|
+
foregroundColor: '#1a73e8',
|
|
181
|
+
logo: 'https://example.com/logo.png',
|
|
182
|
+
logoShape: 'circle',
|
|
183
|
+
rounded: true
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
const blob = await qr.generateToBlob();
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
### Using HTMLImageElement
|
|
190
|
+
|
|
191
|
+
```typescript
|
|
192
|
+
const img = new Image();
|
|
193
|
+
img.src = 'logo.png';
|
|
194
|
+
await img.decode();
|
|
195
|
+
|
|
196
|
+
const qr = new QRGenerator({
|
|
197
|
+
url: 'https://example.com',
|
|
198
|
+
size: 400,
|
|
199
|
+
logo: img
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
await qr.appendTo(document.body);
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### vCard Contact QR
|
|
206
|
+
|
|
207
|
+
```typescript
|
|
208
|
+
import { QRGenerator, formatVCard } from '@qr-styled/browser';
|
|
209
|
+
|
|
210
|
+
const qr = new QRGenerator({
|
|
211
|
+
type: 'vcard',
|
|
212
|
+
data: {
|
|
213
|
+
firstName: 'John',
|
|
214
|
+
lastName: 'Doe',
|
|
215
|
+
organization: 'Company Inc.',
|
|
216
|
+
phone: '+1234567890',
|
|
217
|
+
email: 'john@example.com',
|
|
218
|
+
url: 'https://johndoe.com'
|
|
219
|
+
},
|
|
220
|
+
size: 400,
|
|
221
|
+
gradient: true,
|
|
222
|
+
gradientColors: '#667eea, #764ba2'
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
await qr.download('contact.png');
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
### WiFi QR Code
|
|
229
|
+
|
|
230
|
+
```typescript
|
|
231
|
+
const qr = new QRGenerator({
|
|
232
|
+
type: 'wifi',
|
|
233
|
+
data: {
|
|
234
|
+
ssid: 'MyNetwork',
|
|
235
|
+
password: 'mypassword',
|
|
236
|
+
encryption: 'WPA'
|
|
237
|
+
},
|
|
238
|
+
size: 400,
|
|
239
|
+
foregroundColor: '#2196f3'
|
|
240
|
+
});
|
|
241
|
+
|
|
242
|
+
await qr.appendTo(document.body);
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
### SVG Export
|
|
246
|
+
|
|
247
|
+
```typescript
|
|
248
|
+
const qr = new QRGenerator({
|
|
249
|
+
url: 'https://example.com',
|
|
250
|
+
size: 400,
|
|
251
|
+
foregroundColor: '#ff5722'
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
const svg = await qr.generateToSVG();
|
|
255
|
+
console.log(svg); // SVG string
|
|
256
|
+
|
|
257
|
+
// Or download directly
|
|
258
|
+
await qr.downloadSVG('qrcode.svg');
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
### Custom Eyes
|
|
262
|
+
|
|
263
|
+
```typescript
|
|
264
|
+
const qr = new QRGenerator({
|
|
265
|
+
url: 'https://example.com',
|
|
266
|
+
size: 400,
|
|
267
|
+
foregroundColor: '#000000',
|
|
268
|
+
eyeColor: '#ff0000',
|
|
269
|
+
eyeRadius: 0.5,
|
|
270
|
+
rounded: true
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
await qr.download();
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## Specialized QR Types
|
|
277
|
+
|
|
278
|
+
### Email
|
|
279
|
+
|
|
280
|
+
```typescript
|
|
281
|
+
const qr = new QRGenerator({
|
|
282
|
+
type: 'email',
|
|
283
|
+
data: {
|
|
284
|
+
email: 'hello@example.com',
|
|
285
|
+
subject: 'Hello',
|
|
286
|
+
body: 'Message body'
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
### SMS
|
|
292
|
+
|
|
293
|
+
```typescript
|
|
294
|
+
const qr = new QRGenerator({
|
|
295
|
+
type: 'sms',
|
|
296
|
+
data: {
|
|
297
|
+
phone: '+1234567890',
|
|
298
|
+
message: 'Hello from QR'
|
|
299
|
+
}
|
|
300
|
+
});
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
### Geolocation
|
|
304
|
+
|
|
305
|
+
```typescript
|
|
306
|
+
const qr = new QRGenerator({
|
|
307
|
+
type: 'geo',
|
|
308
|
+
data: {
|
|
309
|
+
latitude: 40.7128,
|
|
310
|
+
longitude: -74.0060
|
|
311
|
+
}
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
## Browser Compatibility
|
|
316
|
+
|
|
317
|
+
- Chrome/Edge 90+
|
|
318
|
+
- Firefox 88+
|
|
319
|
+
- Safari 14+
|
|
320
|
+
- Opera 76+
|
|
321
|
+
|
|
322
|
+
Requires support for:
|
|
323
|
+
- HTML5 Canvas API
|
|
324
|
+
- ES2020+ features
|
|
325
|
+
- Promises/async-await
|
|
326
|
+
|
|
327
|
+
## Related Packages
|
|
328
|
+
|
|
329
|
+
- [@qr-styled/node](../node) - Node.js version with PNG/JPEG file export
|
|
330
|
+
|
|
331
|
+
## License
|
|
332
|
+
|
|
333
|
+
MIT © Luis Manuel Yerena Sosa
|
|
334
|
+
|
|
335
|
+
## Contributing
|
|
336
|
+
|
|
337
|
+
Contributions are welcome! Please open an issue or submit a pull request.
|
|
338
|
+
|
|
339
|
+
## Repository
|
|
340
|
+
|
|
341
|
+
[https://github.com/Luisma92/qr-styled](https://github.com/Luisma92/qr-styled)
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { QRGenerator, generateQR, generateQRToElement, generateQRAndDownload } from './lib/QRGenerator.js';
|
|
2
|
+
export type { QROptions, QRDataType, VCardData, WiFiData, EmailData, SMSData, GeoData } from './lib/utils/types.js';
|
|
3
|
+
export { formatVCard, formatWiFi, formatEmail, formatSMS, formatGeo } from './lib/utils/formatters.js';
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { QROptions } from './utils/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* QR Code Generator with advanced styling options for browsers
|
|
4
|
+
*/
|
|
5
|
+
export declare class QRGenerator {
|
|
6
|
+
private options;
|
|
7
|
+
/**
|
|
8
|
+
* Creates a new QR generator instance
|
|
9
|
+
*/
|
|
10
|
+
constructor(options: QROptions);
|
|
11
|
+
/**
|
|
12
|
+
* Generates QR code content from options
|
|
13
|
+
*/
|
|
14
|
+
private getQRContent;
|
|
15
|
+
/**
|
|
16
|
+
* Generates QR code and returns the canvas
|
|
17
|
+
*/
|
|
18
|
+
generate(): Promise<HTMLCanvasElement>;
|
|
19
|
+
/**
|
|
20
|
+
* Generates QR code and returns data URL
|
|
21
|
+
*/
|
|
22
|
+
generateToDataURL(format?: 'png' | 'jpeg'): Promise<string>;
|
|
23
|
+
/**
|
|
24
|
+
* Generates QR code and returns Blob
|
|
25
|
+
*/
|
|
26
|
+
generateToBlob(format?: 'png' | 'jpeg'): Promise<Blob>;
|
|
27
|
+
/**
|
|
28
|
+
* Generates QR code and downloads it as an image file
|
|
29
|
+
*/
|
|
30
|
+
download(filename?: string): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Generates QR code as SVG string
|
|
33
|
+
*/
|
|
34
|
+
generateToSVG(): Promise<string>;
|
|
35
|
+
/**
|
|
36
|
+
* Generates QR code as SVG and downloads it
|
|
37
|
+
*/
|
|
38
|
+
downloadSVG(filename?: string): Promise<void>;
|
|
39
|
+
/**
|
|
40
|
+
* Appends the generated QR code canvas to a DOM element
|
|
41
|
+
*/
|
|
42
|
+
appendTo(element: HTMLElement): Promise<HTMLCanvasElement>;
|
|
43
|
+
/**
|
|
44
|
+
* Updates generator options
|
|
45
|
+
*/
|
|
46
|
+
updateOptions(options: Partial<QROptions>): void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Helper function to quickly generate a QR code
|
|
50
|
+
*/
|
|
51
|
+
export declare function generateQR(options: QROptions): Promise<HTMLCanvasElement>;
|
|
52
|
+
/**
|
|
53
|
+
* Helper function to quickly generate and append QR code to DOM
|
|
54
|
+
*/
|
|
55
|
+
export declare function generateQRToElement(options: QROptions, element: HTMLElement): Promise<HTMLCanvasElement>;
|
|
56
|
+
/**
|
|
57
|
+
* Helper function to quickly generate and download QR code
|
|
58
|
+
*/
|
|
59
|
+
export declare function generateQRAndDownload(options: QROptions, filename?: string): Promise<void>;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import QRCode from 'qrcode';
|
|
2
|
+
import { BackgroundRenderer } from './renderers/BackgroundRenderer.js';
|
|
3
|
+
import { GradientRenderer } from './renderers/GradientRenderer.js';
|
|
4
|
+
import { ModuleRenderer } from './renderers/ModuleRenderer.js';
|
|
5
|
+
import { LogoRenderer } from './renderers/LogoRenderer.js';
|
|
6
|
+
import { SVGRenderer } from './renderers/SVGRenderer.js';
|
|
7
|
+
import { DEFAULT_OPTIONS } from './utils/types.js';
|
|
8
|
+
import { validateOptions, normalizeOptions } from './utils/validators.js';
|
|
9
|
+
import { formatQRData } from './utils/formatters.js';
|
|
10
|
+
/**
|
|
11
|
+
* QR Code Generator with advanced styling options for browsers
|
|
12
|
+
*/
|
|
13
|
+
export class QRGenerator {
|
|
14
|
+
/**
|
|
15
|
+
* Creates a new QR generator instance
|
|
16
|
+
*/
|
|
17
|
+
constructor(options) {
|
|
18
|
+
this.options = normalizeOptions(options, DEFAULT_OPTIONS);
|
|
19
|
+
// Support deprecated 'color' field with backward compatibility
|
|
20
|
+
if (options.color && !options.foregroundColor) {
|
|
21
|
+
this.options.foregroundColor = options.color;
|
|
22
|
+
}
|
|
23
|
+
validateOptions(this.options);
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Generates QR code content from options
|
|
27
|
+
*/
|
|
28
|
+
getQRContent() {
|
|
29
|
+
const { type, url, data } = this.options;
|
|
30
|
+
// Use formatter to handle different data types
|
|
31
|
+
return formatQRData(type, url, data);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Generates QR code and returns the canvas
|
|
35
|
+
*/
|
|
36
|
+
async generate() {
|
|
37
|
+
const { errorCorrectionLevel, size, padding, foregroundColor } = this.options;
|
|
38
|
+
const qrSize = size - padding * 2;
|
|
39
|
+
// Get formatted content based on type
|
|
40
|
+
const content = this.getQRContent();
|
|
41
|
+
// Generate QR data
|
|
42
|
+
const qrData = await QRCode.create(content, {
|
|
43
|
+
errorCorrectionLevel
|
|
44
|
+
});
|
|
45
|
+
const modules = qrData.modules;
|
|
46
|
+
const moduleCount = modules.size;
|
|
47
|
+
const moduleSize = qrSize / moduleCount;
|
|
48
|
+
// Create canvas
|
|
49
|
+
const canvas = document.createElement('canvas');
|
|
50
|
+
canvas.width = size;
|
|
51
|
+
canvas.height = size;
|
|
52
|
+
const ctx = canvas.getContext('2d');
|
|
53
|
+
if (!ctx) {
|
|
54
|
+
throw new Error('Failed to get 2D context from canvas. Canvas API may not be supported in this environment.');
|
|
55
|
+
}
|
|
56
|
+
// Render background
|
|
57
|
+
const backgroundRenderer = new BackgroundRenderer(ctx, this.options);
|
|
58
|
+
backgroundRenderer.render();
|
|
59
|
+
backgroundRenderer.applyClipping();
|
|
60
|
+
// Create fill style (gradient or solid)
|
|
61
|
+
const gradientRenderer = new GradientRenderer(ctx, this.options);
|
|
62
|
+
const fillStyle = gradientRenderer.getFillStyle();
|
|
63
|
+
// Render QR modules with eye customization support
|
|
64
|
+
const moduleRenderer = new ModuleRenderer(ctx, modules, {
|
|
65
|
+
...this.options,
|
|
66
|
+
color: foregroundColor, // Use new foregroundColor
|
|
67
|
+
moduleCount,
|
|
68
|
+
moduleSize
|
|
69
|
+
});
|
|
70
|
+
moduleRenderer.render(fillStyle);
|
|
71
|
+
backgroundRenderer.restoreClipping();
|
|
72
|
+
// Render logo if provided
|
|
73
|
+
if (this.options.logo) {
|
|
74
|
+
const logoRenderer = new LogoRenderer(ctx, this.options);
|
|
75
|
+
await logoRenderer.render(this.options.logo);
|
|
76
|
+
}
|
|
77
|
+
return canvas;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Generates QR code and returns data URL
|
|
81
|
+
*/
|
|
82
|
+
async generateToDataURL(format = 'png') {
|
|
83
|
+
const canvas = await this.generate();
|
|
84
|
+
if (format === 'jpeg') {
|
|
85
|
+
return canvas.toDataURL('image/jpeg');
|
|
86
|
+
}
|
|
87
|
+
return canvas.toDataURL('image/png');
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Generates QR code and returns Blob
|
|
91
|
+
*/
|
|
92
|
+
async generateToBlob(format = 'png') {
|
|
93
|
+
const canvas = await this.generate();
|
|
94
|
+
return new Promise((resolve, reject) => {
|
|
95
|
+
canvas.toBlob(blob => {
|
|
96
|
+
if (blob) {
|
|
97
|
+
resolve(blob);
|
|
98
|
+
}
|
|
99
|
+
else {
|
|
100
|
+
reject(new Error('Failed to generate blob'));
|
|
101
|
+
}
|
|
102
|
+
}, format === 'jpeg' ? 'image/jpeg' : 'image/png');
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Generates QR code and downloads it as an image file
|
|
107
|
+
*/
|
|
108
|
+
async download(filename = 'qrcode.png') {
|
|
109
|
+
const format = filename.endsWith('.jpeg') || filename.endsWith('.jpg') ? 'jpeg' : 'png';
|
|
110
|
+
const dataURL = await this.generateToDataURL(format);
|
|
111
|
+
const link = document.createElement('a');
|
|
112
|
+
link.href = dataURL;
|
|
113
|
+
link.download = filename;
|
|
114
|
+
link.click();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Generates QR code as SVG string
|
|
118
|
+
*/
|
|
119
|
+
async generateToSVG() {
|
|
120
|
+
const { errorCorrectionLevel, size } = this.options;
|
|
121
|
+
// Get formatted content based on type
|
|
122
|
+
const content = this.getQRContent();
|
|
123
|
+
// Generate QR data
|
|
124
|
+
const qrData = await QRCode.create(content, {
|
|
125
|
+
errorCorrectionLevel
|
|
126
|
+
});
|
|
127
|
+
// Use SVG renderer
|
|
128
|
+
const svgRenderer = new SVGRenderer(qrData, this.options, size);
|
|
129
|
+
return svgRenderer.generate();
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* Generates QR code as SVG and downloads it
|
|
133
|
+
*/
|
|
134
|
+
async downloadSVG(filename = 'qrcode.svg') {
|
|
135
|
+
const svg = await this.generateToSVG();
|
|
136
|
+
const blob = new Blob([svg], { type: 'image/svg+xml' });
|
|
137
|
+
const url = URL.createObjectURL(blob);
|
|
138
|
+
const link = document.createElement('a');
|
|
139
|
+
link.href = url;
|
|
140
|
+
link.download = filename;
|
|
141
|
+
link.click();
|
|
142
|
+
URL.revokeObjectURL(url);
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Appends the generated QR code canvas to a DOM element
|
|
146
|
+
*/
|
|
147
|
+
async appendTo(element) {
|
|
148
|
+
const canvas = await this.generate();
|
|
149
|
+
element.appendChild(canvas);
|
|
150
|
+
return canvas;
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Updates generator options
|
|
154
|
+
*/
|
|
155
|
+
updateOptions(options) {
|
|
156
|
+
this.options = normalizeOptions({ ...this.options, ...options }, DEFAULT_OPTIONS);
|
|
157
|
+
// Support deprecated 'color' field
|
|
158
|
+
if (options.color && !options.foregroundColor) {
|
|
159
|
+
this.options.foregroundColor = options.color;
|
|
160
|
+
}
|
|
161
|
+
validateOptions(this.options);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Helper function to quickly generate a QR code
|
|
166
|
+
*/
|
|
167
|
+
export async function generateQR(options) {
|
|
168
|
+
const generator = new QRGenerator(options);
|
|
169
|
+
return generator.generate();
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Helper function to quickly generate and append QR code to DOM
|
|
173
|
+
*/
|
|
174
|
+
export async function generateQRToElement(options, element) {
|
|
175
|
+
const generator = new QRGenerator(options);
|
|
176
|
+
return generator.appendTo(element);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* Helper function to quickly generate and download QR code
|
|
180
|
+
*/
|
|
181
|
+
export async function generateQRAndDownload(options, filename) {
|
|
182
|
+
const generator = new QRGenerator(options);
|
|
183
|
+
return generator.download(filename);
|
|
184
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { QROptions } from '../utils/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handles background rendering for QR codes
|
|
4
|
+
*/
|
|
5
|
+
export declare class BackgroundRenderer {
|
|
6
|
+
private ctx;
|
|
7
|
+
private options;
|
|
8
|
+
constructor(ctx: CanvasRenderingContext2D, options: Required<QROptions>);
|
|
9
|
+
/**
|
|
10
|
+
* Renders background with rounded corners
|
|
11
|
+
*/
|
|
12
|
+
render(): void;
|
|
13
|
+
/**
|
|
14
|
+
* Applies clipping path for rounded corners
|
|
15
|
+
*/
|
|
16
|
+
applyClipping(): void;
|
|
17
|
+
/**
|
|
18
|
+
* Restores canvas context after clipping
|
|
19
|
+
*/
|
|
20
|
+
restoreClipping(): void;
|
|
21
|
+
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Handles background rendering for QR codes
|
|
3
|
+
*/
|
|
4
|
+
export class BackgroundRenderer {
|
|
5
|
+
constructor(ctx, options) {
|
|
6
|
+
this.ctx = ctx;
|
|
7
|
+
this.options = options;
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Renders background with rounded corners
|
|
11
|
+
*/
|
|
12
|
+
render() {
|
|
13
|
+
const { size, cornerRadius, backgroundColor } = this.options;
|
|
14
|
+
const ctx = this.ctx;
|
|
15
|
+
ctx.fillStyle = backgroundColor;
|
|
16
|
+
ctx.beginPath();
|
|
17
|
+
ctx.moveTo(cornerRadius, 0);
|
|
18
|
+
ctx.arcTo(size, 0, size, size, cornerRadius);
|
|
19
|
+
ctx.arcTo(size, size, 0, size, cornerRadius);
|
|
20
|
+
ctx.arcTo(0, size, 0, 0, cornerRadius);
|
|
21
|
+
ctx.arcTo(0, 0, size, 0, cornerRadius);
|
|
22
|
+
ctx.closePath();
|
|
23
|
+
ctx.fill();
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Applies clipping path for rounded corners
|
|
27
|
+
*/
|
|
28
|
+
applyClipping() {
|
|
29
|
+
const { size, cornerRadius } = this.options;
|
|
30
|
+
const ctx = this.ctx;
|
|
31
|
+
ctx.save();
|
|
32
|
+
ctx.beginPath();
|
|
33
|
+
ctx.moveTo(cornerRadius, 0);
|
|
34
|
+
ctx.arcTo(size, 0, size, size, cornerRadius);
|
|
35
|
+
ctx.arcTo(size, size, 0, size, cornerRadius);
|
|
36
|
+
ctx.arcTo(0, size, 0, 0, cornerRadius);
|
|
37
|
+
ctx.arcTo(0, 0, size, 0, cornerRadius);
|
|
38
|
+
ctx.closePath();
|
|
39
|
+
ctx.clip();
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Restores canvas context after clipping
|
|
43
|
+
*/
|
|
44
|
+
restoreClipping() {
|
|
45
|
+
this.ctx.restore();
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { QROptions } from '../utils/types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Handles gradient creation for QR codes
|
|
4
|
+
*/
|
|
5
|
+
export declare class GradientRenderer {
|
|
6
|
+
private ctx;
|
|
7
|
+
private options;
|
|
8
|
+
constructor(ctx: CanvasRenderingContext2D, options: Required<QROptions>);
|
|
9
|
+
/**
|
|
10
|
+
* Creates a gradient fill style
|
|
11
|
+
*/
|
|
12
|
+
createGradient(): CanvasGradient;
|
|
13
|
+
/**
|
|
14
|
+
* Gets the appropriate fill style (gradient or solid color)
|
|
15
|
+
*/
|
|
16
|
+
getFillStyle(): string | CanvasGradient;
|
|
17
|
+
}
|