@twin.org/qr 0.0.2-next.9 → 0.0.3-next.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/dist/es/data/qrAlphaNumeric.js +79 -0
- package/dist/es/data/qrAlphaNumeric.js.map +1 -0
- package/dist/es/data/qrByte8.js +63 -0
- package/dist/es/data/qrByte8.js.map +1 -0
- package/dist/es/data/qrDataBase.js +102 -0
- package/dist/es/data/qrDataBase.js.map +1 -0
- package/dist/es/data/qrNumber.js +73 -0
- package/dist/es/data/qrNumber.js.map +1 -0
- package/dist/es/helpers/bitBuffer.js +79 -0
- package/dist/es/helpers/bitBuffer.js.map +1 -0
- package/dist/es/helpers/mathHelper.js +71 -0
- package/dist/es/helpers/mathHelper.js.map +1 -0
- package/dist/es/helpers/polynomial.js +117 -0
- package/dist/es/helpers/polynomial.js.map +1 -0
- package/dist/es/helpers/qrHelper.js +269 -0
- package/dist/es/helpers/qrHelper.js.map +1 -0
- package/dist/es/helpers/rsBlock.js +293 -0
- package/dist/es/helpers/rsBlock.js.map +1 -0
- package/dist/es/index.js +12 -0
- package/dist/es/index.js.map +1 -0
- package/dist/es/models/IBitmapRendererOptions.js +2 -0
- package/dist/es/models/IBitmapRendererOptions.js.map +1 -0
- package/dist/es/models/IRendererOptions.js +4 -0
- package/dist/es/models/IRendererOptions.js.map +1 -0
- package/dist/es/models/ITextRendererOptions.js +2 -0
- package/dist/es/models/ITextRendererOptions.js.map +1 -0
- package/dist/es/models/errorCorrectLevel.js +26 -0
- package/dist/es/models/errorCorrectLevel.js.map +1 -0
- package/dist/es/models/maskPattern.js +42 -0
- package/dist/es/models/maskPattern.js.map +1 -0
- package/dist/es/models/qrCellData.js +2 -0
- package/dist/es/models/qrCellData.js.map +1 -0
- package/dist/es/models/qrDataMode.js +22 -0
- package/dist/es/models/qrDataMode.js.map +1 -0
- package/dist/es/qr.js +551 -0
- package/dist/es/qr.js.map +1 -0
- package/dist/es/renderers/jpegRenderer.js +80 -0
- package/dist/es/renderers/jpegRenderer.js.map +1 -0
- package/dist/es/renderers/pngRenderer.js +80 -0
- package/dist/es/renderers/pngRenderer.js.map +1 -0
- package/dist/es/renderers/textRenderer.js +65 -0
- package/dist/es/renderers/textRenderer.js.map +1 -0
- package/dist/types/data/qrAlphaNumeric.d.ts +6 -2
- package/dist/types/data/qrByte8.d.ts +2 -2
- package/dist/types/{models → data}/qrDataBase.d.ts +7 -4
- package/dist/types/data/qrNumber.d.ts +6 -2
- package/dist/types/helpers/mathHelper.d.ts +4 -0
- package/dist/types/helpers/polynomial.d.ts +1 -1
- package/dist/types/helpers/qrHelper.d.ts +7 -3
- package/dist/types/helpers/rsBlock.d.ts +5 -1
- package/dist/types/index.d.ts +9 -9
- package/dist/types/models/IBitmapRendererOptions.d.ts +1 -1
- package/dist/types/models/ITextRendererOptions.d.ts +1 -1
- package/dist/types/qr.d.ts +6 -2
- package/dist/types/renderers/jpegRenderer.d.ts +6 -2
- package/dist/types/renderers/pngRenderer.d.ts +6 -2
- package/dist/types/renderers/textRenderer.d.ts +6 -2
- package/docs/changelog.md +296 -0
- package/docs/reference/classes/JpegRenderer.md +8 -0
- package/docs/reference/classes/PngRenderer.md +8 -0
- package/docs/reference/classes/QR.md +8 -0
- package/docs/reference/classes/TextRenderer.md +8 -0
- package/locales/en.json +9 -9
- package/package.json +20 -11
- package/dist/cjs/index.cjs +0 -1999
- package/dist/esm/index.mjs +0 -1993
package/dist/cjs/index.cjs
DELETED
|
@@ -1,1999 +0,0 @@
|
|
|
1
|
-
'use strict';
|
|
2
|
-
|
|
3
|
-
var core = require('@twin.org/core');
|
|
4
|
-
var image = require('@twin.org/image');
|
|
5
|
-
|
|
6
|
-
// Copyright 2024 IOTA Stiftung.
|
|
7
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
8
|
-
/**
|
|
9
|
-
* Error correction level to use for the QR Code.
|
|
10
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
11
|
-
*/
|
|
12
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
13
|
-
const ErrorCorrectLevel = {
|
|
14
|
-
/**
|
|
15
|
-
* 7% Error correction.
|
|
16
|
-
*/
|
|
17
|
-
L: 1,
|
|
18
|
-
/**
|
|
19
|
-
* 15% Error correction.
|
|
20
|
-
*/
|
|
21
|
-
M: 0,
|
|
22
|
-
/**
|
|
23
|
-
* 25% Error correction.
|
|
24
|
-
*/
|
|
25
|
-
Q: 3,
|
|
26
|
-
/**
|
|
27
|
-
* 30% Error correction.
|
|
28
|
-
*/
|
|
29
|
-
H: 2
|
|
30
|
-
};
|
|
31
|
-
|
|
32
|
-
// Copyright 2024 IOTA Stiftung.
|
|
33
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
34
|
-
/**
|
|
35
|
-
* The mode for the qr data.
|
|
36
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
37
|
-
*/
|
|
38
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
39
|
-
const QRDataMode = {
|
|
40
|
-
/**
|
|
41
|
-
* Number.
|
|
42
|
-
*/
|
|
43
|
-
Number: 1,
|
|
44
|
-
/**
|
|
45
|
-
* Alphabet and number.
|
|
46
|
-
*/
|
|
47
|
-
AlphaNumeric: 2,
|
|
48
|
-
/**
|
|
49
|
-
* 8bit byte.
|
|
50
|
-
*/
|
|
51
|
-
Byte8: 4
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
// Copyright 2024 IOTA Stiftung.
|
|
55
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
56
|
-
/**
|
|
57
|
-
* Base class for storing QR Data.
|
|
58
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
59
|
-
*/
|
|
60
|
-
class QRDataBase {
|
|
61
|
-
/**
|
|
62
|
-
* @internal
|
|
63
|
-
*/
|
|
64
|
-
_className;
|
|
65
|
-
/**
|
|
66
|
-
* @internal
|
|
67
|
-
*/
|
|
68
|
-
_mode;
|
|
69
|
-
/**
|
|
70
|
-
* @internal
|
|
71
|
-
*/
|
|
72
|
-
_data;
|
|
73
|
-
/**
|
|
74
|
-
* Create a new instance of QRDataBase.
|
|
75
|
-
* @param className The class name for the derived class.
|
|
76
|
-
* @param mode The mode for the data.
|
|
77
|
-
* @param data The data.
|
|
78
|
-
*/
|
|
79
|
-
constructor(className, mode, data) {
|
|
80
|
-
this._className = className;
|
|
81
|
-
this._mode = mode;
|
|
82
|
-
this._data = data;
|
|
83
|
-
}
|
|
84
|
-
/**
|
|
85
|
-
* Get the data mode.
|
|
86
|
-
* @returns The data mode.
|
|
87
|
-
*/
|
|
88
|
-
getMode() {
|
|
89
|
-
return this._mode;
|
|
90
|
-
}
|
|
91
|
-
/**
|
|
92
|
-
* Get the data for the qr.
|
|
93
|
-
* @returns The data.
|
|
94
|
-
*/
|
|
95
|
-
getData() {
|
|
96
|
-
return this._data;
|
|
97
|
-
}
|
|
98
|
-
/**
|
|
99
|
-
* Get the length in bits of the data.
|
|
100
|
-
* @param typeNumber The type number to get the length for.
|
|
101
|
-
* @returns The length in bits.
|
|
102
|
-
* @throws Error if the typeNumber if invalid.
|
|
103
|
-
*/
|
|
104
|
-
getLengthInBits(typeNumber) {
|
|
105
|
-
if (typeNumber >= 1 && typeNumber < 10) {
|
|
106
|
-
switch (this._mode) {
|
|
107
|
-
case QRDataMode.Number:
|
|
108
|
-
return 10;
|
|
109
|
-
case QRDataMode.AlphaNumeric:
|
|
110
|
-
return 9;
|
|
111
|
-
case QRDataMode.Byte8:
|
|
112
|
-
return 8;
|
|
113
|
-
default:
|
|
114
|
-
throw new core.GeneralError(this._className, "invalidMode", {
|
|
115
|
-
typeNumber,
|
|
116
|
-
mode: this._mode
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
}
|
|
120
|
-
else if (typeNumber < 27) {
|
|
121
|
-
switch (this._mode) {
|
|
122
|
-
case QRDataMode.Number:
|
|
123
|
-
return 12;
|
|
124
|
-
case QRDataMode.AlphaNumeric:
|
|
125
|
-
return 11;
|
|
126
|
-
case QRDataMode.Byte8:
|
|
127
|
-
return 16;
|
|
128
|
-
default:
|
|
129
|
-
throw new core.GeneralError(this._className, "invalidMode", {
|
|
130
|
-
typeNumber,
|
|
131
|
-
mode: this._mode
|
|
132
|
-
});
|
|
133
|
-
}
|
|
134
|
-
}
|
|
135
|
-
else if (typeNumber < 41) {
|
|
136
|
-
switch (this._mode) {
|
|
137
|
-
case QRDataMode.Number:
|
|
138
|
-
return 14;
|
|
139
|
-
case QRDataMode.AlphaNumeric:
|
|
140
|
-
return 13;
|
|
141
|
-
case QRDataMode.Byte8:
|
|
142
|
-
return 16;
|
|
143
|
-
default:
|
|
144
|
-
throw new core.GeneralError(this._className, "invalidMode", {
|
|
145
|
-
typeNumber,
|
|
146
|
-
mode: this._mode
|
|
147
|
-
});
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
else {
|
|
151
|
-
throw new core.GeneralError(this._className, "invalidTypeNumber", { typeNumber });
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
}
|
|
155
|
-
|
|
156
|
-
// Copyright 2024 IOTA Stiftung.
|
|
157
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
158
|
-
/* eslint-disable no-mixed-operators */
|
|
159
|
-
/**
|
|
160
|
-
* QR Data for representing a alpha numeric.
|
|
161
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
162
|
-
*/
|
|
163
|
-
class QRAlphaNumeric extends QRDataBase {
|
|
164
|
-
/**
|
|
165
|
-
* Runtime name for the class.
|
|
166
|
-
* @internal
|
|
167
|
-
*/
|
|
168
|
-
static _CLASS_NAME = "QRAlphaNumeric";
|
|
169
|
-
/**
|
|
170
|
-
* Create a new instance of QRAlphaNumeric.
|
|
171
|
-
* @param data The data for the qr alpha numeric.
|
|
172
|
-
*/
|
|
173
|
-
constructor(data) {
|
|
174
|
-
super(QRAlphaNumeric._CLASS_NAME, QRDataMode.AlphaNumeric, data);
|
|
175
|
-
}
|
|
176
|
-
/**
|
|
177
|
-
* Get the length of the data.
|
|
178
|
-
* @returns The length of the data.
|
|
179
|
-
*/
|
|
180
|
-
getLength() {
|
|
181
|
-
return this.getData().length;
|
|
182
|
-
}
|
|
183
|
-
/**
|
|
184
|
-
* Write data into the buffer.
|
|
185
|
-
* @param buffer The buffer to write into.
|
|
186
|
-
*/
|
|
187
|
-
write(buffer) {
|
|
188
|
-
const s = this.getData();
|
|
189
|
-
let i = 0;
|
|
190
|
-
while (i + 1 < s.length) {
|
|
191
|
-
buffer.put(this.getCode(s.charAt(i)) * 45 + this.getCode(s.charAt(i + 1)), 11);
|
|
192
|
-
i += 2;
|
|
193
|
-
}
|
|
194
|
-
if (i < s.length) {
|
|
195
|
-
buffer.put(this.getCode(s.charAt(i)), 6);
|
|
196
|
-
}
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* @internal
|
|
200
|
-
*/
|
|
201
|
-
getCode(c) {
|
|
202
|
-
if (c >= "0" && c <= "9") {
|
|
203
|
-
return c.charCodeAt(0) - "0".charCodeAt(0);
|
|
204
|
-
}
|
|
205
|
-
if (c >= "A" && c <= "Z") {
|
|
206
|
-
return c.charCodeAt(0) - "A".charCodeAt(0) + 10;
|
|
207
|
-
}
|
|
208
|
-
switch (c) {
|
|
209
|
-
case " ":
|
|
210
|
-
return 36;
|
|
211
|
-
case "$":
|
|
212
|
-
return 37;
|
|
213
|
-
case "%":
|
|
214
|
-
return 38;
|
|
215
|
-
case "*":
|
|
216
|
-
return 39;
|
|
217
|
-
case "+":
|
|
218
|
-
return 40;
|
|
219
|
-
case "-":
|
|
220
|
-
return 41;
|
|
221
|
-
case ".":
|
|
222
|
-
return 42;
|
|
223
|
-
case "/":
|
|
224
|
-
return 43;
|
|
225
|
-
case ":":
|
|
226
|
-
return 44;
|
|
227
|
-
default:
|
|
228
|
-
throw new core.GeneralError(QRAlphaNumeric._CLASS_NAME, "illegalCharacter", { value: c });
|
|
229
|
-
}
|
|
230
|
-
}
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
/**
|
|
234
|
-
* QR Data for representing a 8 bit data.
|
|
235
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
236
|
-
*/
|
|
237
|
-
class QRByte8 extends QRDataBase {
|
|
238
|
-
/**
|
|
239
|
-
* Runtime name for the class.
|
|
240
|
-
* @internal
|
|
241
|
-
*/
|
|
242
|
-
static _CLASS_NAME = "QRByte8";
|
|
243
|
-
/**
|
|
244
|
-
* Create a new instance of QRByte8.
|
|
245
|
-
* @param data The data for the qr 8 bit data.
|
|
246
|
-
*/
|
|
247
|
-
constructor(data) {
|
|
248
|
-
super(QRByte8._CLASS_NAME, QRDataMode.Byte8, data);
|
|
249
|
-
}
|
|
250
|
-
/**
|
|
251
|
-
* Get the length of the data.
|
|
252
|
-
* @returns The length of the data.
|
|
253
|
-
*/
|
|
254
|
-
getLength() {
|
|
255
|
-
return this.stringToBytes(this.getData()).length;
|
|
256
|
-
}
|
|
257
|
-
/**
|
|
258
|
-
* Write data into the buffer.
|
|
259
|
-
* @param buffer The buffer to write into.
|
|
260
|
-
*/
|
|
261
|
-
write(buffer) {
|
|
262
|
-
const data = this.stringToBytes(this.getData());
|
|
263
|
-
for (let i = 0; i < data.length; i++) {
|
|
264
|
-
buffer.put(data[i], 8);
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
|
-
/**
|
|
268
|
-
* @internal
|
|
269
|
-
*/
|
|
270
|
-
stringToBytes(str) {
|
|
271
|
-
const utf8 = [];
|
|
272
|
-
for (let i = 0; i < str.length; i++) {
|
|
273
|
-
let charCode = str.charCodeAt(i);
|
|
274
|
-
if (charCode < 0x80) {
|
|
275
|
-
utf8.push(charCode);
|
|
276
|
-
}
|
|
277
|
-
else if (charCode < 0x800) {
|
|
278
|
-
utf8.push(0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f));
|
|
279
|
-
}
|
|
280
|
-
else if (charCode < 0xd800 || charCode >= 0xe000) {
|
|
281
|
-
utf8.push(0xe0 | (charCode >> 12), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
|
|
282
|
-
}
|
|
283
|
-
else {
|
|
284
|
-
i++;
|
|
285
|
-
// UTF-16 encodes 0x10000-0x10FFFF by
|
|
286
|
-
// subtracting 0x10000 and splitting the
|
|
287
|
-
// 20 bits of 0x0-0xFFFFF into two halves
|
|
288
|
-
charCode = 0x10000 + (((charCode & 0x3ff) << 10) | (str.charCodeAt(i) & 0x3ff));
|
|
289
|
-
utf8.push(0xf0 | (charCode >> 18), 0x80 | ((charCode >> 12) & 0x3f), 0x80 | ((charCode >> 6) & 0x3f), 0x80 | (charCode & 0x3f));
|
|
290
|
-
}
|
|
291
|
-
}
|
|
292
|
-
return utf8;
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
// Copyright 2024 IOTA Stiftung.
|
|
297
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
298
|
-
/* eslint-disable no-mixed-operators */
|
|
299
|
-
/**
|
|
300
|
-
* QR Data for representing a number.
|
|
301
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
302
|
-
*/
|
|
303
|
-
class QRNumber extends QRDataBase {
|
|
304
|
-
/**
|
|
305
|
-
* Runtime name for the class.
|
|
306
|
-
* @internal
|
|
307
|
-
*/
|
|
308
|
-
static _CLASS_NAME = "QRNumber";
|
|
309
|
-
/**
|
|
310
|
-
* Create a new instance of QRNumber.
|
|
311
|
-
* @param data The data for the qr number.
|
|
312
|
-
*/
|
|
313
|
-
constructor(data) {
|
|
314
|
-
super(QRNumber._CLASS_NAME, QRDataMode.Number, data);
|
|
315
|
-
}
|
|
316
|
-
/**
|
|
317
|
-
* Get the length of the data.
|
|
318
|
-
* @returns The length of the data.
|
|
319
|
-
*/
|
|
320
|
-
getLength() {
|
|
321
|
-
return this.getData().length;
|
|
322
|
-
}
|
|
323
|
-
/**
|
|
324
|
-
* Write data into the buffer.
|
|
325
|
-
* @param buffer The buffer to write into.
|
|
326
|
-
*/
|
|
327
|
-
write(buffer) {
|
|
328
|
-
const data = this.getData();
|
|
329
|
-
let i = 0;
|
|
330
|
-
while (i + 2 < data.length) {
|
|
331
|
-
// eslint-disable-next-line unicorn/prefer-string-slice
|
|
332
|
-
buffer.put(this.strToNum(data.substring(i, i + 3)), 10);
|
|
333
|
-
i += 3;
|
|
334
|
-
}
|
|
335
|
-
if (i < data.length) {
|
|
336
|
-
if (data.length - i === 1) {
|
|
337
|
-
// eslint-disable-next-line unicorn/prefer-string-slice
|
|
338
|
-
buffer.put(this.strToNum(data.substring(i, i + 1)), 4);
|
|
339
|
-
}
|
|
340
|
-
else if (data.length - i === 2) {
|
|
341
|
-
// eslint-disable-next-line unicorn/prefer-string-slice
|
|
342
|
-
buffer.put(this.strToNum(data.substring(i, i + 2)), 7);
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
/**
|
|
347
|
-
* @internal
|
|
348
|
-
*/
|
|
349
|
-
strToNum(s) {
|
|
350
|
-
let num = 0;
|
|
351
|
-
for (let i = 0; i < s.length; i++) {
|
|
352
|
-
num = num * 10 + this.charToNum(s.charAt(i));
|
|
353
|
-
}
|
|
354
|
-
return num;
|
|
355
|
-
}
|
|
356
|
-
/**
|
|
357
|
-
* @internal
|
|
358
|
-
*/
|
|
359
|
-
charToNum(c) {
|
|
360
|
-
if (c >= "0" && c <= "9") {
|
|
361
|
-
return c.charCodeAt(0) - "0".charCodeAt(0);
|
|
362
|
-
}
|
|
363
|
-
throw new core.GeneralError(QRNumber._CLASS_NAME, "illegalCharacter", { value: c });
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
// Copyright 2024 IOTA Stiftung.
|
|
368
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
369
|
-
/* eslint-disable no-bitwise */
|
|
370
|
-
/**
|
|
371
|
-
* Class for maintaining data bits.
|
|
372
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
373
|
-
*/
|
|
374
|
-
class BitBuffer {
|
|
375
|
-
/**
|
|
376
|
-
* @internal
|
|
377
|
-
*/
|
|
378
|
-
_buffer;
|
|
379
|
-
/**
|
|
380
|
-
* @internal
|
|
381
|
-
*/
|
|
382
|
-
_length;
|
|
383
|
-
/**
|
|
384
|
-
* Create a new instance of BitBuffer.
|
|
385
|
-
*/
|
|
386
|
-
constructor() {
|
|
387
|
-
this._buffer = [];
|
|
388
|
-
this._length = 0;
|
|
389
|
-
}
|
|
390
|
-
/**
|
|
391
|
-
* Get the buffer.
|
|
392
|
-
* @returns The buffer.
|
|
393
|
-
*/
|
|
394
|
-
getBuffer() {
|
|
395
|
-
return this._buffer;
|
|
396
|
-
}
|
|
397
|
-
/**
|
|
398
|
-
* Get the length in bits.
|
|
399
|
-
* @returns The length.
|
|
400
|
-
*/
|
|
401
|
-
getLengthInBits() {
|
|
402
|
-
return this._length;
|
|
403
|
-
}
|
|
404
|
-
/**
|
|
405
|
-
* Put a value in to the bit buffer.
|
|
406
|
-
* @param num The value.
|
|
407
|
-
* @param length The length.
|
|
408
|
-
*/
|
|
409
|
-
put(num, length) {
|
|
410
|
-
for (let i = 0; i < length; i++) {
|
|
411
|
-
this.putBit(((num >>> (length - i - 1)) & 1) === 1);
|
|
412
|
-
}
|
|
413
|
-
}
|
|
414
|
-
/**
|
|
415
|
-
* Put a bit.
|
|
416
|
-
* @param bit The bit to put.
|
|
417
|
-
*/
|
|
418
|
-
putBit(bit) {
|
|
419
|
-
if (this._length === this._buffer.length * 8) {
|
|
420
|
-
this._buffer.push(0);
|
|
421
|
-
}
|
|
422
|
-
if (bit) {
|
|
423
|
-
this._buffer[~~(this._length / 8)] |= 0x80 >>> this._length % 8;
|
|
424
|
-
}
|
|
425
|
-
this._length++;
|
|
426
|
-
}
|
|
427
|
-
/**
|
|
428
|
-
* Convert to string.
|
|
429
|
-
* @returns The buffer as string.
|
|
430
|
-
*/
|
|
431
|
-
toString() {
|
|
432
|
-
let buffer = "";
|
|
433
|
-
for (let i = 0; i < this.getLengthInBits(); i++) {
|
|
434
|
-
buffer += this.getBit(i) ? "1" : "0";
|
|
435
|
-
}
|
|
436
|
-
return buffer;
|
|
437
|
-
}
|
|
438
|
-
/**
|
|
439
|
-
* @internal
|
|
440
|
-
*/
|
|
441
|
-
getBit(index) {
|
|
442
|
-
return ((this._buffer[~~(index / 8)] >>> (7 - (index % 8))) & 1) === 1;
|
|
443
|
-
}
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
// Copyright 2024 IOTA Stiftung.
|
|
447
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
448
|
-
/* eslint-disable no-bitwise */
|
|
449
|
-
/**
|
|
450
|
-
* Class to helper with math.
|
|
451
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
452
|
-
*/
|
|
453
|
-
class MathHelper {
|
|
454
|
-
/**
|
|
455
|
-
* Runtime name for the class.
|
|
456
|
-
* @internal
|
|
457
|
-
*/
|
|
458
|
-
static _CLASS_NAME = "MathHelper";
|
|
459
|
-
/**
|
|
460
|
-
* @internal
|
|
461
|
-
*/
|
|
462
|
-
static _EXP_TABLE;
|
|
463
|
-
/**
|
|
464
|
-
* @internal
|
|
465
|
-
*/
|
|
466
|
-
static _LOG_TABLE;
|
|
467
|
-
/**
|
|
468
|
-
* Initialize the math helper.
|
|
469
|
-
*/
|
|
470
|
-
static initialize() {
|
|
471
|
-
if (!MathHelper._EXP_TABLE) {
|
|
472
|
-
MathHelper._EXP_TABLE = [];
|
|
473
|
-
MathHelper._LOG_TABLE = [];
|
|
474
|
-
for (let i = 0; i < 256; i++) {
|
|
475
|
-
MathHelper._EXP_TABLE.push(i < 8
|
|
476
|
-
? 1 << i
|
|
477
|
-
: MathHelper._EXP_TABLE[i - 4] ^
|
|
478
|
-
MathHelper._EXP_TABLE[i - 5] ^
|
|
479
|
-
MathHelper._EXP_TABLE[i - 6] ^
|
|
480
|
-
MathHelper._EXP_TABLE[i - 8]);
|
|
481
|
-
MathHelper._LOG_TABLE.push(0);
|
|
482
|
-
}
|
|
483
|
-
for (let i = 0; i < 255; i++) {
|
|
484
|
-
MathHelper._LOG_TABLE[MathHelper._EXP_TABLE[i]] = i;
|
|
485
|
-
}
|
|
486
|
-
}
|
|
487
|
-
}
|
|
488
|
-
/**
|
|
489
|
-
* Get the log of the value.
|
|
490
|
-
* @param value The value to get the log of.
|
|
491
|
-
* @returns The log of the value.
|
|
492
|
-
* @throws Error if value < 1.
|
|
493
|
-
*/
|
|
494
|
-
static gLog(value) {
|
|
495
|
-
if (value < 1) {
|
|
496
|
-
throw new core.GeneralError(MathHelper._CLASS_NAME, "lessThanOne", { value });
|
|
497
|
-
}
|
|
498
|
-
return MathHelper._LOG_TABLE[value];
|
|
499
|
-
}
|
|
500
|
-
/**
|
|
501
|
-
* Get the exponent of the value.
|
|
502
|
-
* @param value The value to get the exponent of.
|
|
503
|
-
* @returns The exponent of the value.
|
|
504
|
-
*/
|
|
505
|
-
static gExp(value) {
|
|
506
|
-
let localValue = value;
|
|
507
|
-
while (localValue < 0) {
|
|
508
|
-
localValue += 255;
|
|
509
|
-
}
|
|
510
|
-
while (localValue >= 256) {
|
|
511
|
-
localValue -= 255;
|
|
512
|
-
}
|
|
513
|
-
return MathHelper._EXP_TABLE[localValue];
|
|
514
|
-
}
|
|
515
|
-
}
|
|
516
|
-
|
|
517
|
-
// Copyright 2024 IOTA Stiftung.
|
|
518
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
519
|
-
/* eslint-disable no-bitwise */
|
|
520
|
-
/**
|
|
521
|
-
* Class to represent a polynomial.
|
|
522
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
523
|
-
*/
|
|
524
|
-
class Polynomial {
|
|
525
|
-
/**
|
|
526
|
-
* @internal
|
|
527
|
-
*/
|
|
528
|
-
_num;
|
|
529
|
-
/**
|
|
530
|
-
* Create a new instance of Polynomial.
|
|
531
|
-
* @param num The num of the polynomial.
|
|
532
|
-
* @param shift The shift for the polynomial.
|
|
533
|
-
*/
|
|
534
|
-
constructor(num, shift = 0) {
|
|
535
|
-
let offset = 0;
|
|
536
|
-
while (offset < num.length && num[offset] === 0) {
|
|
537
|
-
offset++;
|
|
538
|
-
}
|
|
539
|
-
this._num = [];
|
|
540
|
-
const len = num.length - offset;
|
|
541
|
-
for (let i = 0; i < len; i++) {
|
|
542
|
-
this._num.push(num[offset + i]);
|
|
543
|
-
}
|
|
544
|
-
for (let i = 0; i < shift; i++) {
|
|
545
|
-
this._num.push(0);
|
|
546
|
-
}
|
|
547
|
-
}
|
|
548
|
-
/**
|
|
549
|
-
* The the value of the polynomial at given index.
|
|
550
|
-
* @param index The index.
|
|
551
|
-
* @returns The value of the polynomial.
|
|
552
|
-
*/
|
|
553
|
-
getAt(index) {
|
|
554
|
-
return this._num[index];
|
|
555
|
-
}
|
|
556
|
-
/**
|
|
557
|
-
* Get the length of the polynomial.
|
|
558
|
-
* @returns The polynomial.
|
|
559
|
-
*/
|
|
560
|
-
getLength() {
|
|
561
|
-
return this._num.length;
|
|
562
|
-
}
|
|
563
|
-
/**
|
|
564
|
-
* Convert the polynomial to a string.
|
|
565
|
-
* @returns The string representation of the polynomial.
|
|
566
|
-
*/
|
|
567
|
-
toString() {
|
|
568
|
-
let buffer = "";
|
|
569
|
-
for (let i = 0; i < this.getLength(); i++) {
|
|
570
|
-
if (i > 0) {
|
|
571
|
-
buffer += ",";
|
|
572
|
-
}
|
|
573
|
-
buffer += this.getAt(i);
|
|
574
|
-
}
|
|
575
|
-
return buffer.toString();
|
|
576
|
-
}
|
|
577
|
-
/**
|
|
578
|
-
* Get the log representation of the polynomial.
|
|
579
|
-
* @returns The log representation of the polynomial.
|
|
580
|
-
*/
|
|
581
|
-
toLogString() {
|
|
582
|
-
let buffer = "";
|
|
583
|
-
for (let i = 0; i < this.getLength(); i++) {
|
|
584
|
-
if (i > 0) {
|
|
585
|
-
buffer += ",";
|
|
586
|
-
}
|
|
587
|
-
buffer += MathHelper.gLog(this.getAt(i));
|
|
588
|
-
}
|
|
589
|
-
return buffer.toString();
|
|
590
|
-
}
|
|
591
|
-
/**
|
|
592
|
-
* Multiply the polynomial with another one.
|
|
593
|
-
* @param e The polynomial to multiply.
|
|
594
|
-
* @returns The multiplication of the polynomials.
|
|
595
|
-
*/
|
|
596
|
-
multiply(e) {
|
|
597
|
-
const num = [];
|
|
598
|
-
const len = this.getLength() + e.getLength() - 1;
|
|
599
|
-
for (let i = 0; i < len; i++) {
|
|
600
|
-
num.push(0);
|
|
601
|
-
}
|
|
602
|
-
for (let i = 0; i < this.getLength(); i++) {
|
|
603
|
-
for (let j = 0; j < e.getLength(); j++) {
|
|
604
|
-
num[i + j] ^= MathHelper.gExp(MathHelper.gLog(this.getAt(i)) + MathHelper.gLog(e.getAt(j)));
|
|
605
|
-
}
|
|
606
|
-
}
|
|
607
|
-
return new Polynomial(num);
|
|
608
|
-
}
|
|
609
|
-
/**
|
|
610
|
-
* Get the modulus of the polynomial from another.
|
|
611
|
-
* @param e The polynomial.
|
|
612
|
-
* @returns The modules of the polynomials.
|
|
613
|
-
*/
|
|
614
|
-
mod(e) {
|
|
615
|
-
if (this.getLength() - e.getLength() < 0) {
|
|
616
|
-
return this;
|
|
617
|
-
}
|
|
618
|
-
const ratio = MathHelper.gLog(this.getAt(0)) - MathHelper.gLog(e.getAt(0));
|
|
619
|
-
// create copy
|
|
620
|
-
const num = [];
|
|
621
|
-
for (let i = 0; i < this.getLength(); i++) {
|
|
622
|
-
num.push(this.getAt(i));
|
|
623
|
-
}
|
|
624
|
-
// subtract and calc rest.
|
|
625
|
-
for (let i = 0; i < e.getLength(); i++) {
|
|
626
|
-
num[i] ^= MathHelper.gExp(MathHelper.gLog(e.getAt(i)) + ratio);
|
|
627
|
-
}
|
|
628
|
-
// call recursively
|
|
629
|
-
return new Polynomial(num).mod(e);
|
|
630
|
-
}
|
|
631
|
-
}
|
|
632
|
-
|
|
633
|
-
// Copyright 2024 IOTA Stiftung.
|
|
634
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
635
|
-
/**
|
|
636
|
-
* Mask patterns for QR codes.
|
|
637
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
638
|
-
*/
|
|
639
|
-
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
640
|
-
const MaskPattern = {
|
|
641
|
-
/**
|
|
642
|
-
* Mask pattern 000.
|
|
643
|
-
*/
|
|
644
|
-
PATTERN000: 0b000,
|
|
645
|
-
/**
|
|
646
|
-
* Mask pattern 001.
|
|
647
|
-
*/
|
|
648
|
-
PATTERN001: 0b001,
|
|
649
|
-
/**
|
|
650
|
-
* Mask pattern 010.
|
|
651
|
-
*/
|
|
652
|
-
PATTERN010: 0b010,
|
|
653
|
-
/**
|
|
654
|
-
* Mask pattern 011.
|
|
655
|
-
*/
|
|
656
|
-
PATTERN011: 0b011,
|
|
657
|
-
/**
|
|
658
|
-
* Mask pattern 100.
|
|
659
|
-
*/
|
|
660
|
-
PATTERN100: 0b100,
|
|
661
|
-
/**
|
|
662
|
-
* Mask pattern 101.
|
|
663
|
-
*/
|
|
664
|
-
PATTERN101: 0b101,
|
|
665
|
-
/**
|
|
666
|
-
* Mask pattern 110.
|
|
667
|
-
*/
|
|
668
|
-
PATTERN110: 0b110,
|
|
669
|
-
/**
|
|
670
|
-
* Mask pattern 111.
|
|
671
|
-
*/
|
|
672
|
-
PATTERN111: 0b111
|
|
673
|
-
};
|
|
674
|
-
|
|
675
|
-
// Copyright 2024 IOTA Stiftung.
|
|
676
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
677
|
-
/* eslint-disable no-bitwise */
|
|
678
|
-
/**
|
|
679
|
-
* Helper methods for QR generation.
|
|
680
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
681
|
-
*/
|
|
682
|
-
class QRHelper {
|
|
683
|
-
/**
|
|
684
|
-
* Runtime name for the class.
|
|
685
|
-
* @internal
|
|
686
|
-
*/
|
|
687
|
-
static _CLASS_NAME = "QRHelper";
|
|
688
|
-
/**
|
|
689
|
-
* @internal
|
|
690
|
-
*/
|
|
691
|
-
static _PATTERN_POSITION_TABLE = [
|
|
692
|
-
[],
|
|
693
|
-
[6, 18],
|
|
694
|
-
[6, 22],
|
|
695
|
-
[6, 26],
|
|
696
|
-
[6, 30],
|
|
697
|
-
[6, 34],
|
|
698
|
-
[6, 22, 38],
|
|
699
|
-
[6, 24, 42],
|
|
700
|
-
[6, 26, 46],
|
|
701
|
-
[6, 28, 50],
|
|
702
|
-
[6, 30, 54],
|
|
703
|
-
[6, 32, 58],
|
|
704
|
-
[6, 34, 62],
|
|
705
|
-
[6, 26, 46, 66],
|
|
706
|
-
[6, 26, 48, 70],
|
|
707
|
-
[6, 26, 50, 74],
|
|
708
|
-
[6, 30, 54, 78],
|
|
709
|
-
[6, 30, 56, 82],
|
|
710
|
-
[6, 30, 58, 86],
|
|
711
|
-
[6, 34, 62, 90],
|
|
712
|
-
[6, 28, 50, 72, 94],
|
|
713
|
-
[6, 26, 50, 74, 98],
|
|
714
|
-
[6, 30, 54, 78, 102],
|
|
715
|
-
[6, 28, 54, 80, 106],
|
|
716
|
-
[6, 32, 58, 84, 110],
|
|
717
|
-
[6, 30, 58, 86, 114],
|
|
718
|
-
[6, 34, 62, 90, 118],
|
|
719
|
-
[6, 26, 50, 74, 98, 122],
|
|
720
|
-
[6, 30, 54, 78, 102, 126],
|
|
721
|
-
[6, 26, 52, 78, 104, 130],
|
|
722
|
-
[6, 30, 56, 82, 108, 134],
|
|
723
|
-
[6, 34, 60, 86, 112, 138],
|
|
724
|
-
[6, 30, 58, 86, 114, 142],
|
|
725
|
-
[6, 34, 62, 90, 118, 146],
|
|
726
|
-
[6, 30, 54, 78, 102, 126, 150],
|
|
727
|
-
[6, 24, 50, 76, 102, 128, 154],
|
|
728
|
-
[6, 28, 54, 80, 106, 132, 158],
|
|
729
|
-
[6, 32, 58, 84, 110, 136, 162],
|
|
730
|
-
[6, 26, 54, 82, 110, 138, 166],
|
|
731
|
-
[6, 30, 58, 86, 114, 142, 170]
|
|
732
|
-
];
|
|
733
|
-
/**
|
|
734
|
-
* @internal
|
|
735
|
-
*/
|
|
736
|
-
static _MAX_LENGTH = [
|
|
737
|
-
[
|
|
738
|
-
[41, 25, 17, 10],
|
|
739
|
-
[34, 20, 14, 8],
|
|
740
|
-
[27, 16, 11, 7],
|
|
741
|
-
[17, 10, 7, 4]
|
|
742
|
-
],
|
|
743
|
-
[
|
|
744
|
-
[77, 47, 32, 20],
|
|
745
|
-
[63, 38, 26, 16],
|
|
746
|
-
[48, 29, 20, 12],
|
|
747
|
-
[34, 20, 14, 8]
|
|
748
|
-
],
|
|
749
|
-
[
|
|
750
|
-
[127, 77, 53, 32],
|
|
751
|
-
[101, 61, 42, 26],
|
|
752
|
-
[77, 47, 32, 20],
|
|
753
|
-
[58, 35, 24, 15]
|
|
754
|
-
],
|
|
755
|
-
[
|
|
756
|
-
[187, 114, 78, 48],
|
|
757
|
-
[149, 90, 62, 38],
|
|
758
|
-
[111, 67, 46, 28],
|
|
759
|
-
[82, 50, 34, 21]
|
|
760
|
-
],
|
|
761
|
-
[
|
|
762
|
-
[255, 154, 106, 65],
|
|
763
|
-
[202, 122, 84, 52],
|
|
764
|
-
[144, 87, 60, 37],
|
|
765
|
-
[106, 64, 44, 27]
|
|
766
|
-
],
|
|
767
|
-
[
|
|
768
|
-
[322, 195, 134, 82],
|
|
769
|
-
[255, 154, 106, 65],
|
|
770
|
-
[178, 108, 74, 45],
|
|
771
|
-
[139, 84, 58, 36]
|
|
772
|
-
],
|
|
773
|
-
[
|
|
774
|
-
[370, 224, 154, 95],
|
|
775
|
-
[293, 178, 122, 75],
|
|
776
|
-
[207, 125, 86, 53],
|
|
777
|
-
[154, 93, 64, 39]
|
|
778
|
-
],
|
|
779
|
-
[
|
|
780
|
-
[461, 279, 192, 118],
|
|
781
|
-
[365, 221, 152, 93],
|
|
782
|
-
[259, 157, 108, 66],
|
|
783
|
-
[202, 122, 84, 52]
|
|
784
|
-
],
|
|
785
|
-
[
|
|
786
|
-
[552, 335, 230, 141],
|
|
787
|
-
[432, 262, 180, 111],
|
|
788
|
-
[312, 189, 130, 80],
|
|
789
|
-
[235, 143, 98, 60]
|
|
790
|
-
],
|
|
791
|
-
[
|
|
792
|
-
[652, 395, 271, 167],
|
|
793
|
-
[513, 311, 213, 131],
|
|
794
|
-
[364, 221, 151, 93],
|
|
795
|
-
[288, 174, 119, 74]
|
|
796
|
-
]
|
|
797
|
-
];
|
|
798
|
-
/**
|
|
799
|
-
* @internal
|
|
800
|
-
*/
|
|
801
|
-
static _G15 = (1 << 10) | (1 << 8) | (1 << 5) | (1 << 4) | (1 << 2) | (1 << 1) | (1 << 0);
|
|
802
|
-
/**
|
|
803
|
-
* @internal
|
|
804
|
-
*/
|
|
805
|
-
static _G18 = (1 << 12) | (1 << 11) | (1 << 10) | (1 << 9) | (1 << 8) | (1 << 5) | (1 << 2) | (1 << 0);
|
|
806
|
-
/**
|
|
807
|
-
* @internal
|
|
808
|
-
*/
|
|
809
|
-
static _G15_MASK = (1 << 14) | (1 << 12) | (1 << 10) | (1 << 4) | (1 << 1);
|
|
810
|
-
/**
|
|
811
|
-
* Get the pattern position for the given type number.
|
|
812
|
-
* @param typeNumber The type number to get the pattern for.
|
|
813
|
-
* @returns The pattern for the type number.
|
|
814
|
-
*/
|
|
815
|
-
static getPatternPosition(typeNumber) {
|
|
816
|
-
return QRHelper._PATTERN_POSITION_TABLE[typeNumber - 1];
|
|
817
|
-
}
|
|
818
|
-
/**
|
|
819
|
-
* Get the max length of the data.
|
|
820
|
-
* @param typeNumber The type number to get the max length for.
|
|
821
|
-
* @param mode The data mode to get data max length for.
|
|
822
|
-
* @param errorCorrectLevel The error correction to get the max length for.
|
|
823
|
-
* @returns The max length.
|
|
824
|
-
* @throws Error with unknown correction level.
|
|
825
|
-
*/
|
|
826
|
-
static getMaxLength(typeNumber, mode, errorCorrectLevel) {
|
|
827
|
-
const t = typeNumber - 1;
|
|
828
|
-
let e = 0;
|
|
829
|
-
let m = 0;
|
|
830
|
-
switch (errorCorrectLevel) {
|
|
831
|
-
case ErrorCorrectLevel.L:
|
|
832
|
-
e = 0;
|
|
833
|
-
break;
|
|
834
|
-
case ErrorCorrectLevel.M:
|
|
835
|
-
e = 1;
|
|
836
|
-
break;
|
|
837
|
-
case ErrorCorrectLevel.Q:
|
|
838
|
-
e = 2;
|
|
839
|
-
break;
|
|
840
|
-
case ErrorCorrectLevel.H:
|
|
841
|
-
e = 3;
|
|
842
|
-
break;
|
|
843
|
-
default:
|
|
844
|
-
throw new core.GeneralError(QRHelper._CLASS_NAME, "correctionLevelRange", { errorCorrectLevel });
|
|
845
|
-
}
|
|
846
|
-
switch (mode) {
|
|
847
|
-
case QRDataMode.Number:
|
|
848
|
-
m = 0;
|
|
849
|
-
break;
|
|
850
|
-
case QRDataMode.AlphaNumeric:
|
|
851
|
-
m = 1;
|
|
852
|
-
break;
|
|
853
|
-
case QRDataMode.Byte8:
|
|
854
|
-
m = 2;
|
|
855
|
-
break;
|
|
856
|
-
default:
|
|
857
|
-
throw new core.GeneralError(QRHelper._CLASS_NAME, "modeRange", { mode });
|
|
858
|
-
}
|
|
859
|
-
return QRHelper._MAX_LENGTH[t][e][m];
|
|
860
|
-
}
|
|
861
|
-
/**
|
|
862
|
-
* Get the error correction polynomial for the error correct to length.
|
|
863
|
-
* @param errorCorrectLength The error correction length to get the polynomial for.
|
|
864
|
-
* @returns The polynomial for the error correction length.
|
|
865
|
-
*/
|
|
866
|
-
static getErrorCorrectPolynomial(errorCorrectLength) {
|
|
867
|
-
let a = new Polynomial([1]);
|
|
868
|
-
for (let i = 0; i < errorCorrectLength; i++) {
|
|
869
|
-
a = a.multiply(new Polynomial([1, MathHelper.gExp(i)]));
|
|
870
|
-
}
|
|
871
|
-
return a;
|
|
872
|
-
}
|
|
873
|
-
/**
|
|
874
|
-
* Get the mask method for the given pattern.
|
|
875
|
-
* @param maskPattern The pattern to get the mask for.
|
|
876
|
-
* @returns The mask method for the pattern.
|
|
877
|
-
* @throws Error with invalid mask.
|
|
878
|
-
*/
|
|
879
|
-
static getMaskMethod(maskPattern) {
|
|
880
|
-
switch (maskPattern) {
|
|
881
|
-
case MaskPattern.PATTERN000:
|
|
882
|
-
return (i, j) => (i + j) % 2 === 0;
|
|
883
|
-
case MaskPattern.PATTERN001:
|
|
884
|
-
return (i, j) => i % 2 === 0;
|
|
885
|
-
case MaskPattern.PATTERN010:
|
|
886
|
-
return (i, j) => j % 3 === 0;
|
|
887
|
-
case MaskPattern.PATTERN011:
|
|
888
|
-
return (i, j) => (i + j) % 3 === 0;
|
|
889
|
-
case MaskPattern.PATTERN100:
|
|
890
|
-
return (i, j) => (~~(i / 2) + ~~(j / 3)) % 2 === 0;
|
|
891
|
-
case MaskPattern.PATTERN101:
|
|
892
|
-
return (i, j) => ((i * j) % 2) + ((i * j) % 3) === 0;
|
|
893
|
-
case MaskPattern.PATTERN110:
|
|
894
|
-
return (i, j) => (((i * j) % 2) + ((i * j) % 3)) % 2 === 0;
|
|
895
|
-
case MaskPattern.PATTERN111:
|
|
896
|
-
return (i, j) => (((i * j) % 3) + ((i + j) % 2)) % 2 === 0;
|
|
897
|
-
default:
|
|
898
|
-
throw new core.GeneralError(QRHelper._CLASS_NAME, "maskPatternRange", { maskPattern });
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
/**
|
|
902
|
-
* Get the BCH type info.
|
|
903
|
-
* @param data The data to get the BCH type info for.
|
|
904
|
-
* @returns The type info.
|
|
905
|
-
*/
|
|
906
|
-
static getBCHTypeInfo(data) {
|
|
907
|
-
let d = data << 10;
|
|
908
|
-
while (QRHelper.getBCHDigit(d) - QRHelper.getBCHDigit(QRHelper._G15) >= 0) {
|
|
909
|
-
d ^= QRHelper._G15 << (QRHelper.getBCHDigit(d) - QRHelper.getBCHDigit(QRHelper._G15));
|
|
910
|
-
}
|
|
911
|
-
return ((data << 10) | d) ^ QRHelper._G15_MASK;
|
|
912
|
-
}
|
|
913
|
-
/**
|
|
914
|
-
* Get the BCH type number.
|
|
915
|
-
* @param data The data to get the BCH type number for.
|
|
916
|
-
* @returns The type number.
|
|
917
|
-
*/
|
|
918
|
-
static getBCHTypeNumber(data) {
|
|
919
|
-
let d = data << 12;
|
|
920
|
-
while (QRHelper.getBCHDigit(d) - QRHelper.getBCHDigit(QRHelper._G18) >= 0) {
|
|
921
|
-
d ^= QRHelper._G18 << (QRHelper.getBCHDigit(d) - QRHelper.getBCHDigit(QRHelper._G18));
|
|
922
|
-
}
|
|
923
|
-
return (data << 12) | d;
|
|
924
|
-
}
|
|
925
|
-
/**
|
|
926
|
-
* @internal
|
|
927
|
-
*/
|
|
928
|
-
static getBCHDigit(data) {
|
|
929
|
-
let localData = data;
|
|
930
|
-
let digit = 0;
|
|
931
|
-
while (localData !== 0) {
|
|
932
|
-
digit++;
|
|
933
|
-
localData >>>= 1;
|
|
934
|
-
}
|
|
935
|
-
return digit;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// Copyright 2024 IOTA Stiftung.
|
|
940
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
941
|
-
/* eslint-disable no-mixed-operators */
|
|
942
|
-
/**
|
|
943
|
-
* Class to represent a RS Block.
|
|
944
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
945
|
-
*/
|
|
946
|
-
class RSBlock {
|
|
947
|
-
/**
|
|
948
|
-
* Runtime name for the class.
|
|
949
|
-
* @internal
|
|
950
|
-
*/
|
|
951
|
-
static _CLASS_NAME = "RSBlock";
|
|
952
|
-
/**
|
|
953
|
-
* @internal
|
|
954
|
-
*/
|
|
955
|
-
static _RS_BLOCK_TABLE = [
|
|
956
|
-
// L
|
|
957
|
-
// M
|
|
958
|
-
// Q
|
|
959
|
-
// H
|
|
960
|
-
// 1
|
|
961
|
-
[1, 26, 19],
|
|
962
|
-
[1, 26, 16],
|
|
963
|
-
[1, 26, 13],
|
|
964
|
-
[1, 26, 9],
|
|
965
|
-
// 2
|
|
966
|
-
[1, 44, 34],
|
|
967
|
-
[1, 44, 28],
|
|
968
|
-
[1, 44, 22],
|
|
969
|
-
[1, 44, 16],
|
|
970
|
-
// 3
|
|
971
|
-
[1, 70, 55],
|
|
972
|
-
[1, 70, 44],
|
|
973
|
-
[2, 35, 17],
|
|
974
|
-
[2, 35, 13],
|
|
975
|
-
// 4
|
|
976
|
-
[1, 100, 80],
|
|
977
|
-
[2, 50, 32],
|
|
978
|
-
[2, 50, 24],
|
|
979
|
-
[4, 25, 9],
|
|
980
|
-
// 5
|
|
981
|
-
[1, 134, 108],
|
|
982
|
-
[2, 67, 43],
|
|
983
|
-
[2, 33, 15, 2, 34, 16],
|
|
984
|
-
[2, 33, 11, 2, 34, 12],
|
|
985
|
-
// 6
|
|
986
|
-
[2, 86, 68],
|
|
987
|
-
[4, 43, 27],
|
|
988
|
-
[4, 43, 19],
|
|
989
|
-
[4, 43, 15],
|
|
990
|
-
// 7
|
|
991
|
-
[2, 98, 78],
|
|
992
|
-
[4, 49, 31],
|
|
993
|
-
[2, 32, 14, 4, 33, 15],
|
|
994
|
-
[4, 39, 13, 1, 40, 14],
|
|
995
|
-
// 8
|
|
996
|
-
[2, 121, 97],
|
|
997
|
-
[2, 60, 38, 2, 61, 39],
|
|
998
|
-
[4, 40, 18, 2, 41, 19],
|
|
999
|
-
[4, 40, 14, 2, 41, 15],
|
|
1000
|
-
// 9
|
|
1001
|
-
[2, 146, 116],
|
|
1002
|
-
[3, 58, 36, 2, 59, 37],
|
|
1003
|
-
[4, 36, 16, 4, 37, 17],
|
|
1004
|
-
[4, 36, 12, 4, 37, 13],
|
|
1005
|
-
// 10
|
|
1006
|
-
[2, 86, 68, 2, 87, 69],
|
|
1007
|
-
[4, 69, 43, 1, 70, 44],
|
|
1008
|
-
[6, 43, 19, 2, 44, 20],
|
|
1009
|
-
[6, 43, 15, 2, 44, 16],
|
|
1010
|
-
// 11
|
|
1011
|
-
[4, 101, 81],
|
|
1012
|
-
[1, 80, 50, 4, 81, 51],
|
|
1013
|
-
[4, 50, 22, 4, 51, 23],
|
|
1014
|
-
[3, 36, 12, 8, 37, 13],
|
|
1015
|
-
// 12
|
|
1016
|
-
[2, 116, 92, 2, 117, 93],
|
|
1017
|
-
[6, 58, 36, 2, 59, 37],
|
|
1018
|
-
[4, 46, 20, 6, 47, 21],
|
|
1019
|
-
[7, 42, 14, 4, 43, 15],
|
|
1020
|
-
// 13
|
|
1021
|
-
[4, 133, 107],
|
|
1022
|
-
[8, 59, 37, 1, 60, 38],
|
|
1023
|
-
[8, 44, 20, 4, 45, 21],
|
|
1024
|
-
[12, 33, 11, 4, 34, 12],
|
|
1025
|
-
// 14
|
|
1026
|
-
[3, 145, 115, 1, 146, 116],
|
|
1027
|
-
[4, 64, 40, 5, 65, 41],
|
|
1028
|
-
[11, 36, 16, 5, 37, 17],
|
|
1029
|
-
[11, 36, 12, 5, 37, 13],
|
|
1030
|
-
// 15
|
|
1031
|
-
[5, 109, 87, 1, 110, 88],
|
|
1032
|
-
[5, 65, 41, 5, 66, 42],
|
|
1033
|
-
[5, 54, 24, 7, 55, 25],
|
|
1034
|
-
[11, 36, 12, 7, 37, 13],
|
|
1035
|
-
// 16
|
|
1036
|
-
[5, 122, 98, 1, 123, 99],
|
|
1037
|
-
[7, 73, 45, 3, 74, 46],
|
|
1038
|
-
[15, 43, 19, 2, 44, 20],
|
|
1039
|
-
[3, 45, 15, 13, 46, 16],
|
|
1040
|
-
// 17
|
|
1041
|
-
[1, 135, 107, 5, 136, 108],
|
|
1042
|
-
[10, 74, 46, 1, 75, 47],
|
|
1043
|
-
[1, 50, 22, 15, 51, 23],
|
|
1044
|
-
[2, 42, 14, 17, 43, 15],
|
|
1045
|
-
// 18
|
|
1046
|
-
[5, 150, 120, 1, 151, 121],
|
|
1047
|
-
[9, 69, 43, 4, 70, 44],
|
|
1048
|
-
[17, 50, 22, 1, 51, 23],
|
|
1049
|
-
[2, 42, 14, 19, 43, 15],
|
|
1050
|
-
// 19
|
|
1051
|
-
[3, 141, 113, 4, 142, 114],
|
|
1052
|
-
[3, 70, 44, 11, 71, 45],
|
|
1053
|
-
[17, 47, 21, 4, 48, 22],
|
|
1054
|
-
[9, 39, 13, 16, 40, 14],
|
|
1055
|
-
// 20
|
|
1056
|
-
[3, 135, 107, 5, 136, 108],
|
|
1057
|
-
[3, 67, 41, 13, 68, 42],
|
|
1058
|
-
[15, 54, 24, 5, 55, 25],
|
|
1059
|
-
[15, 43, 15, 10, 44, 16],
|
|
1060
|
-
// 21
|
|
1061
|
-
[4, 144, 116, 4, 145, 117],
|
|
1062
|
-
[17, 68, 42],
|
|
1063
|
-
[17, 50, 22, 6, 51, 23],
|
|
1064
|
-
[19, 46, 16, 6, 47, 17],
|
|
1065
|
-
// 22
|
|
1066
|
-
[2, 139, 111, 7, 140, 112],
|
|
1067
|
-
[17, 74, 46],
|
|
1068
|
-
[7, 54, 24, 16, 55, 25],
|
|
1069
|
-
[34, 37, 13],
|
|
1070
|
-
// 23
|
|
1071
|
-
[4, 151, 121, 5, 152, 122],
|
|
1072
|
-
[4, 75, 47, 14, 76, 48],
|
|
1073
|
-
[11, 54, 24, 14, 55, 25],
|
|
1074
|
-
[16, 45, 15, 14, 46, 16],
|
|
1075
|
-
// 24
|
|
1076
|
-
[6, 147, 117, 4, 148, 118],
|
|
1077
|
-
[6, 73, 45, 14, 74, 46],
|
|
1078
|
-
[11, 54, 24, 16, 55, 25],
|
|
1079
|
-
[30, 46, 16, 2, 47, 17],
|
|
1080
|
-
// 25
|
|
1081
|
-
[8, 132, 106, 4, 133, 107],
|
|
1082
|
-
[8, 75, 47, 13, 76, 48],
|
|
1083
|
-
[7, 54, 24, 22, 55, 25],
|
|
1084
|
-
[22, 45, 15, 13, 46, 16],
|
|
1085
|
-
// 26
|
|
1086
|
-
[10, 142, 114, 2, 143, 115],
|
|
1087
|
-
[19, 74, 46, 4, 75, 47],
|
|
1088
|
-
[28, 50, 22, 6, 51, 23],
|
|
1089
|
-
[33, 46, 16, 4, 47, 17],
|
|
1090
|
-
// 27
|
|
1091
|
-
[8, 152, 122, 4, 153, 123],
|
|
1092
|
-
[22, 73, 45, 3, 74, 46],
|
|
1093
|
-
[8, 53, 23, 26, 54, 24],
|
|
1094
|
-
[12, 45, 15, 28, 46, 16],
|
|
1095
|
-
// 28
|
|
1096
|
-
[3, 147, 117, 10, 148, 118],
|
|
1097
|
-
[3, 73, 45, 23, 74, 46],
|
|
1098
|
-
[4, 54, 24, 31, 55, 25],
|
|
1099
|
-
[11, 45, 15, 31, 46, 16],
|
|
1100
|
-
// 29
|
|
1101
|
-
[7, 146, 116, 7, 147, 117],
|
|
1102
|
-
[21, 73, 45, 7, 74, 46],
|
|
1103
|
-
[1, 53, 23, 37, 54, 24],
|
|
1104
|
-
[19, 45, 15, 26, 46, 16],
|
|
1105
|
-
// 30
|
|
1106
|
-
[5, 145, 115, 10, 146, 116],
|
|
1107
|
-
[19, 75, 47, 10, 76, 48],
|
|
1108
|
-
[15, 54, 24, 25, 55, 25],
|
|
1109
|
-
[23, 45, 15, 25, 46, 16],
|
|
1110
|
-
// 31
|
|
1111
|
-
[13, 145, 115, 3, 146, 116],
|
|
1112
|
-
[2, 74, 46, 29, 75, 47],
|
|
1113
|
-
[42, 54, 24, 1, 55, 25],
|
|
1114
|
-
[23, 45, 15, 28, 46, 16],
|
|
1115
|
-
// 32
|
|
1116
|
-
[17, 145, 115],
|
|
1117
|
-
[10, 74, 46, 23, 75, 47],
|
|
1118
|
-
[10, 54, 24, 35, 55, 25],
|
|
1119
|
-
[19, 45, 15, 35, 46, 16],
|
|
1120
|
-
// 33
|
|
1121
|
-
[17, 145, 115, 1, 146, 116],
|
|
1122
|
-
[14, 74, 46, 21, 75, 47],
|
|
1123
|
-
[29, 54, 24, 19, 55, 25],
|
|
1124
|
-
[11, 45, 15, 46, 46, 16],
|
|
1125
|
-
// 34
|
|
1126
|
-
[13, 145, 115, 6, 146, 116],
|
|
1127
|
-
[14, 74, 46, 23, 75, 47],
|
|
1128
|
-
[44, 54, 24, 7, 55, 25],
|
|
1129
|
-
[59, 46, 16, 1, 47, 17],
|
|
1130
|
-
// 35
|
|
1131
|
-
[12, 151, 121, 7, 152, 122],
|
|
1132
|
-
[12, 75, 47, 26, 76, 48],
|
|
1133
|
-
[39, 54, 24, 14, 55, 25],
|
|
1134
|
-
[22, 45, 15, 41, 46, 16],
|
|
1135
|
-
// 36
|
|
1136
|
-
[6, 151, 121, 14, 152, 122],
|
|
1137
|
-
[6, 75, 47, 34, 76, 48],
|
|
1138
|
-
[46, 54, 24, 10, 55, 25],
|
|
1139
|
-
[2, 45, 15, 64, 46, 16],
|
|
1140
|
-
// 37
|
|
1141
|
-
[17, 152, 122, 4, 153, 123],
|
|
1142
|
-
[29, 74, 46, 14, 75, 47],
|
|
1143
|
-
[49, 54, 24, 10, 55, 25],
|
|
1144
|
-
[24, 45, 15, 46, 46, 16],
|
|
1145
|
-
// 38
|
|
1146
|
-
[4, 152, 122, 18, 153, 123],
|
|
1147
|
-
[13, 74, 46, 32, 75, 47],
|
|
1148
|
-
[48, 54, 24, 14, 55, 25],
|
|
1149
|
-
[42, 45, 15, 32, 46, 16],
|
|
1150
|
-
// 39
|
|
1151
|
-
[20, 147, 117, 4, 148, 118],
|
|
1152
|
-
[40, 75, 47, 7, 76, 48],
|
|
1153
|
-
[43, 54, 24, 22, 55, 25],
|
|
1154
|
-
[10, 45, 15, 67, 46, 16],
|
|
1155
|
-
// 40
|
|
1156
|
-
[19, 148, 118, 6, 149, 119],
|
|
1157
|
-
[18, 75, 47, 31, 76, 48],
|
|
1158
|
-
[34, 54, 24, 34, 55, 25],
|
|
1159
|
-
[20, 45, 15, 61, 46, 16]
|
|
1160
|
-
];
|
|
1161
|
-
/**
|
|
1162
|
-
* @internal
|
|
1163
|
-
*/
|
|
1164
|
-
_totalCount;
|
|
1165
|
-
/**
|
|
1166
|
-
* @internal
|
|
1167
|
-
*/
|
|
1168
|
-
_dataCount;
|
|
1169
|
-
/**
|
|
1170
|
-
* Create a new instance of RSBlock.
|
|
1171
|
-
* @param totalCount The total count for the block.
|
|
1172
|
-
* @param dataCount The data count for the block.
|
|
1173
|
-
*/
|
|
1174
|
-
constructor(totalCount, dataCount) {
|
|
1175
|
-
this._totalCount = totalCount;
|
|
1176
|
-
this._dataCount = dataCount;
|
|
1177
|
-
}
|
|
1178
|
-
/**
|
|
1179
|
-
* Get RS Blocks for the type number and error correct level.
|
|
1180
|
-
* @param typeNumber The type number.
|
|
1181
|
-
* @param errorCorrectLevel The error correct level.
|
|
1182
|
-
* @returns The RS Blocks.
|
|
1183
|
-
*/
|
|
1184
|
-
static getRSBlocks(typeNumber, errorCorrectLevel) {
|
|
1185
|
-
const rsBlock = RSBlock.getRsBlockTable(typeNumber, errorCorrectLevel);
|
|
1186
|
-
const length = rsBlock.length / 3;
|
|
1187
|
-
const list = [];
|
|
1188
|
-
for (let i = 0; i < length; i++) {
|
|
1189
|
-
const count = rsBlock[i * 3 + 0];
|
|
1190
|
-
const totalCount = rsBlock[i * 3 + 1];
|
|
1191
|
-
const dataCount = rsBlock[i * 3 + 2];
|
|
1192
|
-
for (let j = 0; j < count; j++) {
|
|
1193
|
-
list.push(new RSBlock(totalCount, dataCount));
|
|
1194
|
-
}
|
|
1195
|
-
}
|
|
1196
|
-
return list;
|
|
1197
|
-
}
|
|
1198
|
-
/**
|
|
1199
|
-
* @internal
|
|
1200
|
-
*/
|
|
1201
|
-
static getRsBlockTable(typeNumber, errorCorrectLevel) {
|
|
1202
|
-
switch (errorCorrectLevel) {
|
|
1203
|
-
case ErrorCorrectLevel.L:
|
|
1204
|
-
return RSBlock._RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 0];
|
|
1205
|
-
case ErrorCorrectLevel.M:
|
|
1206
|
-
return RSBlock._RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 1];
|
|
1207
|
-
case ErrorCorrectLevel.Q:
|
|
1208
|
-
return RSBlock._RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 2];
|
|
1209
|
-
case ErrorCorrectLevel.H:
|
|
1210
|
-
return RSBlock._RS_BLOCK_TABLE[(typeNumber - 1) * 4 + 3];
|
|
1211
|
-
}
|
|
1212
|
-
throw new core.GeneralError(RSBlock._CLASS_NAME, "correctionLevelRange", { errorCorrectLevel });
|
|
1213
|
-
}
|
|
1214
|
-
/**
|
|
1215
|
-
* Get the data count of the block.
|
|
1216
|
-
* @returns The data count.
|
|
1217
|
-
*/
|
|
1218
|
-
getDataCount() {
|
|
1219
|
-
return this._dataCount;
|
|
1220
|
-
}
|
|
1221
|
-
/**
|
|
1222
|
-
* Get the total count of blocks.
|
|
1223
|
-
* @returns The total count.
|
|
1224
|
-
*/
|
|
1225
|
-
getTotalCount() {
|
|
1226
|
-
return this._totalCount;
|
|
1227
|
-
}
|
|
1228
|
-
}
|
|
1229
|
-
|
|
1230
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1231
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1232
|
-
/* eslint-disable no-bitwise */
|
|
1233
|
-
/* eslint-disable no-continue */
|
|
1234
|
-
/* eslint-disable no-mixed-operators */
|
|
1235
|
-
/**
|
|
1236
|
-
* Class to generates QR codes from data.
|
|
1237
|
-
* Based on https://github.com/kazuhikoarase/qrcode-generator/ .
|
|
1238
|
-
*/
|
|
1239
|
-
class QR {
|
|
1240
|
-
/**
|
|
1241
|
-
* Runtime name for the class.
|
|
1242
|
-
* @internal
|
|
1243
|
-
*/
|
|
1244
|
-
static _CLASS_NAME = "QR";
|
|
1245
|
-
/**
|
|
1246
|
-
* @internal
|
|
1247
|
-
*/
|
|
1248
|
-
static _PAD0 = 0xec;
|
|
1249
|
-
/**
|
|
1250
|
-
* @internal
|
|
1251
|
-
*/
|
|
1252
|
-
static _PAD1 = 0x11;
|
|
1253
|
-
/**
|
|
1254
|
-
* @internal
|
|
1255
|
-
*/
|
|
1256
|
-
_typeNumber;
|
|
1257
|
-
/**
|
|
1258
|
-
* @internal
|
|
1259
|
-
*/
|
|
1260
|
-
_errorCorrectLevel;
|
|
1261
|
-
/**
|
|
1262
|
-
* @internal
|
|
1263
|
-
*/
|
|
1264
|
-
_qrData;
|
|
1265
|
-
/**
|
|
1266
|
-
* @internal
|
|
1267
|
-
*/
|
|
1268
|
-
_modules;
|
|
1269
|
-
/**
|
|
1270
|
-
* @internal
|
|
1271
|
-
*/
|
|
1272
|
-
_moduleCount;
|
|
1273
|
-
/**
|
|
1274
|
-
* Create a new instance of QR.
|
|
1275
|
-
* @param typeNumber 0 to 40, 0 means autodetect.
|
|
1276
|
-
* @param errorCorrectLevel 'L','M','Q','H'.
|
|
1277
|
-
* @throws Error if the typeNumber is invalid.
|
|
1278
|
-
*/
|
|
1279
|
-
constructor(typeNumber = 6, errorCorrectLevel = ErrorCorrectLevel.L) {
|
|
1280
|
-
if (!core.Is.integer(typeNumber) || typeNumber < 0 || typeNumber > 40) {
|
|
1281
|
-
throw new core.GeneralError(QR._CLASS_NAME, "typeNumberRange", { typeNumber });
|
|
1282
|
-
}
|
|
1283
|
-
this._typeNumber = typeNumber;
|
|
1284
|
-
this._errorCorrectLevel = errorCorrectLevel;
|
|
1285
|
-
this._qrData = [];
|
|
1286
|
-
this._moduleCount = 0;
|
|
1287
|
-
this._modules = [];
|
|
1288
|
-
MathHelper.initialize();
|
|
1289
|
-
}
|
|
1290
|
-
/**
|
|
1291
|
-
* Add text data to the QR Code.
|
|
1292
|
-
* @param qrData The data to add.
|
|
1293
|
-
*/
|
|
1294
|
-
addText(qrData) {
|
|
1295
|
-
this._qrData.push(new QRByte8(qrData));
|
|
1296
|
-
}
|
|
1297
|
-
/**
|
|
1298
|
-
* Add number to the QR Code.
|
|
1299
|
-
* @param qrData The data to add.
|
|
1300
|
-
*/
|
|
1301
|
-
addNumber(qrData) {
|
|
1302
|
-
this._qrData.push(new QRNumber(qrData));
|
|
1303
|
-
}
|
|
1304
|
-
/**
|
|
1305
|
-
* Add alpha numeric to the QR Code.
|
|
1306
|
-
* @param qrData The data to add.
|
|
1307
|
-
*/
|
|
1308
|
-
addAlphaNumeric(qrData) {
|
|
1309
|
-
this._qrData.push(new QRAlphaNumeric(qrData));
|
|
1310
|
-
}
|
|
1311
|
-
/**
|
|
1312
|
-
* Generate the display buffer.
|
|
1313
|
-
* @returns Boolean buffer of pixels.
|
|
1314
|
-
*/
|
|
1315
|
-
generate() {
|
|
1316
|
-
this.autoDetectTypeNumber();
|
|
1317
|
-
this.makeImpl(false, this.getBestMaskPattern());
|
|
1318
|
-
const pixels = [];
|
|
1319
|
-
for (let y = 0; y < this._moduleCount; y++) {
|
|
1320
|
-
for (let x = 0; x < this._moduleCount; x++) {
|
|
1321
|
-
pixels[x] = pixels[x] || [];
|
|
1322
|
-
pixels[x][y] = this.isDark(y, x);
|
|
1323
|
-
}
|
|
1324
|
-
}
|
|
1325
|
-
return pixels;
|
|
1326
|
-
}
|
|
1327
|
-
/**
|
|
1328
|
-
* @internal
|
|
1329
|
-
*/
|
|
1330
|
-
isDark(row, col) {
|
|
1331
|
-
if (this._modules[row][col] !== null) {
|
|
1332
|
-
return this._modules[row][col];
|
|
1333
|
-
}
|
|
1334
|
-
return false;
|
|
1335
|
-
}
|
|
1336
|
-
/**
|
|
1337
|
-
* @internal
|
|
1338
|
-
*/
|
|
1339
|
-
getBestMaskPattern() {
|
|
1340
|
-
let minLostPoint = 0;
|
|
1341
|
-
let pattern = 0;
|
|
1342
|
-
for (let i = 0; i < 8; i++) {
|
|
1343
|
-
this.makeImpl(true, i);
|
|
1344
|
-
const lostPoint = this.getLostPoint();
|
|
1345
|
-
if (i === 0 || minLostPoint > lostPoint) {
|
|
1346
|
-
minLostPoint = lostPoint;
|
|
1347
|
-
pattern = i;
|
|
1348
|
-
}
|
|
1349
|
-
}
|
|
1350
|
-
return pattern;
|
|
1351
|
-
}
|
|
1352
|
-
/**
|
|
1353
|
-
* @internal
|
|
1354
|
-
*/
|
|
1355
|
-
makeImpl(test, maskPattern) {
|
|
1356
|
-
this._moduleCount = this._typeNumber * 4 + 17;
|
|
1357
|
-
this._modules = [];
|
|
1358
|
-
for (let i = 0; i < this._moduleCount; i++) {
|
|
1359
|
-
this._modules.push([]);
|
|
1360
|
-
for (let j = 0; j < this._moduleCount; j++) {
|
|
1361
|
-
this._modules[i].push(null);
|
|
1362
|
-
}
|
|
1363
|
-
}
|
|
1364
|
-
this.setupPositionProbePattern(0, 0);
|
|
1365
|
-
this.setupPositionProbePattern(this._moduleCount - 7, 0);
|
|
1366
|
-
this.setupPositionProbePattern(0, this._moduleCount - 7);
|
|
1367
|
-
this.setupPositionAdjustPattern();
|
|
1368
|
-
this.setupTimingPattern();
|
|
1369
|
-
this.setupTypeInfo(test, maskPattern);
|
|
1370
|
-
if (this._typeNumber >= 7) {
|
|
1371
|
-
this.setupTypeNumber(test);
|
|
1372
|
-
}
|
|
1373
|
-
const data = this.createData();
|
|
1374
|
-
this.mapData(data, maskPattern);
|
|
1375
|
-
}
|
|
1376
|
-
/**
|
|
1377
|
-
* @internal
|
|
1378
|
-
*/
|
|
1379
|
-
mapData(data, maskPattern) {
|
|
1380
|
-
let inc = -1;
|
|
1381
|
-
let row = this._moduleCount - 1;
|
|
1382
|
-
let bitIndex = 7;
|
|
1383
|
-
let byteIndex = 0;
|
|
1384
|
-
const maskFunc = QRHelper.getMaskMethod(maskPattern);
|
|
1385
|
-
for (let col = this._moduleCount - 1; col > 0; col -= 2) {
|
|
1386
|
-
if (col === 6) {
|
|
1387
|
-
col -= 1;
|
|
1388
|
-
}
|
|
1389
|
-
let flag = true;
|
|
1390
|
-
while (flag) {
|
|
1391
|
-
for (let c = 0; c < 2; c++) {
|
|
1392
|
-
if (this._modules[row][col - c] === null) {
|
|
1393
|
-
let dark = false;
|
|
1394
|
-
if (byteIndex < data.length) {
|
|
1395
|
-
dark = ((data[byteIndex] >>> bitIndex) & 1) === 1;
|
|
1396
|
-
}
|
|
1397
|
-
const mask = maskFunc(row, col - c);
|
|
1398
|
-
if (mask) {
|
|
1399
|
-
dark = !dark;
|
|
1400
|
-
}
|
|
1401
|
-
this._modules[row][col - c] = dark;
|
|
1402
|
-
bitIndex -= 1;
|
|
1403
|
-
if (bitIndex === -1) {
|
|
1404
|
-
byteIndex++;
|
|
1405
|
-
bitIndex = 7;
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
}
|
|
1409
|
-
row += inc;
|
|
1410
|
-
if (row < 0 || this._moduleCount <= row) {
|
|
1411
|
-
row -= inc;
|
|
1412
|
-
inc = -inc;
|
|
1413
|
-
flag = false;
|
|
1414
|
-
}
|
|
1415
|
-
}
|
|
1416
|
-
}
|
|
1417
|
-
}
|
|
1418
|
-
/**
|
|
1419
|
-
* @internal
|
|
1420
|
-
*/
|
|
1421
|
-
setupPositionAdjustPattern() {
|
|
1422
|
-
const pos = QRHelper.getPatternPosition(this._typeNumber);
|
|
1423
|
-
for (let i = 0; i < pos.length; i++) {
|
|
1424
|
-
for (let j = 0; j < pos.length; j++) {
|
|
1425
|
-
const row = pos[i];
|
|
1426
|
-
const col = pos[j];
|
|
1427
|
-
if (this._modules[row][col] !== null) {
|
|
1428
|
-
continue;
|
|
1429
|
-
}
|
|
1430
|
-
for (let r = -2; r <= 2; r++) {
|
|
1431
|
-
for (let c = -2; c <= 2; c++) {
|
|
1432
|
-
if (r === -2 || r === 2 || c === -2 || c === 2 || (r === 0 && c === 0)) {
|
|
1433
|
-
this._modules[row + r][col + c] = true;
|
|
1434
|
-
}
|
|
1435
|
-
else {
|
|
1436
|
-
this._modules[row + r][col + c] = false;
|
|
1437
|
-
}
|
|
1438
|
-
}
|
|
1439
|
-
}
|
|
1440
|
-
}
|
|
1441
|
-
}
|
|
1442
|
-
}
|
|
1443
|
-
/**
|
|
1444
|
-
* @internal
|
|
1445
|
-
*/
|
|
1446
|
-
setupPositionProbePattern(row, col) {
|
|
1447
|
-
for (let r = -1; r <= 7; r++) {
|
|
1448
|
-
for (let c = -1; c <= 7; c++) {
|
|
1449
|
-
if (row + r <= -1 ||
|
|
1450
|
-
this._moduleCount <= row + r ||
|
|
1451
|
-
col + c <= -1 ||
|
|
1452
|
-
this._moduleCount <= col + c) {
|
|
1453
|
-
continue;
|
|
1454
|
-
}
|
|
1455
|
-
if ((r >= 0 && r <= 6 && (c === 0 || c === 6)) ||
|
|
1456
|
-
(c >= 0 && c <= 6 && (r === 0 || r === 6)) ||
|
|
1457
|
-
(r >= 2 && r <= 4 && c >= 2 && c <= 4)) {
|
|
1458
|
-
this._modules[row + r][col + c] = true;
|
|
1459
|
-
}
|
|
1460
|
-
else {
|
|
1461
|
-
this._modules[row + r][col + c] = false;
|
|
1462
|
-
}
|
|
1463
|
-
}
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
/**
|
|
1467
|
-
* @internal
|
|
1468
|
-
*/
|
|
1469
|
-
setupTimingPattern() {
|
|
1470
|
-
for (let r = 8; r < this._moduleCount - 8; r++) {
|
|
1471
|
-
if (this._modules[r][6] !== null) {
|
|
1472
|
-
continue;
|
|
1473
|
-
}
|
|
1474
|
-
this._modules[r][6] = r % 2 === 0;
|
|
1475
|
-
}
|
|
1476
|
-
for (let c = 8; c < this._moduleCount - 8; c++) {
|
|
1477
|
-
if (this._modules[6][c] !== null) {
|
|
1478
|
-
continue;
|
|
1479
|
-
}
|
|
1480
|
-
this._modules[6][c] = c % 2 === 0;
|
|
1481
|
-
}
|
|
1482
|
-
}
|
|
1483
|
-
/**
|
|
1484
|
-
* @internal
|
|
1485
|
-
*/
|
|
1486
|
-
setupTypeNumber(test) {
|
|
1487
|
-
const bits = QRHelper.getBCHTypeNumber(this._typeNumber);
|
|
1488
|
-
for (let i = 0; i < 18; i++) {
|
|
1489
|
-
this._modules[~~(i / 3)][(i % 3) + this._moduleCount - 8 - 3] =
|
|
1490
|
-
!test && ((bits >> i) & 1) === 1;
|
|
1491
|
-
}
|
|
1492
|
-
for (let i = 0; i < 18; i++) {
|
|
1493
|
-
this._modules[(i % 3) + this._moduleCount - 8 - 3][~~(i / 3)] =
|
|
1494
|
-
!test && ((bits >> i) & 1) === 1;
|
|
1495
|
-
}
|
|
1496
|
-
}
|
|
1497
|
-
/**
|
|
1498
|
-
* @internal
|
|
1499
|
-
*/
|
|
1500
|
-
setupTypeInfo(test, maskPattern) {
|
|
1501
|
-
const data = (this._errorCorrectLevel << 3) | maskPattern;
|
|
1502
|
-
const bits = QRHelper.getBCHTypeInfo(data);
|
|
1503
|
-
// vertical
|
|
1504
|
-
for (let i = 0; i < 15; i++) {
|
|
1505
|
-
const mod = !test && ((bits >> i) & 1) === 1;
|
|
1506
|
-
if (i < 6) {
|
|
1507
|
-
this._modules[i][8] = mod;
|
|
1508
|
-
}
|
|
1509
|
-
else if (i < 8) {
|
|
1510
|
-
this._modules[i + 1][8] = mod;
|
|
1511
|
-
}
|
|
1512
|
-
else {
|
|
1513
|
-
this._modules[this._moduleCount - 15 + i][8] = mod;
|
|
1514
|
-
}
|
|
1515
|
-
}
|
|
1516
|
-
// horizontal
|
|
1517
|
-
for (let i = 0; i < 15; i++) {
|
|
1518
|
-
const mod = !test && ((bits >> i) & 1) === 1;
|
|
1519
|
-
if (i < 8) {
|
|
1520
|
-
this._modules[8][this._moduleCount - i - 1] = mod;
|
|
1521
|
-
}
|
|
1522
|
-
else if (i < 9) {
|
|
1523
|
-
this._modules[8][15 - i - 1 + 1] = mod;
|
|
1524
|
-
}
|
|
1525
|
-
else {
|
|
1526
|
-
this._modules[8][15 - i - 1] = mod;
|
|
1527
|
-
}
|
|
1528
|
-
}
|
|
1529
|
-
// fixed
|
|
1530
|
-
this._modules[this._moduleCount - 8][8] = !test;
|
|
1531
|
-
}
|
|
1532
|
-
/**
|
|
1533
|
-
* @internal
|
|
1534
|
-
*/
|
|
1535
|
-
getLostPoint() {
|
|
1536
|
-
const moduleCount = this._moduleCount;
|
|
1537
|
-
let lostPoint = 0;
|
|
1538
|
-
// LEVEL1
|
|
1539
|
-
for (let row = 0; row < moduleCount; row++) {
|
|
1540
|
-
for (let col = 0; col < moduleCount; col++) {
|
|
1541
|
-
let sameCount = 0;
|
|
1542
|
-
const dark = this.isDark(row, col);
|
|
1543
|
-
for (let r = -1; r <= 1; r++) {
|
|
1544
|
-
if (row + r < 0 || moduleCount <= row + r) {
|
|
1545
|
-
continue;
|
|
1546
|
-
}
|
|
1547
|
-
for (let c = -1; c <= 1; c++) {
|
|
1548
|
-
if (col + c < 0 || moduleCount <= col + c) {
|
|
1549
|
-
continue;
|
|
1550
|
-
}
|
|
1551
|
-
if (r === 0 && c === 0) {
|
|
1552
|
-
continue;
|
|
1553
|
-
}
|
|
1554
|
-
if (dark === this.isDark(row + r, col + c)) {
|
|
1555
|
-
sameCount++;
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
if (sameCount > 5) {
|
|
1560
|
-
lostPoint += 3 + sameCount - 5;
|
|
1561
|
-
}
|
|
1562
|
-
}
|
|
1563
|
-
}
|
|
1564
|
-
// LEVEL2
|
|
1565
|
-
for (let row = 0; row < moduleCount - 1; row++) {
|
|
1566
|
-
for (let col = 0; col < moduleCount - 1; col++) {
|
|
1567
|
-
let count = 0;
|
|
1568
|
-
if (this.isDark(row, col)) {
|
|
1569
|
-
count++;
|
|
1570
|
-
}
|
|
1571
|
-
if (this.isDark(row + 1, col)) {
|
|
1572
|
-
count++;
|
|
1573
|
-
}
|
|
1574
|
-
if (this.isDark(row, col + 1)) {
|
|
1575
|
-
count++;
|
|
1576
|
-
}
|
|
1577
|
-
if (this.isDark(row + 1, col + 1)) {
|
|
1578
|
-
count++;
|
|
1579
|
-
}
|
|
1580
|
-
if (count === 0 || count === 4) {
|
|
1581
|
-
lostPoint += 3;
|
|
1582
|
-
}
|
|
1583
|
-
}
|
|
1584
|
-
}
|
|
1585
|
-
// LEVEL3
|
|
1586
|
-
for (let row = 0; row < moduleCount; row++) {
|
|
1587
|
-
for (let col = 0; col < moduleCount - 6; col++) {
|
|
1588
|
-
if (this.isDark(row, col) &&
|
|
1589
|
-
!this.isDark(row, col + 1) &&
|
|
1590
|
-
this.isDark(row, col + 2) &&
|
|
1591
|
-
this.isDark(row, col + 3) &&
|
|
1592
|
-
this.isDark(row, col + 4) &&
|
|
1593
|
-
!this.isDark(row, col + 5) &&
|
|
1594
|
-
this.isDark(row, col + 6)) {
|
|
1595
|
-
lostPoint += 40;
|
|
1596
|
-
}
|
|
1597
|
-
}
|
|
1598
|
-
}
|
|
1599
|
-
for (let col = 0; col < moduleCount; col++) {
|
|
1600
|
-
for (let row = 0; row < moduleCount - 6; row++) {
|
|
1601
|
-
if (this.isDark(row, col) &&
|
|
1602
|
-
!this.isDark(row + 1, col) &&
|
|
1603
|
-
this.isDark(row + 2, col) &&
|
|
1604
|
-
this.isDark(row + 3, col) &&
|
|
1605
|
-
this.isDark(row + 4, col) &&
|
|
1606
|
-
!this.isDark(row + 5, col) &&
|
|
1607
|
-
this.isDark(row + 6, col)) {
|
|
1608
|
-
lostPoint += 40;
|
|
1609
|
-
}
|
|
1610
|
-
}
|
|
1611
|
-
}
|
|
1612
|
-
// LEVEL4
|
|
1613
|
-
let darkCount = 0;
|
|
1614
|
-
for (let col = 0; col < moduleCount; col++) {
|
|
1615
|
-
for (let row = 0; row < moduleCount; row++) {
|
|
1616
|
-
if (this.isDark(row, col)) {
|
|
1617
|
-
darkCount++;
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
}
|
|
1621
|
-
const ratio = Math.abs((100 * darkCount) / moduleCount / moduleCount - 50) / 5;
|
|
1622
|
-
lostPoint += ratio * 10;
|
|
1623
|
-
return lostPoint;
|
|
1624
|
-
}
|
|
1625
|
-
/**
|
|
1626
|
-
* @internal
|
|
1627
|
-
*/
|
|
1628
|
-
createData() {
|
|
1629
|
-
const rsBlocks = RSBlock.getRSBlocks(this._typeNumber, this._errorCorrectLevel);
|
|
1630
|
-
const buffer = new BitBuffer();
|
|
1631
|
-
for (let i = 0; i < this._qrData.length; i++) {
|
|
1632
|
-
const data = this._qrData[i];
|
|
1633
|
-
buffer.put(data.getMode(), 4);
|
|
1634
|
-
buffer.put(data.getLength(), data.getLengthInBits(this._typeNumber));
|
|
1635
|
-
data.write(buffer);
|
|
1636
|
-
}
|
|
1637
|
-
// calc max data count
|
|
1638
|
-
let totalDataCount = 0;
|
|
1639
|
-
for (let i = 0; i < rsBlocks.length; i++) {
|
|
1640
|
-
totalDataCount += rsBlocks[i].getDataCount();
|
|
1641
|
-
}
|
|
1642
|
-
if (buffer.getLengthInBits() > totalDataCount * 8) {
|
|
1643
|
-
throw new core.GeneralError(QR._CLASS_NAME, "dataOverflow", {
|
|
1644
|
-
lengthInBits: buffer.getLengthInBits(),
|
|
1645
|
-
totalDataCount,
|
|
1646
|
-
typeNumber: this._typeNumber
|
|
1647
|
-
});
|
|
1648
|
-
}
|
|
1649
|
-
// end
|
|
1650
|
-
if (buffer.getLengthInBits() + 4 <= totalDataCount * 8) {
|
|
1651
|
-
buffer.put(0, 4);
|
|
1652
|
-
}
|
|
1653
|
-
// padding
|
|
1654
|
-
while (buffer.getLengthInBits() % 8 !== 0) {
|
|
1655
|
-
buffer.putBit(false);
|
|
1656
|
-
}
|
|
1657
|
-
// padding
|
|
1658
|
-
let flag = true;
|
|
1659
|
-
while (flag) {
|
|
1660
|
-
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
1661
|
-
break;
|
|
1662
|
-
}
|
|
1663
|
-
buffer.put(QR._PAD0, 8);
|
|
1664
|
-
if (buffer.getLengthInBits() >= totalDataCount * 8) {
|
|
1665
|
-
flag = false;
|
|
1666
|
-
}
|
|
1667
|
-
else {
|
|
1668
|
-
buffer.put(QR._PAD1, 8);
|
|
1669
|
-
}
|
|
1670
|
-
}
|
|
1671
|
-
return this.createBytes(buffer, rsBlocks);
|
|
1672
|
-
}
|
|
1673
|
-
/**
|
|
1674
|
-
* @internal
|
|
1675
|
-
*/
|
|
1676
|
-
createBytes(buffer, rsBlocks) {
|
|
1677
|
-
let offset = 0;
|
|
1678
|
-
let maxDcCount = 0;
|
|
1679
|
-
let maxEcCount = 0;
|
|
1680
|
-
const dcData = [];
|
|
1681
|
-
const ecData = [];
|
|
1682
|
-
for (let r = 0; r < rsBlocks.length; r++) {
|
|
1683
|
-
dcData.push([]);
|
|
1684
|
-
ecData.push([]);
|
|
1685
|
-
}
|
|
1686
|
-
for (let r = 0; r < rsBlocks.length; r++) {
|
|
1687
|
-
const dcCount = rsBlocks[r].getDataCount();
|
|
1688
|
-
const ecCount = rsBlocks[r].getTotalCount() - dcCount;
|
|
1689
|
-
maxDcCount = Math.max(maxDcCount, dcCount);
|
|
1690
|
-
maxEcCount = Math.max(maxEcCount, ecCount);
|
|
1691
|
-
dcData[r] = this.createNumArray(dcCount);
|
|
1692
|
-
for (let i = 0; i < dcData[r].length; i++) {
|
|
1693
|
-
dcData[r][i] = 0xff & buffer.getBuffer()[i + offset];
|
|
1694
|
-
}
|
|
1695
|
-
offset += dcCount;
|
|
1696
|
-
const rsPoly = QRHelper.getErrorCorrectPolynomial(ecCount);
|
|
1697
|
-
const rawPoly = new Polynomial(dcData[r], rsPoly.getLength() - 1);
|
|
1698
|
-
const modPoly = rawPoly.mod(rsPoly);
|
|
1699
|
-
ecData[r] = this.createNumArray(rsPoly.getLength() - 1);
|
|
1700
|
-
for (let i = 0; i < ecData[r].length; i++) {
|
|
1701
|
-
const modIndex = i + modPoly.getLength() - ecData[r].length;
|
|
1702
|
-
ecData[r][i] = modIndex >= 0 ? modPoly.getAt(modIndex) : 0;
|
|
1703
|
-
}
|
|
1704
|
-
}
|
|
1705
|
-
let totalCodeCount = 0;
|
|
1706
|
-
for (let i = 0; i < rsBlocks.length; i++) {
|
|
1707
|
-
totalCodeCount += rsBlocks[i].getTotalCount();
|
|
1708
|
-
}
|
|
1709
|
-
const data = this.createNumArray(totalCodeCount);
|
|
1710
|
-
let index = 0;
|
|
1711
|
-
for (let i = 0; i < maxDcCount; i++) {
|
|
1712
|
-
for (let r = 0; r < rsBlocks.length; r++) {
|
|
1713
|
-
if (i < dcData[r].length) {
|
|
1714
|
-
data[index] = dcData[r][i];
|
|
1715
|
-
index++;
|
|
1716
|
-
}
|
|
1717
|
-
}
|
|
1718
|
-
}
|
|
1719
|
-
for (let i = 0; i < maxEcCount; i++) {
|
|
1720
|
-
for (let r = 0; r < rsBlocks.length; r++) {
|
|
1721
|
-
if (i < ecData[r].length) {
|
|
1722
|
-
data[index] = ecData[r][i];
|
|
1723
|
-
index++;
|
|
1724
|
-
}
|
|
1725
|
-
}
|
|
1726
|
-
}
|
|
1727
|
-
return data;
|
|
1728
|
-
}
|
|
1729
|
-
/**
|
|
1730
|
-
* @internal
|
|
1731
|
-
*/
|
|
1732
|
-
createNumArray(len) {
|
|
1733
|
-
const a = [];
|
|
1734
|
-
for (let i = 0; i < len; i++) {
|
|
1735
|
-
a.push(0);
|
|
1736
|
-
}
|
|
1737
|
-
return a;
|
|
1738
|
-
}
|
|
1739
|
-
/**
|
|
1740
|
-
* @internal
|
|
1741
|
-
*/
|
|
1742
|
-
autoDetectTypeNumber() {
|
|
1743
|
-
if (this._typeNumber === 0) {
|
|
1744
|
-
for (let typeNumber = 1; typeNumber <= 40; typeNumber++) {
|
|
1745
|
-
const rsBlocks = RSBlock.getRSBlocks(typeNumber, this._errorCorrectLevel);
|
|
1746
|
-
const buffer = new BitBuffer();
|
|
1747
|
-
for (let i = 0; i < this._qrData.length; i++) {
|
|
1748
|
-
const data = this._qrData[i];
|
|
1749
|
-
buffer.put(data.getMode(), 4);
|
|
1750
|
-
buffer.put(data.getLength(), data.getLengthInBits(typeNumber));
|
|
1751
|
-
data.write(buffer);
|
|
1752
|
-
}
|
|
1753
|
-
let totalDataCount = 0;
|
|
1754
|
-
for (let i = 0; i < rsBlocks.length; i++) {
|
|
1755
|
-
totalDataCount += rsBlocks[i].getDataCount();
|
|
1756
|
-
}
|
|
1757
|
-
if (buffer.getLengthInBits() <= totalDataCount * 8) {
|
|
1758
|
-
this._typeNumber = typeNumber;
|
|
1759
|
-
break;
|
|
1760
|
-
}
|
|
1761
|
-
if (typeNumber === 40) {
|
|
1762
|
-
throw new core.GeneralError(QR._CLASS_NAME, "typeNumberOverflow", {
|
|
1763
|
-
lengthInBits: buffer.getLengthInBits(),
|
|
1764
|
-
totalDataCount
|
|
1765
|
-
});
|
|
1766
|
-
}
|
|
1767
|
-
}
|
|
1768
|
-
}
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
|
|
1772
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1773
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1774
|
-
/* eslint-disable no-mixed-operators */
|
|
1775
|
-
/**
|
|
1776
|
-
* Class to render qr data as jpeg.
|
|
1777
|
-
*/
|
|
1778
|
-
class JpegRenderer {
|
|
1779
|
-
/**
|
|
1780
|
-
* Runtime name for the class.
|
|
1781
|
-
* @internal
|
|
1782
|
-
*/
|
|
1783
|
-
static _CLASS_NAME = "JpegRenderer";
|
|
1784
|
-
/**
|
|
1785
|
-
* Render the QR code data as a bitmap.
|
|
1786
|
-
* @param cellData The cell data for the QR code.
|
|
1787
|
-
* @param options The options for rendering.
|
|
1788
|
-
* @returns The bitmap content.
|
|
1789
|
-
*/
|
|
1790
|
-
static async render(cellData, options) {
|
|
1791
|
-
core.Guards.array(JpegRenderer._CLASS_NAME, "cellData", cellData);
|
|
1792
|
-
options = options ?? {};
|
|
1793
|
-
options.cellSize = options.cellSize ?? 5;
|
|
1794
|
-
options.marginSize = options.marginSize ?? 10;
|
|
1795
|
-
core.Guards.number("IRendererOptions", "options.cellSize", options?.cellSize);
|
|
1796
|
-
core.Guards.number("IRendererOptions", "options.marginSize", options?.marginSize);
|
|
1797
|
-
if (options?.cellSize <= 0) {
|
|
1798
|
-
throw new core.GeneralError("IRendererOptions", "cellSizeZero", {
|
|
1799
|
-
cellSize: options?.cellSize
|
|
1800
|
-
});
|
|
1801
|
-
}
|
|
1802
|
-
if (options?.marginSize <= 0) {
|
|
1803
|
-
throw new core.GeneralError("IRendererOptions", "marginSizeZero", {
|
|
1804
|
-
marginSize: options?.marginSize
|
|
1805
|
-
});
|
|
1806
|
-
}
|
|
1807
|
-
const background = image.Color.coerce(options?.background) ?? image.Color.fromHex("#FFFFFF");
|
|
1808
|
-
const foreground = image.Color.coerce(options?.foreground) ?? image.Color.fromHex("#000000");
|
|
1809
|
-
const dimensions = cellData.length * options?.cellSize + 2 * options?.marginSize;
|
|
1810
|
-
const data = new Uint8Array(dimensions * dimensions * 4);
|
|
1811
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
1812
|
-
data[i] = background.red();
|
|
1813
|
-
data[i + 1] = background.green();
|
|
1814
|
-
data[i + 2] = background.blue();
|
|
1815
|
-
data[i + 3] = 0xff;
|
|
1816
|
-
}
|
|
1817
|
-
let dc = options?.marginSize * dimensions * 4;
|
|
1818
|
-
for (let x = 0; x < cellData.length; x++) {
|
|
1819
|
-
const row = new Uint8Array(dimensions * 4);
|
|
1820
|
-
let r = 0;
|
|
1821
|
-
for (let i = 0; i < options?.marginSize; i++) {
|
|
1822
|
-
row[r++] = background.red();
|
|
1823
|
-
row[r++] = background.green();
|
|
1824
|
-
row[r++] = background.blue();
|
|
1825
|
-
row[r++] = 0xff;
|
|
1826
|
-
}
|
|
1827
|
-
for (let y = 0; y < cellData[x].length; y++) {
|
|
1828
|
-
const colour = cellData[y][x] ? foreground : background;
|
|
1829
|
-
for (let c = 0; c < options.cellSize; c++) {
|
|
1830
|
-
row[r++] = colour.red();
|
|
1831
|
-
row[r++] = colour.green();
|
|
1832
|
-
row[r++] = colour.blue();
|
|
1833
|
-
row[r++] = 0xff;
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1836
|
-
for (let i = 0; i < options.marginSize; i++) {
|
|
1837
|
-
row[r++] = background.red();
|
|
1838
|
-
row[r++] = background.green();
|
|
1839
|
-
row[r++] = background.blue();
|
|
1840
|
-
row[r++] = 0xff;
|
|
1841
|
-
}
|
|
1842
|
-
for (let c = 0; c < options.cellSize; c++) {
|
|
1843
|
-
data.set(row, dc);
|
|
1844
|
-
dc += row.length;
|
|
1845
|
-
}
|
|
1846
|
-
}
|
|
1847
|
-
return new image.JpegEncoder().encode(dimensions, dimensions, data, 75);
|
|
1848
|
-
}
|
|
1849
|
-
}
|
|
1850
|
-
|
|
1851
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1852
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1853
|
-
/* eslint-disable no-mixed-operators */
|
|
1854
|
-
/**
|
|
1855
|
-
* Class to render qr data as png.
|
|
1856
|
-
*/
|
|
1857
|
-
class PngRenderer {
|
|
1858
|
-
/**
|
|
1859
|
-
* Runtime name for the class.
|
|
1860
|
-
* @internal
|
|
1861
|
-
*/
|
|
1862
|
-
static _CLASS_NAME = "PngRenderer";
|
|
1863
|
-
/**
|
|
1864
|
-
* Render the QR code data as a bitmap.
|
|
1865
|
-
* @param cellData The cell data for the QR code.
|
|
1866
|
-
* @param options The options for rendering.
|
|
1867
|
-
* @returns The bitmap content.
|
|
1868
|
-
*/
|
|
1869
|
-
static async render(cellData, options) {
|
|
1870
|
-
core.Guards.array(PngRenderer._CLASS_NAME, "cellData", cellData);
|
|
1871
|
-
options = options ?? {};
|
|
1872
|
-
options.cellSize = options.cellSize ?? 5;
|
|
1873
|
-
options.marginSize = options.marginSize ?? 10;
|
|
1874
|
-
core.Guards.number("IRendererOptions", "options.cellSize", options?.cellSize);
|
|
1875
|
-
core.Guards.number("IRendererOptions", "options.marginSize", options?.marginSize);
|
|
1876
|
-
if (options?.cellSize <= 0) {
|
|
1877
|
-
throw new core.GeneralError("IRendererOptions", "cellSizeZero", {
|
|
1878
|
-
cellSize: options?.cellSize
|
|
1879
|
-
});
|
|
1880
|
-
}
|
|
1881
|
-
if (options?.marginSize <= 0) {
|
|
1882
|
-
throw new core.GeneralError("IRendererOptions", "marginSizeZero", {
|
|
1883
|
-
marginSize: options?.marginSize
|
|
1884
|
-
});
|
|
1885
|
-
}
|
|
1886
|
-
const background = image.Color.coerce(options?.background) ?? image.Color.fromHex("#FFFFFF");
|
|
1887
|
-
const foreground = image.Color.coerce(options?.foreground) ?? image.Color.fromHex("#000000");
|
|
1888
|
-
const dimensions = cellData.length * options?.cellSize + 2 * options?.marginSize;
|
|
1889
|
-
const data = new Uint8Array(dimensions * dimensions * 4);
|
|
1890
|
-
for (let i = 0; i < data.length; i += 4) {
|
|
1891
|
-
data[i] = background.red();
|
|
1892
|
-
data[i + 1] = background.green();
|
|
1893
|
-
data[i + 2] = background.blue();
|
|
1894
|
-
data[i + 3] = background.alpha();
|
|
1895
|
-
}
|
|
1896
|
-
let dc = options?.marginSize * dimensions * 4;
|
|
1897
|
-
for (let x = 0; x < cellData.length; x++) {
|
|
1898
|
-
const row = new Uint8Array(dimensions * 4);
|
|
1899
|
-
let r = 0;
|
|
1900
|
-
for (let i = 0; i < options?.marginSize; i++) {
|
|
1901
|
-
row[r++] = background.red();
|
|
1902
|
-
row[r++] = background.green();
|
|
1903
|
-
row[r++] = background.blue();
|
|
1904
|
-
row[r++] = background.alpha();
|
|
1905
|
-
}
|
|
1906
|
-
for (let y = 0; y < cellData[x].length; y++) {
|
|
1907
|
-
const colour = cellData[y][x] ? foreground : background;
|
|
1908
|
-
for (let c = 0; c < options?.cellSize; c++) {
|
|
1909
|
-
row[r++] = colour.red();
|
|
1910
|
-
row[r++] = colour.green();
|
|
1911
|
-
row[r++] = colour.blue();
|
|
1912
|
-
row[r++] = colour.alpha();
|
|
1913
|
-
}
|
|
1914
|
-
}
|
|
1915
|
-
for (let i = 0; i < options?.marginSize; i++) {
|
|
1916
|
-
row[r++] = background.red();
|
|
1917
|
-
row[r++] = background.green();
|
|
1918
|
-
row[r++] = background.blue();
|
|
1919
|
-
row[r++] = background.alpha();
|
|
1920
|
-
}
|
|
1921
|
-
for (let c = 0; c < options?.cellSize; c++) {
|
|
1922
|
-
data.set(row, dc);
|
|
1923
|
-
dc += row.length;
|
|
1924
|
-
}
|
|
1925
|
-
}
|
|
1926
|
-
return new image.PngEncoder().encode([data.buffer], dimensions, dimensions);
|
|
1927
|
-
}
|
|
1928
|
-
}
|
|
1929
|
-
|
|
1930
|
-
// Copyright 2024 IOTA Stiftung.
|
|
1931
|
-
// SPDX-License-Identifier: Apache-2.0.
|
|
1932
|
-
/**
|
|
1933
|
-
* Class to render qr data as text.
|
|
1934
|
-
*/
|
|
1935
|
-
class TextRenderer {
|
|
1936
|
-
/**
|
|
1937
|
-
* Runtime name for the class.
|
|
1938
|
-
* @internal
|
|
1939
|
-
*/
|
|
1940
|
-
static _CLASS_NAME = "TextRenderer";
|
|
1941
|
-
/**
|
|
1942
|
-
* Render the QR code data as text.
|
|
1943
|
-
* @param cellData The cell data for the QR code.
|
|
1944
|
-
* @param options The options for rendering.
|
|
1945
|
-
* @returns The text content.
|
|
1946
|
-
*/
|
|
1947
|
-
static async render(cellData, options) {
|
|
1948
|
-
core.Guards.array(TextRenderer._CLASS_NAME, "cellData", cellData);
|
|
1949
|
-
options = options ?? {};
|
|
1950
|
-
options.cellSize = options.cellSize ?? 1;
|
|
1951
|
-
options.marginSize = options.marginSize ?? 2;
|
|
1952
|
-
core.Guards.number("IRendererOptions", "options.cellSize", options?.cellSize);
|
|
1953
|
-
core.Guards.number("IRendererOptions", "options.marginSize", options?.marginSize);
|
|
1954
|
-
if (options?.cellSize <= 0) {
|
|
1955
|
-
throw new core.GeneralError("IRendererOptions", "cellSizeZero", {
|
|
1956
|
-
cellSize: options?.cellSize
|
|
1957
|
-
});
|
|
1958
|
-
}
|
|
1959
|
-
if (options?.marginSize <= 0) {
|
|
1960
|
-
throw new core.GeneralError("IRendererOptions", "marginSizeZero", {
|
|
1961
|
-
marginSize: options?.marginSize
|
|
1962
|
-
});
|
|
1963
|
-
}
|
|
1964
|
-
options.onChar = options.onChar ?? "██";
|
|
1965
|
-
options.offChar = options.offChar ?? " ";
|
|
1966
|
-
const marginSize = options?.marginSize;
|
|
1967
|
-
const cellSize = options?.cellSize;
|
|
1968
|
-
let text = "";
|
|
1969
|
-
for (let m = 0; m < marginSize; m++) {
|
|
1970
|
-
text += `${options.offChar.repeat(cellSize * cellData.length)}\r\n`;
|
|
1971
|
-
}
|
|
1972
|
-
for (let x = 0; x < cellData.length; x++) {
|
|
1973
|
-
let line = options.offChar.repeat(marginSize);
|
|
1974
|
-
for (let y = 0; y < cellData[x].length; y++) {
|
|
1975
|
-
if (cellData[y][x]) {
|
|
1976
|
-
line += options.onChar.repeat(cellSize);
|
|
1977
|
-
}
|
|
1978
|
-
else {
|
|
1979
|
-
line += options.offChar.repeat(cellSize);
|
|
1980
|
-
}
|
|
1981
|
-
}
|
|
1982
|
-
line += options.offChar.repeat(marginSize);
|
|
1983
|
-
line += "\r\n";
|
|
1984
|
-
for (let c = 0; c < cellSize; c++) {
|
|
1985
|
-
text += line;
|
|
1986
|
-
}
|
|
1987
|
-
}
|
|
1988
|
-
for (let m = 0; m < marginSize; m++) {
|
|
1989
|
-
text += `${options.offChar.repeat(cellSize * cellData.length)}\r\n`;
|
|
1990
|
-
}
|
|
1991
|
-
return text;
|
|
1992
|
-
}
|
|
1993
|
-
}
|
|
1994
|
-
|
|
1995
|
-
exports.ErrorCorrectLevel = ErrorCorrectLevel;
|
|
1996
|
-
exports.JpegRenderer = JpegRenderer;
|
|
1997
|
-
exports.PngRenderer = PngRenderer;
|
|
1998
|
-
exports.QR = QR;
|
|
1999
|
-
exports.TextRenderer = TextRenderer;
|