@vkontakte/vk-qr 2.0.13 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/qr.ts CHANGED
@@ -21,8 +21,6 @@
21
21
  * Software.
22
22
  */
23
23
 
24
- 'use strict';
25
-
26
24
  type bit = number;
27
25
  type byte = number;
28
26
  type int = number;
@@ -53,7 +51,7 @@ export class QrCode {
53
51
  // Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
54
52
  // QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
55
53
  // ecl argument if it can be done without increasing the version.
56
- public static encodeText(text: string, ecl: QrCode.Ecc): QrCode {
54
+ public static encodeText(text: string, ecl: QrCodeEcc): QrCode {
57
55
  const segs: Array<QrSegment> = QrSegment.makeSegments(text);
58
56
  return QrCode.encodeSegments(segs, ecl);
59
57
  }
@@ -62,7 +60,7 @@ export class QrCode {
62
60
  // This function always encodes using the binary segment mode, not any text mode. The maximum number of
63
61
  // bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
64
62
  // The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
65
- public static encodeBinary(data: Array<byte>, ecl: QrCode.Ecc): QrCode {
63
+ public static encodeBinary(data: Array<byte>, ecl: QrCodeEcc): QrCode {
66
64
  const seg: QrSegment = QrSegment.makeBytes(data);
67
65
  return QrCode.encodeSegments([seg], ecl);
68
66
  }
@@ -80,14 +78,18 @@ export class QrCode {
80
78
  // This is a mid-level API; the high-level API is encodeText() and encodeBinary().
81
79
  public static encodeSegments(
82
80
  segs: Array<QrSegment>,
83
- ecl: QrCode.Ecc,
81
+ ecl: QrCodeEcc,
84
82
  minVersion: int = 1,
85
83
  maxVersion: int = 40,
86
84
  mask: int = -1,
87
- boostEcl: boolean = true
85
+ boostEcl: boolean = true,
88
86
  ): QrCode {
89
87
  if (
90
- !(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION) ||
88
+ !(
89
+ QrCode.MIN_VERSION <= minVersion &&
90
+ minVersion <= maxVersion &&
91
+ maxVersion <= QrCode.MAX_VERSION
92
+ ) ||
91
93
  mask < -1 ||
92
94
  mask > 7
93
95
  )
@@ -109,34 +111,37 @@ export class QrCode {
109
111
  }
110
112
 
111
113
  // Increase the error correction level while the data still fits in the current version number
112
- for (const newEcl of [QrCode.Ecc.MEDIUM, QrCode.Ecc.QUARTILE, QrCode.Ecc.HIGH]) {
114
+ for (const newEcl of [QrCodeEcc.MEDIUM, QrCodeEcc.QUARTILE, QrCodeEcc.HIGH]) {
113
115
  // From low to high
114
116
  if (boostEcl && dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8) ecl = newEcl;
115
117
  }
116
118
 
117
119
  // Concatenate all segments to create the data bit string
118
- let bb = new BitBuffer();
120
+ const bb = new BitBuffer();
119
121
  for (const seg of segs) {
120
122
  bb.appendBits(seg.mode.modeBits, 4);
121
123
  bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
122
124
  for (const b of seg.getData()) bb.array.push(b);
123
125
  }
124
- if (bb.array.length != dataUsedBits) throw 'Assertion error';
126
+ if (bb.array.length !== dataUsedBits) throw 'Assertion error';
125
127
 
126
128
  // Add terminator and pad up to a byte if applicable
127
129
  const dataCapacityBits: int = QrCode.getNumDataCodewords(version, ecl) * 8;
128
130
  if (bb.array.length > dataCapacityBits) throw 'Assertion error';
129
131
  bb.appendBits(0, Math.min(4, dataCapacityBits - bb.array.length));
130
132
  bb.appendBits(0, (8 - (bb.array.length % 8)) % 8);
131
- if (bb.array.length % 8 != 0) throw 'Assertion error';
133
+ if (bb.array.length % 8 !== 0) throw 'Assertion error';
132
134
 
133
135
  // Pad with alternating bytes until data capacity is reached
134
- for (let padByte = 0xec; bb.array.length < dataCapacityBits; padByte ^= 0xec ^ 0x11) bb.appendBits(padByte, 8);
136
+ for (let padByte = 0xec; bb.array.length < dataCapacityBits; padByte ^= 0xec ^ 0x11)
137
+ bb.appendBits(padByte, 8);
135
138
 
136
139
  // Pack bits into bytes in big endian
137
- let dataCodewords: Array<byte> = [];
140
+ const dataCodewords: Array<byte> = [];
138
141
  while (dataCodewords.length * 8 < bb.array.length) dataCodewords.push(0);
139
- bb.array.forEach((b: bit, i: int) => (dataCodewords[i >>> 3] |= b << (7 - (i & 7))));
142
+ bb.array.forEach((b: bit, i: int) => {
143
+ dataCodewords[i >>> 3] |= b << (7 - (i & 7));
144
+ });
140
145
 
141
146
  // Create the QR Code object
142
147
  return new QrCode(version, ecl, dataCodewords, mask);
@@ -157,32 +162,38 @@ export class QrCode {
157
162
 
158
163
  /*-- Constructor (low level) and fields --*/
159
164
 
165
+ // The version number of this QR Code, which is between 1 and 40 (inclusive).
166
+ // This determines the size of this barcode.
167
+ public readonly version: int;
168
+
169
+ // The error correction level used in this QR Code.
170
+ public readonly errorCorrectionLevel: QrCodeEcc;
171
+
172
+ // The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
173
+ // Even if a QR Code is created with automatic masking requested (mask = -1),
174
+ // the resulting object still has a mask value between 0 and 7.
175
+ public readonly mask: int;
176
+
160
177
  // Creates a new QR Code with the given version number,
161
178
  // error correction level, data codeword bytes, and mask number.
162
179
  // This is a low-level API that most users should not use directly.
163
180
  // A mid-level API is the encodeSegments() function.
164
181
  public constructor(
165
- // The version number of this QR Code, which is between 1 and 40 (inclusive).
166
- // This determines the size of this barcode.
167
- public readonly version: int,
168
-
169
- // The error correction level used in this QR Code.
170
- public readonly errorCorrectionLevel: QrCode.Ecc,
171
-
182
+ version: int,
183
+ errorCorrectionLevel: QrCodeEcc,
172
184
  dataCodewords: Array<byte>,
173
-
174
- // The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
175
- // Even if a QR Code is created with automatic masking requested (mask = -1),
176
- // the resulting object still has a mask value between 0 and 7.
177
- public readonly mask: int
185
+ mask: int,
178
186
  ) {
179
187
  // Check scalar arguments
180
- if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION) throw 'Version value out of range';
188
+ if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION)
189
+ throw 'Version value out of range';
181
190
  if (mask < -1 || mask > 7) throw 'Mask value out of range';
191
+ this.version = version;
192
+ this.errorCorrectionLevel = errorCorrectionLevel;
182
193
  this.size = version * 4 + 17;
183
194
 
184
195
  // Initialize both grids to be size*size arrays of Boolean false
185
- let row: Array<boolean> = [];
196
+ const row: Array<boolean> = [];
186
197
  for (let i = 0; i < this.size; i++) row.push(false);
187
198
  for (let i = 0; i < this.size; i++) {
188
199
  this.modules.push(row.slice()); // Initially all white
@@ -195,7 +206,7 @@ export class QrCode {
195
206
  this.drawCodewords(allCodewords);
196
207
 
197
208
  // Do masking
198
- if (mask == -1) {
209
+ if (mask === -1) {
199
210
  // Automatically choose best mask
200
211
  let minPenalty: int = 1000000000;
201
212
  for (let i = 0; i < 8; i++) {
@@ -228,29 +239,11 @@ export class QrCode {
228
239
 
229
240
  /*-- Public instance methods --*/
230
241
 
231
- // Draws this QR Code, with the given module scale and border modules, onto the given HTML
232
- // canvas element. The canvas's width and height is resized to (this.size + border * 2) * scale.
233
- // The drawn image is be purely black and white, and fully opaque.
234
- // The scale must be a positive integer and the border must be a non-negative integer.
235
- public drawCanvas(scale: int, border: int, canvas: HTMLCanvasElement): void {
236
- if (scale <= 0 || border < 0) throw 'Value out of range';
237
- const width: int = (this.size + border * 2) * scale;
238
- canvas.width = width;
239
- canvas.height = width;
240
- let ctx = canvas.getContext('2d') as CanvasRenderingContext2D;
241
- for (let y = -border; y < this.size + border; y++) {
242
- for (let x = -border; x < this.size + border; x++) {
243
- ctx.fillStyle = this.getModule(x, y) ? '#000000' : '#FFFFFF';
244
- ctx.fillRect((x + border) * scale, (y + border) * scale, scale, scale);
245
- }
246
- }
247
- }
248
-
249
242
  // Returns a string of SVG code for an image depicting this QR Code, with the given number
250
243
  // of border modules. The string always uses Unix newlines (\n), regardless of the platform.
251
244
  public toSvgString(border: int): string {
252
245
  if (border < 0) throw 'Border must be non-negative';
253
- let parts: Array<string> = [];
246
+ const parts: Array<string> = [];
254
247
  for (let y = 0; y < this.size; y++) {
255
248
  for (let x = 0; x < this.size; x++) {
256
249
  if (this.getModule(x, y)) parts.push(`M${x + border},${y + border}h1v1h-1z`);
@@ -258,8 +251,9 @@ export class QrCode {
258
251
  }
259
252
  return `<?xml version="1.0" encoding="UTF-8"?>
260
253
  <!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
261
- <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 ${this.size + border * 2} ${this.size +
262
- border * 2}" stroke="none">
254
+ <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 ${this.size + border * 2} ${
255
+ this.size + border * 2
256
+ }" stroke="none">
263
257
  <rect width="100%" height="100%" fill="#FFFFFF"/>
264
258
  <path d="${parts.join(' ')}" fill="#000000"/>
265
259
  </svg>
@@ -272,8 +266,8 @@ export class QrCode {
272
266
  private drawFunctionPatterns(): void {
273
267
  // Draw horizontal and vertical timing patterns
274
268
  for (let i = 0; i < this.size; i++) {
275
- this.setFunctionModule(6, i, i % 2 == 0);
276
- this.setFunctionModule(i, 6, i % 2 == 0);
269
+ this.setFunctionModule(6, i, i % 2 === 0);
270
+ this.setFunctionModule(i, 6, i % 2 === 0);
277
271
  }
278
272
 
279
273
  // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
@@ -287,7 +281,13 @@ export class QrCode {
287
281
  for (let i = 0; i < numAlign; i++) {
288
282
  for (let j = 0; j < numAlign; j++) {
289
283
  // Don't draw on the three finder corners
290
- if (!((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0)))
284
+ if (
285
+ !(
286
+ (i === 0 && j === 0) ||
287
+ (i === 0 && j === numAlign - 1) ||
288
+ (i === numAlign - 1 && j === 0)
289
+ )
290
+ )
291
291
  this.drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
292
292
  }
293
293
  }
@@ -305,7 +305,7 @@ export class QrCode {
305
305
  let rem: int = data;
306
306
  for (let i = 0; i < 10; i++) rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
307
307
  const bits = ((data << 10) | rem) ^ 0x5412; // uint15
308
- if (bits >>> 15 != 0) throw 'Assertion error';
308
+ if (bits >>> 15 !== 0) throw 'Assertion error';
309
309
 
310
310
  // Draw first copy
311
311
  for (let i = 0; i <= 5; i++) this.setFunctionModule(8, i, getBit(bits, i));
@@ -329,7 +329,7 @@ export class QrCode {
329
329
  let rem: int = this.version; // version is uint6, in the range [7, 40]
330
330
  for (let i = 0; i < 12; i++) rem = (rem << 1) ^ ((rem >>> 11) * 0x1f25);
331
331
  const bits: int = (this.version << 12) | rem; // uint18
332
- if (bits >>> 18 != 0) throw 'Assertion error';
332
+ if (bits >>> 18 !== 0) throw 'Assertion error';
333
333
 
334
334
  // Draw two copies
335
335
  for (let i = 0; i < 18; i++) {
@@ -350,7 +350,7 @@ export class QrCode {
350
350
  const xx: int = x + dx;
351
351
  const yy: int = y + dy;
352
352
  if (0 <= xx && xx < this.size && 0 <= yy && yy < this.size)
353
- this.setFunctionModule(xx, yy, dist != 2 && dist != 4);
353
+ this.setFunctionModule(xx, yy, dist !== 2 && dist !== 4);
354
354
  }
355
355
  }
356
356
  }
@@ -360,7 +360,7 @@ export class QrCode {
360
360
  private drawAlignmentPattern(x: int, y: int): void {
361
361
  for (let dy = -2; dy <= 2; dy++) {
362
362
  for (let dx = -2; dx <= 2; dx++)
363
- this.setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1);
363
+ this.setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) !== 1);
364
364
  }
365
365
  }
366
366
 
@@ -377,8 +377,8 @@ export class QrCode {
377
377
  // codewords appended to it, based on this object's version and error correction level.
378
378
  private addEccAndInterleave(data: Array<byte>): Array<byte> {
379
379
  const ver: int = this.version;
380
- const ecl: QrCode.Ecc = this.errorCorrectionLevel;
381
- if (data.length != QrCode.getNumDataCodewords(ver, ecl)) throw 'Invalid argument';
380
+ const ecl: QrCodeEcc = this.errorCorrectionLevel;
381
+ if (data.length !== QrCode.getNumDataCodewords(ver, ecl)) throw 'Invalid argument';
382
382
 
383
383
  // Calculate parameter numbers
384
384
  const numBlocks: int = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
@@ -388,10 +388,13 @@ export class QrCode {
388
388
  const shortBlockLen: int = Math.floor(rawCodewords / numBlocks);
389
389
 
390
390
  // Split data into blocks and append ECC to each block
391
- let blocks: Array<Array<byte>> = [];
391
+ const blocks: Array<Array<byte>> = [];
392
392
  const rs = new ReedSolomonGenerator(blockEccLen);
393
393
  for (let i = 0, k = 0; i < numBlocks; i++) {
394
- let dat: Array<byte> = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
394
+ const dat: Array<byte> = data.slice(
395
+ k,
396
+ k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1),
397
+ );
395
398
  k += dat.length;
396
399
  const ecc: Array<byte> = rs.getRemainder(dat);
397
400
  if (i < numShortBlocks) dat.push(0);
@@ -399,31 +402,32 @@ export class QrCode {
399
402
  }
400
403
 
401
404
  // Interleave (not concatenate) the bytes from every block into a single sequence
402
- let result: Array<byte> = [];
405
+ const result: Array<byte> = [];
403
406
  for (let i = 0; i < blocks[0].length; i++) {
404
407
  for (let j = 0; j < blocks.length; j++) {
405
408
  // Skip the padding byte in short blocks
406
- if (i != shortBlockLen - blockEccLen || j >= numShortBlocks) result.push(blocks[j][i]);
409
+ if (i !== shortBlockLen - blockEccLen || j >= numShortBlocks) result.push(blocks[j][i]);
407
410
  }
408
411
  }
409
- if (result.length != rawCodewords) throw 'Assertion error';
412
+ if (result.length !== rawCodewords) throw 'Assertion error';
410
413
  return result;
411
414
  }
412
415
 
413
416
  // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
414
417
  // data area of this QR Code. Function modules need to be marked off before this is called.
415
418
  private drawCodewords(data: Array<byte>): void {
416
- if (data.length != Math.floor(QrCode.getNumRawDataModules(this.version) / 8)) throw 'Invalid argument';
419
+ if (data.length !== Math.floor(QrCode.getNumRawDataModules(this.version) / 8))
420
+ throw 'Invalid argument';
417
421
  let i: int = 0; // Bit index into the data
418
422
  // Do the funny zigzag scan
419
423
  for (let right = this.size - 1; right >= 1; right -= 2) {
420
424
  // Index of right column in each column pair
421
- if (right == 6) right = 5;
425
+ if (right === 6) right = 5;
422
426
  for (let vert = 0; vert < this.size; vert++) {
423
427
  // Vertical counter
424
428
  for (let j = 0; j < 2; j++) {
425
429
  const x: int = right - j; // Actual x coordinate
426
- const upward: boolean = ((right + 1) & 2) == 0;
430
+ const upward: boolean = ((right + 1) & 2) === 0;
427
431
  const y: int = upward ? this.size - 1 - vert : vert; // Actual y coordinate
428
432
  if (!this.isFunction[y][x] && i < data.length * 8) {
429
433
  this.modules[y][x] = getBit(data[i >>> 3], 7 - (i & 7));
@@ -434,7 +438,7 @@ export class QrCode {
434
438
  }
435
439
  }
436
440
  }
437
- if (i != data.length * 8) throw 'Assertion error';
441
+ if (i !== data.length * 8) throw 'Assertion error';
438
442
  }
439
443
 
440
444
  // XORs the codeword modules in this QR Code with the given mask pattern.
@@ -449,28 +453,28 @@ export class QrCode {
449
453
  let invert: boolean;
450
454
  switch (mask) {
451
455
  case 0:
452
- invert = (x + y) % 2 == 0;
456
+ invert = (x + y) % 2 === 0;
453
457
  break;
454
458
  case 1:
455
- invert = y % 2 == 0;
459
+ invert = y % 2 === 0;
456
460
  break;
457
461
  case 2:
458
- invert = x % 3 == 0;
462
+ invert = x % 3 === 0;
459
463
  break;
460
464
  case 3:
461
- invert = (x + y) % 3 == 0;
465
+ invert = (x + y) % 3 === 0;
462
466
  break;
463
467
  case 4:
464
- invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0;
468
+ invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 === 0;
465
469
  break;
466
470
  case 5:
467
- invert = ((x * y) % 2) + ((x * y) % 3) == 0;
471
+ invert = ((x * y) % 2) + ((x * y) % 3) === 0;
468
472
  break;
469
473
  case 6:
470
- invert = (((x * y) % 2) + ((x * y) % 3)) % 2 == 0;
474
+ invert = (((x * y) % 2) + ((x * y) % 3)) % 2 === 0;
471
475
  break;
472
476
  case 7:
473
- invert = (((x + y) % 2) + ((x * y) % 3)) % 2 == 0;
477
+ invert = (((x + y) % 2) + ((x * y) % 3)) % 2 === 0;
474
478
  break;
475
479
  default:
476
480
  throw 'Assertion error';
@@ -487,13 +491,13 @@ export class QrCode {
487
491
 
488
492
  // Adjacent modules in row having same color, and finder-like patterns
489
493
  for (let y = 0; y < this.size; y++) {
490
- let runHistory = [0, 0, 0, 0, 0, 0, 0];
494
+ const runHistory = [0, 0, 0, 0, 0, 0, 0];
491
495
  let color = false;
492
496
  let runX = 0;
493
497
  for (let x = 0; x < this.size; x++) {
494
- if (this.modules[y][x] == color) {
498
+ if (this.modules[y][x] === color) {
495
499
  runX++;
496
- if (runX == 5) result += QrCode.PENALTY_N1;
500
+ if (runX === 5) result += QrCode.PENALTY_N1;
497
501
  else if (runX > 5) result++;
498
502
  } else {
499
503
  QrCode.addRunToHistory(runX, runHistory);
@@ -508,13 +512,13 @@ export class QrCode {
508
512
  }
509
513
  // Adjacent modules in column having same color, and finder-like patterns
510
514
  for (let x = 0; x < this.size; x++) {
511
- let runHistory = [0, 0, 0, 0, 0, 0, 0];
515
+ const runHistory = [0, 0, 0, 0, 0, 0, 0];
512
516
  let color = false;
513
517
  let runY = 0;
514
518
  for (let y = 0; y < this.size; y++) {
515
- if (this.modules[y][x] == color) {
519
+ if (this.modules[y][x] === color) {
516
520
  runY++;
517
- if (runY == 5) result += QrCode.PENALTY_N1;
521
+ if (runY === 5) result += QrCode.PENALTY_N1;
518
522
  else if (runY > 5) result++;
519
523
  } else {
520
524
  QrCode.addRunToHistory(runY, runHistory);
@@ -532,7 +536,11 @@ export class QrCode {
532
536
  for (let y = 0; y < this.size - 1; y++) {
533
537
  for (let x = 0; x < this.size - 1; x++) {
534
538
  const color: boolean = this.modules[y][x];
535
- if (color == this.modules[y][x + 1] && color == this.modules[y + 1][x] && color == this.modules[y + 1][x + 1])
539
+ if (
540
+ color === this.modules[y][x + 1] &&
541
+ color === this.modules[y + 1][x] &&
542
+ color === this.modules[y + 1][x + 1]
543
+ )
536
544
  result += QrCode.PENALTY_N2;
537
545
  }
538
546
  }
@@ -557,11 +565,12 @@ export class QrCode {
557
565
  // Each position is in the range [0,177), and are used on both the x and y axes.
558
566
  // This could be implemented as lookup table of 40 variable-length lists of integers.
559
567
  private getAlignmentPatternPositions(): Array<int> {
560
- if (this.version == 1) return [];
568
+ if (this.version === 1) return [];
561
569
  else {
562
570
  const numAlign: int = Math.floor(this.version / 7) + 2;
563
- const step: int = this.version == 32 ? 26 : Math.ceil((this.size - 13) / (numAlign * 2 - 2)) * 2;
564
- let result: Array<int> = [6];
571
+ const step: int =
572
+ this.version === 32 ? 26 : Math.ceil((this.size - 13) / (numAlign * 2 - 2)) * 2;
573
+ const result: Array<int> = [6];
565
574
  for (let pos = this.size - 7; result.length < numAlign; pos -= step) result.splice(1, 0, pos);
566
575
  return result;
567
576
  }
@@ -584,10 +593,11 @@ export class QrCode {
584
593
  // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
585
594
  // QR Code of the given version number and error correction level, with remainder bits discarded.
586
595
  // This stateless pure function could be implemented as a (40*4)-cell lookup table.
587
- private static getNumDataCodewords(ver: int, ecl: QrCode.Ecc): int {
596
+ private static getNumDataCodewords(ver: int, ecl: QrCodeEcc): int {
588
597
  return (
589
598
  Math.floor(QrCode.getNumRawDataModules(ver) / 8) -
590
- QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] * QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]
599
+ QrCode.ECC_CODEWORDS_PER_BLOCK[ecl.ordinal][ver] *
600
+ QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver]
591
601
  );
592
602
  }
593
603
 
@@ -605,10 +615,10 @@ export class QrCode {
605
615
  const n: int = runHistory[1];
606
616
  return (
607
617
  n > 0 &&
608
- runHistory[2] == n &&
609
- runHistory[4] == n &&
610
- runHistory[5] == n &&
611
- runHistory[3] == n * 3 &&
618
+ runHistory[2] === n &&
619
+ runHistory[4] === n &&
620
+ runHistory[5] === n &&
621
+ runHistory[3] === n * 3 &&
612
622
  Math.max(runHistory[0], runHistory[6]) >= n * 4
613
623
  );
614
624
  }
@@ -631,13 +641,25 @@ export class QrCode {
631
641
  // Version: (note that index 0 is for padding, and is set to an illegal value)
632
642
  //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
633
643
  // prettier-ignore
634
- [-1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30, 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // Low
644
+ [
645
+ -1, 7, 10, 15, 20, 26, 18, 20, 24, 30, 18, 20, 24, 26, 30, 22, 24, 28, 30, 28, 28, 28, 28, 30,
646
+ 30, 26, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
647
+ ], // Low
635
648
  // prettier-ignore
636
- [-1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28], // Medium
649
+ [
650
+ -1, 10, 16, 26, 18, 24, 16, 18, 22, 22, 26, 30, 22, 22, 24, 24, 28, 28, 26, 26, 26, 26, 28,
651
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
652
+ ], // Medium
637
653
  // prettier-ignore
638
- [-1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30, 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30], // Quartile
654
+ [
655
+ -1, 13, 22, 18, 26, 18, 24, 18, 22, 20, 24, 28, 26, 24, 20, 30, 24, 28, 28, 26, 30, 28, 30,
656
+ 30, 30, 30, 28, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
657
+ ], // Quartile
639
658
  // prettier-ignore
640
- [-1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30] // High
659
+ [
660
+ -1, 17, 28, 22, 16, 22, 28, 26, 26, 24, 28, 24, 28, 22, 24, 24, 30, 28, 28, 26, 28, 30, 24,
661
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
662
+ ], // High
641
663
  /* eslint-enable */
642
664
  ];
643
665
 
@@ -646,20 +668,32 @@ export class QrCode {
646
668
  // Version: (note that index 0 is for padding, and is set to an illegal value)
647
669
  //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
648
670
  // prettier-ignore
649
- [-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25], // Low
671
+ [
672
+ -1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13,
673
+ 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25,
674
+ ], // Low
650
675
  // prettier-ignore
651
- [-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49 ], // Medium
676
+ [
677
+ -1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23,
678
+ 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49,
679
+ ], // Medium
652
680
  // prettier-ignore
653
- [-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68], // Quartile
681
+ [
682
+ -1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29,
683
+ 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68,
684
+ ], // Quartile
654
685
  // prettier-ignore
655
- [-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81] // High
686
+ [
687
+ -1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35,
688
+ 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81,
689
+ ], // High
656
690
  /* eslint-enable */
657
691
  ];
658
692
  }
659
693
 
660
694
  // Returns true iff the i'th bit of x is set to 1.
661
695
  function getBit(x: int, i: int): boolean {
662
- return ((x >>> i) & 1) != 0;
696
+ return ((x >>> i) & 1) !== 0;
663
697
  }
664
698
 
665
699
  /*---- Data segment class ----*/
@@ -682,30 +716,31 @@ export class QrSegment {
682
716
  // byte mode. All input byte arrays are acceptable. Any text string
683
717
  // can be converted to UTF-8 bytes and encoded as a byte mode segment.
684
718
  public static makeBytes(data: Array<byte>): QrSegment {
685
- let bb = new BitBuffer();
719
+ const bb = new BitBuffer();
686
720
  for (const b of data) bb.appendBits(b, 8);
687
- return new QrSegment(QrSegment.Mode.BYTE, data.length, bb.array);
721
+ return new QrSegment(QrSegmentMode.BYTE, data.length, bb.array);
688
722
  }
689
723
 
690
724
  // Returns a segment representing the given string of decimal digits encoded in numeric mode.
691
725
  public static makeNumeric(digits: string): QrSegment {
692
- if (!this.NUMERIC_REGEX.test(digits)) throw 'String contains non-numeric characters';
693
- let bb = new BitBuffer();
726
+ if (!QrSegment.NUMERIC_REGEX.test(digits)) throw 'String contains non-numeric characters';
727
+ const bb = new BitBuffer();
694
728
  for (let i = 0; i < digits.length; ) {
695
729
  // Consume up to 3 digits per iteration
696
730
  const n: int = Math.min(digits.length - i, 3);
697
731
  bb.appendBits(parseInt(digits.substr(i, n), 10), n * 3 + 1);
698
732
  i += n;
699
733
  }
700
- return new QrSegment(QrSegment.Mode.NUMERIC, digits.length, bb.array);
734
+ return new QrSegment(QrSegmentMode.NUMERIC, digits.length, bb.array);
701
735
  }
702
736
 
703
737
  // Returns a segment representing the given text string encoded in alphanumeric mode.
704
738
  // The characters allowed are: 0 to 9, A to Z (uppercase only), space,
705
739
  // dollar, percent, asterisk, plus, hyphen, period, slash, colon.
706
740
  public static makeAlphanumeric(text: string): QrSegment {
707
- if (!this.ALPHANUMERIC_REGEX.test(text)) throw 'String contains unencodable characters in alphanumeric mode';
708
- let bb = new BitBuffer();
741
+ if (!QrSegment.ALPHANUMERIC_REGEX.test(text))
742
+ throw 'String contains unencodable characters in alphanumeric mode';
743
+ const bb = new BitBuffer();
709
744
  let i: int;
710
745
  for (i = 0; i + 2 <= text.length; i += 2) {
711
746
  // Process groups of 2
@@ -716,23 +751,23 @@ export class QrSegment {
716
751
  if (i < text.length)
717
752
  // 1 character remaining
718
753
  bb.appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6);
719
- return new QrSegment(QrSegment.Mode.ALPHANUMERIC, text.length, bb.array);
754
+ return new QrSegment(QrSegmentMode.ALPHANUMERIC, text.length, bb.array);
720
755
  }
721
756
 
722
757
  // Returns a new mutable list of zero or more segments to represent the given Unicode text string.
723
758
  // The result may use various segment modes and switch modes to optimize the length of the bit stream.
724
759
  public static makeSegments(text: string): Array<QrSegment> {
725
760
  // Select the most efficient segment encoding automatically
726
- if (text == '') return [];
727
- else if (this.NUMERIC_REGEX.test(text)) return [QrSegment.makeNumeric(text)];
728
- else if (this.ALPHANUMERIC_REGEX.test(text)) return [QrSegment.makeAlphanumeric(text)];
761
+ if (text === '') return [];
762
+ else if (QrSegment.NUMERIC_REGEX.test(text)) return [QrSegment.makeNumeric(text)];
763
+ else if (QrSegment.ALPHANUMERIC_REGEX.test(text)) return [QrSegment.makeAlphanumeric(text)];
729
764
  else return [QrSegment.makeBytes(QrSegment.toUtf8ByteArray(text))];
730
765
  }
731
766
 
732
767
  // Returns a segment representing an Extended Channel Interpretation
733
768
  // (ECI) designator with the given assignment value.
734
769
  public static makeEci(assignVal: int): QrSegment {
735
- let bb = new BitBuffer();
770
+ const bb = new BitBuffer();
736
771
  if (assignVal < 0) throw 'ECI assignment value out of range';
737
772
  else if (assignVal < 1 << 7) bb.appendBits(assignVal, 8);
738
773
  else if (assignVal < 1 << 14) {
@@ -742,27 +777,29 @@ export class QrSegment {
742
777
  bb.appendBits(6, 3);
743
778
  bb.appendBits(assignVal, 21);
744
779
  } else throw 'ECI assignment value out of range';
745
- return new QrSegment(QrSegment.Mode.ECI, 0, bb.array);
780
+ return new QrSegment(QrSegmentMode.ECI, 0, bb.array);
746
781
  }
747
782
 
748
783
  /*-- Constructor (low level) and fields --*/
749
784
 
785
+ // The mode indicator of this segment.
786
+ public readonly mode: QrSegmentMode;
787
+
788
+ // The length of this segment's unencoded data. Measured in characters for
789
+ // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
790
+ // Always zero or positive. Not the same as the data's bit length.
791
+ public readonly numChars: int;
792
+
793
+ // The data bits of this segment. Accessed through getData().
794
+ private readonly bitData: Array<bit>;
795
+
750
796
  // Creates a new QR Code segment with the given attributes and data.
751
797
  // The character count (numChars) must agree with the mode and the bit buffer length,
752
798
  // but the constraint isn't checked. The given bit buffer is cloned and stored.
753
- public constructor(
754
- // The mode indicator of this segment.
755
- public readonly mode: QrSegment.Mode,
756
-
757
- // The length of this segment's unencoded data. Measured in characters for
758
- // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
759
- // Always zero or positive. Not the same as the data's bit length.
760
- public readonly numChars: int,
761
-
762
- // The data bits of this segment. Accessed through getData().
763
- private readonly bitData: Array<bit>
764
- ) {
799
+ public constructor(mode: QrSegmentMode, numChars: int, bitData: Array<bit>) {
765
800
  if (numChars < 0) throw 'Invalid argument';
801
+ this.mode = mode;
802
+ this.numChars = numChars;
766
803
  this.bitData = bitData.slice(); // Make defensive copy
767
804
  }
768
805
 
@@ -788,9 +825,9 @@ export class QrSegment {
788
825
  // Returns a new array of bytes representing the given string encoded in UTF-8.
789
826
  private static toUtf8ByteArray(str: string): Array<byte> {
790
827
  str = encodeURI(str);
791
- let result: Array<byte> = [];
828
+ const result: Array<byte> = [];
792
829
  for (let i = 0; i < str.length; i++) {
793
- if (str.charAt(i) != '%') result.push(str.charCodeAt(i));
830
+ if (str.charAt(i) !== '%') result.push(str.charCodeAt(i));
794
831
  else {
795
832
  result.push(parseInt(str.substr(i + 1, 2), 16));
796
833
  i += 2;
@@ -810,11 +847,12 @@ export class QrSegment {
810
847
  // whether a string s is encodable: let ok: boolean = ALPHANUMERIC_REGEX.test(s);
811
848
  // A string is encodable iff each character is in the following set: 0 to 9, A to Z
812
849
  // (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
813
- public static readonly ALPHANUMERIC_REGEX: RegExp = /^[A-Z0-9 $%*+.\/:-]*$/;
850
+ public static readonly ALPHANUMERIC_REGEX: RegExp = /^[A-Z0-9 $%*+./:-]*$/;
814
851
 
815
852
  // The set of all legal characters in alphanumeric mode,
816
853
  // where each character value maps to the index in the string.
817
- private static readonly ALPHANUMERIC_CHARSET: string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
854
+ private static readonly ALPHANUMERIC_CHARSET: string =
855
+ '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:';
818
856
  }
819
857
 
820
858
  /*---- Private helper classes ----*/
@@ -833,7 +871,7 @@ class ReedSolomonGenerator {
833
871
  // as a lookup table over all possible parameter values, instead of as an algorithm.
834
872
  public constructor(degree: int) {
835
873
  if (degree < 1 || degree > 255) throw 'Degree out of range';
836
- let coefs = this.coefficients;
874
+ const coefs = this.coefficients;
837
875
 
838
876
  // Start with the monomial x^0
839
877
  for (let i = 0; i < degree - 1; i++) coefs.push(0);
@@ -858,11 +896,13 @@ class ReedSolomonGenerator {
858
896
  // This method does not alter this object's state (because it is immutable).
859
897
  public getRemainder(data: Array<byte>): Array<byte> {
860
898
  // Compute the remainder by performing polynomial division
861
- let result: Array<byte> = this.coefficients.map(_ => 0);
899
+ const result: Array<byte> = this.coefficients.map((_) => 0);
862
900
  for (const b of data) {
863
901
  const factor: byte = b ^ (result.shift() as byte);
864
902
  result.push(0);
865
- this.coefficients.forEach((coef, i) => (result[i] ^= ReedSolomonGenerator.multiply(coef, factor)));
903
+ this.coefficients.forEach((coef, i) => {
904
+ result[i] ^= ReedSolomonGenerator.multiply(coef, factor);
905
+ });
866
906
  }
867
907
  return result;
868
908
  }
@@ -870,14 +910,14 @@ class ReedSolomonGenerator {
870
910
  // Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
871
911
  // are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
872
912
  private static multiply(x: byte, y: byte): byte {
873
- if (x >>> 8 != 0 || y >>> 8 != 0) throw 'Byte out of range';
913
+ if (x >>> 8 !== 0 || y >>> 8 !== 0) throw 'Byte out of range';
874
914
  // Russian peasant multiplication
875
915
  let z: int = 0;
876
916
  for (let i = 7; i >= 0; i--) {
877
917
  z = (z << 1) ^ ((z >>> 7) * 0x11d);
878
918
  z ^= ((y >>> i) & 1) * x;
879
919
  }
880
- if (z >>> 8 != 0) throw 'Assertion error';
920
+ if (z >>> 8 !== 0) throw 'Assertion error';
881
921
  return z as byte;
882
922
  }
883
923
  }
@@ -892,7 +932,7 @@ class BitBuffer {
892
932
  // Appends the given number of low-order bits of the given value
893
933
  // to this buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len.
894
934
  public appendBits(val: int, len: int): void {
895
- if (len < 0 || len > 31 || val >>> len != 0) throw 'Value out of range';
935
+ if (len < 0 || len > 31 || val >>> len !== 0) throw 'Value out of range';
896
936
  for (
897
937
  let i = len - 1;
898
938
  i >= 0;
@@ -904,63 +944,61 @@ class BitBuffer {
904
944
 
905
945
  /*---- Public helper enumeration ----*/
906
946
 
907
- export namespace QrCode {
908
- type int = number;
947
+ /*
948
+ * The error correction level in a QR Code symbol. Immutable.
949
+ */
950
+ export class QrCodeEcc {
951
+ /*-- Constants --*/
909
952
 
910
- /*
911
- * The error correction level in a QR Code symbol. Immutable.
912
- */
913
- export class Ecc {
914
- /*-- Constants --*/
953
+ public static readonly LOW = new QrCodeEcc(0, 1); // The QR Code can tolerate about 7% erroneous codewords
954
+ public static readonly MEDIUM = new QrCodeEcc(1, 0); // The QR Code can tolerate about 15% erroneous codewords
955
+ public static readonly QUARTILE = new QrCodeEcc(2, 3); // The QR Code can tolerate about 25% erroneous codewords
956
+ public static readonly HIGH = new QrCodeEcc(3, 2); // The QR Code can tolerate about 30% erroneous codewords
915
957
 
916
- public static readonly LOW = new Ecc(0, 1); // The QR Code can tolerate about 7% erroneous codewords
917
- public static readonly MEDIUM = new Ecc(1, 0); // The QR Code can tolerate about 15% erroneous codewords
918
- public static readonly QUARTILE = new Ecc(2, 3); // The QR Code can tolerate about 25% erroneous codewords
919
- public static readonly HIGH = new Ecc(3, 2); // The QR Code can tolerate about 30% erroneous codewords
958
+ /*-- Constructor and fields --*/
920
959
 
921
- /*-- Constructor and fields --*/
960
+ // In the range 0 to 3 (unsigned 2-bit integer).
961
+ public readonly ordinal: int;
962
+ // (Package-private) In the range 0 to 3 (unsigned 2-bit integer).
963
+ public readonly formatBits: int;
922
964
 
923
- private constructor(
924
- // In the range 0 to 3 (unsigned 2-bit integer).
925
- public readonly ordinal: int,
926
- // (Package-private) In the range 0 to 3 (unsigned 2-bit integer).
927
- public readonly formatBits: int
928
- ) {}
965
+ private constructor(ordinal: int, formatBits: int) {
966
+ this.ordinal = ordinal;
967
+ this.formatBits = formatBits;
929
968
  }
930
969
  }
931
970
 
932
971
  /*---- Public helper enumeration ----*/
933
972
 
934
- export namespace QrSegment {
935
- type int = number;
973
+ /*
974
+ * Describes how a segment's data bits are interpreted. Immutable.
975
+ */
976
+ export class QrSegmentMode {
977
+ /*-- Constants --*/
936
978
 
937
- /*
938
- * Describes how a segment's data bits are interpreted. Immutable.
939
- */
940
- export class Mode {
941
- /*-- Constants --*/
979
+ public static readonly NUMERIC = new QrSegmentMode(0x1, [10, 12, 14]);
980
+ public static readonly ALPHANUMERIC = new QrSegmentMode(0x2, [9, 11, 13]);
981
+ public static readonly BYTE = new QrSegmentMode(0x4, [8, 16, 16]);
982
+ public static readonly KANJI = new QrSegmentMode(0x8, [8, 10, 12]);
983
+ public static readonly ECI = new QrSegmentMode(0x7, [0, 0, 0]);
942
984
 
943
- public static readonly NUMERIC = new Mode(0x1, [10, 12, 14]);
944
- public static readonly ALPHANUMERIC = new Mode(0x2, [9, 11, 13]);
945
- public static readonly BYTE = new Mode(0x4, [8, 16, 16]);
946
- public static readonly KANJI = new Mode(0x8, [8, 10, 12]);
947
- public static readonly ECI = new Mode(0x7, [0, 0, 0]);
985
+ /*-- Constructor and fields --*/
948
986
 
949
- /*-- Constructor and fields --*/
987
+ // The mode indicator bits, which is a uint4 value (range 0 to 15).
988
+ public readonly modeBits: int;
989
+ // Number of character count bits for three different version ranges.
990
+ private readonly numBitsCharCount: [int, int, int];
950
991
 
951
- private constructor(
952
- // The mode indicator bits, which is a uint4 value (range 0 to 15).
953
- public readonly modeBits: int,
954
- // Number of character count bits for three different version ranges.
955
- private readonly numBitsCharCount: [int, int, int]
956
- ) {}
992
+ private constructor(modeBits: int, numBitsCharCount: [int, int, int]) {
993
+ this.modeBits = modeBits;
994
+ this.numBitsCharCount = numBitsCharCount;
995
+ }
957
996
 
958
- /*-- Method --*/
997
+ /*-- Method --*/
959
998
 
960
- // (Package-private) Returns the bit width of the character count field for a segment in
961
- // this mode in a QR Code at the given version number. The result is in the range [0, 16].
962
- public numCharCountBits(ver: int): int {
963
- return this.numBitsCharCount[Math.floor((ver + 7) / 17)];
964
- }
999
+ // (Package-private) Returns the bit width of the character count field for a segment in
1000
+ // this mode in a QR Code at the given version number. The result is in the range [0, 16].
1001
+ public numCharCountBits(ver: int): int {
1002
+ return this.numBitsCharCount[Math.floor((ver + 7) / 17)];
965
1003
  }
966
1004
  }