|
|
@ -91,7 +91,7 @@ namespace qrcodegen {
|
|
|
|
|
|
|
|
|
|
|
|
if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION)
|
|
|
|
if (!(QrCode.MIN_VERSION <= minVersion && minVersion <= maxVersion && maxVersion <= QrCode.MAX_VERSION)
|
|
|
|
|| mask < -1 || mask > 7)
|
|
|
|
|| mask < -1 || mask > 7)
|
|
|
|
throw "Invalid value";
|
|
|
|
throw new RangeError("Invalid value");
|
|
|
|
|
|
|
|
|
|
|
|
// Find the minimal version number to use
|
|
|
|
// Find the minimal version number to use
|
|
|
|
let version: int;
|
|
|
|
let version: int;
|
|
|
@ -104,7 +104,7 @@ namespace qrcodegen {
|
|
|
|
break; // This version number is found to be suitable
|
|
|
|
break; // This version number is found to be suitable
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (version >= maxVersion) // All versions in the range could not fit the given data
|
|
|
|
if (version >= maxVersion) // All versions in the range could not fit the given data
|
|
|
|
throw "Data too long";
|
|
|
|
throw new RangeError("Data too long");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// Increase the error correction level while the data still fits in the current version number
|
|
|
|
// Increase the error correction level while the data still fits in the current version number
|
|
|
@ -185,9 +185,9 @@ namespace qrcodegen {
|
|
|
|
|
|
|
|
|
|
|
|
// Check scalar arguments
|
|
|
|
// Check scalar arguments
|
|
|
|
if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION)
|
|
|
|
if (version < QrCode.MIN_VERSION || version > QrCode.MAX_VERSION)
|
|
|
|
throw "Version value out of range";
|
|
|
|
throw new RangeError("Version value out of range");
|
|
|
|
if (msk < -1 || msk > 7)
|
|
|
|
if (msk < -1 || msk > 7)
|
|
|
|
throw "Mask value out of range";
|
|
|
|
throw new RangeError("Mask value out of range");
|
|
|
|
this.size = version * 4 + 17;
|
|
|
|
this.size = version * 4 + 17;
|
|
|
|
|
|
|
|
|
|
|
|
// Initialize both grids to be size*size arrays of Boolean false
|
|
|
|
// Initialize both grids to be size*size arrays of Boolean false
|
|
|
@ -363,7 +363,7 @@ namespace qrcodegen {
|
|
|
|
const ver: int = this.version;
|
|
|
|
const ver: int = this.version;
|
|
|
|
const ecl: QrCode.Ecc = this.errorCorrectionLevel;
|
|
|
|
const ecl: QrCode.Ecc = this.errorCorrectionLevel;
|
|
|
|
if (data.length != QrCode.getNumDataCodewords(ver, ecl))
|
|
|
|
if (data.length != QrCode.getNumDataCodewords(ver, ecl))
|
|
|
|
throw "Invalid argument";
|
|
|
|
throw new RangeError("Invalid argument");
|
|
|
|
|
|
|
|
|
|
|
|
// Calculate parameter numbers
|
|
|
|
// Calculate parameter numbers
|
|
|
|
const numBlocks: int = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
|
|
|
|
const numBlocks: int = QrCode.NUM_ERROR_CORRECTION_BLOCKS[ecl.ordinal][ver];
|
|
|
@ -402,7 +402,7 @@ namespace qrcodegen {
|
|
|
|
// data area of this QR Code. Function modules need to be marked off before this is called.
|
|
|
|
// data area of this QR Code. Function modules need to be marked off before this is called.
|
|
|
|
private drawCodewords(data: Readonly<Array<byte>>): void {
|
|
|
|
private drawCodewords(data: Readonly<Array<byte>>): void {
|
|
|
|
if (data.length != Math.floor(QrCode.getNumRawDataModules(this.version) / 8))
|
|
|
|
if (data.length != Math.floor(QrCode.getNumRawDataModules(this.version) / 8))
|
|
|
|
throw "Invalid argument";
|
|
|
|
throw new RangeError("Invalid argument");
|
|
|
|
let i: int = 0; // Bit index into the data
|
|
|
|
let i: int = 0; // Bit index into the data
|
|
|
|
// Do the funny zigzag scan
|
|
|
|
// Do the funny zigzag scan
|
|
|
|
for (let right = this.size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
|
|
|
|
for (let right = this.size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
|
|
|
@ -433,7 +433,7 @@ namespace qrcodegen {
|
|
|
|
// QR Code needs exactly one (not zero, two, etc.) mask applied.
|
|
|
|
// QR Code needs exactly one (not zero, two, etc.) mask applied.
|
|
|
|
private applyMask(mask: int): void {
|
|
|
|
private applyMask(mask: int): void {
|
|
|
|
if (mask < 0 || mask > 7)
|
|
|
|
if (mask < 0 || mask > 7)
|
|
|
|
throw "Mask value out of range";
|
|
|
|
throw new RangeError("Mask value out of range");
|
|
|
|
for (let y = 0; y < this.size; y++) {
|
|
|
|
for (let y = 0; y < this.size; y++) {
|
|
|
|
for (let x = 0; x < this.size; x++) {
|
|
|
|
for (let x = 0; x < this.size; x++) {
|
|
|
|
let invert: boolean;
|
|
|
|
let invert: boolean;
|
|
|
@ -446,7 +446,7 @@ namespace qrcodegen {
|
|
|
|
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
|
|
|
|
case 5: invert = x * y % 2 + x * y % 3 == 0; break;
|
|
|
|
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
|
|
|
|
case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
|
|
|
|
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
|
|
|
|
case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
|
|
|
|
default: throw "Unreachable";
|
|
|
|
default: throw new Error("Unreachable");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (!this.isFunction[y][x] && invert)
|
|
|
|
if (!this.isFunction[y][x] && invert)
|
|
|
|
this.modules[y][x] = !this.modules[y][x];
|
|
|
|
this.modules[y][x] = !this.modules[y][x];
|
|
|
@ -555,7 +555,7 @@ namespace qrcodegen {
|
|
|
|
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
|
|
|
|
// The result is in the range [208, 29648]. This could be implemented as a 40-entry lookup table.
|
|
|
|
private static getNumRawDataModules(ver: int): int {
|
|
|
|
private static getNumRawDataModules(ver: int): int {
|
|
|
|
if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION)
|
|
|
|
if (ver < QrCode.MIN_VERSION || ver > QrCode.MAX_VERSION)
|
|
|
|
throw "Version number out of range";
|
|
|
|
throw new RangeError("Version number out of range");
|
|
|
|
let result: int = (16 * ver + 128) * ver + 64;
|
|
|
|
let result: int = (16 * ver + 128) * ver + 64;
|
|
|
|
if (ver >= 2) {
|
|
|
|
if (ver >= 2) {
|
|
|
|
const numAlign: int = Math.floor(ver / 7) + 2;
|
|
|
|
const numAlign: int = Math.floor(ver / 7) + 2;
|
|
|
@ -582,7 +582,7 @@ namespace qrcodegen {
|
|
|
|
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
|
|
|
|
// implemented as a lookup table over all possible parameter values, instead of as an algorithm.
|
|
|
|
private static reedSolomonComputeDivisor(degree: int): Array<byte> {
|
|
|
|
private static reedSolomonComputeDivisor(degree: int): Array<byte> {
|
|
|
|
if (degree < 1 || degree > 255)
|
|
|
|
if (degree < 1 || degree > 255)
|
|
|
|
throw "Degree out of range";
|
|
|
|
throw new RangeError("Degree out of range");
|
|
|
|
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
|
|
|
|
// Polynomial coefficients are stored from highest to lowest power, excluding the leading term which is always 1.
|
|
|
|
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93].
|
|
|
|
// For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array [255, 8, 93].
|
|
|
|
let result: Array<byte> = [];
|
|
|
|
let result: Array<byte> = [];
|
|
|
@ -624,7 +624,7 @@ namespace qrcodegen {
|
|
|
|
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
|
|
|
|
// are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
|
|
|
|
private static reedSolomonMultiply(x: byte, y: byte): byte {
|
|
|
|
private static reedSolomonMultiply(x: byte, y: byte): byte {
|
|
|
|
if (x >>> 8 != 0 || y >>> 8 != 0)
|
|
|
|
if (x >>> 8 != 0 || y >>> 8 != 0)
|
|
|
|
throw "Byte out of range";
|
|
|
|
throw new RangeError("Byte out of range");
|
|
|
|
// Russian peasant multiplication
|
|
|
|
// Russian peasant multiplication
|
|
|
|
let z: int = 0;
|
|
|
|
let z: int = 0;
|
|
|
|
for (let i = 7; i >= 0; i--) {
|
|
|
|
for (let i = 7; i >= 0; i--) {
|
|
|
@ -706,7 +706,7 @@ namespace qrcodegen {
|
|
|
|
// to the given buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len.
|
|
|
|
// to the given buffer. Requires 0 <= len <= 31 and 0 <= val < 2^len.
|
|
|
|
function appendBits(val: int, len: int, bb: Array<bit>): void {
|
|
|
|
function appendBits(val: int, len: int, bb: Array<bit>): void {
|
|
|
|
if (len < 0 || len > 31 || val >>> len != 0)
|
|
|
|
if (len < 0 || len > 31 || val >>> len != 0)
|
|
|
|
throw "Value out of range";
|
|
|
|
throw new RangeError("Value out of range");
|
|
|
|
for (let i = len - 1; i >= 0; i--) // Append bit by bit
|
|
|
|
for (let i = len - 1; i >= 0; i--) // Append bit by bit
|
|
|
|
bb.push((val >>> i) & 1);
|
|
|
|
bb.push((val >>> i) & 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
@ -721,7 +721,7 @@ namespace qrcodegen {
|
|
|
|
// Throws an exception if the given condition is false.
|
|
|
|
// Throws an exception if the given condition is false.
|
|
|
|
function assert(cond: boolean): void {
|
|
|
|
function assert(cond: boolean): void {
|
|
|
|
if (!cond)
|
|
|
|
if (!cond)
|
|
|
|
throw "Assertion error";
|
|
|
|
throw new Error("Assertion error");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -757,7 +757,7 @@ namespace qrcodegen {
|
|
|
|
// Returns a segment representing the given string of decimal digits encoded in numeric mode.
|
|
|
|
// Returns a segment representing the given string of decimal digits encoded in numeric mode.
|
|
|
|
public static makeNumeric(digits: string): QrSegment {
|
|
|
|
public static makeNumeric(digits: string): QrSegment {
|
|
|
|
if (!QrSegment.isNumeric(digits))
|
|
|
|
if (!QrSegment.isNumeric(digits))
|
|
|
|
throw "String contains non-numeric characters";
|
|
|
|
throw new RangeError("String contains non-numeric characters");
|
|
|
|
let bb: Array<bit> = []
|
|
|
|
let bb: Array<bit> = []
|
|
|
|
for (let i = 0; i < digits.length; ) { // Consume up to 3 digits per iteration
|
|
|
|
for (let i = 0; i < digits.length; ) { // Consume up to 3 digits per iteration
|
|
|
|
const n: int = Math.min(digits.length - i, 3);
|
|
|
|
const n: int = Math.min(digits.length - i, 3);
|
|
|
@ -773,7 +773,7 @@ namespace qrcodegen {
|
|
|
|
// dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
|
|
|
// dollar, percent, asterisk, plus, hyphen, period, slash, colon.
|
|
|
|
public static makeAlphanumeric(text: string): QrSegment {
|
|
|
|
public static makeAlphanumeric(text: string): QrSegment {
|
|
|
|
if (!QrSegment.isAlphanumeric(text))
|
|
|
|
if (!QrSegment.isAlphanumeric(text))
|
|
|
|
throw "String contains unencodable characters in alphanumeric mode";
|
|
|
|
throw new RangeError("String contains unencodable characters in alphanumeric mode");
|
|
|
|
let bb: Array<bit> = []
|
|
|
|
let bb: Array<bit> = []
|
|
|
|
let i: int;
|
|
|
|
let i: int;
|
|
|
|
for (i = 0; i + 2 <= text.length; i += 2) { // Process groups of 2
|
|
|
|
for (i = 0; i + 2 <= text.length; i += 2) { // Process groups of 2
|
|
|
@ -807,7 +807,7 @@ namespace qrcodegen {
|
|
|
|
public static makeEci(assignVal: int): QrSegment {
|
|
|
|
public static makeEci(assignVal: int): QrSegment {
|
|
|
|
let bb: Array<bit> = []
|
|
|
|
let bb: Array<bit> = []
|
|
|
|
if (assignVal < 0)
|
|
|
|
if (assignVal < 0)
|
|
|
|
throw "ECI assignment value out of range";
|
|
|
|
throw new RangeError("ECI assignment value out of range");
|
|
|
|
else if (assignVal < (1 << 7))
|
|
|
|
else if (assignVal < (1 << 7))
|
|
|
|
appendBits(assignVal, 8, bb);
|
|
|
|
appendBits(assignVal, 8, bb);
|
|
|
|
else if (assignVal < (1 << 14)) {
|
|
|
|
else if (assignVal < (1 << 14)) {
|
|
|
@ -817,7 +817,7 @@ namespace qrcodegen {
|
|
|
|
appendBits(0b110, 3, bb);
|
|
|
|
appendBits(0b110, 3, bb);
|
|
|
|
appendBits(assignVal, 21, bb);
|
|
|
|
appendBits(assignVal, 21, bb);
|
|
|
|
} else
|
|
|
|
} else
|
|
|
|
throw "ECI assignment value out of range";
|
|
|
|
throw new RangeError("ECI assignment value out of range");
|
|
|
|
return new QrSegment(QrSegment.Mode.ECI, 0, bb);
|
|
|
|
return new QrSegment(QrSegment.Mode.ECI, 0, bb);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
@ -855,7 +855,7 @@ namespace qrcodegen {
|
|
|
|
private readonly bitData: Array<bit>) {
|
|
|
|
private readonly bitData: Array<bit>) {
|
|
|
|
|
|
|
|
|
|
|
|
if (numChars < 0)
|
|
|
|
if (numChars < 0)
|
|
|
|
throw "Invalid argument";
|
|
|
|
throw new RangeError("Invalid argument");
|
|
|
|
this.bitData = bitData.slice(); // Make defensive copy
|
|
|
|
this.bitData = bitData.slice(); // Make defensive copy
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|