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.
*/ var imgU8 = null;
Version.decodeVersionInformation = function(versionBits) {
let bestDifference = 4294967295;
let bestVersion = 0; for (let i = 0; i < Version.VERSION_DECODE_INFO.length; i++) {
let targetVersion = Version.VERSION_DECODE_INFO[i]; if (targetVersion == versionBits) { returnthis.getVersionForNumber(i + 7);
}
let bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion); if (bitsDifference < bestDifference) {
bestVersion = i + 7;
bestDifference = bitsDifference;
}
} if (bestDifference <= 3) { returnthis.getVersionForNumber(bestVersion);
} returnnull;
};
function buildVersions() { returnnew 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))), newVersion(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))), newVersion(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))), newVersion(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, newECB(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, newECB(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 ECBlocks(30, new ECB(34, 24), new ECB(34, 25)), new ECBlocks(30, new ECB(20, 15), new ECB(61, 16))));
}
function PerspectiveTransform(a11, a21, a31, a12, a22, a32, a13, a23, 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; this.transformPoints1 = function(points) {
let max = points.length;
let a11 = this.a11;
let a12 = this.a12;
let a13 = this.a13;
let a21 = this.a21;
let a22 = this.a22;
let a23 = this.a23;
let a31 = this.a31;
let a32 = this.a32;
let a33 = this.a33; for (let i = 0; i < max; i += 2) {
let x = points[i];
let y = points[i + 1];
let 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) {
let n = xValues.length; for (let i = 0; i < n; i++) {
let x = xValues[i];
let y = yValues[i];
let 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() { returnnew 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) { returnnew 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);
};
}
function Detector(image) { this.image = image; this.resultPointCallback = null; this.sizeOfBlackWhiteBlackRun = function(fromX, fromY, toX, toY) {
let steep = Math.abs(toY - fromY) > Math.abs(toX - fromX); if (steep) {
let temp = fromX;
fromX = fromY;
fromY = temp;
temp = toX;
toX = toY;
toY = temp;
}
let dx = Math.abs(toX - fromX);
let dy = Math.abs(toY - fromY);
let error = -dx >> 1;
let ystep = fromY < toY ? 1 : -1;
let xstep = fromX < toX ? 1 : -1;
let state = 0; for (let x = fromX, y = fromY; x != toX; x += xstep) {
let realX = steep ? y : x;
let realY = steep ? x : y; if (state == 1) { if (this.image[realX + realY * imgWidth]) {
state++;
}
} else { if (!this.image[realX + realY * imgWidth]) {
state++;
}
} if (state == 3) {
let diffX = x - fromX;
let diffY = y - fromY; return Math.sqrt(diffX * diffX + diffY * diffY);
}
error += dy; if (error > 0) { if (y == toY) { break;
}
y += ystep;
error -= dx;
}
}
let diffX2 = toX - fromX;
let diffY2 = toY - fromY; return Math.sqrt(diffX2 * diffX2 + diffY2 * diffY2);
}; this.sizeOfBlackWhiteBlackRunBothWays = function(fromX, fromY, toX, toY) {
let result = this.sizeOfBlackWhiteBlackRun(fromX, fromY, toX, toY);
let scale = 1;
let otherToX = fromX - (toX - fromX); if (otherToX < 0) {
scale = fromX / (fromX - otherToX);
otherToX = 0;
} elseif (otherToX >= imgWidth) {
scale = (imgWidth - 1 - fromX) / (otherToX - fromX);
otherToX = imgWidth - 1;
}
let otherToY = Math.floor(fromY - (toY - fromY) * scale);
scale = 1; if (otherToY < 0) {
scale = fromY / (fromY - otherToY);
otherToY = 0;
} elseif (otherToY >= imgHeight) {
scale = (imgHeight - 1 - fromY) / (otherToY - fromY);
otherToY = imgHeight - 1;
}
otherToX = Math.floor(fromX + (otherToX - fromX) * scale);
result += this.sizeOfBlackWhiteBlackRun(fromX, fromY, otherToX, otherToY); return result - 1;
}; this.calculateModuleSizeOneWay = function(pattern, otherPattern) {
let moduleSizeEst1 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(pattern.X), Math.floor(pattern.Y), Math.floor(otherPattern.X), Math.floor(otherPattern.Y));
let moduleSizeEst2 = this.sizeOfBlackWhiteBlackRunBothWays(Math.floor(otherPattern.X), Math.floor(otherPattern.Y), Math.floor(pattern.X), Math.floor(pattern.Y)); if (isNaN(moduleSizeEst1)) { return moduleSizeEst2 / 7;
} if (isNaN(moduleSizeEst2)) { return moduleSizeEst1 / 7;
} return (moduleSizeEst1 + moduleSizeEst2) / 14;
}; this.calculateModuleSize = function(topLeft, topRight, bottomLeft) { return (this.calculateModuleSizeOneWay(topLeft, topRight) + this.calculateModuleSizeOneWay(topLeft, bottomLeft)) / 2;
}; this.distance = function(pattern1, pattern2) {
let xDiff = pattern1.X - pattern2.X;
let yDiff = pattern1.Y - pattern2.Y; return Math.sqrt(xDiff * xDiff + yDiff * yDiff);
}; this.computeDimension = function(topLeft, topRight, bottomLeft, moduleSize) {
let tltrCentersDimension = Math.round(this.distance(topLeft, topRight) / moduleSize);
let tlblCentersDimension = Math.round(this.distance(topLeft, bottomLeft) / moduleSize);
let dimension = (tltrCentersDimension + tlblCentersDimension >> 1) + 7; switch (dimension & 3) { case 0:
dimension++; break;
case 2:
dimension--; break;
case 3: throw"Error";
} return dimension;
}; this.findAlignmentInRegion = function(overallEstModuleSize, estAlignmentX, estAlignmentY, allowanceFactor) {
let allowance = Math.floor(allowanceFactor * overallEstModuleSize);
let alignmentAreaLeftX = Math.max(0, estAlignmentX - allowance);
let alignmentAreaRightX = Math.min(imgWidth - 1, estAlignmentX + allowance); if (alignmentAreaRightX - alignmentAreaLeftX < overallEstModuleSize * 3) { throw"Error";
}
let alignmentAreaTopY = Math.max(0, estAlignmentY - allowance);
let alignmentAreaBottomY = Math.min(imgHeight - 1, estAlignmentY + allowance);
let alignmentFinder = new AlignmentPatternFinder(this.image, alignmentAreaLeftX, alignmentAreaTopY, alignmentAreaRightX - alignmentAreaLeftX, alignmentAreaBottomY - alignmentAreaTopY, overallEstModuleSize, this.resultPointCallback); return alignmentFinder.find();
}; this.createTransform = function(topLeft, topRight, bottomLeft, alignmentPattern, dimension) {
let dimMinusThree = dimension - 3.5;
let bottomRightX;
let bottomRightY;
let sourceBottomRightX;
let sourceBottomRightY; if (alignmentPattern !== null) {
bottomRightX = alignmentPattern.X;
bottomRightY = alignmentPattern.Y;
sourceBottomRightX = sourceBottomRightY = dimMinusThree - 3;
} else {
bottomRightX = topRight.X - topLeft.X + bottomLeft.X;
bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y;
sourceBottomRightX = sourceBottomRightY = dimMinusThree;
}
let transform = PerspectiveTransform.quadrilateralToQuadrilateral(3.5, 3.5, dimMinusThree, 3.5, sourceBottomRightX, sourceBottomRightY, 3.5, dimMinusThree, topLeft.X, topLeft.Y, topRight.X, topRight.Y, bottomRightX, bottomRightY, bottomLeft.X, bottomLeft.Y); return transform;
}; this.sampleGrid = function(image, transform, dimension) {
let sampler = GridSampler; return sampler.sampleGrid3(image, dimension, transform);
}; this.processFinderPatternInfo = function(info) {
let topLeft = info.TopLeft;
let topRight = info.TopRight;
let bottomLeft = info.BottomLeft;
let moduleSize = this.calculateModuleSize(topLeft, topRight, bottomLeft); if (moduleSize < 1) { throw"Error";
}
let dimension = this.computeDimension(topLeft, topRight, bottomLeft, moduleSize);
let provisionalVersion = Version.getProvisionalVersionForDimension(dimension);
let modulesBetweenFPCenters = provisionalVersion.DimensionForVersion - 7;
let alignmentPattern = null; if (provisionalVersion.AlignmentPatternCenters.length > 0) {
let bottomRightX = topRight.X - topLeft.X + bottomLeft.X;
let bottomRightY = topRight.Y - topLeft.Y + bottomLeft.Y;
let correctionToTopLeft = 1 - 3 / modulesBetweenFPCenters;
let estAlignmentX = Math.floor(topLeft.X + correctionToTopLeft * (bottomRightX - topLeft.X));
let estAlignmentY = Math.floor(topLeft.Y + correctionToTopLeft * (bottomRightY - topLeft.Y)); for (let i = 4; i <= 16; i <<= 1) {
alignmentPattern = this.findAlignmentInRegion(moduleSize, estAlignmentX, estAlignmentY, i); break;
}
}
let transform = this.createTransform(topLeft, topRight, bottomLeft, alignmentPattern, dimension);
let bits = this.sampleGrid(this.image, transform, dimension);
let points; if (alignmentPattern === null) {
points = new Array(bottomLeft, topLeft, topRight);
} else {
points = new Array(bottomLeft, topLeft, topRight, alignmentPattern);
} returnnew DetectorResult(bits, points);
}; this.detect = function() {
let info = new FinderPatternFinder().findFinderPattern(this.image); returnthis.processFinderPatternInfo(info);
};
}
var FORMAT_INFO_MASK_QR = 21522;
var FORMAT_INFO_DECODE_LOOKUP = new Array(new Array(21522, 0), new Array(20773, 1), new Array(24188, 2), new Array(23371, 3), new Array(17913, 4), new Array(16590, 5), new Array(20375, 6), new Array(19104, 7), new Array(30660, 8), new Array(29427, 9), new Array(32170, 10), new Array(30877, 11), new Array(26159, 12), new Array(25368, 13), new Array(27713, 14), new Array(26998, 15), new Array(5769, 16), new Array(5054, 17), new Array(7399, 18), new Array(6608, 19), new Array(1890, 20), new Array(597, 21), new Array(3340, 22), new Array(2107, 23), new Array(13663, 24), new Array(12392, 25), new Array(16177, 26), new Array(14854, 27), new Array(9396, 28), new Array(8579, 29), new Array(11994, 30), new Array(11245, 31));
var BITS_SET_IN_HALF_BYTE = new Array(0, 1, 1, 2, 1, 2, 2, 3, 1, 2, 2, 3, 2, 3, 3, 4);
function DataMask000() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) { return (i + j & 1) === 0;
};
}
function DataMask001() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) { return (i & 1) === 0;
};
}
function DataMask010() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) { return j % 3 === 0;
};
}
function DataMask011() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) { return (i + j) % 3 === 0;
};
}
function DataMask100() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) { return (URShift(i, 1) + j / 3 & 1) === 0;
};
}
function DataMask101() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) {
let temp = i * j; return (temp & 1) + temp % 3 === 0;
};
}
function DataMask110() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) {
let temp = i * j; return ((temp & 1) + temp % 3 & 1) === 0;
};
}
function DataMask111() { this.unmaskBitMatrix = function(bits, dimension) { for (let i = 0; i < dimension; i++) { for (let j = 0; j < dimension; j++) { if (this.isMasked(i, j)) {
bits.flip(j, i);
}
}
}
}; this.isMasked = function(i, j) { return ((i + j & 1) + i * j % 3 & 1) === 0;
};
}
DataMask.DATA_MASKS = new Array(new DataMask000(), new DataMask001(), new DataMask010(), new DataMask011(), new DataMask100(), new DataMask101(), new DataMask110(), new DataMask111());
function ReedSolomonDecoder(field) { this.field = field; this.decode = function(received, twoS) {
let poly = new GF256Poly(this.field, received);
let syndromeCoefficients = new Array(twoS); for (let i = 0; i < syndromeCoefficients.length; i++) syndromeCoefficients[i] = 0;
let dataMatrix = false;
let noError = true; for (let i = 0; i < twoS; i++) {
let value = poly.evaluateAt(this.field.exp(dataMatrix ? i + 1 : i));
syndromeCoefficients[syndromeCoefficients.length - 1 - i] = value; if (value !== 0) {
noError = false;
}
} if (noError) { return;
}
let syndrome = new GF256Poly(this.field, syndromeCoefficients);
let sigmaOmega = this.runEuclideanAlgorithm(this.field.buildMonomial(twoS, 1), syndrome, twoS);
let sigma = sigmaOmega[0];
let omega = sigmaOmega[1];
let errorLocations = this.findErrorLocations(sigma);
let errorMagnitudes = this.findErrorMagnitudes(omega, errorLocations, dataMatrix); for (let i = 0; i < errorLocations.length; i++) {
let position = received.length - 1 - this.field.log(errorLocations[i]); if (position < 0) { throw"ReedSolomonException Bad error location";
}
received[position] = GF256.addOrSubtract(received[position], errorMagnitudes[i]);
}
}; this.runEuclideanAlgorithm = function(a, b, R) { if (a.Degree < b.Degree) {
let temp = a;
a = b;
b = temp;
}
let rLast = a;
let r = b;
let sLast = this.field.One;
let s = this.field.Zero;
let tLast = this.field.Zero;
let t = this.field.One; while (r.Degree >= Math.floor(R / 2)) {
let rLastLast = rLast;
let sLastLast = sLast;
let tLastLast = tLast;
rLast = r;
sLast = s;
tLast = t; if (rLast.Zero) { throw"r_{i-1} was zero";
}
r = rLastLast;
let q = this.field.Zero;
let denominatorLeadingTerm = rLast.getCoefficient(rLast.Degree);
let dltInverse = this.field.inverse(denominatorLeadingTerm); while (r.Degree >= rLast.Degree && !r.Zero) {
let degreeDiff = r.Degree - rLast.Degree;
let scale = this.field.multiply(r.getCoefficient(r.Degree), dltInverse);
q = q.addOrSubtract(this.field.buildMonomial(degreeDiff, scale));
r = r.addOrSubtract(rLast.multiplyByMonomial(degreeDiff, scale));
}
s = q.multiply1(sLast).addOrSubtract(sLastLast);
t = q.multiply1(tLast).addOrSubtract(tLastLast);
}
let sigmaTildeAtZero = t.getCoefficient(0); if (sigmaTildeAtZero === 0) { throw"ReedSolomonException sigmaTilde(0) was zero";
}
let inverse = this.field.inverse(sigmaTildeAtZero);
let sigma = t.multiply2(inverse);
let omega = r.multiply2(inverse); returnnew Array(sigma, omega);
}; this.findErrorLocations = function(errorLocator) {
let numErrors = errorLocator.Degree; if (numErrors == 1) { returnnew Array(errorLocator.getCoefficient(1));
}
let result = new Array(numErrors);
let e = 0; for (let i = 1; i < 256 && e < numErrors; i++) { if (errorLocator.evaluateAt(i) === 0) {
result[e] = this.field.inverse(i);
e++;
}
} if (e != numErrors) { throw"Error locator degree does not match number of roots";
} return result;
}; this.findErrorMagnitudes = function(errorEvaluator, errorLocations, dataMatrix) {
let s = errorLocations.length;
let result = new Array(s); for (let i = 0; i < s; i++) {
let xiInverse = this.field.inverse(errorLocations[i]);
let denominator = 1; for (let j = 0; j < s; j++) { if (i != j) {
denominator = this.field.multiply(denominator, GF256.addOrSubtract(1, this.field.multiply(errorLocations[j], xiInverse)));
}
}
result[i] = this.field.multiply(errorEvaluator.evaluateAt(xiInverse), this.field.inverse(denominator)); if (dataMatrix) {
result[i] = this.field.multiply(result[i], xiInverse);
}
} return result;
};
}
function GF256Poly(field, coefficients) { if (coefficients === null || coefficients.length === 0) { throw"System.ArgumentException";
} this.field = field;
let coefficientsLength = coefficients.length; if (coefficientsLength > 1 && coefficients[0] === 0) {
let firstNonZero = 1; while (firstNonZero < coefficientsLength && coefficients[firstNonZero] === 0) {
firstNonZero++;
} if (firstNonZero == coefficientsLength) { this.coefficients = field.Zero.coefficients;
} else { this.coefficients = new Array(coefficientsLength - firstNonZero); for (let i = 0; i < this.coefficients.length; i++) this.coefficients[i] = 0; for (let ci = 0; ci < this.coefficients.length; ci++) this.coefficients[ci] = coefficients[firstNonZero + ci];
}
} else { this.coefficients = coefficients;
} this.__defineGetter__("Zero", function() { returnthis.coefficients[0] === 0;
}); this.__defineGetter__("Degree", function() { returnthis.coefficients.length - 1;
}); this.__defineGetter__("Coefficients", function() { returnthis.coefficients;
}); this.getCoefficient = function(degree) { returnthis.coefficients[this.coefficients.length - 1 - degree];
}; this.evaluateAt = function(a) { if (a === 0) { returnthis.getCoefficient(0);
}
let size = this.coefficients.length; if (a == 1) {
let result = 0; for (let i = 0; i < size; i++) {
result = GF256.addOrSubtract(result, this.coefficients[i]);
} return result;
}
let result2 = this.coefficients[0]; for (let i = 1; i < size; i++) {
result2 = GF256.addOrSubtract(this.field.multiply(a, result2), this.coefficients[i]);
} return result2;
}; this.addOrSubtract = function(other) { if (this.field != other.field) { throw"GF256Polys do not have same GF256 field";
} if (this.Zero) { return other;
} if (other.Zero) { returnthis;
}
let smallerCoefficients = this.coefficients;
let largerCoefficients = other.coefficients; if (smallerCoefficients.length > largerCoefficients.length) {
let temp = smallerCoefficients;
smallerCoefficients = largerCoefficients;
largerCoefficients = temp;
}
let sumDiff = new Array(largerCoefficients.length);
let lengthDiff = largerCoefficients.length - smallerCoefficients.length; for (let ci = 0; ci < lengthDiff; ci++) sumDiff[ci] = largerCoefficients[ci]; for (let i = lengthDiff; i < largerCoefficients.length; i++) {
sumDiff[i] = GF256.addOrSubtract(smallerCoefficients[i - lengthDiff], largerCoefficients[i]);
} returnnew GF256Poly(field, sumDiff);
}; this.multiply1 = function(other) { if (this.field != other.field) { throw"GF256Polys do not have same GF256 field";
} if (this.Zero || other.Zero) { returnthis.field.Zero;
}
let aCoefficients = this.coefficients;
let aLength = aCoefficients.length;
let bCoefficients = other.coefficients;
let bLength = bCoefficients.length;
let product = new Array(aLength + bLength - 1); for (let i = 0; i < aLength; i++) {
let aCoeff = aCoefficients[i]; for (let j = 0; j < bLength; j++) {
product[i + j] = GF256.addOrSubtract(product[i + j], this.field.multiply(aCoeff, bCoefficients[j]));
}
} returnnew GF256Poly(this.field, product);
}; this.multiply2 = function(scalar) { if (scalar === 0) { returnthis.field.Zero;
} if (scalar == 1) { returnthis;
}
let size = this.coefficients.length;
let product = new Array(size); for (let i = 0; i < size; i++) {
product[i] = this.field.multiply(this.coefficients[i], scalar);
} returnnew GF256Poly(this.field, product);
}; this.multiplyByMonomial = function(degree, coefficient) { if (degree < 0) { throw"System.ArgumentException";
} if (coefficient === 0) { returnthis.field.Zero;
}
let size = this.coefficients.length;
let product = new Array(size + degree); for (let i = 0; i < product.length; i++) product[i] = 0; for (let i = 0; i < size; i++) {
product[i] = this.field.multiply(this.coefficients[i], coefficient);
} returnnew GF256Poly(this.field, product);
}; this.divide = function(other) { if (this.field != other.field) { throw"GF256Polys do not have same GF256 field";
} if (other.Zero) { throw"Divide by 0";
}
let quotient = this.field.Zero;
let remainder = this;
let denominatorLeadingTerm = other.getCoefficient(other.Degree);
let inverseDenominatorLeadingTerm = this.field.inverse(denominatorLeadingTerm); while (remainder.Degree >= other.Degree && !remainder.Zero) {
let degreeDifference = remainder.Degree - other.Degree;
let scale = this.field.multiply(remainder.getCoefficient(remainder.Degree), inverseDenominatorLeadingTerm);
let term = other.multiplyByMonomial(degreeDifference, scale);
let iterationQuotient = this.field.buildMonomial(degreeDifference, scale);
quotient = quotient.addOrSubtract(iterationQuotient);
remainder = remainder.addOrSubtract(term);
} returnnew Array(quotient, remainder);
};
}
function GF256(primitive) { this.expTable = new Array(256); this.logTable = new Array(256);
let x = 1; for (let i = 0; i < 256; i++) { this.expTable[i] = x;
x <<= 1; if (x >= 256) {
x ^= primitive;
}
} for (let i = 0; i < 255; i++) { this.logTable[this.expTable[i]] = i;
}
let at0 = new Array(1);
at0[0] = 0; this.zero = new GF256Poly(this, new Array(at0));
let at1 = new Array(1);
at1[0] = 1; this.one = new GF256Poly(this, new Array(at1)); this.__defineGetter__("Zero", function() { returnthis.zero;
}); this.__defineGetter__("One", function() { returnthis.one;
}); this.buildMonomial = function(degree, coefficient) { if (degree < 0) { throw"System.ArgumentException";
} if (coefficient === 0) { returnthis.zero;
}
let coefficients = new Array(degree + 1); for (let i = 0; i < coefficients.length; i++) coefficients[i] = 0;
coefficients[0] = coefficient; returnnew GF256Poly(this, coefficients);
}; this.exp = function(a) { returnthis.expTable[a];
}; this.log = function(a) { if (a === 0) { throw"System.ArgumentException";
} returnthis.logTable[a];
}; this.inverse = function(a) { if (a === 0) { throw"System.ArithmeticException";
} returnthis.expTable[255 - this.logTable[a]];
}; this.multiply = function(a, b) { if (a === 0 || b === 0) { return 0;
} if (a == 1) { return b;
} if (b == 1) { return a;
} returnthis.expTable[(this.logTable[a] + this.logTable[b]) % 255];
};
}
GF256.QR_CODE_FIELD = new GF256(285);
GF256.DATA_MATRIX_FIELD = new GF256(301);
GF256.addOrSubtract = function(a, b) { return a ^ b;
};
var Decoder = {};
Decoder.rsDecoder = new ReedSolomonDecoder(GF256.QR_CODE_FIELD);
Decoder.correctErrors = function(codewordBytes, numDataCodewords) {
let numCodewords = codewordBytes.length;
let codewordsInts = new Array(numCodewords); for (let i = 0; i < numCodewords; i++) {
codewordsInts[i] = codewordBytes[i] & 255;
}
let numECCodewords = codewordBytes.length - numDataCodewords; try {
Decoder.rsDecoder.decode(codewordsInts, numECCodewords);
} catch (rse) { throw rse;
} for (let i = 0; i < numDataCodewords; i++) {
codewordBytes[i] = codewordsInts[i];
}
};
Decoder.decode = function(bits) {
let parser = new BitMatrixParser(bits);
let version = parser.readVersion();
let ecLevel = parser.readFormatInformation().ErrorCorrectionLevel;
let codewords = parser.readCodewords();
let dataBlocks = DataBlock.getDataBlocks(codewords, version, ecLevel);
let totalBytes = 0; for (let i = 0; i < dataBlocks.length; i++) {
totalBytes += dataBlocks[i].NumDataCodewords;
}
let resultBytes = new Array(totalBytes);
let resultOffset = 0; for (let j = 0; j < dataBlocks.length; j++) {
let dataBlock = dataBlocks[j];
let codewordBytes = dataBlock.Codewords;
let numDataCodewords = dataBlock.NumDataCodewords;
Decoder.correctErrors(codewordBytes, numDataCodewords); for (let i = 0; i < numDataCodewords; i++) {
resultBytes[resultOffset++] = codewordBytes[i];
}
}
let reader = new QRCodeDataBlockReader(resultBytes, version.VersionNumber, ecLevel.Bits); return reader;
};
// mozilla: Get access to a window
var DevToolsServer = require("resource://devtools/server/devtools-server.js").DevToolsServer;
var window = Services.wm.getMostRecentWindow(DevToolsServer.chromeWindowType);
qrcode.process = function(ctx) {
let image = qrcode.grayScaleToBitmap(qrcode.grayscale());
let detector = new Detector(image);
let qRCodeMatrix = detector.detect();
let reader = Decoder.decode(qRCodeMatrix.bits);
let data = reader.DataByte;
let str = ""; for (let i = 0; i < data.length; i++) { for (let j = 0; j < data[i].length; j++) str += String.fromCharCode(data[i][j]);
} return qrcode.decode_utf8(str);
};
qrcode.getMiddleBrightnessPerArea = function(image) {
let numSqrtArea = 4;
let areaWidth = Math.floor(imgWidth / numSqrtArea);
let areaHeight = Math.floor(imgHeight / numSqrtArea);
let minmax = new Array(numSqrtArea); for (let i = 0; i < numSqrtArea; i++) {
minmax[i] = new Array(numSqrtArea); for (let i2 = 0; i2 < numSqrtArea; i2++) {
minmax[i][i2] = new Array(0, 0);
}
} for (let ay = 0; ay < numSqrtArea; ay++) { for (let ax = 0; ax < numSqrtArea; ax++) {
minmax[ax][ay][0] = 255; for (let dy = 0; dy < areaHeight; dy++) { for (let dx = 0; dx < areaWidth; dx++) {
let target = image[areaWidth * ax + dx + (areaHeight * ay + dy) * imgWidth]; if (target < minmax[ax][ay][0]) minmax[ax][ay][0] = target; if (target > minmax[ax][ay][1]) minmax[ax][ay][1] = target;
}
}
}
}
let middle = new Array(numSqrtArea); for (let i3 = 0; i3 < numSqrtArea; i3++) {
middle[i3] = new Array(numSqrtArea);
} for (let ay = 0; ay < numSqrtArea; ay++) { for (let ax = 0; ax < numSqrtArea; ax++) {
middle[ax][ay] = Math.floor((minmax[ax][ay][0] + minmax[ax][ay][1]) / 2);
}
} return middle;
};
qrcode.grayScaleToBitmap = function(grayScale) {
let middle = qrcode.getMiddleBrightnessPerArea(grayScale);
let sqrtNumArea = middle.length;
let areaWidth = Math.floor(imgWidth / sqrtNumArea);
let areaHeight = Math.floor(imgHeight / sqrtNumArea);
let bitmap = new Array(imgHeight * imgWidth); for (let ay = 0; ay < sqrtNumArea; ay++) { for (let ax = 0; ax < sqrtNumArea; ax++) { for (let dy = 0; dy < areaHeight; dy++) { for (let dx = 0; dx < areaWidth; dx++) {
bitmap[areaWidth * ax + dx + (areaHeight * ay + dy) * imgWidth] = grayScale[areaWidth * ax + dx + (areaHeight * ay + dy) * imgWidth] < middle[ax][ay] ? true : false;
}
}
}
} return bitmap;
};
qrcode.grayscale = function() {
let ret = new Uint8ClampedArray(imgWidth * imgHeight); for (let y = 0; y < imgHeight; y++) { for (let x = 0; x < imgWidth; x++) {
let point = x + y * imgWidth;
let rgba = imgU32[point];
let p = (rgba & 0xFF) + ((rgba >> 8) & 0xFF) + ((rgba >> 16) & 0xFF);
ret[x + y * imgWidth] = p / 3;
}
} return ret;
};
function URShift(number, bits) { if (number >= 0) return number >> bits; elsereturn (number >> bits) + (2 << ~bits);
}
// mozilla: Add module support
module.exports = {
decodeFromURI: function(src, cb, errcb) { if (cb) {
qrcode.callback = cb;
} if (errcb) {
qrcode.errback = errcb;
} return qrcode.decode(src);
},
decodeFromCanvas: function(canvas, cb) {
let context = canvas.getContext("2d");
imgWidth = canvas.width;
imgHeight = canvas.height;
imgU8 = context.getImageData(0, 0, imgWidth, imgHeight).data;
imgU32 = new Uint32Array(imgU8.buffer);
let result = qrcode.process(context); if (cb) {
cb(result);
} return result;
}
};
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.36Bemerkung:
(vorverarbeitet)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.