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