UNPKG

angular2-qrscanner

Version:

QrScanner will scan for a QRCode from your Web-cam and return its string representation by drawing the captured image onto a 2D Canvas and use [@LazarSoft/jsqrcode](https://github.com/LazarSoft/jsqrcode) to check for a valid QRCode every *Xms*

1,118 lines (1,111 loc) 152 kB
import { Component, EventEmitter, Input, Output, ViewChild, Renderer2, NgModule } from '@angular/core'; import { Subject } from 'rxjs'; import { CommonModule } from '@angular/common'; /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class AlignmentPattern { /** * @param {?} posX * @param {?} posY * @param {?} estimatedModuleSize */ constructor(posX, posY, estimatedModuleSize) { this.count = 1; this.incrementCount = function () { this.count++; }; this.aboutEquals = function (moduleSize, i, j) { if (Math.abs(i - this.y) <= moduleSize && Math.abs(j - this.x) <= moduleSize) { var /** @type {?} */ moduleSizeDiff = Math.abs(moduleSize - this.estimatedModuleSize); return moduleSizeDiff <= 1.0 || moduleSizeDiff / this.estimatedModuleSize <= 1.0; } return false; }; this.x = posX; this.y = posY; this.estimatedModuleSize = estimatedModuleSize; } /** * @return {?} */ get EstimatedModuleSize() { return this.estimatedModuleSize; } ; /** * @return {?} */ get Count() { return this.count; } ; /** * @return {?} */ get X() { return Math.floor(this.x); } ; /** * @return {?} */ get Y() { return Math.floor(this.y); } ; } class AlignmentPatternFinder { /** * @param {?} image * @param {?} startX * @param {?} startY * @param {?} width * @param {?} height * @param {?} moduleSize * @param {?} imageWidth * @param {?} imageHeight * @param {?} resultPointCallback */ constructor(image, startX, startY, width, height, moduleSize, imageWidth, imageHeight, resultPointCallback) { this.possibleCenters = new Array(); this.crossCheckStateCount = new Array(0, 0, 0); this.centerFromEnd = function (stateCount, end) { return (end - stateCount[2]) - stateCount[1] / 2.0; }; this.foundPatternCross = function (stateCount) { var /** @type {?} */ moduleSize = this.moduleSize; var /** @type {?} */ maxVariance = moduleSize / 2.0; for (var /** @type {?} */ i = 0; i < 3; i++) { if (Math.abs(moduleSize - stateCount[i]) >= maxVariance) { return false; } } return true; }; this.crossCheckVertical = function (startI, centerJ, maxCount, originalStateCountTotal) { var /** @type {?} */ image = this.image; var /** @type {?} */ maxI = this.imageHeight; var /** @type {?} */ stateCount = this.crossCheckStateCount; stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; // Start counting up from center var /** @type {?} */ i = startI; while (i >= 0 && image[centerJ + i * this.imageWidth] && stateCount[1] <= maxCount) { stateCount[1]++; i--; } // If already too many modules in this state or ran off the edge: if (i < 0 || stateCount[1] > maxCount) { return NaN; } while (i >= 0 && !image[centerJ + i * this.imageWidth] && stateCount[0] <= maxCount) { stateCount[0]++; i--; } if (stateCount[0] > maxCount) { return NaN; } // Now also count down from center i = startI + 1; while (i < maxI && image[centerJ + i * this.imageWidth] && stateCount[1] <= maxCount) { stateCount[1]++; i++; } if (i == maxI || stateCount[1] > maxCount) { return NaN; } while (i < maxI && !image[centerJ + i * this.imageWidth] && stateCount[2] <= maxCount) { stateCount[2]++; i++; } if (stateCount[2] > maxCount) { return NaN; } var /** @type {?} */ stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; if (5 * Math.abs(stateCountTotal - originalStateCountTotal) >= 2 * originalStateCountTotal) { return NaN; } return this.foundPatternCross(stateCount) ? this.centerFromEnd(stateCount, i) : NaN; }; this.handlePossibleCenter = function (stateCount, i, j) { var /** @type {?} */ stateCountTotal = stateCount[0] + stateCount[1] + stateCount[2]; var /** @type {?} */ centerJ = this.centerFromEnd(stateCount, j); var /** @type {?} */ centerI = this.crossCheckVertical(i, Math.floor(centerJ), 2 * stateCount[1], stateCountTotal); if (!isNaN(centerI)) { var /** @type {?} */ estimatedModuleSize = (stateCount[0] + stateCount[1] + stateCount[2]) / 3.0; var /** @type {?} */ max = this.possibleCenters.length; for (var /** @type {?} */ index = 0; index < max; index++) { var /** @type {?} */ center = this.possibleCenters[index]; // Look for about the same center and module size: if (center.aboutEquals(estimatedModuleSize, centerI, centerJ)) { return new AlignmentPattern(centerJ, centerI, estimatedModuleSize); } } // Hadn't found this before; save it var /** @type {?} */ point = new AlignmentPattern(centerJ, centerI, estimatedModuleSize); this.possibleCenters.push(point); if (this.resultPointCallback != null) { this.resultPointCallback.foundPossibleResultPoint(point); } } return null; }; this.find = function () { var /** @type {?} */ startX = this.startX; var /** @type {?} */ height = this.height; var /** @type {?} */ maxJ = startX + this.width; var /** @type {?} */ middleI = this.startY + (height >> 1); // We are looking for black/white/black modules in 1:1:1 ratio; // this tracks the number of black/white/black modules seen so far var /** @type {?} */ stateCount = new Array(0, 0, 0); for (var /** @type {?} */ iGen = 0; iGen < height; iGen++) { // Search from middle outwards var /** @type {?} */ i = middleI + ((iGen & 0x01) == 0 ? ((iGen + 1) >> 1) : -((iGen + 1) >> 1)); stateCount[0] = 0; stateCount[1] = 0; stateCount[2] = 0; var /** @type {?} */ j = startX; // Burn off leading white pixels before anything else; if we start in the middle of // a white run, it doesn't make sense to count its length, since we don't know if the // white run continued to the left of the start point while (j < maxJ && !this.image[j + this.imageWidth * i]) { j++; } var /** @type {?} */ currentState = 0; while (j < maxJ) { if (this.image[j + i * this.imageWidth]) { // Black pixel if (currentState == 1) { // Counting black pixels stateCount[currentState]++; } else { // Counting white pixels if (currentState == 2) { // A winner? if (this.foundPatternCross(stateCount)) { // Yes var /** @type {?} */ confirmed = this.handlePossibleCenter(stateCount, i, j); if (confirmed != null) { return confirmed; } } stateCount[0] = stateCount[2]; stateCount[1] = 1; stateCount[2] = 0; currentState = 1; } else { stateCount[++currentState]++; } } } else { // White pixel if (currentState == 1) { // Counting black pixels currentState++; } stateCount[currentState]++; } j++; } if (this.foundPatternCross(stateCount)) { var /** @type {?} */ confirmed = this.handlePossibleCenter(stateCount, i, maxJ); if (confirmed != null) { return confirmed; } } } // Hmm, nothing we saw was observed and confirmed twice. If we had // any guess at all, return it. if (!(this.possibleCenters.length == 0)) { return this.possibleCenters[0]; } throw `Couldn't find enough alignment patterns`; }; this.image = image; this.startX = startX; this.startY = startY; this.width = width; this.height = height; this.moduleSize = moduleSize; this.resultPointCallback = resultPointCallback; this.imageWidth = imageWidth; this.imageHeight = imageHeight; } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ class PerspectiveTransform { /** * @param {?} a11 * @param {?} a21 * @param {?} a31 * @param {?} a12 * @param {?} a22 * @param {?} a32 * @param {?} a13 * @param {?} a23 * @param {?} a33 */ constructor(a11, a21, a31, a12, a22, a32, a13, a23, a33) { this.transformPoints1 = function (points) { var /** @type {?} */ max = points.length; var /** @type {?} */ a11 = this.a11; var /** @type {?} */ a12 = this.a12; var /** @type {?} */ a13 = this.a13; var /** @type {?} */ a21 = this.a21; var /** @type {?} */ a22 = this.a22; var /** @type {?} */ a23 = this.a23; var /** @type {?} */ a31 = this.a31; var /** @type {?} */ a32 = this.a32; var /** @type {?} */ a33 = this.a33; for (var /** @type {?} */ i = 0; i < max; i += 2) { var /** @type {?} */ x = points[i]; var /** @type {?} */ y = points[i + 1]; var /** @type {?} */ denominator = a13 * x + a23 * y + a33; points[i] = (a11 * x + a21 * y + a31) / denominator; points[i + 1] = (a12 * x + a22 * y + a32) / denominator; } }; this.transformPoints2 = function (xValues, yValues) { var /** @type {?} */ n = xValues.length; for (var /** @type {?} */ i = 0; i < n; i++) { var /** @type {?} */ x = xValues[i]; var /** @type {?} */ y = yValues[i]; var /** @type {?} */ denominator = this.a13 * x + this.a23 * y + this.a33; xValues[i] = (this.a11 * x + this.a21 * y + this.a31) / denominator; yValues[i] = (this.a12 * x + this.a22 * y + this.a32) / denominator; } }; this.buildAdjoint = function () { // Adjoint is the transpose of the cofactor matrix: return new PerspectiveTransform(this.a22 * this.a33 - this.a23 * this.a32, this.a23 * this.a31 - this.a21 * this.a33, this.a21 * this.a32 - this.a22 * this.a31, this.a13 * this.a32 - this.a12 * this.a33, this.a11 * this.a33 - this.a13 * this.a31, this.a12 * this.a31 - this.a11 * this.a32, this.a12 * this.a23 - this.a13 * this.a22, this.a13 * this.a21 - this.a11 * this.a23, this.a11 * this.a22 - this.a12 * this.a21); }; this.times = function (other) { return new PerspectiveTransform(this.a11 * other.a11 + this.a21 * other.a12 + this.a31 * other.a13, this.a11 * other.a21 + this.a21 * other.a22 + this.a31 * other.a23, this.a11 * other.a31 + this.a21 * other.a32 + this.a31 * other.a33, this.a12 * other.a11 + this.a22 * other.a12 + this.a32 * other.a13, this.a12 * other.a21 + this.a22 * other.a22 + this.a32 * other.a23, this.a12 * other.a31 + this.a22 * other.a32 + this.a32 * other.a33, this.a13 * other.a11 + this.a23 * other.a12 + this.a33 * other.a13, this.a13 * other.a21 + this.a23 * other.a22 + this.a33 * other.a23, this.a13 * other.a31 + this.a23 * other.a32 + this.a33 * other.a33); }; this.a11 = a11; this.a12 = a12; this.a13 = a13; this.a21 = a21; this.a22 = a22; this.a23 = a23; this.a31 = a31; this.a32 = a32; this.a33 = a33; } /** * @param {?} x0 * @param {?} y0 * @param {?} x1 * @param {?} y1 * @param {?} x2 * @param {?} y2 * @param {?} x3 * @param {?} y3 * @param {?} x0p * @param {?} y0p * @param {?} x1p * @param {?} y1p * @param {?} x2p * @param {?} y2p * @param {?} x3p * @param {?} y3p * @return {?} */ static quadrilateralToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3, x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p) { var /** @type {?} */ qToS = this.quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3); var /** @type {?} */ sToQ = this.squareToQuadrilateral(x0p, y0p, x1p, y1p, x2p, y2p, x3p, y3p); return sToQ.times(qToS); } /** * @param {?} x0 * @param {?} y0 * @param {?} x1 * @param {?} y1 * @param {?} x2 * @param {?} y2 * @param {?} x3 * @param {?} y3 * @return {?} */ static squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3) { var /** @type {?} */ dy2 = y3 - y2; var /** @type {?} */ dy3 = y0 - y1 + y2 - y3; if (dy2 == 0.0 && dy3 == 0.0) { return new PerspectiveTransform(x1 - x0, x2 - x1, x0, y1 - y0, y2 - y1, y0, 0.0, 0.0, 1.0); } else { var /** @type {?} */ dx1 = x1 - x2; var /** @type {?} */ dx2 = x3 - x2; var /** @type {?} */ dx3 = x0 - x1 + x2 - x3; var /** @type {?} */ dy1 = y1 - y2; var /** @type {?} */ denominator = dx1 * dy2 - dx2 * dy1; var /** @type {?} */ a13 = (dx3 * dy2 - dx2 * dy3) / denominator; var /** @type {?} */ a23 = (dx1 * dy3 - dx3 * dy1) / denominator; return new PerspectiveTransform(x1 - x0 + a13 * x1, x3 - x0 + a23 * x3, x0, y1 - y0 + a13 * y1, y3 - y0 + a23 * y3, y0, a13, a23, 1.0); } } /** * @param {?} x0 * @param {?} y0 * @param {?} x1 * @param {?} y1 * @param {?} x2 * @param {?} y2 * @param {?} x3 * @param {?} y3 * @return {?} */ static quadrilateralToSquare(x0, y0, x1, y1, x2, y2, x3, y3) { // Here, the adjoint serves as the inverse: const /** @type {?} */ t = this.squareToQuadrilateral(x0, y0, x1, y1, x2, y2, x3, y3); return t.buildAdjoint(); } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class BitMatrix { /** * @param {?} width * @param {?=} height */ constructor(width, height) { if (!height) height = width; if (width < 1 || height < 1) { throw "Both dimensions must be greater than 0"; } this.width = width; this.height = height; this.rowSize = width >> 5; if ((width & 0x1f) != 0) { this.rowSize++; } this.bits = new Array(this.rowSize * height); for (var /** @type {?} */ i = 0; i < this.bits.length; i++) this.bits[i] = 0; } /** * @return {?} */ get Width() { return this.width; } ; /** * @return {?} */ get Height() { return this.height; } ; /** * @return {?} */ get Dimension() { if (this.width != this.height) { throw "Can't call getDimension() on a non-square matrix"; } return this.width; } ; /** * @param {?} number * @param {?} bits * @return {?} */ URShift(number, bits) { if (number >= 0) return number >> bits; else return (number >> bits) + (2 << ~bits); } /** * @param {?} x * @param {?} y * @return {?} */ get_Renamed(x, y) { var /** @type {?} */ offset = y * this.rowSize + (x >> 5); return ((this.URShift(this.bits[offset], (x & 0x1f))) & 1) != 0; } /** * @param {?} x * @param {?} y * @return {?} */ set_Renamed(x, y) { var /** @type {?} */ offset = y * this.rowSize + (x >> 5); this.bits[offset] |= 1 << (x & 0x1f); } /** * @param {?} x * @param {?} y * @return {?} */ flip(x, y) { var /** @type {?} */ offset = y * this.rowSize + (x >> 5); this.bits[offset] ^= 1 << (x & 0x1f); } /** * @return {?} */ clear() { var /** @type {?} */ max = this.bits.length; for (var /** @type {?} */ i = 0; i < max; i++) { this.bits[i] = 0; } } /** * @param {?} left * @param {?} top * @param {?} width * @param {?} height * @return {?} */ setRegion(left, top, width, height) { if (top < 0 || left < 0) { throw "Left and top must be nonnegative"; } if (height < 1 || width < 1) { throw "Height and width must be at least 1"; } var /** @type {?} */ right = left + width; var /** @type {?} */ bottom = top + height; if (bottom > this.height || right > this.width) { throw "The region must fit inside the matrix"; } for (var /** @type {?} */ y = top; y < bottom; y++) { var /** @type {?} */ offset = y * this.rowSize; for (var /** @type {?} */ x = left; x < right; x++) { this.bits[offset + (x >> 5)] |= 1 << (x & 0x1f); } } } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ class GridSampler { /** * @param {?} width * @param {?} height */ constructor(width, height) { this.width = width; this.height = height; } /** * @param {?} image * @param {?} points * @return {?} */ checkAndNudgePoints(image, points) { var /** @type {?} */ width = this.width; var /** @type {?} */ height = this.height; // Check and nudge points from start until we see some that are OK: var /** @type {?} */ nudged = true; for (var /** @type {?} */ offset = 0; offset < points.length && nudged; offset += 2) { var /** @type {?} */ x = Math.floor(points[offset]); var /** @type {?} */ y = Math.floor(points[offset + 1]); if (x < -1 || x > width || y < -1 || y > height) { throw "Error.checkAndNudgePoints "; } nudged = false; if (x == -1) { points[offset] = 0.0; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == -1) { points[offset + 1] = 0.0; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } // Check and nudge points from end: nudged = true; for (var /** @type {?} */ offset = points.length - 2; offset >= 0 && nudged; offset -= 2) { var /** @type {?} */ x = Math.floor(points[offset]); var /** @type {?} */ y = Math.floor(points[offset + 1]); if (x < -1 || x > width || y < -1 || y > height) { throw "Error.checkAndNudgePoints "; } nudged = false; if (x == -1) { points[offset] = 0.0; nudged = true; } else if (x == width) { points[offset] = width - 1; nudged = true; } if (y == -1) { points[offset + 1] = 0.0; nudged = true; } else if (y == height) { points[offset + 1] = height - 1; nudged = true; } } } /** * @param {?} image * @param {?} rawImage * @param {?} dimension * @param {?} transform * @return {?} */ sampleGrid3(image, rawImage, dimension, transform) { var /** @type {?} */ bits = new BitMatrix(dimension, dimension); var /** @type {?} */ points = new Array(dimension << 1); for (var /** @type {?} */ y = 0; y < dimension; y++) { var /** @type {?} */ max = points.length; var /** @type {?} */ iValue = y + 0.5; for (var /** @type {?} */ x = 0; x < max; x += 2) { points[x] = (x >> 1) + 0.5; points[x + 1] = iValue; } transform.transformPoints1(points); // Quick check to see if points transformed to something inside the image; // sufficient to check the endpoints this.checkAndNudgePoints(image, points); try { for (var /** @type {?} */ x = 0; x < max; x += 2) { var /** @type {?} */ xpoint = (Math.floor(points[x]) * 4) + (Math.floor(points[x + 1]) * this.width * 4); var /** @type {?} */ bit = image[Math.floor(points[x]) + this.width * Math.floor(points[x + 1])]; rawImage.data[xpoint] = bit ? 255 : 0; rawImage.data[xpoint + 1] = bit ? 255 : 0; rawImage.data[xpoint + 2] = 0; rawImage.data[xpoint + 3] = 255; //bits[x >> 1][ y]=bit; if (bit) bits.set_Renamed(x >> 1, y); } } catch (/** @type {?} */ aioobe) { // This feels wrong, but, sometimes if the finder patterns are misidentified, the resulting // transform gets "twisted" such that it maps a straight line of points to a set of points // whose endpoints are in bounds, but others are not. There is probably some mathematical // way to detect this about the transformation that I don't know yet. // This results in an ugly runtime exception despite our clever checks above -- can't have // that. We could check each point's coordinates but that feels duplicative. We settle for // catching and wrapping ArrayIndexOutOfBoundsException. throw "Error.checkAndNudgePoints"; } } return bits; } /** * @param {?} image * @param {?} dimension * @param {?} p1ToX * @param {?} p1ToY * @param {?} p2ToX * @param {?} p2ToY * @param {?} p3ToX * @param {?} p3ToY * @param {?} p4ToX * @param {?} p4ToY * @param {?} p1FromX * @param {?} p1FromY * @param {?} p2FromX * @param {?} p2FromY * @param {?} p3FromX * @param {?} p3FromY * @param {?} p4FromX * @param {?} p4FromY * @return {?} */ sampleGridx(image, dimension, p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY) { var /** @type {?} */ transform = PerspectiveTransform.quadrilateralToQuadrilateral(p1ToX, p1ToY, p2ToX, p2ToY, p3ToX, p3ToY, p4ToX, p4ToY, p1FromX, p1FromY, p2FromX, p2FromY, p3FromX, p3FromY, p4FromX, p4FromY); return this.sampleGrid3(image, {}, dimension, transform); } } /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ /* * * Copyright 2007 ZXing authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ class ErrorCorrectionLevel { /** * @param {?} ordinal * @param {?} bits * @param {?} name */ constructor(ordinal, bits, name) { this.ordinal_Renamed_Field = ordinal; this.bits = bits; this.name = name; } /** * @param {?} bits * @return {?} */ static forBits(bits) { if (bits < 0 || bits >= this.FOR_BITS.length) { throw "ArgumentException"; } return this.FOR_BITS[bits]; } /** * @return {?} */ get Bits() { return this.bits; } ; /** * @return {?} */ get Name() { return this.name; } ; /** * @return {?} */ ordinal() { return this.ordinal_Renamed_Field; } } ErrorCorrectionLevel.L = new ErrorCorrectionLevel(0, 0x01, "L"); ErrorCorrectionLevel.M = new ErrorCorrectionLevel(1, 0x00, "M"); ErrorCorrectionLevel.Q = new ErrorCorrectionLevel(2, 0x03, "Q"); ErrorCorrectionLevel.H = new ErrorCorrectionLevel(3, 0x02, "H"); ErrorCorrectionLevel.FOR_BITS = new Array(ErrorCorrectionLevel.M, ErrorCorrectionLevel.L, ErrorCorrectionLevel.H, ErrorCorrectionLevel.Q); /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ class FormatInformation { /** * @param {?} formatInfo */ constructor(formatInfo) { this.Equals = function (o) { var /** @type {?} */ other = o; return this.errorCorrectionLevel == other.errorCorrectionLevel && this.dataMask == other.dataMask; }; this.errorCorrectionLevel = ErrorCorrectionLevel.forBits((formatInfo >> 3) & 0x03); this.dataMask = (formatInfo & 0x07); } /** * @return {?} */ get ErrorCorrectionLevel() { return this.errorCorrectionLevel; } ; /** * @return {?} */ get DataMask() { return this.dataMask; } ; /** * @return {?} */ GetHashCode() { return (this.errorCorrectionLevel.ordinal() << 3) | this.dataMask; } /** * @param {?} number * @param {?} bits * @return {?} */ static URShift(number, bits) { if (number >= 0) return number >> bits; else return (number >> bits) + (2 << ~bits); } /** * @param {?} a * @param {?} b * @return {?} */ static numBitsDiffering(a, b) { a ^= b; // a now has a 1 bit exactly where its bit differs with b's // Count bits set quickly with a series of lookups: return FormatInformation.BITS_SET_IN_HALF_BYTE[a & 0x0F] + FormatInformation.BITS_SET_IN_HALF_BYTE[(this.URShift(a, 4) & 0x0F)] + FormatInformation.BITS_SET_IN_HALF_BYTE[(this.URShift(a, 8) & 0x0F)] + FormatInformation.BITS_SET_IN_HALF_BYTE[(this.URShift(a, 12) & 0x0F)] + FormatInformation.BITS_SET_IN_HALF_BYTE[(this.URShift(a, 16) & 0x0F)] + FormatInformation.BITS_SET_IN_HALF_BYTE[(this.URShift(a, 20) & 0x0F)] + FormatInformation.BITS_SET_IN_HALF_BYTE[(this.URShift(a, 24) & 0x0F)] + FormatInformation.BITS_SET_IN_HALF_BYTE[(this.URShift(a, 28) & 0x0F)]; } /** * @param {?} maskedFormatInfo * @return {?} */ static decodeFormatInformation(maskedFormatInfo) { var /** @type {?} */ formatInfo = this.doDecodeFormatInformation(maskedFormatInfo); if (formatInfo != null) { return formatInfo; } // Should return null, but, some QR codes apparently // do not mask this info. Try again by actually masking the pattern // first return this.doDecodeFormatInformation(maskedFormatInfo ^ FormatInformation.FORMAT_INFO_MASK_QR); } /** * @param {?} maskedFormatInfo * @return {?} */ static doDecodeFormatInformation(maskedFormatInfo) { // Find the int in FORMAT_INFO_DECODE_LOOKUP with fewest bits differing var /** @type {?} */ bestDifference = 0xffffffff; var /** @type {?} */ bestFormatInfo = 0; for (var /** @type {?} */ i = 0; i < FormatInformation.FORMAT_INFO_DECODE_LOOKUP.length; i++) { var /** @type {?} */ decodeInfo = FormatInformation.FORMAT_INFO_DECODE_LOOKUP[i]; var /** @type {?} */ targetInfo = decodeInfo[0]; if (targetInfo == maskedFormatInfo) { // Found an exact match return new FormatInformation(decodeInfo[1]); } var /** @type {?} */ bitsDifference = FormatInformation.numBitsDiffering(maskedFormatInfo, targetInfo); if (bitsDifference < bestDifference) { bestFormatInfo = decodeInfo[1]; bestDifference = bitsDifference; } } // Hamming distance of the 32 masked codes is 7, by construction, so <= 3 bits // differing means we found a match if (bestDifference <= 3) { return new FormatInformation(bestFormatInfo); } return null; } /** * @param {?} bits * @return {?} */ static forBits(bits) { { if (bits < 0 || bits >= FormatInformation.FOR_BITS.length) { throw "ArgumentException"; } return FormatInformation.FOR_BITS[bits]; } } } FormatInformation.FORMAT_INFO_MASK_QR = 0x5412; FormatInformation.FORMAT_INFO_DECODE_LOOKUP = new Array(new Array(0x5412, 0x00), new Array(0x5125, 0x01), new Array(0x5E7C, 0x02), new Array(0x5B4B, 0x03), new Array(0x45F9, 0x04), new Array(0x40CE, 0x05), new Array(0x4F97, 0x06), new Array(0x4AA0, 0x07), new Array(0x77C4, 0x08), new Array(0x72F3, 0x09), new Array(0x7DAA, 0x0A), new Array(0x789D, 0x0B), new Array(0x662F, 0x0C), new Array(0x6318, 0x0D), new Array(0x6C41, 0x0E), new Array(0x6976, 0x0F), new Array(0x1689, 0x10), new Array(0x13BE, 0x11), new Array(0x1CE7, 0x12), new Array(0x19D0, 0x13), new Array(0x0762, 0x14), new Array(0x0255, 0x15), new Array(0x0D0C, 0x16), new Array(0x083B, 0x17), new Array(0x355F, 0x18), new Array(0x3068, 0x19), new Array(0x3F31, 0x1A), new Array(0x3A06, 0x1B), new Array(0x24B4, 0x1C), new Array(0x2183, 0x1D), new Array(0x2EDA, 0x1E), new Array(0x2BED, 0x1F)); FormatInformation.BITS_SET_IN_HALF_BYTE = new Array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4); FormatInformation.L = new ErrorCorrectionLevel(0, 0x01, "L"); FormatInformation.M = new ErrorCorrectionLevel(1, 0x00, "M"); FormatInformation.Q = new ErrorCorrectionLevel(2, 0x03, "Q"); FormatInformation.H = new ErrorCorrectionLevel(3, 0x02, "H"); FormatInformation.FOR_BITS = new Array(FormatInformation.M, FormatInformation.L, FormatInformation.H, FormatInformation.Q); /** * @fileoverview added by tsickle * @suppress {checkTypes} checked by tsc */ /* Ported to JavaScript by Lazar Laszlo 2011 lazarsoft@gmail.com, www.lazarsoft.info */ class ECB { /** * @param {?} count * @param {?} dataCodewords */ constructor(count, dataCodewords) { this.count = count; this.dataCodewords = dataCodewords; } /** * @return {?} */ get Count() { return this.count; } ; /** * @return {?} */ get DataCodewords() { return this.dataCodewords; } ; } class ECBlocks { /** * @param {?} ecCodewordsPerBlock * @param {?} ecBlocks1 * @param {?=} ecBlocks2 */ constructor(ecCodewordsPerBlock, ecBlocks1, ecBlocks2) { this.getECBlocks = function () { return this.ecBlocks; }; this.ecCodewordsPerBlock = ecCodewordsPerBlock; if (ecBlocks2) this.ecBlocks = new Array(ecBlocks1, ecBlocks2); else this.ecBlocks = new Array(ecBlocks1); } /** * @return {?} */ get ECCodewordsPerBlock() { return this.ecCodewordsPerBlock; } ; /** * @return {?} */ get TotalECCodewords() { return this.ecCodewordsPerBlock * this.NumBlocks; } ; /** * @return {?} */ get NumBlocks() { var /** @type {?} */ total = 0; for (var /** @type {?} */ i = 0; i < this.ecBlocks.length; i++) { total += this.ecBlocks[i].length; } return total; } ; } class Version { /** * @param {?} versionNumber * @param {?} alignmentPatternCenters * @param {?} ecBlocks1 * @param {?} ecBlocks2 * @param {?} ecBlocks3 * @param {?} ecBlocks4 */ constructor(versionNumber, alignmentPatternCenters, ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4) { this.buildFunctionPattern = function () { var /** @type {?} */ dimension = this.DimensionForVersion; var /** @type {?} */ bitMatrix = new BitMatrix(dimension); // Top left finder pattern + separator + format bitMatrix.setRegion(0, 0, 9, 9); // Top right finder pattern + separator + format bitMatrix.setRegion(dimension - 8, 0, 8, 9); // Bottom left finder pattern + separator + format bitMatrix.setRegion(0, dimension - 8, 9, 8); // Alignment patterns var /** @type {?} */ max = this.alignmentPatternCenters.length; for (var /** @type {?} */ x = 0; x < max; x++) { var /** @type {?} */ i = this.alignmentPatternCenters[x] - 2; for (var /** @type {?} */ y = 0; y < max; y++) { if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) { // No alignment patterns near the three finder paterns continue; } bitMatrix.setRegion(this.alignmentPatternCenters[y] - 2, i, 5, 5); } } // Vertical timing pattern bitMatrix.setRegion(6, 9, 1, dimension - 17); // Horizontal timing pattern bitMatrix.setRegion(9, 6, dimension - 17, 1); if (this.versionNumber > 6) { // Version info, top right bitMatrix.setRegion(dimension - 11, 0, 3, 6); // Version info, bottom left bitMatrix.setRegion(0, dimension - 11, 6, 3); } return bitMatrix; }; this.getECBlocksForLevel = function (ecLevel) { return this.ecBlocks[ecLevel.ordinal()]; }; this.versionNumber = versionNumber; this.alignmentPatternCenters = alignmentPatternCenters; this.ecBlocks = new Array(ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4); var /** @type {?} */ total = 0; var /** @type {?} */ ecCodewords = ecBlocks1.ECCodewordsPerBlock; var /** @type {?} */ ecbArray = ecBlocks1.getECBlocks(); for (var /** @type {?} */ i = 0; i < ecbArray.length; i++) { var /** @type {?} */ ecBlock = ecbArray[i]; total += ecBlock.Count * (ecBlock.DataCodewords + ecCodewords); } this.totalCodewords = total; } /** * @return {?} */ get VersionNumber() { return this.versionNumber; } ; /** * @return {?} */ get AlignmentPatternCenters() { return this.alignmentPatternCenters; } ; /** * @return {?} */ get TotalCodewords() { return this.totalCodewords; } ; /** * @return {?} */ get DimensionForVersion() { return 17 + 4 * this.versionNumber; } ; /** * @param {?} versionNumber * @return {?} */ static getVersionForNumber(versionNumber) { if (versionNumber < 1 || versionNumber > 40) { throw "ArgumentException"; } return Version.VERSIONS[versionNumber - 1]; } /** * @param {?} dimension * @return {?} */ static getProvisionalVersionForDimension(dimension) { if (dimension % 4 != 1) { throw "Error getProvisionalVersionForDimension"; } try { return Version.getVersionForNumber((dimension - 17) >> 2); } catch (/** @type {?} */ iae) { throw "Error getVersionForNumber"; } } /** * @param {?} versionBits * @return {?} */ static decodeVersionInformation(versionBits) { var /** @type {?} */ bestDifference = 0xffffffff; var /** @type {?} */ bestVersion = 0; for (var /** @type {?} */ i = 0; i < Version.VERSION_DECODE_INFO.length; i++) { var /** @type {?} */ targetVersion = Version.VERSION_DECODE_INFO[i]; // Do the version info bits match exactly? done. if (targetVersion == versionBits) { return this.getVersionForNumber(i + 7); } // Otherwise see if this is the closest to a real version info bit string // we have seen so far var /** @type {?} */ bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); if (bitsDifference < bestDifference) { bestVersion = i + 7; bestDifference = bitsDifference; } } // We can tolerate up to 3 bits of error since no two version info codewords will // differ in less than 4 bits. if (bestDifference <= 3) { return this.getVersionForNumber(bestVersion); } // If we didn't find a close enough match, fail return null; } /** * @return {?} */ static buildVersions() { return new Array(new Version(1, new Array(), new ECBlocks(7, new ECB(1, 19)), new ECBlocks(10, new ECB(1, 16)), new ECBlocks(13, new ECB(1, 13)), new ECBlocks(17, new ECB(1, 9))), new Version(2, new Array(6, 18), new ECBlocks(10, new ECB(1, 34)), new ECBlocks(16, new ECB(1, 28)), new ECBlocks(22, new ECB(1, 22)), new ECBlocks(28, new ECB(1, 16))), new Version(3, new Array(6, 22), new ECBlocks(15, new ECB(1, 55)), new ECBlocks(26, new ECB(1, 44)), new ECBlocks(18, new ECB(2, 17)), new ECBlocks(22, new ECB(2, 13))), new Version(4, new Array(6, 26), new ECBlocks(20, new ECB(1, 80)), new ECBlocks(18, new ECB(2, 32)), new ECBlocks(26, new ECB(2, 24)), new ECBlocks(16, new ECB(4, 9))), new Version(5, new Array(6, 30), new ECBlocks(26, new ECB(1, 108)), new ECBlocks(24, new ECB(2, 43)), new ECBlocks(18, new ECB(2, 15), new ECB(2, 16)), new ECBlocks(22, new ECB(2, 11), new ECB(2, 12))), new Version(6, new Array(6, 34), new ECBlocks(18, new ECB(2, 68)), new ECBlocks(16, new ECB(4, 27)), new ECBlocks(24, new ECB(4, 19)), new ECBlocks(28, new ECB(4, 15))), new Version(7, new Array(6, 22, 38), new ECBlocks(20, new ECB(2, 78)), new ECBlocks(18, new ECB(4, 31)), new ECBlocks(18, new ECB(2, 14), new ECB(4, 15)), new ECBlocks(26, new ECB(4, 13), new ECB(1, 14))), new Version(8, new Array(6, 24, 42), new ECBlocks(24, new ECB(2, 97)), new ECBlocks(22, new ECB(2, 38), new ECB(2, 39)), new ECBlocks(22, new ECB(4, 18), new ECB(2, 19)), new ECBlocks(26, new ECB(4, 14), new ECB(2, 15))), new Version(9, new Array(6, 26, 46), new ECBlocks(30, new ECB(2, 116)), new ECBlocks(22, new ECB(3, 36), new ECB(2, 37)), new ECBlocks(20, new ECB(4, 16), new ECB(4, 17)), new ECBlocks(24, new ECB(4, 12), new ECB(4, 13))), new Version(10, new Array(6, 28, 50), new ECBlocks(18, new ECB(2, 68), new ECB(2, 69)), new ECBlocks(26, new ECB(4, 43), new ECB(1, 44)), new ECBlocks(24, new ECB(6, 19), new ECB(2, 20)), new ECBlocks(28, new ECB(6, 15), new ECB(2, 16))), new Version(11, new Array(6, 30, 54), new ECBlocks(20, new ECB(4, 81)), new ECBlocks(30, new ECB(1, 50), new ECB(4, 51)), new ECBlocks(28, new ECB(4, 22), new ECB(4, 23)), new ECBlocks(24, new ECB(3, 12), new ECB(8, 13))), new Version(12, new Array(6, 32, 58), new ECBlocks(24, new ECB(2, 92), new ECB(2, 93)), new ECBlocks(22, new ECB(6, 36), new ECB(2, 37)), new ECBlocks(26, new ECB(4, 20), new ECB(6, 21)), new ECBlocks(28, new ECB(7, 14), new ECB(4, 15))), new Version(13, new Array(6, 34, 62), new ECBlocks(26, new ECB(4, 107)), new ECBlocks(22, new ECB(8, 37), new ECB(1, 38)), new ECBlocks(24, new ECB(8, 20), new ECB(4, 21)), new ECBlocks(22, new ECB(12, 11), new ECB(4, 12))), new Version(14, new Array(6, 26, 46, 66), new ECBlocks(30, new ECB(3, 115), new ECB(1, 116)), new ECBlocks(24, new ECB(4, 40), new ECB(5, 41)), new ECBlocks(20, new ECB(11, 16), new ECB(5, 17)), new ECBlocks(24, new ECB(11, 12), new ECB(5, 13))), new Version(15, new Array(6, 26, 48, 70), new ECBlocks(22, new ECB(5, 87), new ECB(1, 88)), new ECBlocks(24, new ECB(5, 41), new ECB(5, 42)), new ECBlocks(30, new ECB(5, 24), new ECB(7, 25)), new ECBlocks(24, new ECB(11, 12), new ECB(7, 13))), new Version(16, new Array(6, 26, 50, 74), new ECBlocks(24, new ECB(5, 98), new ECB(1, 99)), new ECBlocks(28, new ECB(7, 45), new ECB(3, 46)), new ECBlocks(24, new ECB(15, 19), new ECB(2, 20)), new ECBlocks(30, new ECB(3, 15), new ECB(13, 16))), new Version(17, new Array(6, 30, 54, 78), new ECBlocks(28, new ECB(1, 107), new ECB(5, 108)), new ECBlocks(28, new ECB(10, 46), new ECB(1, 47)), new ECBlocks(28, new ECB(1, 22), new ECB(15, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(17, 15))), new Version(18, new Array(6, 30, 56, 82), new ECBlocks(30, new ECB(5, 120), new ECB(1, 121)), new ECBlocks(26, new ECB(9, 43), new ECB(4, 44)), new ECBlocks(28, new ECB(17, 22), new ECB(1, 23)), new ECBlocks(28, new ECB(2, 14), new ECB(19, 15))), new Version(19, new Array(6, 30, 58, 86), new ECBlocks(28, new ECB(3, 113), new ECB(4, 114)), new ECBlocks(26, new ECB(3, 44), new ECB(11, 45)), new ECBlocks(26, new ECB(17, 21), new ECB(4, 22)), new ECBlocks(26, new ECB(9, 13), new ECB(16, 14))), new Version(20, new Array(6, 34, 62, 90), new ECBlocks(28, new ECB(3, 107), new ECB(5, 108)), new ECBlocks(26, new ECB(3, 41), new ECB(13, 42)), new ECBlocks(30, new ECB(15, 24), new ECB(5, 25)), new ECBlocks(28, new ECB(15, 15), new ECB(10, 16))), new Version(21, new Array(6, 28, 50, 72, 94), new ECBlocks(28, new ECB(4, 116), new ECB(4, 117)), new ECBlocks(26, new ECB(17, 42)), new ECBlocks(28, new ECB(17, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(19, 16), new ECB(6, 17))), new Version(22, new Array(6, 26, 50, 74, 98), new ECBlocks(28, new ECB(2, 111), new ECB(7, 112)), new ECBlocks(28, new ECB(17, 46)), new ECBlocks(30, new ECB(7, 24), new ECB(16, 25)), new ECBlocks(24, new ECB(34, 13))), new Version(23, new Array(6, 30, 54, 74, 102), new ECBlocks(30, new ECB(4, 121), new ECB(5, 122)), new ECBlocks(28, new ECB(4, 47), new ECB(14, 48)), new ECBlocks(30, new ECB(11, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(16, 15), new ECB(14, 16))), new Version(24, new Array(6, 28, 54, 80, 106), new ECBlocks(30, new ECB(6, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(6, 45), new ECB(14, 46)), new ECBlocks(30, new ECB(11, 24), new ECB(16, 25)), new ECBlocks(30, new ECB(30, 16), new ECB(2, 17))), new Version(25, new Array(6, 32, 58, 84, 110), new ECBlocks(26, new ECB(8, 106), new ECB(4, 107)), new ECBlocks(28, new ECB(8, 47), new ECB(13, 48)), new ECBlocks(30, new ECB(7, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(13, 16))), new Version(26, new Array(6, 30, 58, 86, 114), new ECBlocks(28, new ECB(10, 114), new ECB(2, 115)), new ECBlocks(28, new ECB(19, 46), new ECB(4, 47)), new ECBlocks(28, new ECB(28, 22), new ECB(6, 23)), new ECBlocks(30, new ECB(33, 16), new ECB(4, 17))), new Version(27, new Array(6, 34, 62, 90, 118), new ECBlocks(30, new ECB(8, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(22, 45), new ECB(3, 46)), new ECBlocks(30, new ECB(8, 23), new ECB(26, 24)), new ECBlocks(30, new ECB(12, 15), new ECB(28, 16))), new Version(28, new Array(6, 26, 50, 74, 98, 122), new ECBlocks(30, new ECB(3, 117), new ECB(10, 118)), new ECBlocks(28, new ECB(3, 45), new ECB(23, 46)), new ECBlocks(30, new ECB(4, 24), new ECB(31, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(31, 16))), new Version(29, new Array(6, 30, 54, 78, 102, 126), new ECBlocks(30, new ECB(7, 116), new ECB(7, 117)), new ECBlocks(28, new ECB(21, 45), new ECB(7, 46)), new ECBlocks(30, new ECB(1, 23), new ECB(37, 24)), new ECBlocks(30, new ECB(19, 15), new ECB(26, 16))), new Version(30, new Array(6, 26, 52, 78, 104, 130), new ECBlocks(30, new ECB(5, 115), new ECB(10, 116)), new ECBlocks(28, new ECB(19, 47), new ECB(10, 48)), new ECBlocks(30, new ECB(15, 24), new ECB(25, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(25, 16))), new Version(31, new Array(6, 30, 56, 82, 108, 134), new ECBlocks(30, new ECB(13, 115), new ECB(3, 116)), new ECBlocks(28, new ECB(2, 46), new ECB(29, 47)), new ECBlocks(30, new ECB(42, 24), new ECB(1, 25)), new ECBlocks(30, new ECB(23, 15), new ECB(28, 16))), new Version(32, new Array(6, 34, 60, 86, 112, 138), new ECBlocks(30, new ECB(17, 115)), new ECBlocks(28, new ECB(10, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(10, 24), new ECB(35, 25)), new ECBlocks(30, new ECB(19, 15), new ECB(35, 16))), new Version(33, new Array(6, 30, 58, 86, 114, 142), new ECBlocks(30, new ECB(17, 115), new ECB(1, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(21, 47)), new ECBlocks(30, new ECB(29, 24), new ECB(19, 25)), new ECBlocks(30, new ECB(11, 15), new ECB(46, 16))), new Version(34, new Array(6, 34, 62, 90, 118, 146), new ECBlocks(30, new ECB(13, 115), new ECB(6, 116)), new ECBlocks(28, new ECB(14, 46), new ECB(23, 47)), new ECBlocks(30, new ECB(44, 24), new ECB(7, 25)), new ECBlocks(30, new ECB(59, 16), new ECB(1, 17))), new Version(35, new Array(6, 30, 54, 78, 102, 126, 150), new ECBlocks(30, new ECB(12, 121), new ECB(7, 122)), new ECBlocks(28, new ECB(12, 47), new ECB(26, 48)), new ECBlocks(30, new ECB(39, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(22, 15), new ECB(41, 16))), new Version(36, new Array(6, 24, 50, 76, 102, 128, 154), new ECBlocks(30, new ECB(6, 121), new ECB(14, 122)), new ECBlocks(28, new ECB(6, 47), new ECB(34, 48)), new ECBlocks(30, new ECB(46, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(2, 15), new ECB(64, 16))), new Version(37, new Array(6, 28, 54, 80, 106, 132, 158), new ECBlocks(30, new ECB(17, 122), new ECB(4, 123)), new ECBlocks(28, new ECB(29, 46), new ECB(14, 47)), new ECBlocks(30, new ECB(49, 24), new ECB(10, 25)), new ECBlocks(30, new ECB(24, 15), new ECB(46, 16))), new Version(38, new Array(6, 32, 58, 84, 110, 136, 162), new ECBlocks(30, new ECB(4, 122), new ECB(18, 123)), new ECBlocks(28, new ECB(13, 46), new ECB(32, 47)), new ECBlocks(30, new ECB(48, 24), new ECB(14, 25)), new ECBlocks(30, new ECB(42, 15), new ECB(32, 16))), new Version(39, new Array(6, 26, 54, 82, 110, 138, 166), new ECBlocks(30, new ECB(20, 117), new ECB(4, 118)), new ECBlocks(28, new ECB(40, 47), new ECB(7, 48)), new ECBlocks(30, new ECB(43, 24), new ECB(22, 25)), new ECBlocks(30, new ECB(10, 15), new ECB(67, 16))), new Version(40, new Array(6, 30, 58, 86, 114, 142, 170), new ECBlocks(30, new ECB(19, 118), new ECB(6, 119)), new ECBlocks(28, new ECB(18, 47), new ECB(31, 48)), new ECBlock