"use strict"; /* * Copyright 2010 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. */ Object.defineProperty(exports, "__esModule", { value: true }); var DecoderResult_1 = require("../../common/DecoderResult"); var GenericGF_1 = require("../../common/reedsolomon/GenericGF"); var ReedSolomonDecoder_1 = require("../../common/reedsolomon/ReedSolomonDecoder"); var IllegalStateException_1 = require("../../IllegalStateException"); var FormatException_1 = require("../../FormatException"); var StringUtils_1 = require("../../common/StringUtils"); var Integer_1 = require("../../util/Integer"); // import java.util.Arrays; var Table; (function (Table) { Table[Table["UPPER"] = 0] = "UPPER"; Table[Table["LOWER"] = 1] = "LOWER"; Table[Table["MIXED"] = 2] = "MIXED"; Table[Table["DIGIT"] = 3] = "DIGIT"; Table[Table["PUNCT"] = 4] = "PUNCT"; Table[Table["BINARY"] = 5] = "BINARY"; })(Table || (Table = {})); /** *
The main class which implements Aztec Code decoding -- as opposed to locating and extracting * the Aztec Code from an image.
* * @author David Olivier */ var Decoder = /** @class */ (function () { function Decoder() { } Decoder.prototype.decode = function (detectorResult) { this.ddata = detectorResult; var matrix = detectorResult.getBits(); var rawbits = this.extractBits(matrix); var correctedBits = this.correctBits(rawbits); var rawBytes = Decoder.convertBoolArrayToByteArray(correctedBits); var result = Decoder.getEncodedData(correctedBits); var decoderResult = new DecoderResult_1.default(rawBytes, result, null, null); decoderResult.setNumBits(correctedBits.length); return decoderResult; }; // This method is used for testing the high-level encoder Decoder.highLevelDecode = function (correctedBits) { return this.getEncodedData(correctedBits); }; /** * Gets the string encoded in the aztec code bits * * @return the decoded string */ Decoder.getEncodedData = function (correctedBits) { var endIndex = correctedBits.length; var latchTable = Table.UPPER; // table most recently latched to var shiftTable = Table.UPPER; // table to use for the next read var result = ''; var index = 0; while (index < endIndex) { if (shiftTable === Table.BINARY) { if (endIndex - index < 5) { break; } var length_1 = Decoder.readCode(correctedBits, index, 5); index += 5; if (length_1 === 0) { if (endIndex - index < 11) { break; } length_1 = Decoder.readCode(correctedBits, index, 11) + 31; index += 11; } for (var charCount = 0; charCount < length_1; charCount++) { if (endIndex - index < 8) { index = endIndex; // Force outer loop to exit break; } var code = Decoder.readCode(correctedBits, index, 8); result += /*(char)*/ StringUtils_1.default.castAsNonUtf8Char(code); index += 8; } // Go back to whatever mode we had been in shiftTable = latchTable; } else { var size = shiftTable === Table.DIGIT ? 4 : 5; if (endIndex - index < size) { break; } var code = Decoder.readCode(correctedBits, index, size); index += size; var str = Decoder.getCharacter(shiftTable, code); if (str.startsWith('CTRL_')) { // Table changes // ISO/IEC 24778:2008 prescribes ending a shift sequence in the mode from which it was invoked. // That's including when that mode is a shift. // Our test case dlusbs.png for issue #642 exercises that. latchTable = shiftTable; // Latch the current mode, so as to return to Upper after U/S B/S shiftTable = Decoder.getTable(str.charAt(5)); if (str.charAt(6) === 'L') { latchTable = shiftTable; } } else { result += str; // Go back to whatever mode we had been in shiftTable = latchTable; } } } return result; }; /** * gets the table corresponding to the char passed */ Decoder.getTable = function (t) { switch (t) { case 'L': return Table.LOWER; case 'P': return Table.PUNCT; case 'M': return Table.MIXED; case 'D': return Table.DIGIT; case 'B': return Table.BINARY; case 'U': default: return Table.UPPER; } }; /** * Gets the character (or string) corresponding to the passed code in the given table * * @param table the table used * @param code the code of the character */ Decoder.getCharacter = function (table, code) { switch (table) { case Table.UPPER: return Decoder.UPPER_TABLE[code]; case Table.LOWER: return Decoder.LOWER_TABLE[code]; case Table.MIXED: return Decoder.MIXED_TABLE[code]; case Table.PUNCT: return Decoder.PUNCT_TABLE[code]; case Table.DIGIT: return Decoder.DIGIT_TABLE[code]; default: // Should not reach here. throw new IllegalStateException_1.default('Bad table'); } }; /** *Performs RS error correction on an array of bits.
* * @return the corrected array * @throws FormatException if the input contains too many errors */ Decoder.prototype.correctBits = function (rawbits) { var gf; var codewordSize; if (this.ddata.getNbLayers() <= 2) { codewordSize = 6; gf = GenericGF_1.default.AZTEC_DATA_6; } else if (this.ddata.getNbLayers() <= 8) { codewordSize = 8; gf = GenericGF_1.default.AZTEC_DATA_8; } else if (this.ddata.getNbLayers() <= 22) { codewordSize = 10; gf = GenericGF_1.default.AZTEC_DATA_10; } else { codewordSize = 12; gf = GenericGF_1.default.AZTEC_DATA_12; } var numDataCodewords = this.ddata.getNbDatablocks(); var numCodewords = rawbits.length / codewordSize; if (numCodewords < numDataCodewords) { throw new FormatException_1.default(); } var offset = rawbits.length % codewordSize; var dataWords = new Int32Array(numCodewords); for (var i = 0; i < numCodewords; i++, offset += codewordSize) { dataWords[i] = Decoder.readCode(rawbits, offset, codewordSize); } try { var rsDecoder = new ReedSolomonDecoder_1.default(gf); rsDecoder.decode(dataWords, numCodewords - numDataCodewords); } catch (ex) { throw new FormatException_1.default(ex); } // Now perform the unstuffing operation. // First, count how many bits are going to be thrown out as stuffing var mask = (1 << codewordSize) - 1; var stuffedBits = 0; for (var i = 0; i < numDataCodewords; i++) { var dataWord = dataWords[i]; if (dataWord === 0 || dataWord === mask) { throw new FormatException_1.default(); } else if (dataWord === 1 || dataWord === mask - 1) { stuffedBits++; } } // Now, actually unpack the bits and remove the stuffing var correctedBits = new Array(numDataCodewords * codewordSize - stuffedBits); var index = 0; for (var i = 0; i < numDataCodewords; i++) { var dataWord = dataWords[i]; if (dataWord === 1 || dataWord === mask - 1) { // next codewordSize-1 bits are all zeros or all ones correctedBits.fill(dataWord > 1, index, index + codewordSize - 1); // Arrays.fill(correctedBits, index, index + codewordSize - 1, dataWord > 1); index += codewordSize - 1; } else { for (var bit = codewordSize - 1; bit >= 0; --bit) { correctedBits[index++] = (dataWord & (1 << bit)) !== 0; } } } return correctedBits; }; /** * Gets the array of bits from an Aztec Code matrix * * @return the array of bits */ Decoder.prototype.extractBits = function (matrix) { var compact = this.ddata.isCompact(); var layers = this.ddata.getNbLayers(); var baseMatrixSize = (compact ? 11 : 14) + layers * 4; // not including alignment lines var alignmentMap = new Int32Array(baseMatrixSize); var rawbits = new Array(this.totalBitsInLayer(layers, compact)); if (compact) { for (var i = 0; i < alignmentMap.length; i++) { alignmentMap[i] = i; } } else { var matrixSize = baseMatrixSize + 1 + 2 * Integer_1.default.truncDivision((Integer_1.default.truncDivision(baseMatrixSize, 2) - 1), 15); var origCenter = baseMatrixSize / 2; var center = Integer_1.default.truncDivision(matrixSize, 2); for (var i = 0; i < origCenter; i++) { var newOffset = i + Integer_1.default.truncDivision(i, 15); alignmentMap[origCenter - i - 1] = center - newOffset - 1; alignmentMap[origCenter + i] = center + newOffset + 1; } } for (var i = 0, rowOffset = 0; i < layers; i++) { var rowSize = (layers - i) * 4 + (compact ? 9 : 12); // The top-left most point of this layer is