isahaq-barcode 1.0.0 → 1.1.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.
@@ -1,401 +1,401 @@
1
- /**
2
- * QR Code Builder - Advanced QR code generation with logo and watermark support
3
- */
4
-
5
- const QRCode = require('qrcode');
6
- const { createCanvas, loadImage } = require('canvas');
7
- const fs = require('fs').promises;
8
-
9
- class QrCodeBuilder {
10
- constructor(options = {}) {
11
- this.options = {
12
- data: '',
13
- size: 300,
14
- margin: 10,
15
- errorCorrectionLevel: 'M',
16
- foregroundColor: [0, 0, 0],
17
- backgroundColor: [255, 255, 255],
18
- logoPath: null,
19
- logoSize: 60, // Percentage of QR code size
20
- label: null,
21
- labelFont: null,
22
- labelFontSize: 16,
23
- watermark: null,
24
- watermarkPosition: 'center',
25
- format: 'png',
26
- ...options,
27
- };
28
- }
29
-
30
- /**
31
- * Create a new QR Code Builder instance
32
- * @param {Object} options - Initial options
33
- * @returns {QrCodeBuilder} Builder instance
34
- */
35
- static create(options = {}) {
36
- return new QrCodeBuilder(options);
37
- }
38
-
39
- /**
40
- * Set the data to encode
41
- * @param {string} data - The data to encode
42
- * @returns {QrCodeBuilder} Builder instance
43
- */
44
- data(data) {
45
- this.options.data = data;
46
- return this;
47
- }
48
-
49
- /**
50
- * Set the QR code size
51
- * @param {number} size - Size in pixels
52
- * @returns {QrCodeBuilder} Builder instance
53
- */
54
- size(size) {
55
- this.options.size = size;
56
- return this;
57
- }
58
-
59
- /**
60
- * Set the margin
61
- * @param {number} margin - Margin in pixels
62
- * @returns {QrCodeBuilder} Builder instance
63
- */
64
- margin(margin) {
65
- this.options.margin = margin;
66
- return this;
67
- }
68
-
69
- /**
70
- * Set the error correction level
71
- * @param {string} level - Error correction level (L, M, Q, H)
72
- * @returns {QrCodeBuilder} Builder instance
73
- */
74
- errorCorrectionLevel(level) {
75
- this.options.errorCorrectionLevel = level;
76
- return this;
77
- }
78
-
79
- /**
80
- * Set the foreground color
81
- * @param {Array} color - RGB color array [r, g, b]
82
- * @returns {QrCodeBuilder} Builder instance
83
- */
84
- foregroundColor(color) {
85
- this.options.foregroundColor = color;
86
- return this;
87
- }
88
-
89
- /**
90
- * Set the background color
91
- * @param {Array} color - RGB color array [r, g, b]
92
- * @returns {QrCodeBuilder} Builder instance
93
- */
94
- backgroundColor(color) {
95
- this.options.backgroundColor = color;
96
- return this;
97
- }
98
-
99
- /**
100
- * Set the logo path
101
- * @param {string} logoPath - Path to logo image
102
- * @returns {QrCodeBuilder} Builder instance
103
- */
104
- logoPath(logoPath) {
105
- this.options.logoPath = logoPath;
106
- return this;
107
- }
108
-
109
- /**
110
- * Set the logo size
111
- * @param {number} logoSize - Logo size as percentage of QR code size
112
- * @returns {QrCodeBuilder} Builder instance
113
- */
114
- logoSize(logoSize) {
115
- this.options.logoSize = logoSize;
116
- return this;
117
- }
118
-
119
- /**
120
- * Set the label text
121
- * @param {string} label - Label text
122
- * @returns {QrCodeBuilder} Builder instance
123
- */
124
- label(label) {
125
- this.options.label = label;
126
- return this;
127
- }
128
-
129
- /**
130
- * Set the label font
131
- * @param {string} fontPath - Path to font file
132
- * @param {number} fontSize - Font size
133
- * @returns {QrCodeBuilder} Builder instance
134
- */
135
- labelFont(fontPath, fontSize = 16) {
136
- this.options.labelFont = fontPath;
137
- this.options.labelFontSize = fontSize;
138
- return this;
139
- }
140
-
141
- /**
142
- * Set the watermark
143
- * @param {string} watermark - Watermark text or image path
144
- * @param {string} position - Watermark position
145
- * @returns {QrCodeBuilder} Builder instance
146
- */
147
- watermark(watermark, position = 'center') {
148
- this.options.watermark = watermark;
149
- this.options.watermarkPosition = position;
150
- return this;
151
- }
152
-
153
- /**
154
- * Set the output format
155
- * @param {string} format - Output format (png, svg, jpg)
156
- * @returns {QrCodeBuilder} Builder instance
157
- */
158
- format(format) {
159
- this.options.format = format;
160
- return this;
161
- }
162
-
163
- /**
164
- * Build the QR code
165
- * @returns {Object} QR code result
166
- */
167
- build() {
168
- return new QrCodeResult(this.options);
169
- }
170
-
171
- /**
172
- * Generate QR code and return as buffer
173
- * @returns {Promise<Buffer>} QR code buffer
174
- */
175
- async generate() {
176
- const result = this.build();
177
- return await result.generate();
178
- }
179
-
180
- /**
181
- * Generate QR code and save to file
182
- * @param {string} filePath - Output file path
183
- * @returns {Promise<void>}
184
- */
185
- async saveToFile(filePath) {
186
- const result = this.build();
187
- return await result.saveToFile(filePath);
188
- }
189
-
190
- /**
191
- * Generate QR code and return as data URI
192
- * @returns {Promise<string>} Data URI
193
- */
194
- async getDataUri() {
195
- const result = this.build();
196
- return await result.getDataUri();
197
- }
198
- }
199
-
200
- /**
201
- * QR Code Result - Handles QR code generation and output
202
- */
203
- class QrCodeResult {
204
- constructor(options) {
205
- this.options = options;
206
- }
207
-
208
- /**
209
- * Generate the QR code
210
- * @returns {Promise<Buffer>} QR code buffer
211
- */
212
- async generate() {
213
- try {
214
- // Create canvas
215
- const canvas = createCanvas(this.options.size, this.options.size);
216
- const ctx = canvas.getContext('2d');
217
-
218
- // Set background
219
- ctx.fillStyle = this.rgbToHex(this.options.backgroundColor);
220
- ctx.fillRect(0, 0, this.options.size, this.options.size);
221
-
222
- // Generate QR code
223
- const qrCodeDataURL = await QRCode.toDataURL(this.options.data, {
224
- width: this.options.size - this.options.margin * 2,
225
- margin: 0,
226
- color: {
227
- dark: this.rgbToHex(this.options.foregroundColor),
228
- light: this.rgbToHex(this.options.backgroundColor),
229
- },
230
- errorCorrectionLevel: this.options.errorCorrectionLevel,
231
- });
232
-
233
- // Load QR code image
234
- const qrCodeImage = await loadImage(qrCodeDataURL);
235
- ctx.drawImage(qrCodeImage, this.options.margin, this.options.margin);
236
-
237
- // Add logo if specified
238
- if (this.options.logoPath) {
239
- await this.addLogo(ctx);
240
- }
241
-
242
- // Add watermark if specified
243
- if (this.options.watermark) {
244
- await this.addWatermark(ctx);
245
- }
246
-
247
- // Add label if specified
248
- if (this.options.label) {
249
- this.addLabel(ctx);
250
- }
251
-
252
- // Convert to buffer
253
- return canvas.toBuffer(`image/${this.options.format}`);
254
- } catch (error) {
255
- throw new Error(`QR code generation failed: ${error.message}`);
256
- }
257
- }
258
-
259
- /**
260
- * Add logo to QR code
261
- * @param {CanvasRenderingContext2D} ctx - Canvas context
262
- */
263
- async addLogo(ctx) {
264
- try {
265
- const logoImage = await loadImage(this.options.logoPath);
266
- const logoSize = (this.options.size * this.options.logoSize) / 100;
267
- const logoX = (this.options.size - logoSize) / 2;
268
- const logoY = (this.options.size - logoSize) / 2;
269
-
270
- // Draw white background for logo
271
- ctx.fillStyle = this.rgbToHex(this.options.backgroundColor);
272
- ctx.fillRect(logoX - 5, logoY - 5, logoSize + 10, logoSize + 10);
273
-
274
- // Draw logo
275
- ctx.drawImage(logoImage, logoX, logoY, logoSize, logoSize);
276
- } catch (error) {
277
- console.warn(`Failed to add logo: ${error.message}`);
278
- }
279
- }
280
-
281
- /**
282
- * Add watermark to QR code
283
- * @param {CanvasRenderingContext2D} ctx - Canvas context
284
- */
285
- async addWatermark(ctx) {
286
- try {
287
- // Check if watermark is an image path
288
- if (
289
- this.options.watermark.includes('.') &&
290
- this.options.watermark.includes('/')
291
- ) {
292
- const watermarkImage = await loadImage(this.options.watermark);
293
- const watermarkSize = this.options.size / 4;
294
- const position = this.getWatermarkPosition(watermarkSize);
295
-
296
- ctx.drawImage(
297
- watermarkImage,
298
- position.x,
299
- position.y,
300
- watermarkSize,
301
- watermarkSize
302
- );
303
- } else {
304
- // Text watermark
305
- ctx.font = `${this.options.labelFontSize}px Arial`;
306
- ctx.fillStyle = this.rgbToHex(this.options.foregroundColor);
307
- ctx.textAlign = 'center';
308
-
309
- const position = this.getWatermarkPosition(0);
310
- ctx.fillText(this.options.watermark, position.x, position.y);
311
- }
312
- } catch (error) {
313
- console.warn(`Failed to add watermark: ${error.message}`);
314
- }
315
- }
316
-
317
- /**
318
- * Add label to QR code
319
- * @param {CanvasRenderingContext2D} ctx - Canvas context
320
- */
321
- addLabel(ctx) {
322
- ctx.font = `${this.options.labelFontSize}px Arial`;
323
- ctx.fillStyle = this.rgbToHex(this.options.foregroundColor);
324
- ctx.textAlign = 'center';
325
-
326
- const labelY = this.options.size - 10;
327
- ctx.fillText(this.options.label, this.options.size / 2, labelY);
328
- }
329
-
330
- /**
331
- * Get watermark position
332
- * @param {number} size - Watermark size
333
- * @returns {Object} Position coordinates
334
- */
335
- getWatermarkPosition(size) {
336
- const positions = {
337
- 'top-left': { x: 10, y: 10 },
338
- 'top-right': { x: this.options.size - size - 10, y: 10 },
339
- 'bottom-left': { x: 10, y: this.options.size - size - 10 },
340
- 'bottom-right': {
341
- x: this.options.size - size - 10,
342
- y: this.options.size - size - 10,
343
- },
344
- center: {
345
- x: (this.options.size - size) / 2,
346
- y: (this.options.size - size) / 2,
347
- },
348
- 'top-center': { x: (this.options.size - size) / 2, y: 10 },
349
- 'bottom-center': {
350
- x: (this.options.size - size) / 2,
351
- y: this.options.size - size - 10,
352
- },
353
- 'left-center': { x: 10, y: (this.options.size - size) / 2 },
354
- 'right-center': {
355
- x: this.options.size - size - 10,
356
- y: (this.options.size - size) / 2,
357
- },
358
- };
359
-
360
- return positions[this.options.watermarkPosition] || positions.center;
361
- }
362
-
363
- /**
364
- * Convert RGB array to hex color
365
- * @param {Array} rgb - RGB color array
366
- * @returns {string} Hex color
367
- */
368
- rgbToHex(rgb) {
369
- return `#${rgb.map((c) => c.toString(16).padStart(2, '0')).join('')}`;
370
- }
371
-
372
- /**
373
- * Save QR code to file
374
- * @param {string} filePath - Output file path
375
- * @returns {Promise<void>}
376
- */
377
- async saveToFile(filePath) {
378
- const buffer = await this.generate();
379
- await fs.writeFile(filePath, buffer);
380
- }
381
-
382
- /**
383
- * Get QR code as data URI
384
- * @returns {Promise<string>} Data URI
385
- */
386
- async getDataUri() {
387
- const buffer = await this.generate();
388
- const base64 = buffer.toString('base64');
389
- return `data:image/${this.options.format};base64,${base64}`;
390
- }
391
-
392
- /**
393
- * Get QR code as string
394
- * @returns {Promise<string>} QR code string
395
- */
396
- async getString() {
397
- return await this.generate();
398
- }
399
- }
400
-
401
- module.exports = QrCodeBuilder;
1
+ /**
2
+ * QR Code Builder - Advanced QR code generation with logo and watermark support
3
+ */
4
+
5
+ const QRCode = require('qrcode');
6
+ const { createCanvas, loadImage } = require('canvas');
7
+ const fs = require('fs').promises;
8
+
9
+ class QrCodeBuilder {
10
+ constructor(options = {}) {
11
+ this.options = {
12
+ data: '',
13
+ size: 300,
14
+ margin: 10,
15
+ errorCorrectionLevel: 'M',
16
+ foregroundColor: [0, 0, 0],
17
+ backgroundColor: [255, 255, 255],
18
+ logoPath: null,
19
+ logoSize: 60, // Percentage of QR code size
20
+ label: null,
21
+ labelFont: null,
22
+ labelFontSize: 16,
23
+ watermark: null,
24
+ watermarkPosition: 'center',
25
+ format: 'png',
26
+ ...options,
27
+ };
28
+ }
29
+
30
+ /**
31
+ * Create a new QR Code Builder instance
32
+ * @param {Object} options - Initial options
33
+ * @returns {QrCodeBuilder} Builder instance
34
+ */
35
+ static create(options = {}) {
36
+ return new QrCodeBuilder(options);
37
+ }
38
+
39
+ /**
40
+ * Set the data to encode
41
+ * @param {string} data - The data to encode
42
+ * @returns {QrCodeBuilder} Builder instance
43
+ */
44
+ data(data) {
45
+ this.options.data = data;
46
+ return this;
47
+ }
48
+
49
+ /**
50
+ * Set the QR code size
51
+ * @param {number} size - Size in pixels
52
+ * @returns {QrCodeBuilder} Builder instance
53
+ */
54
+ size(size) {
55
+ this.options.size = size;
56
+ return this;
57
+ }
58
+
59
+ /**
60
+ * Set the margin
61
+ * @param {number} margin - Margin in pixels
62
+ * @returns {QrCodeBuilder} Builder instance
63
+ */
64
+ margin(margin) {
65
+ this.options.margin = margin;
66
+ return this;
67
+ }
68
+
69
+ /**
70
+ * Set the error correction level
71
+ * @param {string} level - Error correction level (L, M, Q, H)
72
+ * @returns {QrCodeBuilder} Builder instance
73
+ */
74
+ errorCorrectionLevel(level) {
75
+ this.options.errorCorrectionLevel = level;
76
+ return this;
77
+ }
78
+
79
+ /**
80
+ * Set the foreground color
81
+ * @param {Array} color - RGB color array [r, g, b]
82
+ * @returns {QrCodeBuilder} Builder instance
83
+ */
84
+ foregroundColor(color) {
85
+ this.options.foregroundColor = color;
86
+ return this;
87
+ }
88
+
89
+ /**
90
+ * Set the background color
91
+ * @param {Array} color - RGB color array [r, g, b]
92
+ * @returns {QrCodeBuilder} Builder instance
93
+ */
94
+ backgroundColor(color) {
95
+ this.options.backgroundColor = color;
96
+ return this;
97
+ }
98
+
99
+ /**
100
+ * Set the logo path
101
+ * @param {string} logoPath - Path to logo image
102
+ * @returns {QrCodeBuilder} Builder instance
103
+ */
104
+ logoPath(logoPath) {
105
+ this.options.logoPath = logoPath;
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * Set the logo size
111
+ * @param {number} logoSize - Logo size as percentage of QR code size
112
+ * @returns {QrCodeBuilder} Builder instance
113
+ */
114
+ logoSize(logoSize) {
115
+ this.options.logoSize = logoSize;
116
+ return this;
117
+ }
118
+
119
+ /**
120
+ * Set the label text
121
+ * @param {string} label - Label text
122
+ * @returns {QrCodeBuilder} Builder instance
123
+ */
124
+ label(label) {
125
+ this.options.label = label;
126
+ return this;
127
+ }
128
+
129
+ /**
130
+ * Set the label font
131
+ * @param {string} fontPath - Path to font file
132
+ * @param {number} fontSize - Font size
133
+ * @returns {QrCodeBuilder} Builder instance
134
+ */
135
+ labelFont(fontPath, fontSize = 16) {
136
+ this.options.labelFont = fontPath;
137
+ this.options.labelFontSize = fontSize;
138
+ return this;
139
+ }
140
+
141
+ /**
142
+ * Set the watermark
143
+ * @param {string} watermark - Watermark text or image path
144
+ * @param {string} position - Watermark position
145
+ * @returns {QrCodeBuilder} Builder instance
146
+ */
147
+ watermark(watermark, position = 'center') {
148
+ this.options.watermark = watermark;
149
+ this.options.watermarkPosition = position;
150
+ return this;
151
+ }
152
+
153
+ /**
154
+ * Set the output format
155
+ * @param {string} format - Output format (png, svg, jpg)
156
+ * @returns {QrCodeBuilder} Builder instance
157
+ */
158
+ format(format) {
159
+ this.options.format = format;
160
+ return this;
161
+ }
162
+
163
+ /**
164
+ * Build the QR code
165
+ * @returns {Object} QR code result
166
+ */
167
+ build() {
168
+ return new QrCodeResult(this.options);
169
+ }
170
+
171
+ /**
172
+ * Generate QR code and return as buffer
173
+ * @returns {Promise<Buffer>} QR code buffer
174
+ */
175
+ async generate() {
176
+ const result = this.build();
177
+ return await result.generate();
178
+ }
179
+
180
+ /**
181
+ * Generate QR code and save to file
182
+ * @param {string} filePath - Output file path
183
+ * @returns {Promise<void>}
184
+ */
185
+ async saveToFile(filePath) {
186
+ const result = this.build();
187
+ return await result.saveToFile(filePath);
188
+ }
189
+
190
+ /**
191
+ * Generate QR code and return as data URI
192
+ * @returns {Promise<string>} Data URI
193
+ */
194
+ async getDataUri() {
195
+ const result = this.build();
196
+ return await result.getDataUri();
197
+ }
198
+ }
199
+
200
+ /**
201
+ * QR Code Result - Handles QR code generation and output
202
+ */
203
+ class QrCodeResult {
204
+ constructor(options) {
205
+ this.options = options;
206
+ }
207
+
208
+ /**
209
+ * Generate the QR code
210
+ * @returns {Promise<Buffer>} QR code buffer
211
+ */
212
+ async generate() {
213
+ try {
214
+ // Create canvas
215
+ const canvas = createCanvas(this.options.size, this.options.size);
216
+ const ctx = canvas.getContext('2d');
217
+
218
+ // Set background
219
+ ctx.fillStyle = this.rgbToHex(this.options.backgroundColor);
220
+ ctx.fillRect(0, 0, this.options.size, this.options.size);
221
+
222
+ // Generate QR code
223
+ const qrCodeDataURL = await QRCode.toDataURL(this.options.data, {
224
+ width: this.options.size - this.options.margin * 2,
225
+ margin: 0,
226
+ color: {
227
+ dark: this.rgbToHex(this.options.foregroundColor),
228
+ light: this.rgbToHex(this.options.backgroundColor),
229
+ },
230
+ errorCorrectionLevel: this.options.errorCorrectionLevel,
231
+ });
232
+
233
+ // Load QR code image
234
+ const qrCodeImage = await loadImage(qrCodeDataURL);
235
+ ctx.drawImage(qrCodeImage, this.options.margin, this.options.margin);
236
+
237
+ // Add logo if specified
238
+ if (this.options.logoPath) {
239
+ await this.addLogo(ctx);
240
+ }
241
+
242
+ // Add watermark if specified
243
+ if (this.options.watermark) {
244
+ await this.addWatermark(ctx);
245
+ }
246
+
247
+ // Add label if specified
248
+ if (this.options.label) {
249
+ this.addLabel(ctx);
250
+ }
251
+
252
+ // Convert to buffer
253
+ return canvas.toBuffer(`image/${this.options.format}`);
254
+ } catch (error) {
255
+ throw new Error(`QR code generation failed: ${error.message}`);
256
+ }
257
+ }
258
+
259
+ /**
260
+ * Add logo to QR code
261
+ * @param {CanvasRenderingContext2D} ctx - Canvas context
262
+ */
263
+ async addLogo(ctx) {
264
+ try {
265
+ const logoImage = await loadImage(this.options.logoPath);
266
+ const logoSize = (this.options.size * this.options.logoSize) / 100;
267
+ const logoX = (this.options.size - logoSize) / 2;
268
+ const logoY = (this.options.size - logoSize) / 2;
269
+
270
+ // Draw white background for logo
271
+ ctx.fillStyle = this.rgbToHex(this.options.backgroundColor);
272
+ ctx.fillRect(logoX - 5, logoY - 5, logoSize + 10, logoSize + 10);
273
+
274
+ // Draw logo
275
+ ctx.drawImage(logoImage, logoX, logoY, logoSize, logoSize);
276
+ } catch (error) {
277
+ console.warn(`Failed to add logo: ${error.message}`);
278
+ }
279
+ }
280
+
281
+ /**
282
+ * Add watermark to QR code
283
+ * @param {CanvasRenderingContext2D} ctx - Canvas context
284
+ */
285
+ async addWatermark(ctx) {
286
+ try {
287
+ // Check if watermark is an image path
288
+ if (
289
+ this.options.watermark.includes('.') &&
290
+ this.options.watermark.includes('/')
291
+ ) {
292
+ const watermarkImage = await loadImage(this.options.watermark);
293
+ const watermarkSize = this.options.size / 4;
294
+ const position = this.getWatermarkPosition(watermarkSize);
295
+
296
+ ctx.drawImage(
297
+ watermarkImage,
298
+ position.x,
299
+ position.y,
300
+ watermarkSize,
301
+ watermarkSize
302
+ );
303
+ } else {
304
+ // Text watermark
305
+ ctx.font = `${this.options.labelFontSize}px Arial`;
306
+ ctx.fillStyle = this.rgbToHex(this.options.foregroundColor);
307
+ ctx.textAlign = 'center';
308
+
309
+ const position = this.getWatermarkPosition(0);
310
+ ctx.fillText(this.options.watermark, position.x, position.y);
311
+ }
312
+ } catch (error) {
313
+ console.warn(`Failed to add watermark: ${error.message}`);
314
+ }
315
+ }
316
+
317
+ /**
318
+ * Add label to QR code
319
+ * @param {CanvasRenderingContext2D} ctx - Canvas context
320
+ */
321
+ addLabel(ctx) {
322
+ ctx.font = `${this.options.labelFontSize}px Arial`;
323
+ ctx.fillStyle = this.rgbToHex(this.options.foregroundColor);
324
+ ctx.textAlign = 'center';
325
+
326
+ const labelY = this.options.size - 10;
327
+ ctx.fillText(this.options.label, this.options.size / 2, labelY);
328
+ }
329
+
330
+ /**
331
+ * Get watermark position
332
+ * @param {number} size - Watermark size
333
+ * @returns {Object} Position coordinates
334
+ */
335
+ getWatermarkPosition(size) {
336
+ const positions = {
337
+ 'top-left': { x: 10, y: 10 },
338
+ 'top-right': { x: this.options.size - size - 10, y: 10 },
339
+ 'bottom-left': { x: 10, y: this.options.size - size - 10 },
340
+ 'bottom-right': {
341
+ x: this.options.size - size - 10,
342
+ y: this.options.size - size - 10,
343
+ },
344
+ center: {
345
+ x: (this.options.size - size) / 2,
346
+ y: (this.options.size - size) / 2,
347
+ },
348
+ 'top-center': { x: (this.options.size - size) / 2, y: 10 },
349
+ 'bottom-center': {
350
+ x: (this.options.size - size) / 2,
351
+ y: this.options.size - size - 10,
352
+ },
353
+ 'left-center': { x: 10, y: (this.options.size - size) / 2 },
354
+ 'right-center': {
355
+ x: this.options.size - size - 10,
356
+ y: (this.options.size - size) / 2,
357
+ },
358
+ };
359
+
360
+ return positions[this.options.watermarkPosition] || positions.center;
361
+ }
362
+
363
+ /**
364
+ * Convert RGB array to hex color
365
+ * @param {Array} rgb - RGB color array
366
+ * @returns {string} Hex color
367
+ */
368
+ rgbToHex(rgb) {
369
+ return `#${rgb.map(c => c.toString(16).padStart(2, '0')).join('')}`;
370
+ }
371
+
372
+ /**
373
+ * Save QR code to file
374
+ * @param {string} filePath - Output file path
375
+ * @returns {Promise<void>}
376
+ */
377
+ async saveToFile(filePath) {
378
+ const buffer = await this.generate();
379
+ await fs.writeFile(filePath, buffer);
380
+ }
381
+
382
+ /**
383
+ * Get QR code as data URI
384
+ * @returns {Promise<string>} Data URI
385
+ */
386
+ async getDataUri() {
387
+ const buffer = await this.generate();
388
+ const base64 = buffer.toString('base64');
389
+ return `data:image/${this.options.format};base64,${base64}`;
390
+ }
391
+
392
+ /**
393
+ * Get QR code as string
394
+ * @returns {Promise<string>} QR code string
395
+ */
396
+ async getString() {
397
+ return await this.generate();
398
+ }
399
+ }
400
+
401
+ module.exports = QrCodeBuilder;