UNPKG

jsqr

Version:

A pure javascript QR code reading library that takes in raw images and will locate, extract and parse any QR code found within.

1,444 lines (1,410 loc) 257 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["jsQR"] = factory(); else root["jsQR"] = factory(); })(typeof self !== 'undefined' ? self : this, function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { /******/ configurable: false, /******/ enumerable: true, /******/ get: getter /******/ }); /******/ } /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 3); /******/ }) /************************************************************************/ /******/ ([ /* 0 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var BitMatrix = /** @class */ (function () { function BitMatrix(data, width) { this.width = width; this.height = data.length / width; this.data = data; } BitMatrix.createEmpty = function (width, height) { return new BitMatrix(new Uint8ClampedArray(width * height), width); }; BitMatrix.prototype.get = function (x, y) { if (x < 0 || x >= this.width || y < 0 || y >= this.height) { return false; } return !!this.data[y * this.width + x]; }; BitMatrix.prototype.set = function (x, y, v) { this.data[y * this.width + x] = v ? 1 : 0; }; BitMatrix.prototype.setRegion = function (left, top, width, height, v) { for (var y = top; y < top + height; y++) { for (var x = left; x < left + width; x++) { this.set(x, y, !!v); } } }; return BitMatrix; }()); exports.BitMatrix = BitMatrix; /***/ }), /* 1 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var GenericGFPoly_1 = __webpack_require__(2); function addOrSubtractGF(a, b) { return a ^ b; // tslint:disable-line:no-bitwise } exports.addOrSubtractGF = addOrSubtractGF; var GenericGF = /** @class */ (function () { function GenericGF(primitive, size, genBase) { this.primitive = primitive; this.size = size; this.generatorBase = genBase; this.expTable = new Array(this.size); this.logTable = new Array(this.size); var x = 1; for (var i = 0; i < this.size; i++) { this.expTable[i] = x; x = x * 2; if (x >= this.size) { x = (x ^ this.primitive) & (this.size - 1); // tslint:disable-line:no-bitwise } } for (var i = 0; i < this.size - 1; i++) { this.logTable[this.expTable[i]] = i; } this.zero = new GenericGFPoly_1.default(this, Uint8ClampedArray.from([0])); this.one = new GenericGFPoly_1.default(this, Uint8ClampedArray.from([1])); } GenericGF.prototype.multiply = function (a, b) { if (a === 0 || b === 0) { return 0; } return this.expTable[(this.logTable[a] + this.logTable[b]) % (this.size - 1)]; }; GenericGF.prototype.inverse = function (a) { if (a === 0) { throw new Error("Can't invert 0"); } return this.expTable[this.size - this.logTable[a] - 1]; }; GenericGF.prototype.buildMonomial = function (degree, coefficient) { if (degree < 0) { throw new Error("Invalid monomial degree less than 0"); } if (coefficient === 0) { return this.zero; } var coefficients = new Uint8ClampedArray(degree + 1); coefficients[0] = coefficient; return new GenericGFPoly_1.default(this, coefficients); }; GenericGF.prototype.log = function (a) { if (a === 0) { throw new Error("Can't take log(0)"); } return this.logTable[a]; }; GenericGF.prototype.exp = function (a) { return this.expTable[a]; }; return GenericGF; }()); exports.default = GenericGF; /***/ }), /* 2 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var GenericGF_1 = __webpack_require__(1); var GenericGFPoly = /** @class */ (function () { function GenericGFPoly(field, coefficients) { if (coefficients.length === 0) { throw new Error("No coefficients."); } this.field = field; var coefficientsLength = coefficients.length; if (coefficientsLength > 1 && coefficients[0] === 0) { // Leading term must be non-zero for anything except the constant polynomial "0" var firstNonZero = 1; while (firstNonZero < coefficientsLength && coefficients[firstNonZero] === 0) { firstNonZero++; } if (firstNonZero === coefficientsLength) { this.coefficients = field.zero.coefficients; } else { this.coefficients = new Uint8ClampedArray(coefficientsLength - firstNonZero); for (var i = 0; i < this.coefficients.length; i++) { this.coefficients[i] = coefficients[firstNonZero + i]; } } } else { this.coefficients = coefficients; } } GenericGFPoly.prototype.degree = function () { return this.coefficients.length - 1; }; GenericGFPoly.prototype.isZero = function () { return this.coefficients[0] === 0; }; GenericGFPoly.prototype.getCoefficient = function (degree) { return this.coefficients[this.coefficients.length - 1 - degree]; }; GenericGFPoly.prototype.addOrSubtract = function (other) { var _a; if (this.isZero()) { return other; } if (other.isZero()) { return this; } var smallerCoefficients = this.coefficients; var largerCoefficients = other.coefficients; if (smallerCoefficients.length > largerCoefficients.length) { _a = [largerCoefficients, smallerCoefficients], smallerCoefficients = _a[0], largerCoefficients = _a[1]; } var sumDiff = new Uint8ClampedArray(largerCoefficients.length); var lengthDiff = largerCoefficients.length - smallerCoefficients.length; for (var i = 0; i < lengthDiff; i++) { sumDiff[i] = largerCoefficients[i]; } for (var i = lengthDiff; i < largerCoefficients.length; i++) { sumDiff[i] = GenericGF_1.addOrSubtractGF(smallerCoefficients[i - lengthDiff], largerCoefficients[i]); } return new GenericGFPoly(this.field, sumDiff); }; GenericGFPoly.prototype.multiply = function (scalar) { if (scalar === 0) { return this.field.zero; } if (scalar === 1) { return this; } var size = this.coefficients.length; var product = new Uint8ClampedArray(size); for (var i = 0; i < size; i++) { product[i] = this.field.multiply(this.coefficients[i], scalar); } return new GenericGFPoly(this.field, product); }; GenericGFPoly.prototype.multiplyPoly = function (other) { if (this.isZero() || other.isZero()) { return this.field.zero; } var aCoefficients = this.coefficients; var aLength = aCoefficients.length; var bCoefficients = other.coefficients; var bLength = bCoefficients.length; var product = new Uint8ClampedArray(aLength + bLength - 1); for (var i = 0; i < aLength; i++) { var aCoeff = aCoefficients[i]; for (var j = 0; j < bLength; j++) { product[i + j] = GenericGF_1.addOrSubtractGF(product[i + j], this.field.multiply(aCoeff, bCoefficients[j])); } } return new GenericGFPoly(this.field, product); }; GenericGFPoly.prototype.multiplyByMonomial = function (degree, coefficient) { if (degree < 0) { throw new Error("Invalid degree less than 0"); } if (coefficient === 0) { return this.field.zero; } var size = this.coefficients.length; var product = new Uint8ClampedArray(size + degree); for (var i = 0; i < size; i++) { product[i] = this.field.multiply(this.coefficients[i], coefficient); } return new GenericGFPoly(this.field, product); }; GenericGFPoly.prototype.evaluateAt = function (a) { var result = 0; if (a === 0) { // Just return the x^0 coefficient return this.getCoefficient(0); } var size = this.coefficients.length; if (a === 1) { // Just the sum of the coefficients this.coefficients.forEach(function (coefficient) { result = GenericGF_1.addOrSubtractGF(result, coefficient); }); return result; } result = this.coefficients[0]; for (var i = 1; i < size; i++) { result = GenericGF_1.addOrSubtractGF(this.field.multiply(a, result), this.coefficients[i]); } return result; }; return GenericGFPoly; }()); exports.default = GenericGFPoly; /***/ }), /* 3 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var binarizer_1 = __webpack_require__(4); var decoder_1 = __webpack_require__(5); var extractor_1 = __webpack_require__(11); var locator_1 = __webpack_require__(12); function scan(matrix) { var locations = locator_1.locate(matrix); if (!locations) { return null; } for (var _i = 0, locations_1 = locations; _i < locations_1.length; _i++) { var location_1 = locations_1[_i]; var extracted = extractor_1.extract(matrix, location_1); var decoded = decoder_1.decode(extracted.matrix); if (decoded) { return { binaryData: decoded.bytes, data: decoded.text, chunks: decoded.chunks, version: decoded.version, location: { topRightCorner: extracted.mappingFunction(location_1.dimension, 0), topLeftCorner: extracted.mappingFunction(0, 0), bottomRightCorner: extracted.mappingFunction(location_1.dimension, location_1.dimension), bottomLeftCorner: extracted.mappingFunction(0, location_1.dimension), topRightFinderPattern: location_1.topRight, topLeftFinderPattern: location_1.topLeft, bottomLeftFinderPattern: location_1.bottomLeft, bottomRightAlignmentPattern: location_1.alignmentPattern, }, }; } } return null; } var defaultOptions = { inversionAttempts: "attemptBoth", }; function jsQR(data, width, height, providedOptions) { if (providedOptions === void 0) { providedOptions = {}; } var options = defaultOptions; Object.keys(options || {}).forEach(function (opt) { options[opt] = providedOptions[opt] || options[opt]; }); var shouldInvert = options.inversionAttempts === "attemptBoth" || options.inversionAttempts === "invertFirst"; var tryInvertedFirst = options.inversionAttempts === "onlyInvert" || options.inversionAttempts === "invertFirst"; var _a = binarizer_1.binarize(data, width, height, shouldInvert), binarized = _a.binarized, inverted = _a.inverted; var result = scan(tryInvertedFirst ? inverted : binarized); if (!result && (options.inversionAttempts === "attemptBoth" || options.inversionAttempts === "invertFirst")) { result = scan(tryInvertedFirst ? binarized : inverted); } return result; } jsQR.default = jsQR; exports.default = jsQR; /***/ }), /* 4 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var BitMatrix_1 = __webpack_require__(0); var REGION_SIZE = 8; var MIN_DYNAMIC_RANGE = 24; function numBetween(value, min, max) { return value < min ? min : value > max ? max : value; } // Like BitMatrix but accepts arbitry Uint8 values var Matrix = /** @class */ (function () { function Matrix(width, height) { this.width = width; this.data = new Uint8ClampedArray(width * height); } Matrix.prototype.get = function (x, y) { return this.data[y * this.width + x]; }; Matrix.prototype.set = function (x, y, value) { this.data[y * this.width + x] = value; }; return Matrix; }()); function binarize(data, width, height, returnInverted) { if (data.length !== width * height * 4) { throw new Error("Malformed data passed to binarizer."); } // Convert image to greyscale var greyscalePixels = new Matrix(width, height); for (var x = 0; x < width; x++) { for (var y = 0; y < height; y++) { var r = data[((y * width + x) * 4) + 0]; var g = data[((y * width + x) * 4) + 1]; var b = data[((y * width + x) * 4) + 2]; greyscalePixels.set(x, y, 0.2126 * r + 0.7152 * g + 0.0722 * b); } } var horizontalRegionCount = Math.ceil(width / REGION_SIZE); var verticalRegionCount = Math.ceil(height / REGION_SIZE); var blackPoints = new Matrix(horizontalRegionCount, verticalRegionCount); for (var verticalRegion = 0; verticalRegion < verticalRegionCount; verticalRegion++) { for (var hortizontalRegion = 0; hortizontalRegion < horizontalRegionCount; hortizontalRegion++) { var sum = 0; var min = Infinity; var max = 0; for (var y = 0; y < REGION_SIZE; y++) { for (var x = 0; x < REGION_SIZE; x++) { var pixelLumosity = greyscalePixels.get(hortizontalRegion * REGION_SIZE + x, verticalRegion * REGION_SIZE + y); sum += pixelLumosity; min = Math.min(min, pixelLumosity); max = Math.max(max, pixelLumosity); } } var average = sum / (Math.pow(REGION_SIZE, 2)); if (max - min <= MIN_DYNAMIC_RANGE) { // If variation within the block is low, assume this is a block with only light or only // dark pixels. In that case we do not want to use the average, as it would divide this // low contrast area into black and white pixels, essentially creating data out of noise. // // Default the blackpoint for these blocks to be half the min - effectively white them out average = min / 2; if (verticalRegion > 0 && hortizontalRegion > 0) { // Correct the "white background" assumption for blocks that have neighbors by comparing // the pixels in this block to the previously calculated black points. This is based on // the fact that dark barcode symbology is always surrounded by some amount of light // background for which reasonable black point estimates were made. The bp estimated at // the boundaries is used for the interior. // The (min < bp) is arbitrary but works better than other heuristics that were tried. var averageNeighborBlackPoint = (blackPoints.get(hortizontalRegion, verticalRegion - 1) + (2 * blackPoints.get(hortizontalRegion - 1, verticalRegion)) + blackPoints.get(hortizontalRegion - 1, verticalRegion - 1)) / 4; if (min < averageNeighborBlackPoint) { average = averageNeighborBlackPoint; } } } blackPoints.set(hortizontalRegion, verticalRegion, average); } } var binarized = BitMatrix_1.BitMatrix.createEmpty(width, height); var inverted = null; if (returnInverted) { inverted = BitMatrix_1.BitMatrix.createEmpty(width, height); } for (var verticalRegion = 0; verticalRegion < verticalRegionCount; verticalRegion++) { for (var hortizontalRegion = 0; hortizontalRegion < horizontalRegionCount; hortizontalRegion++) { var left = numBetween(hortizontalRegion, 2, horizontalRegionCount - 3); var top_1 = numBetween(verticalRegion, 2, verticalRegionCount - 3); var sum = 0; for (var xRegion = -2; xRegion <= 2; xRegion++) { for (var yRegion = -2; yRegion <= 2; yRegion++) { sum += blackPoints.get(left + xRegion, top_1 + yRegion); } } var threshold = sum / 25; for (var xRegion = 0; xRegion < REGION_SIZE; xRegion++) { for (var yRegion = 0; yRegion < REGION_SIZE; yRegion++) { var x = hortizontalRegion * REGION_SIZE + xRegion; var y = verticalRegion * REGION_SIZE + yRegion; var lum = greyscalePixels.get(x, y); binarized.set(x, y, lum <= threshold); if (returnInverted) { inverted.set(x, y, !(lum <= threshold)); } } } } } if (returnInverted) { return { binarized: binarized, inverted: inverted }; } return { binarized: binarized }; } exports.binarize = binarize; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); var BitMatrix_1 = __webpack_require__(0); var decodeData_1 = __webpack_require__(6); var reedsolomon_1 = __webpack_require__(9); var version_1 = __webpack_require__(10); // tslint:disable:no-bitwise function numBitsDiffering(x, y) { var z = x ^ y; var bitCount = 0; while (z) { bitCount++; z &= z - 1; } return bitCount; } function pushBit(bit, byte) { return (byte << 1) | bit; } // tslint:enable:no-bitwise var FORMAT_INFO_TABLE = [ { bits: 0x5412, formatInfo: { errorCorrectionLevel: 1, dataMask: 0 } }, { bits: 0x5125, formatInfo: { errorCorrectionLevel: 1, dataMask: 1 } }, { bits: 0x5E7C, formatInfo: { errorCorrectionLevel: 1, dataMask: 2 } }, { bits: 0x5B4B, formatInfo: { errorCorrectionLevel: 1, dataMask: 3 } }, { bits: 0x45F9, formatInfo: { errorCorrectionLevel: 1, dataMask: 4 } }, { bits: 0x40CE, formatInfo: { errorCorrectionLevel: 1, dataMask: 5 } }, { bits: 0x4F97, formatInfo: { errorCorrectionLevel: 1, dataMask: 6 } }, { bits: 0x4AA0, formatInfo: { errorCorrectionLevel: 1, dataMask: 7 } }, { bits: 0x77C4, formatInfo: { errorCorrectionLevel: 0, dataMask: 0 } }, { bits: 0x72F3, formatInfo: { errorCorrectionLevel: 0, dataMask: 1 } }, { bits: 0x7DAA, formatInfo: { errorCorrectionLevel: 0, dataMask: 2 } }, { bits: 0x789D, formatInfo: { errorCorrectionLevel: 0, dataMask: 3 } }, { bits: 0x662F, formatInfo: { errorCorrectionLevel: 0, dataMask: 4 } }, { bits: 0x6318, formatInfo: { errorCorrectionLevel: 0, dataMask: 5 } }, { bits: 0x6C41, formatInfo: { errorCorrectionLevel: 0, dataMask: 6 } }, { bits: 0x6976, formatInfo: { errorCorrectionLevel: 0, dataMask: 7 } }, { bits: 0x1689, formatInfo: { errorCorrectionLevel: 3, dataMask: 0 } }, { bits: 0x13BE, formatInfo: { errorCorrectionLevel: 3, dataMask: 1 } }, { bits: 0x1CE7, formatInfo: { errorCorrectionLevel: 3, dataMask: 2 } }, { bits: 0x19D0, formatInfo: { errorCorrectionLevel: 3, dataMask: 3 } }, { bits: 0x0762, formatInfo: { errorCorrectionLevel: 3, dataMask: 4 } }, { bits: 0x0255, formatInfo: { errorCorrectionLevel: 3, dataMask: 5 } }, { bits: 0x0D0C, formatInfo: { errorCorrectionLevel: 3, dataMask: 6 } }, { bits: 0x083B, formatInfo: { errorCorrectionLevel: 3, dataMask: 7 } }, { bits: 0x355F, formatInfo: { errorCorrectionLevel: 2, dataMask: 0 } }, { bits: 0x3068, formatInfo: { errorCorrectionLevel: 2, dataMask: 1 } }, { bits: 0x3F31, formatInfo: { errorCorrectionLevel: 2, dataMask: 2 } }, { bits: 0x3A06, formatInfo: { errorCorrectionLevel: 2, dataMask: 3 } }, { bits: 0x24B4, formatInfo: { errorCorrectionLevel: 2, dataMask: 4 } }, { bits: 0x2183, formatInfo: { errorCorrectionLevel: 2, dataMask: 5 } }, { bits: 0x2EDA, formatInfo: { errorCorrectionLevel: 2, dataMask: 6 } }, { bits: 0x2BED, formatInfo: { errorCorrectionLevel: 2, dataMask: 7 } }, ]; var DATA_MASKS = [ function (p) { return ((p.y + p.x) % 2) === 0; }, function (p) { return (p.y % 2) === 0; }, function (p) { return p.x % 3 === 0; }, function (p) { return (p.y + p.x) % 3 === 0; }, function (p) { return (Math.floor(p.y / 2) + Math.floor(p.x / 3)) % 2 === 0; }, function (p) { return ((p.x * p.y) % 2) + ((p.x * p.y) % 3) === 0; }, function (p) { return ((((p.y * p.x) % 2) + (p.y * p.x) % 3) % 2) === 0; }, function (p) { return ((((p.y + p.x) % 2) + (p.y * p.x) % 3) % 2) === 0; }, ]; function buildFunctionPatternMask(version) { var dimension = 17 + 4 * version.versionNumber; var matrix = BitMatrix_1.BitMatrix.createEmpty(dimension, dimension); matrix.setRegion(0, 0, 9, 9, true); // Top left finder pattern + separator + format matrix.setRegion(dimension - 8, 0, 8, 9, true); // Top right finder pattern + separator + format matrix.setRegion(0, dimension - 8, 9, 8, true); // Bottom left finder pattern + separator + format // Alignment patterns for (var _i = 0, _a = version.alignmentPatternCenters; _i < _a.length; _i++) { var x = _a[_i]; for (var _b = 0, _c = version.alignmentPatternCenters; _b < _c.length; _b++) { var y = _c[_b]; if (!(x === 6 && y === 6 || x === 6 && y === dimension - 7 || x === dimension - 7 && y === 6)) { matrix.setRegion(x - 2, y - 2, 5, 5, true); } } } matrix.setRegion(6, 9, 1, dimension - 17, true); // Vertical timing pattern matrix.setRegion(9, 6, dimension - 17, 1, true); // Horizontal timing pattern if (version.versionNumber > 6) { matrix.setRegion(dimension - 11, 0, 3, 6, true); // Version info, top right matrix.setRegion(0, dimension - 11, 6, 3, true); // Version info, bottom left } return matrix; } function readCodewords(matrix, version, formatInfo) { var dataMask = DATA_MASKS[formatInfo.dataMask]; var dimension = matrix.height; var functionPatternMask = buildFunctionPatternMask(version); var codewords = []; var currentByte = 0; var bitsRead = 0; // Read columns in pairs, from right to left var readingUp = true; for (var columnIndex = dimension - 1; columnIndex > 0; columnIndex -= 2) { if (columnIndex === 6) { // Skip whole column with vertical alignment pattern; columnIndex--; } for (var i = 0; i < dimension; i++) { var y = readingUp ? dimension - 1 - i : i; for (var columnOffset = 0; columnOffset < 2; columnOffset++) { var x = columnIndex - columnOffset; if (!functionPatternMask.get(x, y)) { bitsRead++; var bit = matrix.get(x, y); if (dataMask({ y: y, x: x })) { bit = !bit; } currentByte = pushBit(bit, currentByte); if (bitsRead === 8) { // Whole bytes codewords.push(currentByte); bitsRead = 0; currentByte = 0; } } } } readingUp = !readingUp; } return codewords; } function readVersion(matrix) { var dimension = matrix.height; var provisionalVersion = Math.floor((dimension - 17) / 4); if (provisionalVersion <= 6) { // 6 and under dont have version info in the QR code return version_1.VERSIONS[provisionalVersion - 1]; } var topRightVersionBits = 0; for (var y = 5; y >= 0; y--) { for (var x = dimension - 9; x >= dimension - 11; x--) { topRightVersionBits = pushBit(matrix.get(x, y), topRightVersionBits); } } var bottomLeftVersionBits = 0; for (var x = 5; x >= 0; x--) { for (var y = dimension - 9; y >= dimension - 11; y--) { bottomLeftVersionBits = pushBit(matrix.get(x, y), bottomLeftVersionBits); } } var bestDifference = Infinity; var bestVersion; for (var _i = 0, VERSIONS_1 = version_1.VERSIONS; _i < VERSIONS_1.length; _i++) { var version = VERSIONS_1[_i]; if (version.infoBits === topRightVersionBits || version.infoBits === bottomLeftVersionBits) { return version; } var difference = numBitsDiffering(topRightVersionBits, version.infoBits); if (difference < bestDifference) { bestVersion = version; bestDifference = difference; } difference = numBitsDiffering(bottomLeftVersionBits, version.infoBits); if (difference < bestDifference) { bestVersion = version; bestDifference = difference; } } // We can tolerate up to 3 bits of error since no two version info codewords will // differ in less than 8 bits. if (bestDifference <= 3) { return bestVersion; } } function readFormatInformation(matrix) { var topLeftFormatInfoBits = 0; for (var x = 0; x <= 8; x++) { if (x !== 6) { // Skip timing pattern bit topLeftFormatInfoBits = pushBit(matrix.get(x, 8), topLeftFormatInfoBits); } } for (var y = 7; y >= 0; y--) { if (y !== 6) { // Skip timing pattern bit topLeftFormatInfoBits = pushBit(matrix.get(8, y), topLeftFormatInfoBits); } } var dimension = matrix.height; var topRightBottomRightFormatInfoBits = 0; for (var y = dimension - 1; y >= dimension - 7; y--) { // bottom left topRightBottomRightFormatInfoBits = pushBit(matrix.get(8, y), topRightBottomRightFormatInfoBits); } for (var x = dimension - 8; x < dimension; x++) { // top right topRightBottomRightFormatInfoBits = pushBit(matrix.get(x, 8), topRightBottomRightFormatInfoBits); } var bestDifference = Infinity; var bestFormatInfo = null; for (var _i = 0, FORMAT_INFO_TABLE_1 = FORMAT_INFO_TABLE; _i < FORMAT_INFO_TABLE_1.length; _i++) { var _a = FORMAT_INFO_TABLE_1[_i], bits = _a.bits, formatInfo = _a.formatInfo; if (bits === topLeftFormatInfoBits || bits === topRightBottomRightFormatInfoBits) { return formatInfo; } var difference = numBitsDiffering(topLeftFormatInfoBits, bits); if (difference < bestDifference) { bestFormatInfo = formatInfo; bestDifference = difference; } if (topLeftFormatInfoBits !== topRightBottomRightFormatInfoBits) { // also try the other option difference = numBitsDiffering(topRightBottomRightFormatInfoBits, bits); if (difference < bestDifference) { bestFormatInfo = formatInfo; bestDifference = difference; } } } // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits differing means we found a match if (bestDifference <= 3) { return bestFormatInfo; } return null; } function getDataBlocks(codewords, version, ecLevel) { var ecInfo = version.errorCorrectionLevels[ecLevel]; var dataBlocks = []; var totalCodewords = 0; ecInfo.ecBlocks.forEach(function (block) { for (var i = 0; i < block.numBlocks; i++) { dataBlocks.push({ numDataCodewords: block.dataCodewordsPerBlock, codewords: [] }); totalCodewords += block.dataCodewordsPerBlock + ecInfo.ecCodewordsPerBlock; } }); // In some cases the QR code will be malformed enough that we pull off more or less than we should. // If we pull off less there's nothing we can do. // If we pull off more we can safely truncate if (codewords.length < totalCodewords) { return null; } codewords = codewords.slice(0, totalCodewords); var shortBlockSize = ecInfo.ecBlocks[0].dataCodewordsPerBlock; // Pull codewords to fill the blocks up to the minimum size for (var i = 0; i < shortBlockSize; i++) { for (var _i = 0, dataBlocks_1 = dataBlocks; _i < dataBlocks_1.length; _i++) { var dataBlock = dataBlocks_1[_i]; dataBlock.codewords.push(codewords.shift()); } } // If there are any large blocks, pull codewords to fill the last element of those if (ecInfo.ecBlocks.length > 1) { var smallBlockCount = ecInfo.ecBlocks[0].numBlocks; var largeBlockCount = ecInfo.ecBlocks[1].numBlocks; for (var i = 0; i < largeBlockCount; i++) { dataBlocks[smallBlockCount + i].codewords.push(codewords.shift()); } } // Add the rest of the codewords to the blocks. These are the error correction codewords. while (codewords.length > 0) { for (var _a = 0, dataBlocks_2 = dataBlocks; _a < dataBlocks_2.length; _a++) { var dataBlock = dataBlocks_2[_a]; dataBlock.codewords.push(codewords.shift()); } } return dataBlocks; } function decodeMatrix(matrix) { var version = readVersion(matrix); if (!version) { return null; } var formatInfo = readFormatInformation(matrix); if (!formatInfo) { return null; } var codewords = readCodewords(matrix, version, formatInfo); var dataBlocks = getDataBlocks(codewords, version, formatInfo.errorCorrectionLevel); if (!dataBlocks) { return null; } // Count total number of data bytes var totalBytes = dataBlocks.reduce(function (a, b) { return a + b.numDataCodewords; }, 0); var resultBytes = new Uint8ClampedArray(totalBytes); var resultIndex = 0; for (var _i = 0, dataBlocks_3 = dataBlocks; _i < dataBlocks_3.length; _i++) { var dataBlock = dataBlocks_3[_i]; var correctedBytes = reedsolomon_1.decode(dataBlock.codewords, dataBlock.codewords.length - dataBlock.numDataCodewords); if (!correctedBytes) { return null; } for (var i = 0; i < dataBlock.numDataCodewords; i++) { resultBytes[resultIndex++] = correctedBytes[i]; } } try { return decodeData_1.decode(resultBytes, version.versionNumber); } catch (_a) { return null; } } function decode(matrix) { if (matrix == null) { return null; } var result = decodeMatrix(matrix); if (result) { return result; } // Decoding didn't work, try mirroring the QR across the topLeft -> bottomRight line. for (var x = 0; x < matrix.width; x++) { for (var y = x + 1; y < matrix.height; y++) { if (matrix.get(x, y) !== matrix.get(y, x)) { matrix.set(x, y, !matrix.get(x, y)); matrix.set(y, x, !matrix.get(y, x)); } } } return decodeMatrix(matrix); } exports.decode = decode; /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); // tslint:disable:no-bitwise var BitStream_1 = __webpack_require__(7); var shiftJISTable_1 = __webpack_require__(8); var Mode; (function (Mode) { Mode["Numeric"] = "numeric"; Mode["Alphanumeric"] = "alphanumeric"; Mode["Byte"] = "byte"; Mode["Kanji"] = "kanji"; Mode["ECI"] = "eci"; })(Mode = exports.Mode || (exports.Mode = {})); var ModeByte; (function (ModeByte) { ModeByte[ModeByte["Terminator"] = 0] = "Terminator"; ModeByte[ModeByte["Numeric"] = 1] = "Numeric"; ModeByte[ModeByte["Alphanumeric"] = 2] = "Alphanumeric"; ModeByte[ModeByte["Byte"] = 4] = "Byte"; ModeByte[ModeByte["Kanji"] = 8] = "Kanji"; ModeByte[ModeByte["ECI"] = 7] = "ECI"; // StructuredAppend = 0x3, // FNC1FirstPosition = 0x5, // FNC1SecondPosition = 0x9, })(ModeByte || (ModeByte = {})); function decodeNumeric(stream, size) { var bytes = []; var text = ""; var characterCountSize = [10, 12, 14][size]; var length = stream.readBits(characterCountSize); // Read digits in groups of 3 while (length >= 3) { var num = stream.readBits(10); if (num >= 1000) { throw new Error("Invalid numeric value above 999"); } var a = Math.floor(num / 100); var b = Math.floor(num / 10) % 10; var c = num % 10; bytes.push(48 + a, 48 + b, 48 + c); text += a.toString() + b.toString() + c.toString(); length -= 3; } // If the number of digits aren't a multiple of 3, the remaining digits are special cased. if (length === 2) { var num = stream.readBits(7); if (num >= 100) { throw new Error("Invalid numeric value above 99"); } var a = Math.floor(num / 10); var b = num % 10; bytes.push(48 + a, 48 + b); text += a.toString() + b.toString(); } else if (length === 1) { var num = stream.readBits(4); if (num >= 10) { throw new Error("Invalid numeric value above 9"); } bytes.push(48 + num); text += num.toString(); } return { bytes: bytes, text: text }; } var AlphanumericCharacterCodes = [ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", " ", "$", "%", "*", "+", "-", ".", "/", ":", ]; function decodeAlphanumeric(stream, size) { var bytes = []; var text = ""; var characterCountSize = [9, 11, 13][size]; var length = stream.readBits(characterCountSize); while (length >= 2) { var v = stream.readBits(11); var a = Math.floor(v / 45); var b = v % 45; bytes.push(AlphanumericCharacterCodes[a].charCodeAt(0), AlphanumericCharacterCodes[b].charCodeAt(0)); text += AlphanumericCharacterCodes[a] + AlphanumericCharacterCodes[b]; length -= 2; } if (length === 1) { var a = stream.readBits(6); bytes.push(AlphanumericCharacterCodes[a].charCodeAt(0)); text += AlphanumericCharacterCodes[a]; } return { bytes: bytes, text: text }; } function decodeByte(stream, size) { var bytes = []; var text = ""; var characterCountSize = [8, 16, 16][size]; var length = stream.readBits(characterCountSize); for (var i = 0; i < length; i++) { var b = stream.readBits(8); bytes.push(b); } try { text += decodeURIComponent(bytes.map(function (b) { return "%" + ("0" + b.toString(16)).substr(-2); }).join("")); } catch (_a) { // failed to decode } return { bytes: bytes, text: text }; } function decodeKanji(stream, size) { var bytes = []; var text = ""; var characterCountSize = [8, 10, 12][size]; var length = stream.readBits(characterCountSize); for (var i = 0; i < length; i++) { var k = stream.readBits(13); var c = (Math.floor(k / 0xC0) << 8) | (k % 0xC0); if (c < 0x1F00) { c += 0x8140; } else { c += 0xC140; } bytes.push(c >> 8, c & 0xFF); text += String.fromCharCode(shiftJISTable_1.shiftJISTable[c]); } return { bytes: bytes, text: text }; } function decode(data, version) { var _a, _b, _c, _d; var stream = new BitStream_1.BitStream(data); // There are 3 'sizes' based on the version. 1-9 is small (0), 10-26 is medium (1) and 27-40 is large (2). var size = version <= 9 ? 0 : version <= 26 ? 1 : 2; var result = { text: "", bytes: [], chunks: [], version: version, }; while (stream.available() >= 4) { var mode = stream.readBits(4); if (mode === ModeByte.Terminator) { return result; } else if (mode === ModeByte.ECI) { if (stream.readBits(1) === 0) { result.chunks.push({ type: Mode.ECI, assignmentNumber: stream.readBits(7), }); } else if (stream.readBits(1) === 0) { result.chunks.push({ type: Mode.ECI, assignmentNumber: stream.readBits(14), }); } else if (stream.readBits(1) === 0) { result.chunks.push({ type: Mode.ECI, assignmentNumber: stream.readBits(21), }); } else { // ECI data seems corrupted result.chunks.push({ type: Mode.ECI, assignmentNumber: -1, }); } } else if (mode === ModeByte.Numeric) { var numericResult = decodeNumeric(stream, size); result.text += numericResult.text; (_a = result.bytes).push.apply(_a, numericResult.bytes); result.chunks.push({ type: Mode.Numeric, text: numericResult.text, }); } else if (mode === ModeByte.Alphanumeric) { var alphanumericResult = decodeAlphanumeric(stream, size); result.text += alphanumericResult.text; (_b = result.bytes).push.apply(_b, alphanumericResult.bytes); result.chunks.push({ type: Mode.Alphanumeric, text: alphanumericResult.text, }); } else if (mode === ModeByte.Byte) { var byteResult = decodeByte(stream, size); result.text += byteResult.text; (_c = result.bytes).push.apply(_c, byteResult.bytes); result.chunks.push({ type: Mode.Byte, bytes: byteResult.bytes, text: byteResult.text, }); } else if (mode === ModeByte.Kanji) { var kanjiResult = decodeKanji(stream, size); result.text += kanjiResult.text; (_d = result.bytes).push.apply(_d, kanjiResult.bytes); result.chunks.push({ type: Mode.Kanji, bytes: kanjiResult.bytes, text: kanjiResult.text, }); } } // If there is no data left, or the remaining bits are all 0, then that counts as a termination marker if (stream.available() === 0 || stream.readBits(stream.available()) === 0) { return result; } } exports.decode = decode; /***/ }), /* 7 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; // tslint:disable:no-bitwise Object.defineProperty(exports, "__esModule", { value: true }); var BitStream = /** @class */ (function () { function BitStream(bytes) { this.byteOffset = 0; this.bitOffset = 0; this.bytes = bytes; } BitStream.prototype.readBits = function (numBits) { if (numBits < 1 || numBits > 32 || numBits > this.available()) { throw new Error("Cannot read " + numBits.toString() + " bits"); } var result = 0; // First, read remainder from current byte if (this.bitOffset > 0) { var bitsLeft = 8 - this.bitOffset; var toRead = numBits < bitsLeft ? numBits : bitsLeft; var bitsToNotRead = bitsLeft - toRead; var mask = (0xFF >> (8 - toRead)) << bitsToNotRead; result = (this.bytes[this.byteOffset] & mask) >> bitsToNotRead; numBits -= toRead; this.bitOffset += toRead; if (this.bitOffset === 8) { this.bitOffset = 0; this.byteOffset++; } } // Next read whole bytes if (numBits > 0) { while (numBits >= 8) { result = (result << 8) | (this.bytes[this.byteOffset] & 0xFF); this.byteOffset++; numBits -= 8; } // Finally read a partial byte if (numBits > 0) { var bitsToNotRead = 8 - numBits; var mask = (0xFF >> bitsToNotRead) << bitsToNotRead; result = (result << numBits) | ((this.bytes[this.byteOffset] & mask) >> bitsToNotRead); this.bitOffset += numBits; } } return result; }; BitStream.prototype.available = function () { return 8 * (this.bytes.length - this.byteOffset) - this.bitOffset; }; return BitStream; }()); exports.BitStream = BitStream; /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { "use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.shiftJISTable = { 0x20: 0x0020, 0x21: 0x0021, 0x22: 0x0022, 0x23: 0x0023, 0x24: 0x0024, 0x25: 0x0025, 0x26: 0x0026, 0x27: 0x0027, 0x28: 0x0028, 0x29: 0x0029, 0x2A: 0x002A, 0x2B: 0x002B, 0x2C: 0x002C, 0x2D: 0x002D, 0x2E: 0x002E, 0x2F: 0x002F, 0x30: 0x0030, 0x31: 0x0031, 0x32: 0x0032, 0x33: 0x0033, 0x34: 0x0034, 0x35: 0x0035, 0x36: 0x0036, 0x37: 0x0037, 0x38: 0x0038, 0x39: 0x0039, 0x3A: 0x003A, 0x3B: 0x003B, 0x3C: 0x003C, 0x3D: 0x003D, 0x3E: 0x003E, 0x3F: 0x003F, 0x40: 0x0040, 0x41: 0x0041, 0x42: 0x0042, 0x43: 0x0043, 0x44: 0x0044, 0x45: 0x0045, 0x46: 0x0046, 0x47: 0x0047, 0x48: 0x0048, 0x49: 0x0049, 0x4A: 0x004A, 0x4B: 0x004B, 0x4C: 0x004C, 0x4D: 0x004D, 0x4E: 0x004E, 0x4F: 0x004F, 0x50: 0x0050, 0x51: 0x0051, 0x52: 0x0052, 0x53: 0x0053, 0x54: 0x0054, 0x55: 0x0055, 0x56: 0x0056, 0x57: 0x0057, 0x58: 0x0058, 0x59: 0x0059, 0x5A: 0x005A, 0x5B: 0x005B, 0x5C: 0x00A5, 0x5D: 0x005D, 0x5E: 0x005E, 0x5F: 0x005F, 0x60: 0x0060, 0x61: 0x0061, 0x62: 0x0062, 0x63: 0x0063, 0x64: 0x0064, 0x65: 0x0065, 0x66: 0x0066, 0x67: 0x0067, 0x68: 0x0068, 0x69: 0x0069, 0x6A: 0x006A, 0x6B: 0x006B, 0x6C: 0x006C, 0x6D: 0x006D, 0x6E: 0x006E, 0x6F: 0x006F, 0x70: 0x0070, 0x71: 0x0071, 0x72: 0x0072, 0x73: 0x0073, 0x74: 0x0074, 0x75: 0x0075, 0x76: 0x0076, 0x77: 0x0077, 0x78: 0x0078, 0x79: 0x0079, 0x7A: 0x007A, 0x7B: 0x007B, 0x7C: 0x007C, 0x7D: 0x007D, 0x7E: 0x203E, 0x8140: 0x3000, 0x8141: 0x3001, 0x8142: 0x3002, 0x8143: 0xFF0C, 0x8144: 0xFF0E, 0x8145: 0x30FB, 0x8146: 0xFF1A, 0x8147: 0xFF1B, 0x8148: 0xFF1F, 0x8149: 0xFF01, 0x814A: 0x309B, 0x814B: 0x309C, 0x814C: 0x00B4, 0x814D: 0xFF40, 0x814E: 0x00A8, 0x814F: 0xFF3E, 0x8150: 0xFFE3, 0x8151: 0xFF3F, 0x8152: 0x30FD, 0x8153: 0x30FE, 0x8154: 0x309D, 0x8155: 0x309E, 0x8156: 0x3003, 0x8157: 0x4EDD, 0x8158: 0x3005, 0x8159: 0x3006, 0x815A: 0x3007, 0x815B: 0x30FC, 0x815C: 0x2015, 0x815D: 0x2010, 0x815E: 0xFF0F, 0x815F: 0x005C, 0x8160: 0x301C, 0x8161: 0x2016, 0x8162: 0xFF5C, 0x8163: 0x2026, 0x8164: 0x2025, 0x8165: 0x2018, 0x8166: 0x2019, 0x8167: 0x201C, 0x8168: 0x201D, 0x8169: 0xFF08, 0x816A: 0xFF09, 0x816B: 0x3014, 0x816C: 0x3015, 0x816D: 0xFF3B, 0x816E: 0xFF3D, 0x816F: 0xFF5B, 0x8170: 0xFF5D, 0x8171: 0x3008, 0x8172: 0x3009, 0x8173: 0x300A, 0x8174: 0x300B, 0x8175: 0x300C, 0x8176: 0x300D, 0x8177: 0x300E, 0x8178: 0x300F, 0x8179: 0x3010, 0x817A: 0x3011, 0x817B: 0xFF0B, 0x817C: 0x2212, 0x817D: 0x00B1, 0x817E: 0x00D7, 0x8180: 0x00F7, 0x8181: 0xFF1D, 0x8182: 0x2260, 0x8183: 0xFF1C, 0x8184: 0xFF1E, 0x8185: 0x2266, 0x8186: 0x2267, 0x8187: 0x221E, 0x8188: 0x2234, 0x8189: 0x2642, 0x818A: 0x2640, 0x818B: 0x00B0, 0x818C: 0x2032, 0x818D: 0x2033, 0x818E: 0x2103, 0x818F: 0xFFE5, 0x8190: 0xFF04, 0x8191: 0x00A2, 0x8192: 0x00A3, 0x8193: 0xFF05, 0x8194: 0xFF03, 0x8195: 0xFF06, 0x8196: 0xFF0A, 0x8197: 0xFF20, 0x8198: 0x00A7, 0x8199: 0x2606, 0x819A: 0x2605, 0x819B: 0x25CB, 0x819C: 0x25CF, 0x819D: 0x25CE, 0x819E: 0x25C7, 0x819F: 0x25C6, 0x81A0: 0x25A1, 0x81A1: 0x25A0, 0x81A2: 0x25B3, 0x81A3: 0x25B2, 0x81A4: 0x25BD, 0x81A5: 0x25BC, 0x81A6: 0x203B, 0x81A7: 0x3012, 0x81A8: 0x2192, 0x81A9: 0x2190, 0x81AA: 0x2191, 0x81AB: 0x2193, 0x81AC: 0x3013, 0x81B8: 0x2208, 0x81B9: 0x220B, 0x81BA: 0x2286, 0x81BB: 0x2287, 0x81BC: 0x2282, 0x81BD: 0x2283, 0x81BE: 0x222A, 0x81BF: 0x2229, 0x81C8: 0x2227, 0x81C9: 0x2228, 0x81CA: 0x00AC, 0x81CB: 0x21D2, 0x81CC: 0x21D4, 0x81CD: 0x2200, 0x81CE: 0x2203, 0x81DA: 0x2220, 0x81DB: 0x22A5, 0x81DC: 0x2312, 0x81DD: 0x2202, 0x81DE: 0x2207, 0x81DF: 0x2261, 0x81E0: 0x2252, 0x81E1: 0x226A, 0x81E2: 0x226B, 0x81E3: 0x221A, 0x81E4: 0x223D, 0x81E5: 0x221D, 0x81E6: 0x2235, 0x81E7: 0x222B, 0x81E8: 0x222C, 0x81F0: 0x212B, 0x81F1: 0x2030, 0x81F2: 0x266F, 0x81F3: 0x266D, 0x81F4: 0x266A, 0x81F5: 0x2020, 0x81F6: 0x2021, 0x81F7: 0x00B6, 0x81FC: 0x25EF, 0x824F: 0xFF10, 0x8250: 0xFF11, 0x8251: 0xFF12, 0x8252: 0xFF13, 0x8253: 0xFF14, 0x8254: 0xFF15, 0x8255: 0xFF16, 0x8256: 0xFF17, 0x8257: 0xFF18, 0x8258: 0xFF19, 0x8260: 0xFF21, 0x8261: 0xFF22, 0x8262: 0xFF23, 0x8263: 0xFF24, 0x8264: 0xFF25, 0x8265: 0xFF26, 0x8266: 0xFF27, 0x8267: 0xFF28, 0x8268: 0xFF29, 0x8269: 0xFF2A, 0x826A: 0xFF2B, 0x826B: 0xFF2C, 0x826C: 0xFF2D, 0x826D: 0xFF2E, 0x826E: 0xFF2F, 0x826F: 0xFF30, 0x8270: 0xFF31, 0x8271: 0xFF32, 0x8272: 0xFF33, 0x8273: 0xFF34, 0x8274: 0xFF35, 0x8275: 0xFF36, 0x8276: 0xFF37, 0x8277: 0xFF38, 0x8278: 0xFF39, 0x8279: 0xFF3A, 0x8281: 0xFF41, 0x8282: 0xFF42, 0x8283: 0xFF43, 0x8284: 0xFF44, 0x8285: 0xFF45, 0x8286: 0xFF46, 0x8287: 0xFF47, 0x8288: 0xFF48, 0x8289: 0xFF49, 0x828A: 0xFF4A, 0x828B: 0xFF4B, 0x828C: 0xFF4C, 0x828D: 0xFF4D, 0x828E: 0xFF4E, 0x828F: 0xFF4F, 0x8290: 0xFF50, 0x8291: 0xFF51, 0x8292: 0xFF52, 0x8293: 0xFF53, 0x8294: 0xFF54, 0x8295: 0xFF55, 0x8296: 0xFF56, 0x8297: 0xFF57, 0x8298: 0xFF58, 0x8299: 0xFF59, 0x829A: 0xFF5A, 0x829F: 0x3041, 0x82A0: 0x3042, 0x82A1: 0x3043, 0x82A2: 0x3044, 0x82A3: 0x3045, 0x82A4: 0x3046, 0x82A5: 0x3047, 0x82A6: 0x3048, 0x82A7: 0x3049, 0x82A8: 0x304A, 0x82A9: 0x304B, 0x82AA: 0x304C, 0x82AB: 0x304D, 0x82AC: 0x304E, 0x82AD: 0x304F, 0x82AE: 0x3050, 0x82AF: 0x3051, 0x82B0: 0x3052, 0x82B1: 0x3053, 0x82B2: 0x3054, 0x82B3: 0x3055, 0x82B4: 0x3056, 0x82B5: 0x3057, 0x82B6: 0x3058, 0x82B7: 0x3059, 0x82B8: 0x305A, 0x82B9: 0x305B, 0x82BA: 0x305C, 0x82BB: 0x305D, 0x82BC: 0x305E, 0x82BD: 0x305F, 0x82BE: 0x3060, 0x82BF: 0x3061, 0x82