qreator 9.0.6

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.
Files changed (80) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +92 -0
  3. package/lib/browser/encode.d.ts +2 -0
  4. package/lib/browser/errorcode.d.ts +1 -0
  5. package/lib/browser/matrix.d.ts +9 -0
  6. package/lib/browser/pdf.d.ts +2 -0
  7. package/lib/browser/pdf.umd.js +26816 -0
  8. package/lib/browser/pdf.umd.js.map +1 -0
  9. package/lib/browser/png.d.ts +6 -0
  10. package/lib/browser/png.umd.js +1540 -0
  11. package/lib/browser/png.umd.js.map +1 -0
  12. package/lib/browser/png_browser.d.ts +5 -0
  13. package/lib/browser/qr-base.d.ts +4 -0
  14. package/lib/browser/qr.d.ts +2 -0
  15. package/lib/browser/svg.d.ts +7 -0
  16. package/lib/browser/svg.umd.js +1536 -0
  17. package/lib/browser/svg.umd.js.map +1 -0
  18. package/lib/browser/tests/_common.d.ts +4 -0
  19. package/lib/browser/tests/browser.test.d.ts +1 -0
  20. package/lib/browser/tests/test.d.ts +1 -0
  21. package/lib/browser/typing/types.d.ts +28 -0
  22. package/lib/browser/utils.d.ts +17 -0
  23. package/lib/encode.d.ts +2 -0
  24. package/lib/encode.js +137 -0
  25. package/lib/encode.js.map +1 -0
  26. package/lib/errorcode.d.ts +1 -0
  27. package/lib/errorcode.js +62 -0
  28. package/lib/errorcode.js.map +1 -0
  29. package/lib/matrix.d.ts +9 -0
  30. package/lib/matrix.js +347 -0
  31. package/lib/matrix.js.map +1 -0
  32. package/lib/pdf.d.ts +2 -0
  33. package/lib/pdf.js +64 -0
  34. package/lib/pdf.js.map +1 -0
  35. package/lib/png.d.ts +6 -0
  36. package/lib/png.js +30 -0
  37. package/lib/png.js.map +1 -0
  38. package/lib/png_browser.d.ts +5 -0
  39. package/lib/png_browser.js +53 -0
  40. package/lib/png_browser.js.map +1 -0
  41. package/lib/qr-base.d.ts +4 -0
  42. package/lib/qr-base.js +151 -0
  43. package/lib/qr-base.js.map +1 -0
  44. package/lib/qr.d.ts +2 -0
  45. package/lib/qr.js +2 -0
  46. package/lib/qr.js.map +1 -0
  47. package/lib/svg.d.ts +7 -0
  48. package/lib/svg.js +49 -0
  49. package/lib/svg.js.map +1 -0
  50. package/lib/tests/_common.d.ts +4 -0
  51. package/lib/tests/_common.js +36 -0
  52. package/lib/tests/_common.js.map +1 -0
  53. package/lib/tests/browser.test.d.ts +1 -0
  54. package/lib/tests/browser.test.js +193 -0
  55. package/lib/tests/browser.test.js.map +1 -0
  56. package/lib/tests/test.d.ts +1 -0
  57. package/lib/tests/test.js +238 -0
  58. package/lib/tests/test.js.map +1 -0
  59. package/lib/typing/types.d.ts +28 -0
  60. package/lib/typing/types.js +2 -0
  61. package/lib/typing/types.js.map +1 -0
  62. package/lib/utils.d.ts +17 -0
  63. package/lib/utils.js +68 -0
  64. package/lib/utils.js.map +1 -0
  65. package/package.json +105 -0
  66. package/src/encode.ts +176 -0
  67. package/src/errorcode.ts +75 -0
  68. package/src/matrix.ts +393 -0
  69. package/src/pdf.ts +80 -0
  70. package/src/png.ts +42 -0
  71. package/src/png_browser.ts +73 -0
  72. package/src/qr-base.ts +180 -0
  73. package/src/qr.ts +2 -0
  74. package/src/svg.ts +89 -0
  75. package/src/tests/_common.ts +40 -0
  76. package/src/tests/browser.test.ts +209 -0
  77. package/src/tests/test.ts +250 -0
  78. package/src/typing/index.d.ts +5 -0
  79. package/src/typing/types.ts +99 -0
  80. package/src/utils.ts +86 -0
@@ -0,0 +1,75 @@
1
+ // {{{1 export functions
2
+ export function calculateEC(msg: number[], ec_len: number): Uint8Array {
3
+ // `msg` could be array or buffer
4
+ // convert `msg` to array
5
+ msg = [].slice.call(msg);
6
+
7
+ // Generator Polynomial
8
+ const poly = generatorPolynomial(ec_len);
9
+
10
+ for (let i = 0; i < ec_len; i++) msg.push(0);
11
+ while (msg.length > ec_len) {
12
+ if (!msg[0]) {
13
+ msg.shift();
14
+ continue;
15
+ }
16
+ const log_k = log(msg[0]);
17
+ for (let i = 0; i <= ec_len; i++) {
18
+ msg[i] = msg[i] ^ exp(poly[i] + log_k);
19
+ }
20
+ msg.shift();
21
+ }
22
+ return new Uint8Array(msg);
23
+ }
24
+
25
+ // {{{1 Galois Field Math
26
+ const GF256_BASE = 285;
27
+
28
+ const EXP_TABLE: number[] = [1];
29
+ const LOG_TABLE: number[] = [];
30
+
31
+ for (let i = 1; i < 256; i++) {
32
+ let n = EXP_TABLE[i - 1] << 1;
33
+ if (n > 255) n ^= GF256_BASE;
34
+ EXP_TABLE[i] = n;
35
+ }
36
+
37
+ for (let i = 0; i < 255; i++) {
38
+ LOG_TABLE[EXP_TABLE[i]] = i;
39
+ }
40
+
41
+ function exp(k: number) {
42
+ while (k < 0) k += 255;
43
+ while (k > 255) k -= 255;
44
+ return EXP_TABLE[k];
45
+ }
46
+
47
+ function log(k: number) {
48
+ if (k < 1 || k > 255) {
49
+ throw Error(`Bad log(${k})`);
50
+ }
51
+ return LOG_TABLE[k];
52
+ }
53
+
54
+ // {{{1 Generator Polynomials
55
+ const POLYNOMIALS = [
56
+ [0], // a^0 x^0
57
+ [0, 0], // a^0 x^1 + a^0 x^0
58
+ [0, 25, 1], // a^0 x^2 + a^25 x^1 + a^1 x^0
59
+ // and so on...
60
+ ];
61
+
62
+ function generatorPolynomial(num: number): number[] {
63
+ if (POLYNOMIALS[num]) {
64
+ return POLYNOMIALS[num];
65
+ }
66
+ const prev = generatorPolynomial(num - 1);
67
+ const res = [];
68
+
69
+ res[0] = prev[0];
70
+ for (let i = 1; i <= num; i++) {
71
+ res[i] = log(exp(prev[i]) ^ exp(prev[i - 1] + num - 1));
72
+ }
73
+ POLYNOMIALS[num] = res;
74
+ return res;
75
+ }
package/src/matrix.ts ADDED
@@ -0,0 +1,393 @@
1
+ import { Data, EcLevel, Matrix } from "./typing/types";
2
+
3
+ // {{{1 Initialize matrix with zeros
4
+ export function init(version: number): Matrix {
5
+ const N = (version << 2) + 0b10001;
6
+ const matrix: Matrix = [];
7
+ let zeros: number[] = Array(N).fill(0);
8
+ for (let i = 0; i < N; i++) {
9
+ matrix[i] = [...zeros];
10
+ }
11
+ return matrix;
12
+ }
13
+
14
+ // {{{1 Put finders into matrix
15
+ export function fillFinders(matrix: Matrix) {
16
+ const N = matrix.length;
17
+ for (var i = -3; i <= 3; i++) {
18
+ for (let j = -3; j <= 3; j++) {
19
+ const max = Math.max(i, j);
20
+ const min = Math.min(i, j);
21
+ const pixel =
22
+ (max == 2 && min >= -2) || (min == -2 && max <= 2)
23
+ ? 0x80
24
+ : 0x81;
25
+ matrix[3 + i][3 + j] = pixel;
26
+ matrix[3 + i][N - 4 + j] = pixel;
27
+ matrix[N - 4 + i][3 + j] = pixel;
28
+ }
29
+ }
30
+ for (var i = 0; i < 8; i++) {
31
+ matrix[7][i] =
32
+ matrix[i][7] =
33
+ matrix[7][N - i - 1] =
34
+ matrix[i][N - 8] =
35
+ matrix[N - 8][i] =
36
+ matrix[N - 1 - i][7] =
37
+ 0x80;
38
+ }
39
+ }
40
+
41
+ // {{{1 Put align and timinig
42
+ export function fillAlignAndTiming(matrix: Matrix) {
43
+ const N = matrix.length;
44
+ if (N > 21) {
45
+ const len = N - 13;
46
+ let delta = Math.round(len / Math.ceil(len / 28));
47
+ if (delta % 2) delta++;
48
+ const res = [];
49
+ for (let p = len + 6; p > 10; p -= delta) {
50
+ res.unshift(p);
51
+ }
52
+ res.unshift(6);
53
+ for (var i = 0; i < res.length; i++) {
54
+ for (let j = 0; j < res.length; j++) {
55
+ const x = res[i];
56
+ const y = res[j];
57
+ if (matrix[x][y]) continue;
58
+ for (let r = -2; r <= 2; r++) {
59
+ for (let c = -2; c <= 2; c++) {
60
+ const max = Math.max(r, c);
61
+ const min = Math.min(r, c);
62
+ const pixel =
63
+ (max == 1 && min >= -1) || (min == -1 && max <= 1)
64
+ ? 0x80
65
+ : 0x81;
66
+ matrix[x + r][y + c] = pixel;
67
+ }
68
+ }
69
+ }
70
+ }
71
+ }
72
+ for (var i = 8; i < N - 8; i++) {
73
+ matrix[6][i] = matrix[i][6] = i % 2 ? 0x80 : 0x81;
74
+ }
75
+ }
76
+
77
+ // {{{1 Fill reserved areas with zeroes
78
+ export function fillStub(matrix: Matrix) {
79
+ const N = matrix.length;
80
+ for (var i = 0; i < 8; i++) {
81
+ if (i != 6) {
82
+ matrix[8][i] = matrix[i][8] = 0x80;
83
+ }
84
+ matrix[8][N - 1 - i] = 0x80;
85
+ matrix[N - 1 - i][8] = 0x80;
86
+ }
87
+ matrix[8][8] = 0x80;
88
+ matrix[N - 8][8] = 0x81;
89
+
90
+ if (N < 45) return;
91
+
92
+ for (var i = N - 11; i < N - 8; i++) {
93
+ for (let j = 0; j < 6; j++) {
94
+ matrix[i][j] = matrix[j][i] = 0x80;
95
+ }
96
+ }
97
+ }
98
+
99
+ // {{{1 Fill reserved areas
100
+ export const fillReserved = (function () {
101
+ const FORMATS: number[] = Array(32);
102
+ const VERSIONS: number[] = Array(40);
103
+
104
+ const gf15 = 0x0537;
105
+ const gf18 = 0x1f25;
106
+ const formats_mask = 0x5412;
107
+
108
+ for (let format = 0; format < 32; format++) {
109
+ let res = format << 10;
110
+ for (let i = 5; i > 0; i--) {
111
+ if (res >>> (9 + i)) {
112
+ res ^= gf15 << (i - 1);
113
+ }
114
+ }
115
+ FORMATS[format] = (res | (format << 10)) ^ formats_mask;
116
+ }
117
+
118
+ for (let version = 7; version <= 40; version++) {
119
+ let res = version << 12;
120
+ for (let i = 6; i > 0; i--) {
121
+ if (res >>> (11 + i)) {
122
+ res ^= gf18 << (i - 1);
123
+ }
124
+ }
125
+ VERSIONS[version] = res | (version << 12);
126
+ }
127
+
128
+ const EC_LEVELS: { [K in EcLevel]: number } = {
129
+ L: 1,
130
+ M: 0,
131
+ Q: 3,
132
+ H: 2,
133
+ };
134
+
135
+ return function fillReserved(
136
+ matrix: Matrix,
137
+ ec_level: EcLevel,
138
+ mask: number
139
+ ) {
140
+ const N = matrix.length;
141
+ const format = FORMATS[(EC_LEVELS[ec_level] << 3) | mask];
142
+
143
+ function F(k: number) {
144
+ return (format >> k) & 1 ? 0x81 : 0x80;
145
+ }
146
+ for (var i = 0; i < 8; i++) {
147
+ matrix[8][N - 1 - i] = F(i);
148
+ if (i < 6) matrix[i][8] = F(i);
149
+ }
150
+ for (var i = 8; i < 15; i++) {
151
+ matrix[N - 15 + i][8] = F(i);
152
+ if (i > 8) matrix[8][14 - i] = F(i);
153
+ }
154
+ matrix[7][8] = F(6);
155
+ matrix[8][8] = F(7);
156
+ matrix[8][7] = F(8);
157
+
158
+ const version = VERSIONS[(N - 17) / 4];
159
+ if (!version) {
160
+ return;
161
+ }
162
+
163
+ function V(k: number) {
164
+ return (version >> k) & 1 ? 0x81 : 0x80;
165
+ }
166
+ for (var i = 0; i < 6; i++) {
167
+ for (let j = 0; j < 3; j++) {
168
+ matrix[N - 11 + j][i] = matrix[i][N - 11 + j] = V(i * 3 + j);
169
+ }
170
+ }
171
+ };
172
+ })();
173
+
174
+ // {{{1 Fill data
175
+ export const fillData = (function () {
176
+ const MASK_FUNCTIONS = [
177
+ (i: number, j: number) => (i + j) % 2 == 0,
178
+ (i: number, j: number) => i % 2 == 0,
179
+ (i: number, j: number) => j % 3 == 0,
180
+ (i: number, j: number) => (i + j) % 3 == 0,
181
+ (i: number, j: number) => (Math.floor(i / 2) + Math.floor(j / 3)) % 2 == 0,
182
+ (i: number, j: number) => ((i * j) % 2) + ((i * j) % 3) == 0,
183
+ (i: number, j: number) => (((i * j) % 2) + ((i * j) % 3)) % 2 == 0,
184
+ (i: number, j: number) => (((i * j) % 3) + ((i + j) % 2)) % 2 == 0,
185
+ ];
186
+
187
+ return function fillData(matrix: Matrix, data: Data, mask: number) {
188
+ const N = matrix.length;
189
+ let row: number;
190
+ let col: number;
191
+ let dir = -1;
192
+ row = col = N - 1;
193
+ const mask_fn = MASK_FUNCTIONS[mask];
194
+ let len = data.blocks[data.blocks.length - 1].length;
195
+
196
+ for (var i = 0; i < len; i++) {
197
+ for (var b = 0; b < data.blocks.length; b++) {
198
+ if (data.blocks[b].length <= i) {
199
+ continue;
200
+ }
201
+ put(data.blocks[b][i]);
202
+ }
203
+ }
204
+
205
+ len = data.ec_len;
206
+ for (var i = 0; i < len; i++) {
207
+ for (var b = 0; b < data.ec.length; b++) {
208
+ put(data.ec[b][i]);
209
+ }
210
+ }
211
+
212
+ if (col > -1) {
213
+ do {
214
+ matrix[row][col] = mask_fn(row, col) ? 1 : 0;
215
+ } while (next());
216
+ }
217
+
218
+ function put(byte: number) {
219
+ for (let mask = 0x80; mask; mask >>= 1) {
220
+ let pixel = !!(mask & byte);
221
+ if (mask_fn(row, col)) pixel = !pixel;
222
+ matrix[row][col] = pixel ? 1 : 0;
223
+ next();
224
+ }
225
+ }
226
+
227
+ function next() {
228
+ do {
229
+ if (col % 2 ^ Number(col < 6)) {
230
+ if ((dir < 0 && row == 0) || (dir > 0 && row == N - 1)) {
231
+ col--;
232
+ dir = -dir;
233
+ } else {
234
+ col++;
235
+ row += dir;
236
+ }
237
+ } else {
238
+ col--;
239
+ }
240
+ if (col == 6) {
241
+ col--;
242
+ }
243
+ if (col < 0) {
244
+ return false;
245
+ }
246
+ } while (matrix[row][col] & 0xf0);
247
+ return true;
248
+ }
249
+ };
250
+ })();
251
+
252
+ // {{{1 Calculate penalty
253
+ export function calculatePenalty(matrix: Matrix) {
254
+ const N = matrix.length;
255
+ let penalty = 0;
256
+ // Rule 1
257
+ for (var i = 0; i < N; i++) {
258
+ var pixel = matrix[i][0] & 1;
259
+ var len = 1;
260
+ for (var j = 1; j < N; j++) {
261
+ var p = matrix[i][j] & 1;
262
+ if (p == pixel) {
263
+ len++;
264
+ continue;
265
+ }
266
+ if (len >= 5) {
267
+ penalty += len - 2;
268
+ }
269
+ pixel = p;
270
+ len = 1;
271
+ }
272
+ if (len >= 5) {
273
+ penalty += len - 2;
274
+ }
275
+ }
276
+ for (var j = 0; j < N; j++) {
277
+ var pixel = matrix[0][j] & 1;
278
+ var len = 1;
279
+ for (var i = 1; i < N; i++) {
280
+ var p = matrix[i][j] & 1;
281
+ if (p == pixel) {
282
+ len++;
283
+ continue;
284
+ }
285
+ if (len >= 5) {
286
+ penalty += len - 2;
287
+ }
288
+ pixel = p;
289
+ len = 1;
290
+ }
291
+ if (len >= 5) {
292
+ penalty += len - 2;
293
+ }
294
+ }
295
+
296
+ // Rule 2
297
+ for (var i = 0; i < N - 1; i++) {
298
+ for (var j = 0; j < N - 1; j++) {
299
+ const s =
300
+ (matrix[i][j] +
301
+ matrix[i][j + 1] +
302
+ matrix[i + 1][j] +
303
+ matrix[i + 1][j + 1]) &
304
+ 7;
305
+ if (s == 0 || s == 4) {
306
+ penalty += 3;
307
+ }
308
+ }
309
+ }
310
+
311
+ // Rule 3
312
+ function I(k: number) {
313
+ return matrix[i][j + k] & 1;
314
+ }
315
+ function J(k: number) {
316
+ return matrix[i + k][j] & 1;
317
+ }
318
+ for (var i = 0; i < N; i++) {
319
+ for (var j = 0; j < N; j++) {
320
+ if (
321
+ j < N - 6 &&
322
+ I(0) &&
323
+ !I(1) &&
324
+ I(2) &&
325
+ I(3) &&
326
+ I(4) &&
327
+ !I(5) &&
328
+ I(6)
329
+ ) {
330
+ if (j >= 4 && !(I(-4) || I(-3) || I(-2) || I(-1))) {
331
+ penalty += 40;
332
+ }
333
+ if (j < N - 10 && !(I(7) || I(8) || I(9) || I(10))) {
334
+ penalty += 40;
335
+ }
336
+ }
337
+
338
+ if (
339
+ i < N - 6 &&
340
+ J(0) &&
341
+ !J(1) &&
342
+ J(2) &&
343
+ J(3) &&
344
+ J(4) &&
345
+ !J(5) &&
346
+ J(6)
347
+ ) {
348
+ if (i >= 4 && !(J(-4) || J(-3) || J(-2) || J(-1))) {
349
+ penalty += 40;
350
+ }
351
+ if (i < N - 10 && !(J(7) || J(8) || J(9) || J(10))) {
352
+ penalty += 40;
353
+ }
354
+ }
355
+ }
356
+ }
357
+
358
+ // Rule 4
359
+ let numDark = 0;
360
+ for (var i = 0; i < N; i++) {
361
+ for (var j = 0; j < N; j++) {
362
+ if (matrix[i][j] & 1) numDark++;
363
+ }
364
+ }
365
+ penalty += 10 * Math.floor(Math.abs(10 - (20 * numDark) / (N * N)));
366
+
367
+ return penalty;
368
+ }
369
+
370
+ // {{{1 All-in-one function
371
+ export function getMatrix(data: Data) {
372
+ const matrix = init(data.version);
373
+ fillFinders(matrix);
374
+ fillAlignAndTiming(matrix);
375
+ fillStub(matrix);
376
+
377
+ let penalty = Infinity;
378
+ let bestMask = 0;
379
+ for (let mask = 0; mask < 8; mask++) {
380
+ fillData(matrix, data, mask);
381
+ fillReserved(matrix, data.ec_level, mask);
382
+ const p = calculatePenalty(matrix);
383
+ if (p < penalty) {
384
+ penalty = p;
385
+ bestMask = mask;
386
+ }
387
+ }
388
+
389
+ fillData(matrix, data, bestMask);
390
+ fillReserved(matrix, data.ec_level, bestMask);
391
+
392
+ return matrix.map((row) => row.map((cell) => cell & 1));
393
+ }
package/src/pdf.ts ADDED
@@ -0,0 +1,80 @@
1
+ import { PDFDocument, PDFImage, rgb } from "pdf-lib";
2
+ import { QR } from "./qr-base.js";
3
+ import { ImageOptions, Matrix } from "./typing/types";
4
+ import { getOptions, getSVGPath } from "./utils.js";
5
+ import colorString from "color-string";
6
+
7
+ const textDec = new TextDecoder();
8
+
9
+ export async function getPDF(text: string, inOptions: ImageOptions) {
10
+ const options = getOptions(inOptions);
11
+ const matrix = QR(text, options.ec_level, options.parse_url);
12
+ return PDF({ matrix, ...options });
13
+ }
14
+
15
+ function colorToRGB(color: string | number): [number, number, number] {
16
+ if (typeof color === "string") {
17
+ const [red, green, blue] = colorString.get.rgb(color);
18
+ return [red / 255, green / 255, blue / 255];
19
+ }
20
+ return [
21
+ ((color >>> 24) % 256) / 255,
22
+ ((color >>> 16) % 256) / 255,
23
+ ((color >>> 8) % 256) / 255,
24
+ ];
25
+ }
26
+
27
+ function getOpacity(color: string | number): number {
28
+ if (typeof color === "string") {
29
+ return colorString.get.rgb(color)[3];
30
+ }
31
+ return ((color % 256) / 255);
32
+ }
33
+
34
+ async function PDF({
35
+ matrix,
36
+ margin,
37
+ logo,
38
+ logoWidth,
39
+ logoHeight,
40
+ color,
41
+ bgColor,
42
+ borderRadius,
43
+ }: ImageOptions & {
44
+ matrix: Matrix;
45
+ }) {
46
+ const size = 9;
47
+ const document = await PDFDocument.create();
48
+ const pageSize = (matrix.length + 2 * margin) * size;
49
+ const page = document.addPage([pageSize, pageSize]);
50
+ page.drawSquare({
51
+ size: pageSize,
52
+ color: rgb(...colorToRGB(bgColor)),
53
+ });
54
+ page.moveTo(0, page.getHeight());
55
+ const path = getSVGPath(matrix, size, margin * size, borderRadius);
56
+ page.drawSvgPath(path, {
57
+ color: rgb(...colorToRGB(color)),
58
+ opacity: getOpacity(color),
59
+ borderColor: rgb(...colorToRGB(color)),
60
+ borderOpacity: getOpacity(color),
61
+ });
62
+ if (logo) {
63
+ let logoData: PDFImage;
64
+ const header = new Uint8Array(logo.slice(0, 4));
65
+ if (textDec.decode(header.slice(1, 4)) === "PNG" && header.at(0) === 0x89) {
66
+ logoData = await document.embedPng(logo);
67
+ } else {
68
+ logoData = await document.embedJpg(logo);
69
+ }
70
+ page.drawImage(logoData, {
71
+ x: page.getWidth() / 2 - (logoWidth / 100) * (page.getWidth() / 2),
72
+ y:
73
+ page.getHeight() / 2 -
74
+ (logoHeight / 100) * (page.getWidth() / 2),
75
+ width: (logoWidth / 100) * page.getWidth(),
76
+ height: (logoHeight / 100) * page.getHeight(),
77
+ });
78
+ }
79
+ return document.save();
80
+ }
package/src/png.ts ADDED
@@ -0,0 +1,42 @@
1
+ import { ImageOptions, Matrix } from "./typing/types";
2
+ import { QR } from "./qr-base.js";
3
+ import { createSVG } from './svg.js';
4
+ import { getOptions } from "./utils.js";
5
+ import sharp from "sharp";
6
+
7
+ export async function getPNG(text: string, inOptions: ImageOptions = {}) {
8
+ const options = getOptions({...inOptions, type: 'png'});
9
+ const matrix = QR(text, options.ec_level, options.parse_url);
10
+ return generateImage({ matrix, ...options, type: 'png' });
11
+ }
12
+
13
+ export async function generateImage({
14
+ matrix,
15
+ size,
16
+ margin,
17
+ logo,
18
+ logoWidth,
19
+ logoHeight,
20
+ color,
21
+ bgColor,
22
+ borderRadius,
23
+ }: ImageOptions & { matrix: Matrix }) {
24
+ const marginPx = margin * size;
25
+ const imageSize = matrix.length * size + marginPx * 2;
26
+ const svg = await createSVG({
27
+ matrix, size, margin, color, bgColor,
28
+ imageWidth: imageSize, imageHeight: imageSize,
29
+ borderRadius,
30
+ });
31
+ const qrImage = sharp(svg);
32
+ const layers: sharp.OverlayOptions[] = [];
33
+ if (logo) {
34
+ const sharpLogo = sharp(logo).resize(imageSize * logoWidth / 100, imageSize * logoHeight / 100, {fit: 'contain'});
35
+ const data = await sharpLogo.toBuffer()
36
+ layers.push({
37
+ input: data,
38
+ })
39
+ qrImage.composite(layers);
40
+ }
41
+ return await qrImage.png().toBuffer();
42
+ }
@@ -0,0 +1,73 @@
1
+ import { QR } from "./qr-base.js";
2
+ import { getOptions, colorToHex, getSVGPath } from "./utils.js";
3
+ import { ImageOptions, Matrix } from "./typing/types";
4
+ import { Base64 } from "js-base64";
5
+
6
+ export async function getPNG(text: string, inOptions: ImageOptions) {
7
+ const options = getOptions(inOptions);
8
+ const matrix = QR(text, options.ec_level, options.parse_url);
9
+ return generateImage({ matrix, ...options, type: 'png' });
10
+ }
11
+
12
+ function dataURItoArrayBuffer(dataURI: string) {
13
+ return Base64.toUint8Array(dataURI.split(',')[1]);
14
+ }
15
+
16
+ function blobToDataURL(blob: Blob) {
17
+ return new Promise<string>((resolve, reject) => {
18
+ try {
19
+ var a = new FileReader();
20
+ a.onload = function(e) {resolve(e.target.result as string);}
21
+ a.onerror = reject;
22
+ a.readAsDataURL(blob);
23
+ } catch (e) {
24
+ reject(e);
25
+ }
26
+ });
27
+ }
28
+
29
+
30
+ export async function generateImage({
31
+ matrix,
32
+ size,
33
+ margin,
34
+ logo,
35
+ logoWidth,
36
+ logoHeight,
37
+ color,
38
+ bgColor,
39
+ borderRadius,
40
+ }: ImageOptions & { matrix: Matrix }) {
41
+ const marginPx = margin * size;
42
+ const imageSize = matrix.length * size + marginPx * 2;
43
+
44
+ const canvas = document.createElement('canvas');
45
+ canvas.width = imageSize;
46
+ canvas.height = imageSize;
47
+ const context = canvas.getContext('2d');
48
+ context.fillStyle = colorToHex(bgColor);
49
+ context.fillRect(0, 0, imageSize, imageSize);
50
+ const path = new Path2D(getSVGPath(matrix, size, marginPx, borderRadius));
51
+ context.fillStyle = colorToHex(color);
52
+ context.fill(path);
53
+ if (logo) {
54
+ const logoImage = await new Promise<HTMLImageElement>(async (resolve, reject) => {
55
+ try {
56
+ const image = new Image();
57
+ image.onload = () => resolve(image);
58
+ image.onerror = reject;
59
+ image.src = await blobToDataURL(new window.Blob([logo]));
60
+ } catch (e) {
61
+ reject(e);
62
+ }
63
+ });
64
+ context.drawImage(
65
+ logoImage,
66
+ imageSize / 2 - (logoWidth / 2 / 100) * imageSize,
67
+ imageSize / 2 - (logoHeight / 2 / 100) * imageSize,
68
+ (logoWidth / 100) * imageSize,
69
+ (logoHeight / 100) * imageSize
70
+ );
71
+ }
72
+ return dataURItoArrayBuffer(canvas.toDataURL('image/png'));
73
+ }