diff options
author | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-01-12 15:50:09 -0800 |
---|---|---|
committer | Dominik Schürmann <dominik@dominikschuermann.de> | 2014-01-12 15:50:09 -0800 |
commit | 92aa5b36bba57e4927f146d49c9f124a37b7b5f9 (patch) | |
tree | 865d3962e54225fc4f13e0d19852ddc061e7e05f /OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder | |
parent | 536c4db48f12287eaf1875e2d208c0ad07e31ee6 (diff) | |
parent | e3bcf64d9e63e293c51db921572a9b87533d26ad (diff) | |
download | open-keychain-92aa5b36bba57e4927f146d49c9f124a37b7b5f9.tar.gz open-keychain-92aa5b36bba57e4927f146d49c9f124a37b7b5f9.tar.bz2 open-keychain-92aa5b36bba57e4927f146d49c9f124a37b7b5f9.zip |
Merge pull request #179 from dschuermann/key-details
Key details
Diffstat (limited to 'OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder')
6 files changed, 0 insertions, 1672 deletions
diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/BlockPair.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/BlockPair.java deleted file mode 100644 index 5714d9c3a..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/BlockPair.java +++ /dev/null @@ -1,37 +0,0 @@ -/* - * Copyright 2008 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. - */ - -package com.google.zxing.qrcode.encoder; - -final class BlockPair { - - private final byte[] dataBytes; - private final byte[] errorCorrectionBytes; - - BlockPair(byte[] data, byte[] errorCorrection) { - dataBytes = data; - errorCorrectionBytes = errorCorrection; - } - - public byte[] getDataBytes() { - return dataBytes; - } - - public byte[] getErrorCorrectionBytes() { - return errorCorrectionBytes; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/ByteMatrix.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/ByteMatrix.java deleted file mode 100644 index eb248a26c..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/ByteMatrix.java +++ /dev/null @@ -1,97 +0,0 @@ -/* - * Copyright 2008 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. - */ - -package com.google.zxing.qrcode.encoder; - -/** - * A class which wraps a 2D array of bytes. The default usage is signed. If you want to use it as a - * unsigned container, it's up to you to do byteValue & 0xff at each location. - * - * JAVAPORT: The original code was a 2D array of ints, but since it only ever gets assigned - * -1, 0, and 1, I'm going to use less memory and go with bytes. - * - * @author dswitkin@google.com (Daniel Switkin) - */ -public final class ByteMatrix { - - private final byte[][] bytes; - private final int width; - private final int height; - - public ByteMatrix(int width, int height) { - bytes = new byte[height][width]; - this.width = width; - this.height = height; - } - - public int getHeight() { - return height; - } - - public int getWidth() { - return width; - } - - public byte get(int x, int y) { - return bytes[y][x]; - } - - public byte[][] getArray() { - return bytes; - } - - public void set(int x, int y, byte value) { - bytes[y][x] = value; - } - - public void set(int x, int y, int value) { - bytes[y][x] = (byte) value; - } - - public void set(int x, int y, boolean value) { - bytes[y][x] = (byte) (value ? 1 : 0); - } - - public void clear(byte value) { - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - bytes[y][x] = value; - } - } - } - - public String toString() { - StringBuffer result = new StringBuffer(2 * width * height + 2); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - switch (bytes[y][x]) { - case 0: - result.append(" 0"); - break; - case 1: - result.append(" 1"); - break; - default: - result.append(" "); - break; - } - } - result.append('\n'); - } - return result.toString(); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/Encoder.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/Encoder.java deleted file mode 100644 index 8796511ab..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/Encoder.java +++ /dev/null @@ -1,557 +0,0 @@ -/* - * Copyright 2008 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. - */ - -package com.google.zxing.qrcode.encoder; - -import com.google.zxing.EncodeHintType; -import com.google.zxing.WriterException; -import com.google.zxing.common.BitArray; -import com.google.zxing.common.CharacterSetECI; -import com.google.zxing.common.ECI; -import com.google.zxing.common.reedsolomon.GenericGF; -import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.google.zxing.qrcode.decoder.Mode; -import com.google.zxing.qrcode.decoder.Version; - -import java.io.UnsupportedEncodingException; -import java.util.Hashtable; -import java.util.Vector; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class Encoder { - - // The original table is defined in the table 5 of JISX0510:2004 (p.19). - private static final int[] ALPHANUMERIC_TABLE = { - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x00-0x0f - -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, // 0x10-0x1f - 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, // 0x20-0x2f - 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, // 0x30-0x3f - -1, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, // 0x40-0x4f - 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f - }; - - static final String DEFAULT_BYTE_MODE_ENCODING = "ISO-8859-1"; - - private Encoder() { - } - - // The mask penalty calculation is complicated. See Table 21 of JISX0510:2004 (p.45) for details. - // Basically it applies four rules and summate all penalties. - private static int calculateMaskPenalty(ByteMatrix matrix) { - int penalty = 0; - penalty += MaskUtil.applyMaskPenaltyRule1(matrix); - penalty += MaskUtil.applyMaskPenaltyRule2(matrix); - penalty += MaskUtil.applyMaskPenaltyRule3(matrix); - penalty += MaskUtil.applyMaskPenaltyRule4(matrix); - return penalty; - } - - /** - * Encode "bytes" with the error correction level "ecLevel". The encoding mode will be chosen - * internally by chooseMode(). On success, store the result in "qrCode". - * - * We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for - * "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very - * strong error correction for this purpose. - * - * Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() - * with which clients can specify the encoding mode. For now, we don't need the functionality. - */ - public static void encode(String content, ErrorCorrectionLevel ecLevel, QRCode qrCode) - throws WriterException { - encode(content, ecLevel, null, qrCode); - } - - public static void encode(String content, ErrorCorrectionLevel ecLevel, Hashtable hints, - QRCode qrCode) throws WriterException { - - String encoding = hints == null ? null : (String) hints.get(EncodeHintType.CHARACTER_SET); - if (encoding == null) { - encoding = DEFAULT_BYTE_MODE_ENCODING; - } - - // Step 1: Choose the mode (encoding). - Mode mode = chooseMode(content, encoding); - - // Step 2: Append "bytes" into "dataBits" in appropriate encoding. - BitArray dataBits = new BitArray(); - appendBytes(content, mode, dataBits, encoding); - // Step 3: Initialize QR code that can contain "dataBits". - int numInputBytes = dataBits.getSizeInBytes(); - initQRCode(numInputBytes, ecLevel, mode, qrCode); - - // Step 4: Build another bit vector that contains header and data. - BitArray headerAndDataBits = new BitArray(); - - // Step 4.5: Append ECI message if applicable - if (mode == Mode.BYTE && !DEFAULT_BYTE_MODE_ENCODING.equals(encoding)) { - CharacterSetECI eci = CharacterSetECI.getCharacterSetECIByName(encoding); - if (eci != null) { - appendECI(eci, headerAndDataBits); - } - } - - appendModeInfo(mode, headerAndDataBits); - - int numLetters = mode.equals(Mode.BYTE) ? dataBits.getSizeInBytes() : content.length(); - appendLengthInfo(numLetters, qrCode.getVersion(), mode, headerAndDataBits); - headerAndDataBits.appendBitArray(dataBits); - - // Step 5: Terminate the bits properly. - terminateBits(qrCode.getNumDataBytes(), headerAndDataBits); - - // Step 6: Interleave data bits with error correction code. - BitArray finalBits = new BitArray(); - interleaveWithECBytes(headerAndDataBits, qrCode.getNumTotalBytes(), qrCode.getNumDataBytes(), - qrCode.getNumRSBlocks(), finalBits); - - // Step 7: Choose the mask pattern and set to "qrCode". - ByteMatrix matrix = new ByteMatrix(qrCode.getMatrixWidth(), qrCode.getMatrixWidth()); - qrCode.setMaskPattern(chooseMaskPattern(finalBits, qrCode.getECLevel(), qrCode.getVersion(), - matrix)); - - // Step 8. Build the matrix and set it to "qrCode". - MatrixUtil.buildMatrix(finalBits, qrCode.getECLevel(), qrCode.getVersion(), - qrCode.getMaskPattern(), matrix); - qrCode.setMatrix(matrix); - // Step 9. Make sure we have a valid QR Code. - if (!qrCode.isValid()) { - throw new WriterException("Invalid QR code: " + qrCode.toString()); - } - } - - /** - * @return the code point of the table used in alphanumeric mode or - * -1 if there is no corresponding code in the table. - */ - static int getAlphanumericCode(int code) { - if (code < ALPHANUMERIC_TABLE.length) { - return ALPHANUMERIC_TABLE[code]; - } - return -1; - } - - public static Mode chooseMode(String content) { - return chooseMode(content, null); - } - - /** - * Choose the best mode by examining the content. Note that 'encoding' is used as a hint; - * if it is Shift_JIS, and the input is only double-byte Kanji, then we return {@link Mode#KANJI}. - */ - public static Mode chooseMode(String content, String encoding) { - if ("Shift_JIS".equals(encoding)) { - // Choose Kanji mode if all input are double-byte characters - return isOnlyDoubleByteKanji(content) ? Mode.KANJI : Mode.BYTE; - } - boolean hasNumeric = false; - boolean hasAlphanumeric = false; - for (int i = 0; i < content.length(); ++i) { - char c = content.charAt(i); - if (c >= '0' && c <= '9') { - hasNumeric = true; - } else if (getAlphanumericCode(c) != -1) { - hasAlphanumeric = true; - } else { - return Mode.BYTE; - } - } - if (hasAlphanumeric) { - return Mode.ALPHANUMERIC; - } else if (hasNumeric) { - return Mode.NUMERIC; - } - return Mode.BYTE; - } - - private static boolean isOnlyDoubleByteKanji(String content) { - byte[] bytes; - try { - bytes = content.getBytes("Shift_JIS"); - } catch (UnsupportedEncodingException uee) { - return false; - } - int length = bytes.length; - if (length % 2 != 0) { - return false; - } - for (int i = 0; i < length; i += 2) { - int byte1 = bytes[i] & 0xFF; - if ((byte1 < 0x81 || byte1 > 0x9F) && (byte1 < 0xE0 || byte1 > 0xEB)) { - return false; - } - } - return true; - } - - private static int chooseMaskPattern(BitArray bits, ErrorCorrectionLevel ecLevel, int version, - ByteMatrix matrix) throws WriterException { - - int minPenalty = Integer.MAX_VALUE; // Lower penalty is better. - int bestMaskPattern = -1; - // We try all mask patterns to choose the best one. - for (int maskPattern = 0; maskPattern < QRCode.NUM_MASK_PATTERNS; maskPattern++) { - MatrixUtil.buildMatrix(bits, ecLevel, version, maskPattern, matrix); - int penalty = calculateMaskPenalty(matrix); - if (penalty < minPenalty) { - minPenalty = penalty; - bestMaskPattern = maskPattern; - } - } - return bestMaskPattern; - } - - /** - * Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, - * modify "qrCode". - */ - private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, Mode mode, - QRCode qrCode) throws WriterException { - qrCode.setECLevel(ecLevel); - qrCode.setMode(mode); - - // In the following comments, we use numbers of Version 7-H. - for (int versionNum = 1; versionNum <= 40; versionNum++) { - Version version = Version.getVersionForNumber(versionNum); - // numBytes = 196 - int numBytes = version.getTotalCodewords(); - // getNumECBytes = 130 - Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel); - int numEcBytes = ecBlocks.getTotalECCodewords(); - // getNumRSBlocks = 5 - int numRSBlocks = ecBlocks.getNumBlocks(); - // getNumDataBytes = 196 - 130 = 66 - int numDataBytes = numBytes - numEcBytes; - // We want to choose the smallest version which can contain data of "numInputBytes" + some - // extra bits for the header (mode info and length info). The header can be three bytes - // (precisely 4 + 16 bits) at most. Hence we do +3 here. - if (numDataBytes >= numInputBytes + 3) { - // Yay, we found the proper rs block info! - qrCode.setVersion(versionNum); - qrCode.setNumTotalBytes(numBytes); - qrCode.setNumDataBytes(numDataBytes); - qrCode.setNumRSBlocks(numRSBlocks); - // getNumECBytes = 196 - 66 = 130 - qrCode.setNumECBytes(numEcBytes); - // matrix width = 21 + 6 * 4 = 45 - qrCode.setMatrixWidth(version.getDimensionForVersion()); - return; - } - } - throw new WriterException("Cannot find proper rs block info (input data too big?)"); - } - - /** - * Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24). - */ - static void terminateBits(int numDataBytes, BitArray bits) throws WriterException { - int capacity = numDataBytes << 3; - if (bits.getSize() > capacity) { - throw new WriterException("data bits cannot fit in the QR Code" + bits.getSize() + " > " + - capacity); - } - for (int i = 0; i < 4 && bits.getSize() < capacity; ++i) { - bits.appendBit(false); - } - // Append termination bits. See 8.4.8 of JISX0510:2004 (p.24) for details. - // If the last byte isn't 8-bit aligned, we'll add padding bits. - int numBitsInLastByte = bits.getSize() & 0x07; - if (numBitsInLastByte > 0) { - for (int i = numBitsInLastByte; i < 8; i++) { - bits.appendBit(false); - } - } - // If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24). - int numPaddingBytes = numDataBytes - bits.getSizeInBytes(); - for (int i = 0; i < numPaddingBytes; ++i) { - bits.appendBits((i & 0x01) == 0 ? 0xEC : 0x11, 8); - } - if (bits.getSize() != capacity) { - throw new WriterException("Bits size does not equal capacity"); - } - } - - /** - * Get number of data bytes and number of error correction bytes for block id "blockID". Store - * the result in "numDataBytesInBlock", and "numECBytesInBlock". See table 12 in 8.5.1 of - * JISX0510:2004 (p.30) - */ - static void getNumDataBytesAndNumECBytesForBlockID(int numTotalBytes, int numDataBytes, - int numRSBlocks, int blockID, int[] numDataBytesInBlock, - int[] numECBytesInBlock) throws WriterException { - if (blockID >= numRSBlocks) { - throw new WriterException("Block ID too large"); - } - // numRsBlocksInGroup2 = 196 % 5 = 1 - int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks; - // numRsBlocksInGroup1 = 5 - 1 = 4 - int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2; - // numTotalBytesInGroup1 = 196 / 5 = 39 - int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks; - // numTotalBytesInGroup2 = 39 + 1 = 40 - int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1; - // numDataBytesInGroup1 = 66 / 5 = 13 - int numDataBytesInGroup1 = numDataBytes / numRSBlocks; - // numDataBytesInGroup2 = 13 + 1 = 14 - int numDataBytesInGroup2 = numDataBytesInGroup1 + 1; - // numEcBytesInGroup1 = 39 - 13 = 26 - int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1; - // numEcBytesInGroup2 = 40 - 14 = 26 - int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2; - // Sanity checks. - // 26 = 26 - if (numEcBytesInGroup1 != numEcBytesInGroup2) { - throw new WriterException("EC bytes mismatch"); - } - // 5 = 4 + 1. - if (numRSBlocks != numRsBlocksInGroup1 + numRsBlocksInGroup2) { - throw new WriterException("RS blocks mismatch"); - } - // 196 = (13 + 26) * 4 + (14 + 26) * 1 - if (numTotalBytes != - ((numDataBytesInGroup1 + numEcBytesInGroup1) * - numRsBlocksInGroup1) + - ((numDataBytesInGroup2 + numEcBytesInGroup2) * - numRsBlocksInGroup2)) { - throw new WriterException("Total bytes mismatch"); - } - - if (blockID < numRsBlocksInGroup1) { - numDataBytesInBlock[0] = numDataBytesInGroup1; - numECBytesInBlock[0] = numEcBytesInGroup1; - } else { - numDataBytesInBlock[0] = numDataBytesInGroup2; - numECBytesInBlock[0] = numEcBytesInGroup2; - } - } - - /** - * Interleave "bits" with corresponding error correction bytes. On success, store the result in - * "result". The interleave rule is complicated. See 8.6 of JISX0510:2004 (p.37) for details. - */ - static void interleaveWithECBytes(BitArray bits, int numTotalBytes, - int numDataBytes, int numRSBlocks, BitArray result) throws WriterException { - - // "bits" must have "getNumDataBytes" bytes of data. - if (bits.getSizeInBytes() != numDataBytes) { - throw new WriterException("Number of bits and data bytes does not match"); - } - - // Step 1. Divide data bytes into blocks and generate error correction bytes for them. We'll - // store the divided data bytes blocks and error correction bytes blocks into "blocks". - int dataBytesOffset = 0; - int maxNumDataBytes = 0; - int maxNumEcBytes = 0; - - // Since, we know the number of reedsolmon blocks, we can initialize the vector with the number. - Vector blocks = new Vector(numRSBlocks); - - for (int i = 0; i < numRSBlocks; ++i) { - int[] numDataBytesInBlock = new int[1]; - int[] numEcBytesInBlock = new int[1]; - getNumDataBytesAndNumECBytesForBlockID( - numTotalBytes, numDataBytes, numRSBlocks, i, - numDataBytesInBlock, numEcBytesInBlock); - - int size = numDataBytesInBlock[0]; - byte[] dataBytes = new byte[size]; - bits.toBytes(8*dataBytesOffset, dataBytes, 0, size); - byte[] ecBytes = generateECBytes(dataBytes, numEcBytesInBlock[0]); - blocks.addElement(new BlockPair(dataBytes, ecBytes)); - - maxNumDataBytes = Math.max(maxNumDataBytes, size); - maxNumEcBytes = Math.max(maxNumEcBytes, ecBytes.length); - dataBytesOffset += numDataBytesInBlock[0]; - } - if (numDataBytes != dataBytesOffset) { - throw new WriterException("Data bytes does not match offset"); - } - - // First, place data blocks. - for (int i = 0; i < maxNumDataBytes; ++i) { - for (int j = 0; j < blocks.size(); ++j) { - byte[] dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes(); - if (i < dataBytes.length) { - result.appendBits(dataBytes[i], 8); - } - } - } - // Then, place error correction blocks. - for (int i = 0; i < maxNumEcBytes; ++i) { - for (int j = 0; j < blocks.size(); ++j) { - byte[] ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes(); - if (i < ecBytes.length) { - result.appendBits(ecBytes[i], 8); - } - } - } - if (numTotalBytes != result.getSizeInBytes()) { // Should be same. - throw new WriterException("Interleaving error: " + numTotalBytes + " and " + - result.getSizeInBytes() + " differ."); - } - } - - static byte[] generateECBytes(byte[] dataBytes, int numEcBytesInBlock) { - int numDataBytes = dataBytes.length; - int[] toEncode = new int[numDataBytes + numEcBytesInBlock]; - for (int i = 0; i < numDataBytes; i++) { - toEncode[i] = dataBytes[i] & 0xFF; - } - new ReedSolomonEncoder(GenericGF.QR_CODE_FIELD_256).encode(toEncode, numEcBytesInBlock); - - byte[] ecBytes = new byte[numEcBytesInBlock]; - for (int i = 0; i < numEcBytesInBlock; i++) { - ecBytes[i] = (byte) toEncode[numDataBytes + i]; - } - return ecBytes; - } - - /** - * Append mode info. On success, store the result in "bits". - */ - static void appendModeInfo(Mode mode, BitArray bits) { - bits.appendBits(mode.getBits(), 4); - } - - - /** - * Append length info. On success, store the result in "bits". - */ - static void appendLengthInfo(int numLetters, int version, Mode mode, BitArray bits) - throws WriterException { - int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version)); - if (numLetters > ((1 << numBits) - 1)) { - throw new WriterException(numLetters + "is bigger than" + ((1 << numBits) - 1)); - } - bits.appendBits(numLetters, numBits); - } - - /** - * Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits". - */ - static void appendBytes(String content, Mode mode, BitArray bits, String encoding) - throws WriterException { - if (mode.equals(Mode.NUMERIC)) { - appendNumericBytes(content, bits); - } else if (mode.equals(Mode.ALPHANUMERIC)) { - appendAlphanumericBytes(content, bits); - } else if (mode.equals(Mode.BYTE)) { - append8BitBytes(content, bits, encoding); - } else if (mode.equals(Mode.KANJI)) { - appendKanjiBytes(content, bits); - } else { - throw new WriterException("Invalid mode: " + mode); - } - } - - static void appendNumericBytes(String content, BitArray bits) { - int length = content.length(); - int i = 0; - while (i < length) { - int num1 = content.charAt(i) - '0'; - if (i + 2 < length) { - // Encode three numeric letters in ten bits. - int num2 = content.charAt(i + 1) - '0'; - int num3 = content.charAt(i + 2) - '0'; - bits.appendBits(num1 * 100 + num2 * 10 + num3, 10); - i += 3; - } else if (i + 1 < length) { - // Encode two numeric letters in seven bits. - int num2 = content.charAt(i + 1) - '0'; - bits.appendBits(num1 * 10 + num2, 7); - i += 2; - } else { - // Encode one numeric letter in four bits. - bits.appendBits(num1, 4); - i++; - } - } - } - - static void appendAlphanumericBytes(String content, BitArray bits) throws WriterException { - int length = content.length(); - int i = 0; - while (i < length) { - int code1 = getAlphanumericCode(content.charAt(i)); - if (code1 == -1) { - throw new WriterException(); - } - if (i + 1 < length) { - int code2 = getAlphanumericCode(content.charAt(i + 1)); - if (code2 == -1) { - throw new WriterException(); - } - // Encode two alphanumeric letters in 11 bits. - bits.appendBits(code1 * 45 + code2, 11); - i += 2; - } else { - // Encode one alphanumeric letter in six bits. - bits.appendBits(code1, 6); - i++; - } - } - } - - static void append8BitBytes(String content, BitArray bits, String encoding) - throws WriterException { - byte[] bytes; - try { - bytes = content.getBytes(encoding); - } catch (UnsupportedEncodingException uee) { - throw new WriterException(uee.toString()); - } - for (int i = 0; i < bytes.length; ++i) { - bits.appendBits(bytes[i], 8); - } - } - - static void appendKanjiBytes(String content, BitArray bits) throws WriterException { - byte[] bytes; - try { - bytes = content.getBytes("Shift_JIS"); - } catch (UnsupportedEncodingException uee) { - throw new WriterException(uee.toString()); - } - int length = bytes.length; - for (int i = 0; i < length; i += 2) { - int byte1 = bytes[i] & 0xFF; - int byte2 = bytes[i + 1] & 0xFF; - int code = (byte1 << 8) | byte2; - int subtracted = -1; - if (code >= 0x8140 && code <= 0x9ffc) { - subtracted = code - 0x8140; - } else if (code >= 0xe040 && code <= 0xebbf) { - subtracted = code - 0xc140; - } - if (subtracted == -1) { - throw new WriterException("Invalid byte sequence"); - } - int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff); - bits.appendBits(encoded, 13); - } - } - - private static void appendECI(ECI eci, BitArray bits) { - bits.appendBits(Mode.ECI.getBits(), 4); - // This is correct for values up to 127, which is all we need now. - bits.appendBits(eci.getValue(), 8); - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MaskUtil.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MaskUtil.java deleted file mode 100644 index 61ccf48c1..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MaskUtil.java +++ /dev/null @@ -1,218 +0,0 @@ -/* - * Copyright 2008 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. - */ - -package com.google.zxing.qrcode.encoder; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class MaskUtil { - - private MaskUtil() { - // do nothing - } - - // Apply mask penalty rule 1 and return the penalty. Find repetitive cells with the same color and - // give penalty to them. Example: 00000 or 11111. - public static int applyMaskPenaltyRule1(ByteMatrix matrix) { - return applyMaskPenaltyRule1Internal(matrix, true) + applyMaskPenaltyRule1Internal(matrix, false); - } - - // Apply mask penalty rule 2 and return the penalty. Find 2x2 blocks with the same color and give - // penalty to them. - public static int applyMaskPenaltyRule2(ByteMatrix matrix) { - int penalty = 0; - byte[][] array = matrix.getArray(); - int width = matrix.getWidth(); - int height = matrix.getHeight(); - for (int y = 0; y < height - 1; ++y) { - for (int x = 0; x < width - 1; ++x) { - int value = array[y][x]; - if (value == array[y][x + 1] && value == array[y + 1][x] && value == array[y + 1][x + 1]) { - penalty += 3; - } - } - } - return penalty; - } - - // Apply mask penalty rule 3 and return the penalty. Find consecutive cells of 00001011101 or - // 10111010000, and give penalty to them. If we find patterns like 000010111010000, we give - // penalties twice (i.e. 40 * 2). - public static int applyMaskPenaltyRule3(ByteMatrix matrix) { - int penalty = 0; - byte[][] array = matrix.getArray(); - int width = matrix.getWidth(); - int height = matrix.getHeight(); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - // Tried to simplify following conditions but failed. - if (x + 6 < width && - array[y][x] == 1 && - array[y][x + 1] == 0 && - array[y][x + 2] == 1 && - array[y][x + 3] == 1 && - array[y][x + 4] == 1 && - array[y][x + 5] == 0 && - array[y][x + 6] == 1 && - ((x + 10 < width && - array[y][x + 7] == 0 && - array[y][x + 8] == 0 && - array[y][x + 9] == 0 && - array[y][x + 10] == 0) || - (x - 4 >= 0 && - array[y][x - 1] == 0 && - array[y][x - 2] == 0 && - array[y][x - 3] == 0 && - array[y][x - 4] == 0))) { - penalty += 40; - } - if (y + 6 < height && - array[y][x] == 1 && - array[y + 1][x] == 0 && - array[y + 2][x] == 1 && - array[y + 3][x] == 1 && - array[y + 4][x] == 1 && - array[y + 5][x] == 0 && - array[y + 6][x] == 1 && - ((y + 10 < height && - array[y + 7][x] == 0 && - array[y + 8][x] == 0 && - array[y + 9][x] == 0 && - array[y + 10][x] == 0) || - (y - 4 >= 0 && - array[y - 1][x] == 0 && - array[y - 2][x] == 0 && - array[y - 3][x] == 0 && - array[y - 4][x] == 0))) { - penalty += 40; - } - } - } - return penalty; - } - - // Apply mask penalty rule 4 and return the penalty. Calculate the ratio of dark cells and give - // penalty if the ratio is far from 50%. It gives 10 penalty for 5% distance. Examples: - // - 0% => 100 - // - 40% => 20 - // - 45% => 10 - // - 50% => 0 - // - 55% => 10 - // - 55% => 20 - // - 100% => 100 - public static int applyMaskPenaltyRule4(ByteMatrix matrix) { - int numDarkCells = 0; - byte[][] array = matrix.getArray(); - int width = matrix.getWidth(); - int height = matrix.getHeight(); - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - if (array[y][x] == 1) { - numDarkCells += 1; - } - } - } - int numTotalCells = matrix.getHeight() * matrix.getWidth(); - double darkRatio = (double) numDarkCells / numTotalCells; - return Math.abs((int) (darkRatio * 100 - 50)) / 5 * 10; - } - - // Return the mask bit for "getMaskPattern" at "x" and "y". See 8.8 of JISX0510:2004 for mask - // pattern conditions. - public static boolean getDataMaskBit(int maskPattern, int x, int y) { - if (!QRCode.isValidMaskPattern(maskPattern)) { - throw new IllegalArgumentException("Invalid mask pattern"); - } - int intermediate; - int temp; - switch (maskPattern) { - case 0: - intermediate = (y + x) & 0x1; - break; - case 1: - intermediate = y & 0x1; - break; - case 2: - intermediate = x % 3; - break; - case 3: - intermediate = (y + x) % 3; - break; - case 4: - intermediate = ((y >>> 1) + (x / 3)) & 0x1; - break; - case 5: - temp = y * x; - intermediate = (temp & 0x1) + (temp % 3); - break; - case 6: - temp = y * x; - intermediate = ((temp & 0x1) + (temp % 3)) & 0x1; - break; - case 7: - temp = y * x; - intermediate = ((temp % 3) + ((y + x) & 0x1)) & 0x1; - break; - default: - throw new IllegalArgumentException("Invalid mask pattern: " + maskPattern); - } - return intermediate == 0; - } - - // Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both - // vertical and horizontal orders respectively. - private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, boolean isHorizontal) { - int penalty = 0; - int numSameBitCells = 0; - int prevBit = -1; - // Horizontal mode: - // for (int i = 0; i < matrix.height(); ++i) { - // for (int j = 0; j < matrix.width(); ++j) { - // int bit = matrix.get(i, j); - // Vertical mode: - // for (int i = 0; i < matrix.width(); ++i) { - // for (int j = 0; j < matrix.height(); ++j) { - // int bit = matrix.get(j, i); - int iLimit = isHorizontal ? matrix.getHeight() : matrix.getWidth(); - int jLimit = isHorizontal ? matrix.getWidth() : matrix.getHeight(); - byte[][] array = matrix.getArray(); - for (int i = 0; i < iLimit; ++i) { - for (int j = 0; j < jLimit; ++j) { - int bit = isHorizontal ? array[i][j] : array[j][i]; - if (bit == prevBit) { - numSameBitCells += 1; - // Found five repetitive cells with the same color (bit). - // We'll give penalty of 3. - if (numSameBitCells == 5) { - penalty += 3; - } else if (numSameBitCells > 5) { - // After five repetitive cells, we'll add the penalty one - // by one. - penalty += 1; - } - } else { - numSameBitCells = 1; // Include the cell itself. - prevBit = bit; - } - } - numSameBitCells = 0; // Clear at each row/column. - } - return penalty; - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MatrixUtil.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MatrixUtil.java deleted file mode 100644 index 3d434e675..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/MatrixUtil.java +++ /dev/null @@ -1,524 +0,0 @@ -/* - * Copyright 2008 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. - */ - -package com.google.zxing.qrcode.encoder; - -import com.google.zxing.WriterException; -import com.google.zxing.common.BitArray; -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class MatrixUtil { - - private MatrixUtil() { - // do nothing - } - - private static final int[][] POSITION_DETECTION_PATTERN = { - {1, 1, 1, 1, 1, 1, 1}, - {1, 0, 0, 0, 0, 0, 1}, - {1, 0, 1, 1, 1, 0, 1}, - {1, 0, 1, 1, 1, 0, 1}, - {1, 0, 1, 1, 1, 0, 1}, - {1, 0, 0, 0, 0, 0, 1}, - {1, 1, 1, 1, 1, 1, 1}, - }; - - private static final int[][] HORIZONTAL_SEPARATION_PATTERN = { - {0, 0, 0, 0, 0, 0, 0, 0}, - }; - - private static final int[][] VERTICAL_SEPARATION_PATTERN = { - {0}, {0}, {0}, {0}, {0}, {0}, {0}, - }; - - private static final int[][] POSITION_ADJUSTMENT_PATTERN = { - {1, 1, 1, 1, 1}, - {1, 0, 0, 0, 1}, - {1, 0, 1, 0, 1}, - {1, 0, 0, 0, 1}, - {1, 1, 1, 1, 1}, - }; - - // From Appendix E. Table 1, JIS0510X:2004 (p 71). The table was double-checked by komatsu. - private static final int[][] POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE = { - {-1, -1, -1, -1, -1, -1, -1}, // Version 1 - { 6, 18, -1, -1, -1, -1, -1}, // Version 2 - { 6, 22, -1, -1, -1, -1, -1}, // Version 3 - { 6, 26, -1, -1, -1, -1, -1}, // Version 4 - { 6, 30, -1, -1, -1, -1, -1}, // Version 5 - { 6, 34, -1, -1, -1, -1, -1}, // Version 6 - { 6, 22, 38, -1, -1, -1, -1}, // Version 7 - { 6, 24, 42, -1, -1, -1, -1}, // Version 8 - { 6, 26, 46, -1, -1, -1, -1}, // Version 9 - { 6, 28, 50, -1, -1, -1, -1}, // Version 10 - { 6, 30, 54, -1, -1, -1, -1}, // Version 11 - { 6, 32, 58, -1, -1, -1, -1}, // Version 12 - { 6, 34, 62, -1, -1, -1, -1}, // Version 13 - { 6, 26, 46, 66, -1, -1, -1}, // Version 14 - { 6, 26, 48, 70, -1, -1, -1}, // Version 15 - { 6, 26, 50, 74, -1, -1, -1}, // Version 16 - { 6, 30, 54, 78, -1, -1, -1}, // Version 17 - { 6, 30, 56, 82, -1, -1, -1}, // Version 18 - { 6, 30, 58, 86, -1, -1, -1}, // Version 19 - { 6, 34, 62, 90, -1, -1, -1}, // Version 20 - { 6, 28, 50, 72, 94, -1, -1}, // Version 21 - { 6, 26, 50, 74, 98, -1, -1}, // Version 22 - { 6, 30, 54, 78, 102, -1, -1}, // Version 23 - { 6, 28, 54, 80, 106, -1, -1}, // Version 24 - { 6, 32, 58, 84, 110, -1, -1}, // Version 25 - { 6, 30, 58, 86, 114, -1, -1}, // Version 26 - { 6, 34, 62, 90, 118, -1, -1}, // Version 27 - { 6, 26, 50, 74, 98, 122, -1}, // Version 28 - { 6, 30, 54, 78, 102, 126, -1}, // Version 29 - { 6, 26, 52, 78, 104, 130, -1}, // Version 30 - { 6, 30, 56, 82, 108, 134, -1}, // Version 31 - { 6, 34, 60, 86, 112, 138, -1}, // Version 32 - { 6, 30, 58, 86, 114, 142, -1}, // Version 33 - { 6, 34, 62, 90, 118, 146, -1}, // Version 34 - { 6, 30, 54, 78, 102, 126, 150}, // Version 35 - { 6, 24, 50, 76, 102, 128, 154}, // Version 36 - { 6, 28, 54, 80, 106, 132, 158}, // Version 37 - { 6, 32, 58, 84, 110, 136, 162}, // Version 38 - { 6, 26, 54, 82, 110, 138, 166}, // Version 39 - { 6, 30, 58, 86, 114, 142, 170}, // Version 40 - }; - - // Type info cells at the left top corner. - private static final int[][] TYPE_INFO_COORDINATES = { - {8, 0}, - {8, 1}, - {8, 2}, - {8, 3}, - {8, 4}, - {8, 5}, - {8, 7}, - {8, 8}, - {7, 8}, - {5, 8}, - {4, 8}, - {3, 8}, - {2, 8}, - {1, 8}, - {0, 8}, - }; - - // From Appendix D in JISX0510:2004 (p. 67) - private static final int VERSION_INFO_POLY = 0x1f25; // 1 1111 0010 0101 - - // From Appendix C in JISX0510:2004 (p.65). - private static final int TYPE_INFO_POLY = 0x537; - private static final int TYPE_INFO_MASK_PATTERN = 0x5412; - - // Set all cells to -1. -1 means that the cell is empty (not set yet). - // - // JAVAPORT: We shouldn't need to do this at all. The code should be rewritten to begin encoding - // with the ByteMatrix initialized all to zero. - public static void clearMatrix(ByteMatrix matrix) { - matrix.clear((byte) -1); - } - - // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On - // success, store the result in "matrix" and return true. - public static void buildMatrix(BitArray dataBits, ErrorCorrectionLevel ecLevel, int version, - int maskPattern, ByteMatrix matrix) throws WriterException { - clearMatrix(matrix); - embedBasicPatterns(version, matrix); - // Type information appear with any version. - embedTypeInfo(ecLevel, maskPattern, matrix); - // Version info appear if version >= 7. - maybeEmbedVersionInfo(version, matrix); - // Data should be embedded at end. - embedDataBits(dataBits, maskPattern, matrix); - } - - // Embed basic patterns. On success, modify the matrix and return true. - // The basic patterns are: - // - Position detection patterns - // - Timing patterns - // - Dark dot at the left bottom corner - // - Position adjustment patterns, if need be - public static void embedBasicPatterns(int version, ByteMatrix matrix) throws WriterException { - // Let's get started with embedding big squares at corners. - embedPositionDetectionPatternsAndSeparators(matrix); - // Then, embed the dark dot at the left bottom corner. - embedDarkDotAtLeftBottomCorner(matrix); - - // Position adjustment patterns appear if version >= 2. - maybeEmbedPositionAdjustmentPatterns(version, matrix); - // Timing patterns should be embedded after position adj. patterns. - embedTimingPatterns(matrix); - } - - // Embed type information. On success, modify the matrix. - public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix) - throws WriterException { - BitArray typeInfoBits = new BitArray(); - makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); - - for (int i = 0; i < typeInfoBits.getSize(); ++i) { - // Place bits in LSB to MSB order. LSB (least significant bit) is the last value in - // "typeInfoBits". - boolean bit = typeInfoBits.get(typeInfoBits.getSize() - 1 - i); - - // Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46). - int x1 = TYPE_INFO_COORDINATES[i][0]; - int y1 = TYPE_INFO_COORDINATES[i][1]; - matrix.set(x1, y1, bit); - - if (i < 8) { - // Right top corner. - int x2 = matrix.getWidth() - i - 1; - int y2 = 8; - matrix.set(x2, y2, bit); - } else { - // Left bottom corner. - int x2 = 8; - int y2 = matrix.getHeight() - 7 + (i - 8); - matrix.set(x2, y2, bit); - } - } - } - - // Embed version information if need be. On success, modify the matrix and return true. - // See 8.10 of JISX0510:2004 (p.47) for how to embed version information. - public static void maybeEmbedVersionInfo(int version, ByteMatrix matrix) throws WriterException { - if (version < 7) { // Version info is necessary if version >= 7. - return; // Don't need version info. - } - BitArray versionInfoBits = new BitArray(); - makeVersionInfoBits(version, versionInfoBits); - - int bitIndex = 6 * 3 - 1; // It will decrease from 17 to 0. - for (int i = 0; i < 6; ++i) { - for (int j = 0; j < 3; ++j) { - // Place bits in LSB (least significant bit) to MSB order. - boolean bit = versionInfoBits.get(bitIndex); - bitIndex--; - // Left bottom corner. - matrix.set(i, matrix.getHeight() - 11 + j, bit); - // Right bottom corner. - matrix.set(matrix.getHeight() - 11 + j, i, bit); - } - } - } - - // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. - // For debugging purposes, it skips masking process if "getMaskPattern" is -1. - // See 8.7 of JISX0510:2004 (p.38) for how to embed data bits. - public static void embedDataBits(BitArray dataBits, int maskPattern, ByteMatrix matrix) - throws WriterException { - int bitIndex = 0; - int direction = -1; - // Start from the right bottom cell. - int x = matrix.getWidth() - 1; - int y = matrix.getHeight() - 1; - while (x > 0) { - // Skip the vertical timing pattern. - if (x == 6) { - x -= 1; - } - while (y >= 0 && y < matrix.getHeight()) { - for (int i = 0; i < 2; ++i) { - int xx = x - i; - // Skip the cell if it's not empty. - if (!isEmpty(matrix.get(xx, y))) { - continue; - } - boolean bit; - if (bitIndex < dataBits.getSize()) { - bit = dataBits.get(bitIndex); - ++bitIndex; - } else { - // Padding bit. If there is no bit left, we'll fill the left cells with 0, as described - // in 8.4.9 of JISX0510:2004 (p. 24). - bit = false; - } - - // Skip masking if mask_pattern is -1. - if (maskPattern != -1) { - if (MaskUtil.getDataMaskBit(maskPattern, xx, y)) { - bit = !bit; - } - } - matrix.set(xx, y, bit); - } - y += direction; - } - direction = -direction; // Reverse the direction. - y += direction; - x -= 2; // Move to the left. - } - // All bits should be consumed. - if (bitIndex != dataBits.getSize()) { - throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.getSize()); - } - } - - // Return the position of the most significant bit set (to one) in the "value". The most - // significant bit is position 32. If there is no bit set, return 0. Examples: - // - findMSBSet(0) => 0 - // - findMSBSet(1) => 1 - // - findMSBSet(255) => 8 - public static int findMSBSet(int value) { - int numDigits = 0; - while (value != 0) { - value >>>= 1; - ++numDigits; - } - return numDigits; - } - - // Calculate BCH (Bose-Chaudhuri-Hocquenghem) code for "value" using polynomial "poly". The BCH - // code is used for encoding type information and version information. - // Example: Calculation of version information of 7. - // f(x) is created from 7. - // - 7 = 000111 in 6 bits - // - f(x) = x^2 + x^1 + x^0 - // g(x) is given by the standard (p. 67) - // - g(x) = x^12 + x^11 + x^10 + x^9 + x^8 + x^5 + x^2 + 1 - // Multiply f(x) by x^(18 - 6) - // - f'(x) = f(x) * x^(18 - 6) - // - f'(x) = x^14 + x^13 + x^12 - // Calculate the remainder of f'(x) / g(x) - // x^2 - // __________________________________________________ - // g(x) )x^14 + x^13 + x^12 - // x^14 + x^13 + x^12 + x^11 + x^10 + x^7 + x^4 + x^2 - // -------------------------------------------------- - // x^11 + x^10 + x^7 + x^4 + x^2 - // - // The remainder is x^11 + x^10 + x^7 + x^4 + x^2 - // Encode it in binary: 110010010100 - // The return value is 0xc94 (1100 1001 0100) - // - // Since all coefficients in the polynomials are 1 or 0, we can do the calculation by bit - // operations. We don't care if cofficients are positive or negative. - public static int calculateBCHCode(int value, int poly) { - // If poly is "1 1111 0010 0101" (version info poly), msbSetInPoly is 13. We'll subtract 1 - // from 13 to make it 12. - int msbSetInPoly = findMSBSet(poly); - value <<= msbSetInPoly - 1; - // Do the division business using exclusive-or operations. - while (findMSBSet(value) >= msbSetInPoly) { - value ^= poly << (findMSBSet(value) - msbSetInPoly); - } - // Now the "value" is the remainder (i.e. the BCH code) - return value; - } - - // Make bit vector of type information. On success, store the result in "bits" and return true. - // Encode error correction level and mask pattern. See 8.9 of - // JISX0510:2004 (p.45) for details. - public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitArray bits) - throws WriterException { - if (!QRCode.isValidMaskPattern(maskPattern)) { - throw new WriterException("Invalid mask pattern"); - } - int typeInfo = (ecLevel.getBits() << 3) | maskPattern; - bits.appendBits(typeInfo, 5); - - int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY); - bits.appendBits(bchCode, 10); - - BitArray maskBits = new BitArray(); - maskBits.appendBits(TYPE_INFO_MASK_PATTERN, 15); - bits.xor(maskBits); - - if (bits.getSize() != 15) { // Just in case. - throw new WriterException("should not happen but we got: " + bits.getSize()); - } - } - - // Make bit vector of version information. On success, store the result in "bits" and return true. - // See 8.10 of JISX0510:2004 (p.45) for details. - public static void makeVersionInfoBits(int version, BitArray bits) throws WriterException { - bits.appendBits(version, 6); - int bchCode = calculateBCHCode(version, VERSION_INFO_POLY); - bits.appendBits(bchCode, 12); - - if (bits.getSize() != 18) { // Just in case. - throw new WriterException("should not happen but we got: " + bits.getSize()); - } - } - - // Check if "value" is empty. - private static boolean isEmpty(int value) { - return value == -1; - } - - // Check if "value" is valid. - private static boolean isValidValue(int value) { - return value == -1 || // Empty. - value == 0 || // Light (white). - value == 1; // Dark (black). - } - - private static void embedTimingPatterns(ByteMatrix matrix) throws WriterException { - // -8 is for skipping position detection patterns (size 7), and two horizontal/vertical - // separation patterns (size 1). Thus, 8 = 7 + 1. - for (int i = 8; i < matrix.getWidth() - 8; ++i) { - int bit = (i + 1) % 2; - // Horizontal line. - if (!isValidValue(matrix.get(i, 6))) { - throw new WriterException(); - } - if (isEmpty(matrix.get(i, 6))) { - matrix.set(i, 6, bit); - } - // Vertical line. - if (!isValidValue(matrix.get(6, i))) { - throw new WriterException(); - } - if (isEmpty(matrix.get(6, i))) { - matrix.set(6, i, bit); - } - } - } - - // Embed the lonely dark dot at left bottom corner. JISX0510:2004 (p.46) - private static void embedDarkDotAtLeftBottomCorner(ByteMatrix matrix) throws WriterException { - if (matrix.get(8, matrix.getHeight() - 8) == 0) { - throw new WriterException(); - } - matrix.set(8, matrix.getHeight() - 8, 1); - } - - private static void embedHorizontalSeparationPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (HORIZONTAL_SEPARATION_PATTERN[0].length != 8 || HORIZONTAL_SEPARATION_PATTERN.length != 1) { - throw new WriterException("Bad horizontal separation pattern"); - } - for (int x = 0; x < 8; ++x) { - if (!isEmpty(matrix.get(xStart + x, yStart))) { - throw new WriterException(); - } - matrix.set(xStart + x, yStart, HORIZONTAL_SEPARATION_PATTERN[0][x]); - } - } - - private static void embedVerticalSeparationPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (VERTICAL_SEPARATION_PATTERN[0].length != 1 || VERTICAL_SEPARATION_PATTERN.length != 7) { - throw new WriterException("Bad vertical separation pattern"); - } - for (int y = 0; y < 7; ++y) { - if (!isEmpty(matrix.get(xStart, yStart + y))) { - throw new WriterException(); - } - matrix.set(xStart, yStart + y, VERTICAL_SEPARATION_PATTERN[y][0]); - } - } - - // Note that we cannot unify the function with embedPositionDetectionPattern() despite they are - // almost identical, since we cannot write a function that takes 2D arrays in different sizes in - // C/C++. We should live with the fact. - private static void embedPositionAdjustmentPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (POSITION_ADJUSTMENT_PATTERN[0].length != 5 || POSITION_ADJUSTMENT_PATTERN.length != 5) { - throw new WriterException("Bad position adjustment"); - } - for (int y = 0; y < 5; ++y) { - for (int x = 0; x < 5; ++x) { - if (!isEmpty(matrix.get(xStart + x, yStart + y))) { - throw new WriterException(); - } - matrix.set(xStart + x, yStart + y, POSITION_ADJUSTMENT_PATTERN[y][x]); - } - } - } - - private static void embedPositionDetectionPattern(int xStart, int yStart, - ByteMatrix matrix) throws WriterException { - // We know the width and height. - if (POSITION_DETECTION_PATTERN[0].length != 7 || POSITION_DETECTION_PATTERN.length != 7) { - throw new WriterException("Bad position detection pattern"); - } - for (int y = 0; y < 7; ++y) { - for (int x = 0; x < 7; ++x) { - if (!isEmpty(matrix.get(xStart + x, yStart + y))) { - throw new WriterException(); - } - matrix.set(xStart + x, yStart + y, POSITION_DETECTION_PATTERN[y][x]); - } - } - } - - // Embed position detection patterns and surrounding vertical/horizontal separators. - private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) throws WriterException { - // Embed three big squares at corners. - int pdpWidth = POSITION_DETECTION_PATTERN[0].length; - // Left top corner. - embedPositionDetectionPattern(0, 0, matrix); - // Right top corner. - embedPositionDetectionPattern(matrix.getWidth() - pdpWidth, 0, matrix); - // Left bottom corner. - embedPositionDetectionPattern(0, matrix.getWidth() - pdpWidth, matrix); - - // Embed horizontal separation patterns around the squares. - int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].length; - // Left top corner. - embedHorizontalSeparationPattern(0, hspWidth - 1, matrix); - // Right top corner. - embedHorizontalSeparationPattern(matrix.getWidth() - hspWidth, - hspWidth - 1, matrix); - // Left bottom corner. - embedHorizontalSeparationPattern(0, matrix.getWidth() - hspWidth, matrix); - - // Embed vertical separation patterns around the squares. - int vspSize = VERTICAL_SEPARATION_PATTERN.length; - // Left top corner. - embedVerticalSeparationPattern(vspSize, 0, matrix); - // Right top corner. - embedVerticalSeparationPattern(matrix.getHeight() - vspSize - 1, 0, matrix); - // Left bottom corner. - embedVerticalSeparationPattern(vspSize, matrix.getHeight() - vspSize, - matrix); - } - - // Embed position adjustment patterns if need be. - private static void maybeEmbedPositionAdjustmentPatterns(int version, ByteMatrix matrix) - throws WriterException { - if (version < 2) { // The patterns appear if version >= 2 - return; - } - int index = version - 1; - int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index]; - int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].length; - for (int i = 0; i < numCoordinates; ++i) { - for (int j = 0; j < numCoordinates; ++j) { - int y = coordinates[i]; - int x = coordinates[j]; - if (x == -1 || y == -1) { - continue; - } - // If the cell is unset, we embed the position adjustment pattern here. - if (isEmpty(matrix.get(x, y))) { - // -2 is necessary since the x/y coordinates point to the center of the pattern, not the - // left top corner. - embedPositionAdjustmentPattern(x - 2, y - 2, matrix); - } - } - } - } - -} diff --git a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/QRCode.java b/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/QRCode.java deleted file mode 100644 index 05c818513..000000000 --- a/OpenPGP-Keychain/src/com/google/zxing/qrcode/encoder/QRCode.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Copyright 2008 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. - */ - -package com.google.zxing.qrcode.encoder; - -import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel; -import com.google.zxing.qrcode.decoder.Mode; - -/** - * @author satorux@google.com (Satoru Takabayashi) - creator - * @author dswitkin@google.com (Daniel Switkin) - ported from C++ - */ -public final class QRCode { - - public static final int NUM_MASK_PATTERNS = 8; - - private Mode mode; - private ErrorCorrectionLevel ecLevel; - private int version; - private int matrixWidth; - private int maskPattern; - private int numTotalBytes; - private int numDataBytes; - private int numECBytes; - private int numRSBlocks; - private ByteMatrix matrix; - - public QRCode() { - mode = null; - ecLevel = null; - version = -1; - matrixWidth = -1; - maskPattern = -1; - numTotalBytes = -1; - numDataBytes = -1; - numECBytes = -1; - numRSBlocks = -1; - matrix = null; - } - - // Mode of the QR Code. - public Mode getMode() { - return mode; - } - - // Error correction level of the QR Code. - public ErrorCorrectionLevel getECLevel() { - return ecLevel; - } - - // Version of the QR Code. The bigger size, the bigger version. - public int getVersion() { - return version; - } - - // ByteMatrix width of the QR Code. - public int getMatrixWidth() { - return matrixWidth; - } - - // Mask pattern of the QR Code. - public int getMaskPattern() { - return maskPattern; - } - - // Number of total bytes in the QR Code. - public int getNumTotalBytes() { - return numTotalBytes; - } - - // Number of data bytes in the QR Code. - public int getNumDataBytes() { - return numDataBytes; - } - - // Number of error correction bytes in the QR Code. - public int getNumECBytes() { - return numECBytes; - } - - // Number of Reedsolomon blocks in the QR Code. - public int getNumRSBlocks() { - return numRSBlocks; - } - - // ByteMatrix data of the QR Code. - public ByteMatrix getMatrix() { - return matrix; - } - - - // Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They - // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell. - public int at(int x, int y) { - // The value must be zero or one. - int value = matrix.get(x, y); - if (!(value == 0 || value == 1)) { - // this is really like an assert... not sure what better exception to use? - throw new RuntimeException("Bad value"); - } - return value; - } - - // Checks all the member variables are set properly. Returns true on success. Otherwise, returns - // false. - public boolean isValid() { - return - // First check if all version are not uninitialized. - mode != null && - ecLevel != null && - version != -1 && - matrixWidth != -1 && - maskPattern != -1 && - numTotalBytes != -1 && - numDataBytes != -1 && - numECBytes != -1 && - numRSBlocks != -1 && - // Then check them in other ways.. - isValidMaskPattern(maskPattern) && - numTotalBytes == numDataBytes + numECBytes && - // ByteMatrix stuff. - matrix != null && - matrixWidth == matrix.getWidth() && - // See 7.3.1 of JISX0510:2004 (p.5). - matrix.getWidth() == matrix.getHeight(); // Must be square. - } - - // Return debug String. - public String toString() { - StringBuffer result = new StringBuffer(200); - result.append("<<\n"); - result.append(" mode: "); - result.append(mode); - result.append("\n ecLevel: "); - result.append(ecLevel); - result.append("\n version: "); - result.append(version); - result.append("\n matrixWidth: "); - result.append(matrixWidth); - result.append("\n maskPattern: "); - result.append(maskPattern); - result.append("\n numTotalBytes: "); - result.append(numTotalBytes); - result.append("\n numDataBytes: "); - result.append(numDataBytes); - result.append("\n numECBytes: "); - result.append(numECBytes); - result.append("\n numRSBlocks: "); - result.append(numRSBlocks); - if (matrix == null) { - result.append("\n matrix: null\n"); - } else { - result.append("\n matrix:\n"); - result.append(matrix.toString()); - } - result.append(">>\n"); - return result.toString(); - } - - public void setMode(Mode value) { - mode = value; - } - - public void setECLevel(ErrorCorrectionLevel value) { - ecLevel = value; - } - - public void setVersion(int value) { - version = value; - } - - public void setMatrixWidth(int value) { - matrixWidth = value; - } - - public void setMaskPattern(int value) { - maskPattern = value; - } - - public void setNumTotalBytes(int value) { - numTotalBytes = value; - } - - public void setNumDataBytes(int value) { - numDataBytes = value; - } - - public void setNumECBytes(int value) { - numECBytes = value; - } - - public void setNumRSBlocks(int value) { - numRSBlocks = value; - } - - // This takes ownership of the 2D array. - public void setMatrix(ByteMatrix value) { - matrix = value; - } - - // Check if "mask_pattern" is valid. - public static boolean isValidMaskPattern(int maskPattern) { - return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; - } - - // Return true if the all values in the matrix are binary numbers. - // - // JAVAPORT: This is going to be super expensive and unnecessary, we should not call this in - // production. I'm leaving it because it may be useful for testing. It should be removed entirely - // if ByteMatrix is changed never to contain a -1. - /* - private static boolean EverythingIsBinary(final ByteMatrix matrix) { - for (int y = 0; y < matrix.height(); ++y) { - for (int x = 0; x < matrix.width(); ++x) { - int value = matrix.get(y, x); - if (!(value == 0 || value == 1)) { - // Found non zero/one value. - return false; - } - } - } - return true; - } - */ - -} |