UNPKG

45.6 kBJavaScriptView Raw
1"use strict";
2/* eslint-disable */
3var qrcodegen = new function() {
4
5 /*---- QR Code symbol class ----*/
6 this.qrBorder = 7;
7 this.tileSize = 96;
8 this.incTileSize = 96;
9 this.minImageTiles = 5;
10 /*
11 * A class that represents a QR Code symbol, which is a type of two-dimension barcode.
12 * Invented by Denso Wave and described in the ISO/IEC 18004 standard.
13 * Instances of this class represent an immutable square grid of black and white cells.
14 * The class provides static factory functions to create a QR Code from text or binary data.
15 * The class covers the QR Code Model 2 specification, supporting all versions (sizes)
16 * from 1 to 40, all 4 error correction levels, and 4 character encoding modes.
17 *
18 * Ways to create a QR Code object:
19 * - High level: Take the payload data and call QrCode.encodeText() or QrCode.encodeBinary().
20 * - Mid level: Custom-make the list of segments and call QrCode.encodeSegments().
21 * - Low level: Custom-make the array of data codeword bytes (including
22 * segment headers and final padding, excluding error correction codewords),
23 * supply the appropriate version number, and call the QrCode() constructor.
24 * (Note that all ways require supplying the desired error correction level.)
25 *
26 * This constructor creates a new QR Code with the given version number,
27 * error correction level, data codeword bytes, and mask number.
28 * This is a low-level API that most users should not use directly.
29 * A mid-level API is the encodeSegments() function.
30 */
31 this.QrCode = function(version, errCorLvl, dataCodewords, mask) {
32
33 /*---- Constructor (low level) ----*/
34
35 // Check scalar arguments
36 if (version < MIN_VERSION || version > MAX_VERSION)
37 throw "Version value out of range";
38 if (mask < -1 || mask > 7)
39 throw "Mask value out of range";
40 if (!(errCorLvl instanceof Ecc))
41 throw "QrCode.Ecc expected";
42 var size = version * 4 + 17;
43
44 // Initialize both grids to be size*size arrays of Boolean false
45 var row = [];
46 for (var i = 0; i < size; i++)
47 row.push(false);
48 var modules = []; // Initially all white
49 var isFunction = [];
50 for (var i = 0; i < size; i++) {
51 modules.push(row.slice());
52 isFunction.push(row.slice());
53 }
54
55 // Compute ECC, draw modules
56 drawFunctionPatterns();
57 var allCodewords = addEccAndInterleave(dataCodewords);
58 drawCodewords(allCodewords);
59
60 // Do masking
61 if (mask == -1) { // Automatically choose best mask
62 var minPenalty = Infinity;
63 for (var i = 0; i < 8; i++) {
64 applyMask(i);
65 drawFormatBits(i);
66 var penalty = getPenaltyScore();
67 if (penalty < minPenalty) {
68 mask = i;
69 minPenalty = penalty;
70 }
71 applyMask(i); // Undoes the mask due to XOR
72 }
73 }
74 if (mask < 0 || mask > 7)
75 throw "Assertion error";
76 applyMask(mask); // Apply the final choice of mask
77 drawFormatBits(mask); // Overwrite old format bits
78
79 isFunction = null;
80
81
82 /*---- Read-only instance properties ----*/
83
84 // The version number of this QR Code, which is between 1 and 40 (inclusive).
85 // This determines the size of this barcode.
86 Object.defineProperty(this, "version", {value: version});
87
88 // The width and height of this QR Code, measured in modules, between
89 // 21 and 177 (inclusive). This is equal to version * 4 + 17.
90 Object.defineProperty(this, "size", {value: size});
91
92 // The error correction level used in this QR Code.
93 Object.defineProperty(this, "errorCorrectionLevel", {value: errCorLvl});
94
95 // The index of the mask pattern used in this QR Code, which is between 0 and 7 (inclusive).
96 // Even if a QR Code is created with automatic masking requested (mask = -1),
97 // the resulting object still has a mask value between 0 and 7.
98 Object.defineProperty(this, "mask", {value: mask});
99
100
101 /*---- Accessor methods ----*/
102
103 // Returns the color of the module (pixel) at the given coordinates, which is false
104 // for white or true for black. The top left corner has the coordinates (x=0, y=0).
105 // If the given coordinates are out of bounds, then false (white) is returned.
106 this.getPixel = function(x, y) {
107
108 var imageTiles = (size - 13) / 2;
109 if (imageTiles < qrcodegen.minImageTiles) {
110 imageTiles = qrcodegen.minImageTiles;
111 }
112
113 var padding = (size - (qrcodegen.qrBorder * 2) - imageTiles);
114 if (padding % 2 === 0) {
115 padding++;
116 }
117 padding /= 2;
118 padding--;
119
120 if (x > qrcodegen.qrBorder + padding && y > qrcodegen.qrBorder + padding && x < size - padding - qrcodegen.qrBorder - 1 && y < size - padding - qrcodegen.qrBorder - 1) {
121 return false;
122 }
123
124 return 0 <= x && x < size && 0 <= y && y < size && modules[y][x];
125 };
126
127
128 /*---- Public instance methods ----*/
129
130 // Draws this QR Code, with the given module scale and border modules, onto the given HTML
131 // canvas element. The canvas's width and height is resized to (this.size + border * 2) * scale.
132 // The drawn image is be purely black and white, and fully opaque.
133 // The scale must be a positive integer and the border must be a non-negative integer.
134 this.drawCanvas = function(scale, border, canvas) {
135 if (scale <= 0 || border < 0)
136 throw "Value out of range";
137 var width = (size + border * 2) * scale;
138 canvas.width = width;
139 canvas.height = width;
140 var ctx = canvas.getContext("2d");
141 for (var y = -border; y < size + border; y++) {
142 for (var x = -border; x < size + border; x++) {
143 ctx.fillStyle = this.getPixel(x, y) ? "#000000" : "#FFFFFF";
144 ctx.fillRect((x + border) * scale, (y + border) * scale, scale, scale);
145 }
146 }
147 };
148
149 this.getNeighbors = function(x, y) {
150 return {
151 l: this.getPixel(x - 1, y),
152 r: this.getPixel(x + 1, y),
153 t: this.getPixel(x, y - 1),
154 b: this.getPixel(x, y + 1)
155 };
156 };
157
158 this.toSvgString = function() {
159 var parts = [];
160 var leftPadding = 0;
161 var topPadding = 0;
162 var xCoord = 0;
163 var yCoord = 0;
164 for (var y = 0; y < size; y++) {
165 leftPadding = 0;
166 for (var x = 0; x < size; x++) {
167 xCoord = x + leftPadding;
168 leftPadding += qrcodegen.tileSize;
169 yCoord = y + topPadding;
170 var neighbors = this.getNeighbors(x, y);
171 var path = '';
172 if (this.getPixel(x, y)) {
173 path = '';
174 if (!neighbors.l && !neighbors.r && !neighbors.t && !neighbors.b) {
175 path = '<path d="M0,28.6v42.9C0,87.3,12.8,100,28.6,100h42.9c15.9,0,28.6-12.8,28.6-28.6V28.6C100,12.7,87.2,0,71.4,0H28.6 C12.8,0,0,12.8,0,28.6z"/>';
176 } else if (!neighbors.l && !neighbors.r && !neighbors.t && neighbors.b) {
177 path = '<path d="M100,100V28.6C100,12.7,87.2,0,71.4,0H28.6C12.7,0,0,12.8,0,28.6V100H100z"/>';
178 } else if (!neighbors.l && neighbors.r && !neighbors.t && !neighbors.b) {
179 path = '<path d="M100,0H28.6C12.7,0,0,12.8,0,28.6v42.9C0,87.3,12.8,100,28.6,100H100V0z"/>';
180 } else if (neighbors.l && !neighbors.r && !neighbors.t && !neighbors.b) {
181 path = '<path d="M0,100h71.4c15.9,0,28.6-12.8,28.6-28.6V28.6C100,12.7,87.2,0,71.4,0H0V100z"/>';
182 } else if (!neighbors.l && !neighbors.r && neighbors.t && !neighbors.b) {
183 path = '<path d="M0,0v71.4C0,87.3,12.8,100,28.6,100h42.9c15.9,0,28.6-12.8,28.6-28.6V0H0z"/>';
184 } else if (neighbors.l && !neighbors.r && !neighbors.t && neighbors.b) {
185 path = '<path d="m0 100h100v-71.5c0-15.8-12.8-28.5-28.5-28.5h-71.5v100z"/>';
186 } else if (neighbors.l && !neighbors.r && neighbors.t && !neighbors.b) {
187 path = '<path d="m0 0v100h71.5c15.8 0 28.5-12.8 28.5-28.5v-71.5h-100z"/>';
188 } else if (!neighbors.l && neighbors.r && !neighbors.t && neighbors.b) {
189 path = '<path d="m100 100v-100h-71.5c-15.8 0-28.5 12.8-28.5 28.5v71.5h100z"/>';
190 } else if (!neighbors.l && neighbors.r && neighbors.t && !neighbors.b) {
191 path = '<path d="m100 0h-100v71.5c0 15.8 12.8 28.5 28.5 28.5h71.5v-100z"/>';
192 } else {
193 path = '<rect width="100" height="100"/>';
194 }
195
196 parts.push('<g transform="translate(' + xCoord + (yCoord !== 0 ? ',' + yCoord : '') + ')">' + path + '</g>');
197 } else {
198 if (neighbors.l && neighbors.t && this.getPixel(x - 1, y - 1)) {
199 parts.push('<g transform="translate(' + xCoord + (yCoord !== 0 ? ',' + yCoord : '') + ')"><path d="M30.5,2V0H0v30.5h2C2,14.7,14.8,2,30.5,2z"/></g>');
200 }
201 if (neighbors.l && neighbors.b && this.getPixel(x - 1, y + 1)) {
202 parts.push('<g transform="translate(' + xCoord + (yCoord !== 0 ? ',' + yCoord : '') + ')"><path d="M2,69.5H0V100h30.5v-2C14.7,98,2,85.2,2,69.5z"/></g>');
203 }
204 if (neighbors.r && neighbors.t && this.getPixel(x + 1, y - 1)) {
205 parts.push('<g transform="translate(' + xCoord + (yCoord !== 0 ? ',' + yCoord : '') + ')"><path d="M98,30.5h2V0H69.5v2C85.3,2,98,14.8,98,30.5z"/></g>');
206 }
207 if (neighbors.r && neighbors.b && this.getPixel(x + 1, y + 1)) {
208 parts.push('<g transform="translate(' + xCoord + (yCoord !== 0 ? ',' + yCoord : '') + ')"><path d="M69.5,98v2H100V69.5h-2C98,85.3,85.2,98,69.5,98z"/></g>');
209 }
210 }
211 }
212 topPadding += qrcodegen.tileSize;
213 }
214
215 var imgWidthInTiles = (size - ((qrcodegen.qrBorder * 2) - 1)) / 2;
216 var width = (imgWidthInTiles * qrcodegen.incTileSize);
217 var position = ((size - imgWidthInTiles) / 2) * qrcodegen.incTileSize + (qrcodegen.incTileSize / 4);
218 parts.push('<image transform="translate(' + position + ',' + position + ')" width="' + width + '" height="' + width + '" xlink:href="https://upload.wikimedia.org/wikipedia/commons/2/21/VK.com-logo.svg"/>');
219
220 return '<?xml version="1.0" encoding="UTF-8"?>\n' +
221 '<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">\n' +
222 '<svg version="1.1" viewBox="0 0 ' + (size * qrcodegen.incTileSize + qrcodegen.incTileSize) + ' ' + (size * qrcodegen.incTileSize + qrcodegen.incTileSize) + '" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink">\n' +
223 '<g transform="translate(0,0)">\n' +
224 parts.join("\n") +
225 '</g>\n' +
226 '</svg>\n';
227 };
228
229 /*---- Private helper methods for constructor: Drawing function modules ----*/
230
231 // Reads this object's version field, and draws and marks all function modules.
232 function drawFunctionPatterns() {
233 // Draw horizontal and vertical timing patterns
234 for (var i = 0; i < size; i++) {
235 setFunctionModule(6, i, i % 2 == 0);
236 setFunctionModule(i, 6, i % 2 == 0);
237 }
238
239 // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
240 drawFinderPattern(3, 3);
241 drawFinderPattern(size - 4, 3);
242 drawFinderPattern(3, size - 4);
243
244 // Draw numerous alignment patterns
245 var alignPatPos = getAlignmentPatternPositions();
246 var numAlign = alignPatPos.length;
247 for (var i = 0; i < numAlign; i++) {
248 for (var j = 0; j < numAlign; j++) {
249 // Don't draw on the three finder corners
250 if (!(i == 0 && j == 0 || i == 0 && j == numAlign - 1 || i == numAlign - 1 && j == 0))
251 drawAlignmentPattern(alignPatPos[i], alignPatPos[j]);
252 }
253 }
254
255 // Draw configuration data
256 drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
257 drawVersion();
258 }
259
260
261 // Draws two copies of the format bits (with its own error correction code)
262 // based on the given mask and this object's error correction level field.
263 function drawFormatBits(mask) {
264 // Calculate error correction code and pack bits
265 var data = errCorLvl.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3
266 var rem = data;
267 for (var i = 0; i < 10; i++)
268 rem = (rem << 1) ^ ((rem >>> 9) * 0x537);
269 var bits = (data << 10 | rem) ^ 0x5412; // uint15
270 if (bits >>> 15 != 0)
271 throw "Assertion error";
272
273 // Draw first copy
274 for (var i = 0; i <= 5; i++)
275 setFunctionModule(8, i, getBit(bits, i));
276 setFunctionModule(8, 7, getBit(bits, 6));
277 setFunctionModule(8, 8, getBit(bits, 7));
278 setFunctionModule(7, 8, getBit(bits, 8));
279 for (var i = 9; i < 15; i++)
280 setFunctionModule(14 - i, 8, getBit(bits, i));
281
282 // Draw second copy
283 for (var i = 0; i < 8; i++)
284 setFunctionModule(size - 1 - i, 8, getBit(bits, i));
285 for (var i = 8; i < 15; i++)
286 setFunctionModule(8, size - 15 + i, getBit(bits, i));
287 setFunctionModule(8, size - 8, true); // Always black
288 }
289
290
291 // Draws two copies of the version bits (with its own error correction code),
292 // based on this object's version field, iff 7 <= version <= 40.
293 function drawVersion() {
294 if (version < 7)
295 return;
296
297 // Calculate error correction code and pack bits
298 var rem = version; // version is uint6, in the range [7, 40]
299 for (var i = 0; i < 12; i++)
300 rem = (rem << 1) ^ ((rem >>> 11) * 0x1F25);
301 var bits = version << 12 | rem; // uint18
302 if (bits >>> 18 != 0)
303 throw "Assertion error";
304
305 // Draw two copies
306 for (var i = 0; i < 18; i++) {
307 var bit = getBit(bits, i);
308 var a = size - 11 + i % 3;
309 var b = Math.floor(i / 3);
310 setFunctionModule(a, b, bit);
311 setFunctionModule(b, a, bit);
312 }
313 }
314
315
316 // Draws a 9*9 finder pattern including the border separator,
317 // with the center module at (x, y). Modules can be out of bounds.
318 function drawFinderPattern(x, y) {
319 for (var dy = -4; dy <= 4; dy++) {
320 for (var dx = -4; dx <= 4; dx++) {
321 var dist = Math.max(Math.abs(dx), Math.abs(dy)); // Chebyshev/infinity norm
322 var xx = x + dx, yy = y + dy;
323 if (0 <= xx && xx < size && 0 <= yy && yy < size)
324 setFunctionModule(xx, yy, dist != 2 && dist != 4);
325 }
326 }
327 }
328
329
330 // Draws a 5*5 alignment pattern, with the center module
331 // at (x, y). All modules must be in bounds.
332 function drawAlignmentPattern(x, y) {
333 for (var dy = -2; dy <= 2; dy++) {
334 for (var dx = -2; dx <= 2; dx++)
335 setFunctionModule(x + dx, y + dy, Math.max(Math.abs(dx), Math.abs(dy)) != 1);
336 }
337 }
338
339
340 // Sets the color of a module and marks it as a function module.
341 // Only used by the constructor. Coordinates must be in bounds.
342 function setFunctionModule(x, y, isBlack) {
343 modules[y][x] = isBlack;
344 isFunction[y][x] = true;
345 }
346
347
348 /*---- Private helper methods for constructor: Codewords and masking ----*/
349
350 // Returns a new byte string representing the given data with the appropriate error correction
351 // codewords appended to it, based on this object's version and error correction level.
352 function addEccAndInterleave(data) {
353 if (data.length != QrCode.getNumDataCodewords(version, errCorLvl))
354 throw "Invalid argument";
355
356 // Calculate parameter numbers
357 var numBlocks = QrCode.NUM_ERROR_CORRECTION_BLOCKS[errCorLvl.ordinal][version];
358 var blockEccLen = QrCode.ECC_CODEWORDS_PER_BLOCK [errCorLvl.ordinal][version];
359 var rawCodewords = Math.floor(QrCode.getNumRawDataModules(version) / 8);
360 var numShortBlocks = numBlocks - rawCodewords % numBlocks;
361 var shortBlockLen = Math.floor(rawCodewords / numBlocks);
362
363 // Split data into blocks and append ECC to each block
364 var blocks = [];
365 var rs = new ReedSolomonGenerator(blockEccLen);
366 for (var i = 0, k = 0; i < numBlocks; i++) {
367 var dat = data.slice(k, k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1));
368 k += dat.length;
369 var ecc = rs.getRemainder(dat);
370 if (i < numShortBlocks)
371 dat.push(0);
372 blocks.push(dat.concat(ecc));
373 }
374
375 // Interleave (not concatenate) the bytes from every block into a single sequence
376 var result = [];
377 for (var i = 0; i < blocks[0].length; i++) {
378 for (var j = 0; j < blocks.length; j++) {
379 // Skip the padding byte in short blocks
380 if (i != shortBlockLen - blockEccLen || j >= numShortBlocks)
381 result.push(blocks[j][i]);
382 }
383 }
384 if (result.length != rawCodewords)
385 throw "Assertion error";
386 return result;
387 }
388
389
390 // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
391 // data area of this QR Code. Function modules need to be marked off before this is called.
392 function drawCodewords(data) {
393 if (data.length != Math.floor(QrCode.getNumRawDataModules(version) / 8))
394 throw "Invalid argument";
395 var i = 0; // Bit index into the data
396 // Do the funny zigzag scan
397 for (var right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
398 if (right == 6)
399 right = 5;
400 for (var vert = 0; vert < size; vert++) { // Vertical counter
401 for (var j = 0; j < 2; j++) {
402 var x = right - j; // Actual x coordinate
403 var upward = ((right + 1) & 2) == 0;
404 var y = upward ? size - 1 - vert : vert; // Actual y coordinate
405 if (!isFunction[y][x] && i < data.length * 8) {
406 modules[y][x] = getBit(data[i >>> 3], 7 - (i & 7));
407 i++;
408 }
409 // If this QR Code has any remainder bits (0 to 7), they were assigned as
410 // 0/false/white by the constructor and are left unchanged by this method
411 }
412 }
413 }
414 if (i != data.length * 8)
415 throw "Assertion error";
416 }
417
418
419 // XORs the codeword modules in this QR Code with the given mask pattern.
420 // The function modules must be marked and the codeword bits must be drawn
421 // before masking. Due to the arithmetic of XOR, calling applyMask() with
422 // the same mask value a second time will undo the mask. A final well-formed
423 // QR Code needs exactly one (not zero, two, etc.) mask applied.
424 function applyMask(mask) {
425 if (mask < 0 || mask > 7)
426 throw "Mask value out of range";
427 for (var y = 0; y < size; y++) {
428 for (var x = 0; x < size; x++) {
429 var invert;
430 switch (mask) {
431 case 0:
432 invert = (x + y) % 2 == 0;
433 break;
434 case 1:
435 invert = y % 2 == 0;
436 break;
437 case 2:
438 invert = x % 3 == 0;
439 break;
440 case 3:
441 invert = (x + y) % 3 == 0;
442 break;
443 case 4:
444 invert = (Math.floor(x / 3) + Math.floor(y / 2)) % 2 == 0;
445 break;
446 case 5:
447 invert = x * y % 2 + x * y % 3 == 0;
448 break;
449 case 6:
450 invert = (x * y % 2 + x * y % 3) % 2 == 0;
451 break;
452 case 7:
453 invert = ((x + y) % 2 + x * y % 3) % 2 == 0;
454 break;
455 default:
456 throw "Assertion error";
457 }
458 if (!isFunction[y][x] && invert)
459 modules[y][x] = !modules[y][x];
460 }
461 }
462 }
463
464
465 // Calculates and returns the penalty score based on state of this QR Code's current modules.
466 // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
467 function getPenaltyScore() {
468 var result = 0;
469
470 // Adjacent modules in row having same color, and finder-like patterns
471 for (var y = 0; y < size; y++) {
472 var runHistory = [0, 0, 0, 0, 0, 0, 0];
473 var color = false;
474 var runX = 0;
475 for (var x = 0; x < size; x++) {
476 if (modules[y][x] == color) {
477 runX++;
478 if (runX == 5)
479 result += QrCode.PENALTY_N1;
480 else if (runX > 5)
481 result++;
482 } else {
483 QrCode.addRunToHistory(runX, runHistory);
484 if (!color && QrCode.hasFinderLikePattern(runHistory))
485 result += QrCode.PENALTY_N3;
486 color = modules[y][x];
487 runX = 1;
488 }
489 }
490 QrCode.addRunToHistory(runX, runHistory);
491 if (color)
492 QrCode.addRunToHistory(0, runHistory); // Dummy run of white
493 if (QrCode.hasFinderLikePattern(runHistory))
494 result += QrCode.PENALTY_N3;
495 }
496 // Adjacent modules in column having same color, and finder-like patterns
497 for (var x = 0; x < size; x++) {
498 var runHistory = [0, 0, 0, 0, 0, 0, 0];
499 var color = false;
500 var runY = 0;
501 for (var y = 0; y < size; y++) {
502 if (modules[y][x] == color) {
503 runY++;
504 if (runY == 5)
505 result += QrCode.PENALTY_N1;
506 else if (runY > 5)
507 result++;
508 } else {
509 QrCode.addRunToHistory(runY, runHistory);
510 if (!color && QrCode.hasFinderLikePattern(runHistory))
511 result += QrCode.PENALTY_N3;
512 color = modules[y][x];
513 runY = 1;
514 }
515 }
516 QrCode.addRunToHistory(runY, runHistory);
517 if (color)
518 QrCode.addRunToHistory(0, runHistory); // Dummy run of white
519 if (QrCode.hasFinderLikePattern(runHistory))
520 result += QrCode.PENALTY_N3;
521 }
522
523 // 2*2 blocks of modules having same color
524 for (var y = 0; y < size - 1; y++) {
525 for (var x = 0; x < size - 1; x++) {
526 var color = modules[y][x];
527 if (color == modules[y][x + 1] &&
528 color == modules[y + 1][x] &&
529 color == modules[y + 1][x + 1])
530 result += QrCode.PENALTY_N2;
531 }
532 }
533
534 // Balance of black and white modules
535 var black = 0;
536 modules.forEach(function(row) {
537 row.forEach(function(color) {
538 if (color)
539 black++;
540 });
541 });
542 var total = size * size; // Note that size is odd, so black/total != 1/2
543 // Compute the smallest integer k >= 0 such that (45-5k)% <= black/total <= (55+5k)%
544 var k = Math.ceil(Math.abs(black * 20 - total * 10) / total) - 1;
545 result += k * QrCode.PENALTY_N4;
546 return result;
547 }
548
549
550 // Returns an ascending list of positions of alignment patterns for this version number.
551 // Each position is in the range [0,177), and are used on both the x and y axes.
552 // This could be implemented as lookup table of 40 variable-length lists of integers.
553 function getAlignmentPatternPositions() {
554 if (version == 1)
555 return [];
556 else {
557 var numAlign = Math.floor(version / 7) + 2;
558 var step = (version == 32) ? 26 :
559 Math.ceil((size - 13) / (numAlign * 2 - 2)) * 2;
560 var result = [6];
561 for (var pos = size - 7; result.length < numAlign; pos -= step)
562 result.splice(1, 0, pos);
563 return result;
564 }
565 }
566
567
568 // Returns true iff the i'th bit of x is set to 1.
569 function getBit(x, i) {
570 return ((x >>> i) & 1) != 0;
571 }
572 };
573
574
575 /*---- Static factory functions (high level) for QrCode ----*/
576
577 /*
578 * Returns a QR Code representing the given Unicode text string at the given error correction level.
579 * As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer
580 * Unicode code points (not UTF-16 code units) if the low error correction level is used. The smallest possible
581 * QR Code version is automatically chosen for the output. The ECC level of the result may be higher than the
582 * ecl argument if it can be done without increasing the version.
583 */
584 this.QrCode.encodeText = function(text, ecl) {
585 var segs = qrcodegen.QrSegment.makeSegments(text);
586 return this.encodeSegments(segs, ecl);
587 };
588
589
590 /*
591 * Returns a QR Code representing the given binary data at the given error correction level.
592 * This function always encodes using the binary segment mode, not any text mode. The maximum number of
593 * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
594 * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
595 */
596 this.QrCode.encodeBinary = function(data, ecl) {
597 var seg = qrcodegen.QrSegment.makeBytes(data);
598 return this.encodeSegments([seg], ecl);
599 };
600
601
602 /*---- Static factory functions (mid level) for QrCode ----*/
603
604 /*
605 * Returns a QR Code representing the given segments with the given encoding parameters.
606 * The smallest possible QR Code version within the given range is automatically
607 * chosen for the output. Iff boostEcl is true, then the ECC level of the result
608 * may be higher than the ecl argument if it can be done without increasing the
609 * version. The mask number is either between 0 to 7 (inclusive) to force that
610 * mask, or -1 to automatically choose an appropriate mask (which may be slow).
611 * This function allows the user to create a custom sequence of segments that switches
612 * between modes (such as alphanumeric and byte) to encode text in less space.
613 * This is a mid-level API; the high-level API is encodeText() and encodeBinary().
614 */
615 this.QrCode.encodeSegments = function(segs, ecl, minVersion, maxVersion, mask, boostEcl) {
616 if (minVersion == undefined) minVersion = MIN_VERSION;
617 if (maxVersion == undefined) maxVersion = MAX_VERSION;
618 if (mask == undefined) mask = -1;
619 if (boostEcl == undefined) boostEcl = true;
620 if (!(MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= MAX_VERSION) || mask < -1 || mask > 7)
621 throw "Invalid value";
622
623 // Find the minimal version number to use
624 var version, dataUsedBits;
625 for (version = minVersion; ; version++) {
626 var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8; // Number of data bits available
627 dataUsedBits = qrcodegen.QrSegment.getTotalBits(segs, version);
628 if (dataUsedBits <= dataCapacityBits)
629 break; // This version number is found to be suitable
630 if (version >= maxVersion) // All versions in the range could not fit the given data
631 throw "Data too long";
632 }
633
634 // Increase the error correction level while the data still fits in the current version number
635 [this.Ecc.MEDIUM, this.Ecc.QUARTILE, this.Ecc.HIGH].forEach(function(newEcl) { // From low to high
636 if (boostEcl && dataUsedBits <= QrCode.getNumDataCodewords(version, newEcl) * 8)
637 ecl = newEcl;
638 });
639
640 // Concatenate all segments to create the data bit string
641 var bb = new BitBuffer();
642 segs.forEach(function(seg) {
643 bb.appendBits(seg.mode.modeBits, 4);
644 bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
645 seg.getData().forEach(function(bit) {
646 bb.push(bit);
647 });
648 });
649 if (bb.length != dataUsedBits)
650 throw "Assertion error";
651
652 // Add terminator and pad up to a byte if applicable
653 var dataCapacityBits = QrCode.getNumDataCodewords(version, ecl) * 8;
654 if (bb.length > dataCapacityBits)
655 throw "Assertion error";
656 bb.appendBits(0, Math.min(4, dataCapacityBits - bb.length));
657 bb.appendBits(0, (8 - bb.length % 8) % 8);
658 if (bb.length % 8 != 0)
659 throw "Assertion error";
660
661 // Pad with alternating bytes until data capacity is reached
662 for (var padByte = 0xEC; bb.length < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
663 bb.appendBits(padByte, 8);
664
665 // Pack bits into bytes in big endian
666 var dataCodewords = [];
667 while (dataCodewords.length * 8 < bb.length)
668 dataCodewords.push(0);
669 bb.forEach(function(bit, i) {
670 dataCodewords[i >>> 3] |= bit << (7 - (i & 7));
671 });
672
673 // Create the QR Code object
674 return new this(version, ecl, dataCodewords, mask);
675 };
676
677
678 /*---- Private static helper functions for QrCode ----*/
679
680 var QrCode = {}; // Private object to assign properties to. Not the same object as 'this.QrCode'.
681
682
683 // Returns the number of data bits that can be stored in a QR Code of the given version number, after
684 // all function modules are excluded. This includes remainder bits, so it might not be a multiple of 8.
685 // The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
686 QrCode.getNumRawDataModules = function(ver) {
687 if (ver < MIN_VERSION || ver > MAX_VERSION)
688 throw "Version number out of range";
689 var result = (16 * ver + 128) * ver + 64;
690 if (ver >= 2) {
691 var numAlign = Math.floor(ver / 7) + 2;
692 result -= (25 * numAlign - 10) * numAlign - 55;
693 if (ver >= 7)
694 result -= 36;
695 }
696 return result;
697 };
698
699
700 // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
701 // QR Code of the given version number and error correction level, with remainder bits discarded.
702 // This stateless pure function could be implemented as a (40*4)-cell lookup table.
703 QrCode.getNumDataCodewords = function(ver, ecl) {
704 return Math.floor(QrCode.getNumRawDataModules(ver) / 8) -
705 QrCode.ECC_CODEWORDS_PER_BLOCK [ecl.ordinal][ver] *
706 QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
707 };
708
709
710 // Inserts the given value to the front of the given array, which shifts over the
711 // existing values and deletes the last value. A helper function for getPenaltyScore().
712 QrCode.addRunToHistory = function(run, history) {
713 history.pop();
714 history.unshift(run);
715 };
716
717
718 // Tests whether the given run history has the pattern of ratio 1:1:3:1:1 in the middle, and
719 // surrounded by at least 4 on either or both ends. A helper function for getPenaltyScore().
720 // Must only be called immediately after a run of white modules has ended.
721 QrCode.hasFinderLikePattern = function(runHistory) {
722 var n = runHistory[1];
723 return n > 0 && runHistory[2] == n && runHistory[4] == n && runHistory[5] == n
724 && runHistory[3] == n * 3 && Math.max(runHistory[0], runHistory[6]) >= n * 4;
725 };
726
727
728 /*---- Constants and tables for QrCode ----*/
729
730 var MIN_VERSION = 1; // The minimum version number supported in the QR Code Model 2 standard
731 var MAX_VERSION = 40; // The maximum version number supported in the QR Code Model 2 standard
732 Object.defineProperty(this.QrCode, "MIN_VERSION", {value: MIN_VERSION});
733 Object.defineProperty(this.QrCode, "MAX_VERSION", {value: MAX_VERSION});
734
735 // For use in getPenaltyScore(), when evaluating which mask is best.
736 QrCode.PENALTY_N1 = 3;
737 QrCode.PENALTY_N2 = 3;
738 QrCode.PENALTY_N3 = 40;
739 QrCode.PENALTY_N4 = 10;
740
741 QrCode.ECC_CODEWORDS_PER_BLOCK = [
742 // Version: (note that index 0 is for padding, and is set to an illegal value)
743 // 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
744 [null, 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
745 [null, 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
746 [null, 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
747 [null, 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
748 ];
749
750 QrCode.NUM_ERROR_CORRECTION_BLOCKS = [
751 // Version: (note that index 0 is for padding, and is set to an illegal value)
752 // 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
753 [null, 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
754 [null, 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
755 [null, 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
756 [null, 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
757 ];
758
759
760 /*---- Public helper enumeration ----*/
761
762 /*
763 * The error correction level in a QR Code symbol. Immutable.
764 */
765 this.QrCode.Ecc = {
766 LOW: new Ecc(0, 1), // The QR Code can tolerate about 7% erroneous codewords
767 MEDIUM: new Ecc(1, 0), // The QR Code can tolerate about 15% erroneous codewords
768 QUARTILE: new Ecc(2, 3), // The QR Code can tolerate about 25% erroneous codewords
769 HIGH: new Ecc(3, 2), // The QR Code can tolerate about 30% erroneous codewords
770 };
771
772
773 // Private constructor.
774 function Ecc(ord, fb) {
775 // (Public) In the range 0 to 3 (unsigned 2-bit integer)
776 Object.defineProperty(this, "ordinal", {value: ord});
777
778 // (Package-private) In the range 0 to 3 (unsigned 2-bit integer)
779 Object.defineProperty(this, "formatBits", {value: fb});
780 }
781
782
783 /*---- Data segment class ----*/
784
785 /*
786 * A segment of character/binary/control data in a QR Code symbol.
787 * Instances of this class are immutable.
788 * The mid-level way to create a segment is to take the payload data
789 * and call a static factory function such as QrSegment.makeNumeric().
790 * The low-level way to create a segment is to custom-make the bit buffer
791 * and call the QrSegment() constructor with appropriate values.
792 * This segment class imposes no length restrictions, but QR Codes have restrictions.
793 * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
794 * Any segment longer than this is meaningless for the purpose of generating QR Codes.
795 * This constructor creates a QR Code segment with the given attributes and data.
796 * The character count (numChars) must agree with the mode and the bit buffer length,
797 * but the constraint isn't checked. The given bit buffer is cloned and stored.
798 */
799 this.QrSegment = function(mode, numChars, bitData) {
800 /*---- Constructor (low level) ----*/
801 if (numChars < 0 || !(mode instanceof Mode))
802 throw "Invalid argument";
803
804 // The data bits of this segment. Accessed through getData().
805 bitData = bitData.slice(); // Make defensive copy
806
807 // The mode indicator of this segment.
808 Object.defineProperty(this, "mode", {value: mode});
809
810 // The length of this segment's unencoded data. Measured in characters for
811 // numeric/alphanumeric/kanji mode, bytes for byte mode, and 0 for ECI mode.
812 // Always zero or positive. Not the same as the data's bit length.
813 Object.defineProperty(this, "numChars", {value: numChars});
814
815 // Returns a new copy of the data bits of this segment.
816 this.getData = function() {
817 return bitData.slice(); // Make defensive copy
818 };
819 };
820
821
822 /*---- Static factory functions (mid level) for QrSegment ----*/
823
824 /*
825 * Returns a segment representing the given binary data encoded in
826 * byte mode. All input byte arrays are acceptable. Any text string
827 * can be converted to UTF-8 bytes and encoded as a byte mode segment.
828 */
829 this.QrSegment.makeBytes = function(data) {
830 var bb = new BitBuffer();
831 data.forEach(function(b) {
832 bb.appendBits(b, 8);
833 });
834 return new this(this.Mode.BYTE, data.length, bb);
835 };
836
837
838 /*
839 * Returns a segment representing the given string of decimal digits encoded in numeric mode.
840 */
841 this.QrSegment.makeNumeric = function(digits) {
842 if (!this.NUMERIC_REGEX.test(digits))
843 throw "String contains non-numeric characters";
844 var bb = new BitBuffer();
845 for (var i = 0; i < digits.length;) { // Consume up to 3 digits per iteration
846 var n = Math.min(digits.length - i, 3);
847 bb.appendBits(parseInt(digits.substring(i, i + n), 10), n * 3 + 1);
848 i += n;
849 }
850 return new this(this.Mode.NUMERIC, digits.length, bb);
851 };
852
853
854 /*
855 * Returns a segment representing the given text string encoded in alphanumeric mode.
856 * The characters allowed are: 0 to 9, A to Z (uppercase only), space,
857 * dollar, percent, asterisk, plus, hyphen, period, slash, colon.
858 */
859 this.QrSegment.makeAlphanumeric = function(text) {
860 if (!this.ALPHANUMERIC_REGEX.test(text))
861 throw "String contains unencodable characters in alphanumeric mode";
862 var bb = new BitBuffer();
863 var i;
864 for (i = 0; i + 2 <= text.length; i += 2) { // Process groups of 2
865 var temp = QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)) * 45;
866 temp += QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i + 1));
867 bb.appendBits(temp, 11);
868 }
869 if (i < text.length) // 1 character remaining
870 bb.appendBits(QrSegment.ALPHANUMERIC_CHARSET.indexOf(text.charAt(i)), 6);
871 return new this(this.Mode.ALPHANUMERIC, text.length, bb);
872 };
873
874
875 /*
876 * Returns a new mutable list of zero or more segments to represent the given Unicode text string.
877 * The result may use various segment modes and switch modes to optimize the length of the bit stream.
878 */
879 this.QrSegment.makeSegments = function(text) {
880 // Select the most efficient segment encoding automatically
881 if (text == "")
882 return [];
883 else if (this.NUMERIC_REGEX.test(text))
884 return [this.makeNumeric(text)];
885 else if (this.ALPHANUMERIC_REGEX.test(text))
886 return [this.makeAlphanumeric(text)];
887 else
888 return [this.makeBytes(toUtf8ByteArray(text))];
889 };
890
891
892 /*
893 * Returns a segment representing an Extended Channel Interpretation
894 * (ECI) designator with the given assignment value.
895 */
896 this.QrSegment.makeEci = function(assignVal) {
897 var bb = new BitBuffer();
898 if (assignVal < 0)
899 throw "ECI assignment value out of range";
900 else if (assignVal < (1 << 7))
901 bb.appendBits(assignVal, 8);
902 else if (assignVal < (1 << 14)) {
903 bb.appendBits(2, 2);
904 bb.appendBits(assignVal, 14);
905 } else if (assignVal < 1000000) {
906 bb.appendBits(6, 3);
907 bb.appendBits(assignVal, 21);
908 } else
909 throw "ECI assignment value out of range";
910 return new this(this.Mode.ECI, 0, bb);
911 };
912
913
914 // (Package-private) Calculates and returns the number of bits needed to encode the given segments at the
915 // given version. The result is infinity if a segment has too many characters to fit its length field.
916 this.QrSegment.getTotalBits = function(segs, version) {
917 var result = 0;
918 for (var i = 0; i < segs.length; i++) {
919 var seg = segs[i];
920 var ccbits = seg.mode.numCharCountBits(version);
921 if (seg.numChars >= (1 << ccbits))
922 return Infinity; // The segment's length doesn't fit the field's bit width
923 result += 4 + ccbits + seg.getData().length;
924 }
925 return result;
926 };
927
928
929 /*---- Constants for QrSegment ----*/
930
931 var QrSegment = {}; // Private object to assign properties to. Not the same object as 'this.QrSegment'.
932
933 // (Public) Describes precisely all strings that are encodable in numeric mode.
934 // To test whether a string s is encodable: var ok = NUMERIC_REGEX.test(s);
935 // A string is encodable iff each character is in the range 0 to 9.
936 this.QrSegment.NUMERIC_REGEX = /^[0-9]*$/;
937
938 // (Public) Describes precisely all strings that are encodable in alphanumeric mode.
939 // To test whether a string s is encodable: var ok = ALPHANUMERIC_REGEX.test(s);
940 // A string is encodable iff each character is in the following set: 0 to 9, A to Z
941 // (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
942 this.QrSegment.ALPHANUMERIC_REGEX = /^[A-Z0-9 $%*+.\/:-]*$/;
943
944 // (Private) The set of all legal characters in alphanumeric mode,
945 // where each character value maps to the index in the string.
946 QrSegment.ALPHANUMERIC_CHARSET = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:";
947
948
949 /*---- Public helper enumeration ----*/
950
951 /*
952 * Describes how a segment's data bits are interpreted. Immutable.
953 */
954 this.QrSegment.Mode = { // Constants
955 NUMERIC: new Mode(0x1, [10, 12, 14]),
956 ALPHANUMERIC: new Mode(0x2, [9, 11, 13]),
957 BYTE: new Mode(0x4, [8, 16, 16]),
958 KANJI: new Mode(0x8, [8, 10, 12]),
959 ECI: new Mode(0x7, [0, 0, 0]),
960 };
961
962
963 // Private constructor.
964 function Mode(mode, ccbits) {
965 // (Package-private) The mode indicator bits, which is a uint4 value (range 0 to 15).
966 Object.defineProperty(this, "modeBits", {value: mode});
967
968 // (Package-private) Returns the bit width of the character count field for a segment in
969 // this mode in a QR Code at the given version number. The result is in the range [0, 16].
970 this.numCharCountBits = function(ver) {
971 return ccbits[Math.floor((ver + 7) / 17)];
972 };
973 }
974
975
976 /*---- Private helper functions and classes ----*/
977
978 // Returns a new array of bytes representing the given string encoded in UTF-8.
979 function toUtf8ByteArray(str) {
980 str = encodeURI(str);
981 var result = [];
982 for (var i = 0; i < str.length; i++) {
983 if (str.charAt(i) != "%")
984 result.push(str.charCodeAt(i));
985 else {
986 result.push(parseInt(str.substring(i + 1, i + 3), 16));
987 i += 2;
988 }
989 }
990 return result;
991 }
992
993
994 /*
995 * A private helper class that computes the Reed-Solomon error correction codewords for a sequence of
996 * data codewords at a given degree. Objects are immutable, and the state only depends on the degree.
997 * This class exists because each data block in a QR Code shares the same the divisor polynomial.
998 * This constructor creates a Reed-Solomon ECC generator for the given degree. This could be implemented
999 * as a lookup table over all possible parameter values, instead of as an algorithm.
1000 */
1001 function ReedSolomonGenerator(degree) {
1002 if (degree < 1 || degree > 255)
1003 throw "Degree out of range";
1004
1005 // Coefficients of the divisor polynomial, stored from highest to lowest power, excluding the leading term which
1006 // is always 1. For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
1007 var coefficients = [];
1008
1009 // Start with the monomial x^0
1010 for (var i = 0; i < degree - 1; i++)
1011 coefficients.push(0);
1012 coefficients.push(1);
1013
1014 // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
1015 // drop the highest term, and store the rest of the coefficients in order of descending powers.
1016 // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
1017 var root = 1;
1018 for (var i = 0; i < degree; i++) {
1019 // Multiply the current product by (x - r^i)
1020 for (var j = 0; j < coefficients.length; j++) {
1021 coefficients[j] = ReedSolomonGenerator.multiply(coefficients[j], root);
1022 if (j + 1 < coefficients.length)
1023 coefficients[j] ^= coefficients[j + 1];
1024 }
1025 root = ReedSolomonGenerator.multiply(root, 0x02);
1026 }
1027
1028 // Computes and returns the Reed-Solomon error correction codewords for the given
1029 // sequence of data codewords. The returned object is always a new byte array.
1030 // This method does not alter this object's state (because it is immutable).
1031 this.getRemainder = function(data) {
1032 // Compute the remainder by performing polynomial division
1033 var result = coefficients.map(function() { return 0; });
1034 data.forEach(function(b) {
1035 var factor = b ^ result.shift();
1036 result.push(0);
1037 coefficients.forEach(function(coef, i) {
1038 result[i] ^= ReedSolomonGenerator.multiply(coef, factor);
1039 });
1040 });
1041 return result;
1042 };
1043 }
1044
1045 // This static function returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and
1046 // result are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
1047 ReedSolomonGenerator.multiply = function(x, y) {
1048 if (x >>> 8 != 0 || y >>> 8 != 0)
1049 throw "Byte out of range";
1050 // Russian peasant multiplication
1051 var z = 0;
1052 for (var i = 7; i >= 0; i--) {
1053 z = (z << 1) ^ ((z >>> 7) * 0x11D);
1054 z ^= ((y >>> i) & 1) * x;
1055 }
1056 if (z >>> 8 != 0)
1057 throw "Assertion error";
1058 return z;
1059 };
1060
1061
1062 /*
1063 * A private helper class that represents an appendable sequence of bits (0s and 1s).
1064 * Mainly used by QrSegment. This constructor creates an empty bit buffer (length 0).
1065 */
1066 function BitBuffer() {
1067 Array.call(this);
1068
1069 // Appends the given number of low-order bits of the given value
1070 // to this buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len.
1071 this.appendBits = function(val, len) {
1072 if (len < 0 || len > 31 || val >>> len != 0)
1073 throw "Value out of range";
1074 for (var i = len - 1; i >= 0; i--) // Append bit by bit
1075 this.push((val >>> i) & 1);
1076 };
1077 }
1078
1079 BitBuffer.prototype = Object.create(Array.prototype);
1080 BitBuffer.prototype.constructor = BitBuffer;
1081
1082};
1083
1084export default qrcodegen;
\No newline at end of file