@vkontakte/vk-qr 2.1.1 → 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/LICENSE +1 -1
- package/README.md +1 -1
- package/dist/index.d.ts +17 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +1135 -0
- package/dist/index.js.map +1 -0
- package/dist/{types/qr.d.ts → qr.d.ts} +79 -87
- package/dist/qr.d.ts.map +1 -0
- package/dist/{types/svg.d.ts → svg.d.ts} +10 -9
- package/dist/svg.d.ts.map +1 -0
- package/dist/{types/types.d.ts → types.d.ts} +57 -51
- package/dist/types.d.ts.map +1 -0
- package/package.json +55 -80
- package/src/index.ts +38 -26
- package/src/qr.ts +217 -179
- package/src/svg.ts +28 -12
- package/src/types.ts +15 -11
- package/dist/cjs/index.js +0 -1185
- package/dist/es/index.js +0 -1183
- package/dist/types/index.d.ts +0 -20
- package/dist/umd/qrCodeGenerator.js +0 -1191
- package/dist/umd/qrCodeGenerator.min.js +0 -1
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:
|
|
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:
|
|
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:
|
|
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
|
-
!(
|
|
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 [
|
|
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
|
-
|
|
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
|
|
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
|
|
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)
|
|
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
|
-
|
|
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) =>
|
|
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
|
-
|
|
166
|
-
|
|
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)
|
|
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
|
-
|
|
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
|
|
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
|
-
|
|
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} ${
|
|
262
|
-
border * 2
|
|
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
|
|
276
|
-
this.setFunctionModule(i, 6, i % 2
|
|
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 (
|
|
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
|
|
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
|
|
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
|
|
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))
|
|
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:
|
|
381
|
-
if (data.length
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
|
409
|
+
if (i !== shortBlockLen - blockEccLen || j >= numShortBlocks) result.push(blocks[j][i]);
|
|
407
410
|
}
|
|
408
411
|
}
|
|
409
|
-
if (result.length
|
|
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
|
|
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
|
|
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)
|
|
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
|
|
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
|
|
456
|
+
invert = (x + y) % 2 === 0;
|
|
453
457
|
break;
|
|
454
458
|
case 1:
|
|
455
|
-
invert = y % 2
|
|
459
|
+
invert = y % 2 === 0;
|
|
456
460
|
break;
|
|
457
461
|
case 2:
|
|
458
|
-
invert = x % 3
|
|
462
|
+
invert = x % 3 === 0;
|
|
459
463
|
break;
|
|
460
464
|
case 3:
|
|
461
|
-
invert = (x + y) % 3
|
|
465
|
+
invert = (x + y) % 3 === 0;
|
|
462
466
|
break;
|
|
463
467
|
case 4:
|
|
464
|
-
invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2
|
|
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)
|
|
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
|
|
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
|
|
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
|
-
|
|
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]
|
|
498
|
+
if (this.modules[y][x] === color) {
|
|
495
499
|
runX++;
|
|
496
|
-
if (runX
|
|
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
|
-
|
|
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]
|
|
519
|
+
if (this.modules[y][x] === color) {
|
|
516
520
|
runY++;
|
|
517
|
-
if (runY
|
|
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 (
|
|
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
|
|
568
|
+
if (this.version === 1) return [];
|
|
561
569
|
else {
|
|
562
570
|
const numAlign: int = Math.floor(this.version / 7) + 2;
|
|
563
|
-
const step: int =
|
|
564
|
-
|
|
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:
|
|
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] *
|
|
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]
|
|
609
|
-
runHistory[4]
|
|
610
|
-
runHistory[5]
|
|
611
|
-
runHistory[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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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
|
-
[
|
|
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)
|
|
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
|
-
|
|
719
|
+
const bb = new BitBuffer();
|
|
686
720
|
for (const b of data) bb.appendBits(b, 8);
|
|
687
|
-
return new QrSegment(
|
|
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 (!
|
|
693
|
-
|
|
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(
|
|
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 (!
|
|
708
|
-
|
|
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(
|
|
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
|
|
727
|
-
else if (
|
|
728
|
-
else if (
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
828
|
+
const result: Array<byte> = [];
|
|
792
829
|
for (let i = 0; i < str.length; i++) {
|
|
793
|
-
if (str.charAt(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 =
|
|
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
|
-
|
|
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
|
-
|
|
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) =>
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
908
|
-
|
|
947
|
+
/*
|
|
948
|
+
* The error correction level in a QR Code symbol. Immutable.
|
|
949
|
+
*/
|
|
950
|
+
export class QrCodeEcc {
|
|
951
|
+
/*-- Constants --*/
|
|
909
952
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
924
|
-
|
|
925
|
-
|
|
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
|
-
|
|
935
|
-
|
|
973
|
+
/*
|
|
974
|
+
* Describes how a segment's data bits are interpreted. Immutable.
|
|
975
|
+
*/
|
|
976
|
+
export class QrSegmentMode {
|
|
977
|
+
/*-- Constants --*/
|
|
936
978
|
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
|
|
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
|
-
|
|
997
|
+
/*-- Method --*/
|
|
959
998
|
|
|
960
|
-
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
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
|
}
|