this.size = size;
}
- public ByteArray(String string) {
- bytes = string.getBytes();
- size = bytes.length;
- }
-
public ByteArray(byte[] byteArray) {
bytes = byteArray;
size = bytes.length;
}
QRCode code = new QRCode();
- Encoder.encode(new ByteArray(contents), errorCorrectionLevel, code);
+ Encoder.encode(contents, errorCorrectionLevel, code);
return renderResult(code, width, height);
}
Version.ECB ecBlock = ecBlockArray[j];\r
for (int i = 0; i < ecBlock.getCount(); i++) {\r
int numDataCodewords = ecBlock.getDataCodewords();\r
- int numBlockCodewords = ecBlocks.getECCodewords() + numDataCodewords;\r
+ int numBlockCodewords = ecBlocks.getECCodewordsPerBlock() + numDataCodewords;\r
result[numResultBlocks++] = new DataBlock(numDataCodewords, new byte[numBlockCodewords]);\r
}\r
}\r
}\r
longerBlocksStartAt++;\r
\r
- int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewords();\r
+ int shorterBlocksNumDataCodewords = shorterBlocksTotalCodewords - ecBlocks.getECCodewordsPerBlock();\r
// The last elements of result may be 1 element longer;\r
// first fill out as many elements as all of them have\r
int rawCodewordsOffset = 0;\r
this.alignmentPatternCenters = alignmentPatternCenters;\r
this.ecBlocks = new ECBlocks[]{ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4};\r
int total = 0;\r
- int ecCodewords = ecBlocks1.getECCodewords();\r
+ int ecCodewords = ecBlocks1.getECCodewordsPerBlock();\r
ECB[] ecbArray = ecBlocks1.getECBlocks();\r
for (int i = 0; i < ecbArray.length; i++) {\r
ECB ecBlock = ecbArray[i];\r
return 17 + 4 * versionNumber;\r
}\r
\r
- ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {\r
+ public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {\r
return ecBlocks[ecLevel.ordinal()];\r
}\r
\r
return VERSIONS[versionNumber - 1];\r
}\r
\r
- static Version decodeVersionInformation(int versionBits) throws ReaderException {\r
+ static Version decodeVersionInformation(int versionBits) {\r
int bestDifference = Integer.MAX_VALUE;\r
int bestVersion = 0;\r
for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {\r
* each set of blocks. It also holds the number of error-correction codewords per block since it\r
* will be the same across all blocks within one version.</p>\r
*/\r
- static final class ECBlocks {\r
- private final int ecCodewords;\r
+ public static final class ECBlocks {\r
+ private final int ecCodewordsPerBlock;\r
private final ECB[] ecBlocks;\r
\r
- private ECBlocks(int ecCodewords, ECB ecBlocks) {\r
- this.ecCodewords = ecCodewords;\r
+ private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) {\r
+ this.ecCodewordsPerBlock = ecCodewordsPerBlock;\r
this.ecBlocks = new ECB[]{ecBlocks};\r
}\r
\r
- private ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) {\r
- this.ecCodewords = ecCodewords;\r
+ private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) {\r
+ this.ecCodewordsPerBlock = ecCodewordsPerBlock;\r
this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};\r
}\r
\r
- int getECCodewords() {\r
- return ecCodewords;\r
+ public int getECCodewordsPerBlock() {\r
+ return ecCodewordsPerBlock;\r
}\r
\r
- ECB[] getECBlocks() {\r
+ public int getNumBlocks() {\r
+ int total = 0;\r
+ for (int i = 0; i < ecBlocks.length; i++) {\r
+ total += ecBlocks[i].getCount();\r
+ }\r
+ return total;\r
+ }\r
+\r
+ public int getTotalECCodewords() {\r
+ return ecCodewordsPerBlock * getNumBlocks();\r
+ }\r
+\r
+ public ECB[] getECBlocks() {\r
return ecBlocks;\r
}\r
}\r
* This includes the number of data codewords, and the number of times a block with these\r
* parameters is used consecutively in the QR code version's format.</p>\r
*/\r
- static final class ECB {\r
- final int count;\r
- final int dataCodewords;\r
+ public static final class ECB {\r
+ private final int count;\r
+ private final int dataCodewords;\r
\r
ECB(int count, int dataCodewords) {\r
this.count = count;\r
this.dataCodewords = dataCodewords;\r
}\r
\r
- int getCount() {\r
+ public int getCount() {\r
return count;\r
}\r
\r
- int getDataCodewords() {\r
+ public int getDataCodewords() {\r
return dataCodewords;\r
}\r
}\r
}
// Return the bit value at "index".
- public int at(final int index) {
+ public int at(int index) {
if (index < 0 || index >= sizeInBits) {
throw new IllegalArgumentException("Bad index: " + index);
}
- final int value = array[index >> 3] & 0xff;
+ int value = array[index >> 3] & 0xff;
return (value >> (7 - (index & 0x7))) & 1;
}
}
// Append one bit to the bit vector.
- public void appendBit(final int bit) {
+ public void appendBit(int bit) {
if (!(bit == 0 || bit == 1)) {
throw new IllegalArgumentException("Bad bit");
}
- final int numBitsInLastByte = sizeInBits & 0x7;
+ int numBitsInLastByte = sizeInBits & 0x7;
// We'll expand array if we don't have bits in the last byte.
if (numBitsInLastByte == 0) {
appendByte(0);
// - appendBits(0x00, 1) adds 0.
// - appendBits(0x00, 4) adds 0000.
// - appendBits(0xff, 8) adds 11111111.
- public void appendBits(final int value, final int numBits) {
+ public void appendBits(int value, int numBits) {
if (numBits < 0 || numBits > 32) {
throw new IllegalArgumentException("Num bits must be between 0 and 32");
}
while (numBitsLeft > 0) {
// Optimization for byte-oriented appending.
if ((sizeInBits & 0x7) == 0 && numBitsLeft >= 8) {
- final int newByte = (value >> (numBitsLeft - 8)) & 0xff;
+ int newByte = (value >> (numBitsLeft - 8)) & 0xff;
appendByte(newByte);
numBitsLeft -= 8;
} else {
- final int bit = (value >> (numBitsLeft - 1)) & 1;
+ int bit = (value >> (numBitsLeft - 1)) & 1;
appendBit(bit);
--numBitsLeft;
}
}
// Append "bits".
- public void appendBitVector(final BitVector bits) {
+ public void appendBitVector(BitVector bits) {
int size = bits.size();
for (int i = 0; i < size; ++i) {
appendBit(bits.at(i));
}
// Modify the bit vector by XOR'ing with "other"
- public void xor(final BitVector other) {
+ public void xor(BitVector other) {
if (sizeInBits != other.size()) {
throw new IllegalArgumentException("BitVector sizes don't match");
}
StringBuffer result = new StringBuffer(sizeInBits);
for (int i = 0; i < sizeInBits; ++i) {
if (at(i) == 0) {
- result.append("0");
+ result.append('0');
} else if (at(i) == 1) {
- result.append("1");
+ result.append('1');
} else {
throw new IllegalArgumentException("Byte isn't 0 or 1");
}
// run out of room.
private void appendByte(int value) {
if ((sizeInBits >> 3) == array.length) {
- byte[] newArray = new byte[array.length * 2];
+ byte[] newArray = new byte[(array.length << 1)];
System.arraycopy(array, 0, newArray, 0, array.length);
array = newArray;
}
import com.google.zxing.qrcode.decoder.Version;
import java.util.Vector;
+import java.io.UnsupportedEncodingException;
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, -1, -1, -1, -1, -1, // 0x50-0x5f
};
- private static final class RSBlockInfo {
-
- final int numBytes;
- final int[][] blockInfo;
-
- public RSBlockInfo(int numBytes, int[][] blockInfo) {
- this.numBytes = numBytes;
- this.blockInfo = blockInfo;
- }
-
+ private Encoder() {
}
- // The table is from table 12 of JISX0510:2004 (p. 30). The "blockInfo" parts are ordered by
- // L, M, Q, H. Within each blockInfo, the 0th element is getNumECBytes, and the 1st element is
- // getNumRSBlocks. The table was doublechecked by komatsu.
- private static final RSBlockInfo[] RS_BLOCK_TABLE = {
- new RSBlockInfo( 26, new int[][]{ { 7, 1}, { 10, 1}, { 13, 1}, { 17, 1}}), // Version 1
- new RSBlockInfo( 44, new int[][]{ { 10, 1}, { 16, 1}, { 22, 1}, { 28, 1}}), // Version 2
- new RSBlockInfo( 70, new int[][]{ { 15, 1}, { 26, 1}, { 36, 2}, { 44, 2}}), // Version 3
- new RSBlockInfo( 100, new int[][]{ { 20, 1}, { 36, 2}, { 52, 2}, { 64, 4}}), // Version 4
- new RSBlockInfo( 134, new int[][]{ { 26, 1}, { 48, 2}, { 72, 4}, { 88, 4}}), // Version 5
- new RSBlockInfo( 172, new int[][]{ { 36, 2}, { 64, 4}, { 96, 4}, { 112, 4}}), // Version 6
- new RSBlockInfo( 196, new int[][]{ { 40, 2}, { 72, 4}, { 108, 6}, { 130, 5}}), // Version 7
- new RSBlockInfo( 242, new int[][]{ { 48, 2}, { 88, 4}, { 132, 6}, { 156, 6}}), // Version 8
- new RSBlockInfo( 292, new int[][]{ { 60, 2}, { 110, 5}, { 160, 8}, { 192, 8}}), // Version 9
- new RSBlockInfo( 346, new int[][]{ { 72, 4}, { 130, 5}, { 192, 8}, { 224, 8}}), // Version 10
- new RSBlockInfo( 404, new int[][]{ { 80, 4}, { 150, 5}, { 224, 8}, { 264, 11}}), // Version 11
- new RSBlockInfo( 466, new int[][]{ { 96, 4}, { 176, 8}, { 260, 10}, { 308, 11}}), // Version 12
- new RSBlockInfo( 532, new int[][]{ {104, 4}, { 198, 9}, { 288, 12}, { 352, 16}}), // Version 13
- new RSBlockInfo( 581, new int[][]{ {120, 4}, { 216, 9}, { 320, 16}, { 384, 16}}), // Version 14
- new RSBlockInfo( 655, new int[][]{ {132, 6}, { 240, 10}, { 360, 12}, { 432, 18}}), // Version 15
- new RSBlockInfo( 733, new int[][]{ {144, 6}, { 280, 10}, { 408, 17}, { 480, 16}}), // Version 16
- new RSBlockInfo( 815, new int[][]{ {168, 6}, { 308, 11}, { 448, 16}, { 532, 19}}), // Version 17
- new RSBlockInfo( 901, new int[][]{ {180, 6}, { 338, 13}, { 504, 18}, { 588, 21}}), // Version 18
- new RSBlockInfo( 991, new int[][]{ {196, 7}, { 364, 14}, { 546, 21}, { 650, 25}}), // Version 19
- new RSBlockInfo(1085, new int[][]{ {224, 8}, { 416, 16}, { 600, 20}, { 700, 25}}), // Version 20
- new RSBlockInfo(1156, new int[][]{ {224, 8}, { 442, 17}, { 644, 23}, { 750, 25}}), // Version 21
- new RSBlockInfo(1258, new int[][]{ {252, 9}, { 476, 17}, { 690, 23}, { 816, 34}}), // Version 22
- new RSBlockInfo(1364, new int[][]{ {270, 9}, { 504, 18}, { 750, 25}, { 900, 30}}), // Version 23
- new RSBlockInfo(1474, new int[][]{ {300, 10}, { 560, 20}, { 810, 27}, { 960, 32}}), // Version 24
- new RSBlockInfo(1588, new int[][]{ {312, 12}, { 588, 21}, { 870, 29}, {1050, 35}}), // Version 25
- new RSBlockInfo(1706, new int[][]{ {336, 12}, { 644, 23}, { 952, 34}, {1110, 37}}), // Version 26
- new RSBlockInfo(1828, new int[][]{ {360, 12}, { 700, 25}, {1020, 34}, {1200, 40}}), // Version 27
- new RSBlockInfo(1921, new int[][]{ {390, 13}, { 728, 26}, {1050, 35}, {1260, 42}}), // Version 28
- new RSBlockInfo(2051, new int[][]{ {420, 14}, { 784, 28}, {1140, 38}, {1350, 45}}), // Version 29
- new RSBlockInfo(2185, new int[][]{ {450, 15}, { 812, 29}, {1200, 40}, {1440, 48}}), // Version 30
- new RSBlockInfo(2323, new int[][]{ {480, 16}, { 868, 31}, {1290, 43}, {1530, 51}}), // Version 31
- new RSBlockInfo(2465, new int[][]{ {510, 17}, { 924, 33}, {1350, 45}, {1620, 54}}), // Version 32
- new RSBlockInfo(2611, new int[][]{ {540, 18}, { 980, 35}, {1440, 48}, {1710, 57}}), // Version 33
- new RSBlockInfo(2761, new int[][]{ {570, 19}, {1036, 37}, {1530, 51}, {1800, 60}}), // Version 34
- new RSBlockInfo(2876, new int[][]{ {570, 19}, {1064, 38}, {1590, 53}, {1890, 63}}), // Version 35
- new RSBlockInfo(3034, new int[][]{ {600, 20}, {1120, 40}, {1680, 56}, {1980, 66}}), // Version 36
- new RSBlockInfo(3196, new int[][]{ {630, 21}, {1204, 43}, {1770, 59}, {2100, 70}}), // Version 37
- new RSBlockInfo(3362, new int[][]{ {660, 22}, {1260, 45}, {1860, 62}, {2220, 74}}), // Version 38
- new RSBlockInfo(3532, new int[][]{ {720, 24}, {1316, 47}, {1950, 65}, {2310, 77}}), // Version 39
- new RSBlockInfo(3706, new int[][]{ {750, 25}, {1372, 49}, {2040, 68}, {2430, 81}}), // Version 40
- };
+ // 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;
+ }
private static final class BlockPair {
private final ByteArray dataBytes;
private final ByteArray errorCorrectionBytes;
- public BlockPair(ByteArray data, ByteArray errorCorrection) {
+ BlockPair(ByteArray data, ByteArray errorCorrection) {
dataBytes = data;
errorCorrectionBytes = errorCorrection;
}
//
// 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(final ByteArray bytes, ErrorCorrectionLevel ecLevel, QRCode qrCode)
+ public static void encode(String content, ErrorCorrectionLevel ecLevel, QRCode qrCode)
throws WriterException {
// Step 1: Choose the mode (encoding).
- final Mode mode = chooseMode(bytes);
+ Mode mode = chooseMode(content);
// Step 2: Append "bytes" into "dataBits" in appropriate encoding.
BitVector dataBits = new BitVector();
- appendBytes(bytes, mode, dataBits);
+ appendBytes(content, mode, dataBits);
// Step 3: Initialize QR code that can contain "dataBits".
- final int numInputBytes = dataBits.sizeInBytes();
+ int numInputBytes = dataBits.sizeInBytes();
initQRCode(numInputBytes, ecLevel, mode, qrCode);
// Step 4: Build another bit vector that contains header and data.
BitVector headerAndDataBits = new BitVector();
appendModeInfo(qrCode.getMode(), headerAndDataBits);
- appendLengthInfo(bytes.size(), qrCode.getVersion(), qrCode.getMode(), headerAndDataBits);
+ appendLengthInfo(content.length(), qrCode.getVersion(), qrCode.getMode(), headerAndDataBits);
headerAndDataBits.appendBitVector(dataBits);
// Step 5: Terminate the bits properly.
return -1;
}
- // Choose the best mode by examining the content of "bytes". The function is guaranteed to return
- // a valid mode.
+ // Choose the best mode by examining the content.
//
// Note that this function does not return MODE_KANJI, as we cannot distinguish Shift_JIS from
// other encodings such as ISO-8859-1, from data bytes alone. For example "\xE0\xE0" can be
// interpreted as one character in Shift_JIS, but also two characters in ISO-8859-1.
//
// JAVAPORT: This MODE_KANJI limitation sounds like a problem for us.
- public static Mode chooseMode(final ByteArray bytes) throws WriterException {
+ public static Mode chooseMode(String content) {
boolean hasNumeric = false;
boolean hasAlphanumeric = false;
- boolean hasOther = false;
- for (int i = 0; i < bytes.size(); ++i) {
- final int oneByte = bytes.at(i);
- if (oneByte >= '0' && oneByte <= '9') {
+ for (int i = 0; i < content.length(); ++i) {
+ char c = content.charAt(i);
+ if (c >= '0' && c <= '9') {
hasNumeric = true;
- } else if (getAlphanumericCode(oneByte) != -1) {
+ } else if (getAlphanumericCode(c) != -1) {
hasAlphanumeric = true;
} else {
- hasOther = true;
+ return Mode.BYTE;
}
}
- if (hasOther) {
- return Mode.BYTE;
- } else if (hasAlphanumeric) {
+ if (hasAlphanumeric) {
return Mode.ALPHANUMERIC;
} else if (hasNumeric) {
return Mode.NUMERIC;
}
- // "bytes" must be empty to reach here.
- if (!bytes.empty()) {
- throw new WriterException("Bytes left over");
- }
return Mode.BYTE;
}
- private static int chooseMaskPattern(final BitVector bits, ErrorCorrectionLevel ecLevel, int version,
+ private static int chooseMaskPattern(BitVector bits, ErrorCorrectionLevel ecLevel, int version,
ByteMatrix matrix) throws WriterException {
- if (!QRCode.isValidMatrixWidth(matrix.width())) {
- throw new WriterException("Invalid matrix width: " + matrix.width());
- }
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);
- final int penalty = MaskUtil.calculateMaskPenalty(matrix);
+ int penalty = calculateMaskPenalty(matrix);
if (penalty < minPenalty) {
minPenalty = penalty;
bestMaskPattern = maskPattern;
}
// Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, modify
- // "qrCode" and return true.
+ // "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 i = 0; i < RS_BLOCK_TABLE.length; ++i) {
- final RSBlockInfo row = RS_BLOCK_TABLE[i];
+ for (int versionNum = 1; versionNum <= 40; versionNum++) {
+ Version version = Version.getVersionForNumber(versionNum);
// numBytes = 196
- final int numBytes = row.numBytes;
+ int numBytes = version.getTotalCodewords();
// getNumECBytes = 130
- final int numEcBytes = row.blockInfo[ecLevel.ordinal()][0];
+ Version.ECBlocks ecBlocks = version.getECBlocksForLevel(ecLevel);
+ int numEcBytes = ecBlocks.getTotalECCodewords();
// getNumRSBlocks = 5
- final int numRSBlocks = row.blockInfo[ecLevel.ordinal()][1];
+ int numRSBlocks = ecBlocks.getNumBlocks();
// getNumDataBytes = 196 - 130 = 66
- final int numDataBytes = numBytes - numEcBytes;
+ 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(i + 1);
+ qrCode.setVersion(versionNum);
qrCode.setNumTotalBytes(numBytes);
qrCode.setNumDataBytes(numDataBytes);
qrCode.setNumRSBlocks(numRSBlocks);
// getNumECBytes = 196 - 66 = 130
- qrCode.setNumECBytes(numBytes - numDataBytes);
+ qrCode.setNumECBytes(numEcBytes);
// matrix width = 21 + 6 * 4 = 45
- qrCode.setMatrixWidth(21 + i * 4);
+ qrCode.setMatrixWidth(version.getDimensionForVersion());
return;
}
}
// Terminate bits as described in 8.4.8 and 8.4.9 of JISX0510:2004 (p.24).
static void terminateBits(int numDataBytes, BitVector bits) throws WriterException {
- final int capacity = numDataBytes * 8;
+ int capacity = numDataBytes << 3;
if (bits.size() > capacity) {
throw new WriterException("data bits cannot fit in the QR Code" + bits.size() + " > " + capacity);
}
for (int i = 0; i < 4 && bits.size() < capacity; ++i) {
bits.appendBit(0);
}
- final int numBitsInLastByte = bits.size() % 8;
+ int numBitsInLastByte = bits.size() % 8;
// If the last byte isn't 8-bit aligned, we'll add padding bits.
if (numBitsInLastByte > 0) {
- final int numPaddingBits = 8 - numBitsInLastByte;
+ int numPaddingBits = 8 - numBitsInLastByte;
for (int i = 0; i < numPaddingBits; ++i) {
bits.appendBit(0);
}
throw new WriterException("Number of bits is not a multiple of 8");
}
// If we have more space, we'll fill the space with padding patterns defined in 8.4.9 (p.24).
- final int numPaddingBytes = numDataBytes - bits.sizeInBytes();
+ int numPaddingBytes = numDataBytes - bits.sizeInBytes();
for (int i = 0; i < numPaddingBytes; ++i) {
if (i % 2 == 0) {
bits.appendBits(0xec, 8);
throw new WriterException("Block ID too large");
}
// numRsBlocksInGroup2 = 196 % 5 = 1
- final int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
+ int numRsBlocksInGroup2 = numTotalBytes % numRSBlocks;
// numRsBlocksInGroup1 = 5 - 1 = 4
- final int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
+ int numRsBlocksInGroup1 = numRSBlocks - numRsBlocksInGroup2;
// numTotalBytesInGroup1 = 196 / 5 = 39
- final int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
+ int numTotalBytesInGroup1 = numTotalBytes / numRSBlocks;
// numTotalBytesInGroup2 = 39 + 1 = 40
- final int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
+ int numTotalBytesInGroup2 = numTotalBytesInGroup1 + 1;
// numDataBytesInGroup1 = 66 / 5 = 13
- final int numDataBytesInGroup1 = numDataBytes / numRSBlocks;
+ int numDataBytesInGroup1 = numDataBytes / numRSBlocks;
// numDataBytesInGroup2 = 13 + 1 = 14
- final int numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
+ int numDataBytesInGroup2 = numDataBytesInGroup1 + 1;
// numEcBytesInGroup1 = 39 - 13 = 26
- final int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
+ int numEcBytesInGroup1 = numTotalBytesInGroup1 - numDataBytesInGroup1;
// numEcBytesInGroup2 = 40 - 14 = 26
- final int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
+ int numEcBytesInGroup2 = numTotalBytesInGroup2 - numDataBytesInGroup2;
// Sanity checks.
// 26 = 26
if (numEcBytesInGroup1 != numEcBytesInGroup2) {
// Interleave "bits" with corresponding error correction bytes. On success, store the result in
// "result" and return true. The interleave rule is complicated. See 8.6
// of JISX0510:2004 (p.37) for details.
- static void interleaveWithECBytes(final BitVector bits, int numTotalBytes,
+ static void interleaveWithECBytes(BitVector bits, int numTotalBytes,
int numDataBytes, int numRSBlocks, BitVector result) throws WriterException {
// "bits" must have "getNumDataBytes" bytes of data.
// First, place data blocks.
for (int i = 0; i < maxNumDataBytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) {
- final ByteArray dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes();
+ ByteArray dataBytes = ((BlockPair) blocks.elementAt(j)).getDataBytes();
if (i < dataBytes.size()) {
result.appendBits(dataBytes.at(i), 8);
}
// Then, place error correction blocks.
for (int i = 0; i < maxNumEcBytes; ++i) {
for (int j = 0; j < blocks.size(); ++j) {
- final ByteArray ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes();
+ ByteArray ecBytes = ((BlockPair) blocks.elementAt(j)).getErrorCorrectionBytes();
if (i < ecBytes.size()) {
result.appendBits(ecBytes.at(i), 8);
}
// Append length info. On success, store the result in "bits" and return true. On error, return
// false.
- static void appendLengthInfo(int numBytes, int version, Mode mode, BitVector bits) throws WriterException {
- int numLetters = numBytes;
- // In Kanji mode, a letter is represented in two bytes.
- if (mode.equals(Mode.KANJI)) {
- if (numLetters % 2 != 0) {
- throw new WriterException("Number of letters must be even");
- }
- numLetters /= 2;
- }
-
- final int numBits = mode.getCharacterCountBits(Version.getVersionForNumber(version));
-
+ static void appendLengthInfo(int numLetters, int version, Mode mode, BitVector 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));
}
// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits"
// and return true.
- static void appendBytes(final ByteArray bytes, Mode mode, BitVector bits) throws WriterException {
+ static void appendBytes(String content, Mode mode, BitVector bits) throws WriterException {
if (mode.equals(Mode.NUMERIC)) {
- appendNumericBytes(bytes, bits);
+ appendNumericBytes(content, bits);
} else if (mode.equals(Mode.ALPHANUMERIC)) {
- appendAlphanumericBytes(bytes, bits);
+ appendAlphanumericBytes(content, bits);
} else if (mode.equals(Mode.BYTE)) {
- append8BitBytes(bytes, bits);
+ append8BitBytes(content, bits);
} else if (mode.equals(Mode.KANJI)) {
- appendKanjiBytes(bytes, bits);
+ appendKanjiBytes(content, bits);
} else {
throw new WriterException("Invalid mode: " + mode);
}
}
- // Append "bytes" to "bits" using QRCode.MODE_NUMERIC mode. On success, store the result in "bits"
- // and return true.
- static void appendNumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
- // Validate all the bytes first.
- for (int i = 0; i < bytes.size(); ++i) {
- int oneByte = bytes.at(i);
- if (oneByte < '0' || oneByte > '9') {
- throw new WriterException("Non-digit found");
- }
- }
- for (int i = 0; i < bytes.size();) {
- final int num1 = bytes.at(i) - '0';
- if (i + 2 < bytes.size()) {
+ static void appendNumericBytes(String content, BitVector 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.
- final int num2 = bytes.at(i + 1) - '0';
- final int num3 = bytes.at(i + 2) - '0';
+ 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 < bytes.size()) {
+ } else if (i + 1 < length) {
// Encode two numeric letters in seven bits.
- final int num2 = bytes.at(i + 1) - '0';
+ 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;
+ i++;
}
}
}
- // Append "bytes" to "bits" using QRCode.MODE_ALPHANUMERIC mode. On success, store the result in
- // "bits" and return true.
- static void appendAlphanumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
- for (int i = 0; i < bytes.size();) {
- final int code1 = getAlphanumericCode(bytes.at(i));
+ static void appendAlphanumericBytes(String content, BitVector 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 < bytes.size()) {
- final int code2 = getAlphanumericCode(bytes.at(i + 1));
+ if (i + 1 < length) {
+ int code2 = getAlphanumericCode(content.charAt(i + 1));
if (code2 == -1) {
throw new WriterException();
}
} else {
// Encode one alphanumeric letter in six bits.
bits.appendBits(code1, 6);
- ++i;
+ i++;
}
}
}
- // Append "bytes" to "bits" using QRCode.MODE_8BIT_BYTE mode. On success, store the result in
- // "bits" and return true.
- static void append8BitBytes(final ByteArray bytes, BitVector bits) {
- for (int i = 0; i < bytes.size(); ++i) {
- bits.appendBits(bytes.at(i), 8);
+ static void append8BitBytes(String content, BitVector bits) throws WriterException {
+ byte[] bytes;
+ try {
+ bytes = content.getBytes("ISO-8859-1"); // TODO support specifying encoding?
+ } catch (UnsupportedEncodingException uee) {
+ throw new WriterException(uee.toString());
+ }
+ for (int i = 0; i < bytes.length; ++i) {
+ bits.appendBits(bytes[i], 8);
}
}
- // Append "bytes" to "bits" using QRCode.MODE_KANJI mode. On success, store the result in "bits"
- // and return true. See 8.4.5 of JISX0510:2004 (p.21) for how to encode
- // Kanji bytes.
- static void appendKanjiBytes(final ByteArray bytes, BitVector bits) throws WriterException {
- if (bytes.size() % 2 != 0) {
- throw new WriterException("Number of bytes must be even");
- }
- for (int i = 0; i < bytes.size(); i += 2) {
- if (!isValidKanji(bytes.at(i), bytes.at(i + 1))) {
- throw new WriterException("Invalid Kanji at " + i);
- }
- final int code = (bytes.at(i) << 8) | bytes.at(i + 1);
+ static void appendKanjiBytes(String content, BitVector 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;
subtracted = code - 0xc140;
}
if (subtracted == -1) {
- throw new WriterException("Invalid byte sequence: " + bytes);
+ throw new WriterException("Invalid byte sequence");
}
- final int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
+ int encoded = ((subtracted >> 8) * 0xc0) + (subtracted & 0xff);
bits.appendBits(encoded, 13);
}
}
- // Check if "byte1" and "byte2" can compose a valid Kanji letter (2-byte Shift_JIS letter). The
- // numbers are from http://ja.wikipedia.org/wiki/Shift_JIS.
- static boolean isValidKanji(final int byte1, final int byte2) {
- return (byte2 != 0x7f &&
- ((byte1 >= 0x81 && byte1 <= 0x9f &&
- byte2 >= 0x40 && byte2 <= 0xfc) ||
- ((byte1 >= 0xe0 && byte1 <= 0xfc &&
- byte2 >= 0x40 && byte2 <= 0xfc))));
- }
-
- // Check if "bytes" is a valid Kanji sequence. Used by the unit tests.
- static boolean isValidKanjiSequence(final ByteArray bytes) {
- if (bytes.size() % 2 != 0) {
- return false;
- }
- int i = 0;
- for (; i < bytes.size(); i += 2) {
- if (!isValidKanji(bytes.at(i), bytes.at(i + 1))) {
- break;
- }
- }
- return i == bytes.size(); // Consumed all bytes?
- }
-
}
// do nothing
}
- // 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.
- public static int calculateMaskPenalty(final ByteMatrix matrix) {
- int penalty = 0;
- penalty += applyMaskPenaltyRule1(matrix);
- penalty += applyMaskPenaltyRule2(matrix);
- penalty += applyMaskPenaltyRule3(matrix);
- penalty += applyMaskPenaltyRule4(matrix);
- return penalty;
- }
-
// 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(final ByteMatrix matrix) {
+ 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(final ByteMatrix matrix) {
+ public static int applyMaskPenaltyRule2(ByteMatrix matrix) {
int penalty = 0;
byte[][] array = matrix.getArray();
int width = matrix.width();
// 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(final ByteMatrix matrix) {
+ public static int applyMaskPenaltyRule3(ByteMatrix matrix) {
int penalty = 0;
byte[][] array = matrix.getArray();
int width = matrix.width();
// - 55% => 10
// - 55% => 20
// - 100% => 100
- public static int applyMaskPenaltyRule4(final ByteMatrix matrix) {
+ public static int applyMaskPenaltyRule4(ByteMatrix matrix) {
int numDarkCells = 0;
byte[][] array = matrix.getArray();
int width = matrix.width();
}
}
}
- final int numTotalCells = matrix.height() * matrix.width();
+ int numTotalCells = matrix.height() * matrix.width();
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 int getDataMaskBit(final int maskPattern, final int x, final int y) {
+ public static int getDataMaskBit(int maskPattern, int x, int y) {
if (!QRCode.isValidMaskPattern(maskPattern)) {
throw new IllegalArgumentException("Invalid mask pattern");
}
// Helper function for applyMaskPenaltyRule1. We need this for doing this calculation in both
// vertical and horizontal orders respectively.
- private static int applyMaskPenaltyRule1Internal(final ByteMatrix matrix, boolean isHorizontal) {
+ private static int applyMaskPenaltyRule1Internal(ByteMatrix matrix, boolean isHorizontal) {
int penalty = 0;
int numSameBitCells = 0;
int prevBit = -1;
// for (int i = 0; i < matrix.width(); ++i) {
// for (int j = 0; j < matrix.height(); ++j) {
// int bit = matrix.get(j, i);
- final int iLimit = isHorizontal ? matrix.height() : matrix.width();
- final int jLimit = isHorizontal ? matrix.width() : matrix.height();
+ int iLimit = isHorizontal ? matrix.height() : matrix.width();
+ int jLimit = isHorizontal ? matrix.width() : matrix.height();
byte[][] array = matrix.getArray();
for (int i = 0; i < iLimit; ++i) {
for (int j = 0; j < jLimit; ++j) {
- final int bit = isHorizontal ? array[i][j] : array[j][i];
+ int bit = isHorizontal ? array[i][j] : array[j][i];
if (bit == prevBit) {
numSameBitCells += 1;
// Found five repetitive cells with the same color (bit).
// 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(final BitVector dataBits, ErrorCorrectionLevel ecLevel, int version,
+ public static void buildMatrix(BitVector dataBits, ErrorCorrectionLevel ecLevel, int version,
int maskPattern, ByteMatrix matrix) throws WriterException {
- MatrixUtil.clearMatrix(matrix);
+ clearMatrix(matrix);
embedBasicPatterns(version, matrix);
// Type information appear with any version.
embedTypeInfo(ecLevel, maskPattern, matrix);
for (int i = 0; i < typeInfoBits.size(); ++i) {
// Place bits in LSB to MSB order. LSB (least significant bit) is the last value in
// "typeInfoBits".
- final int bit = typeInfoBits.at(typeInfoBits.size() - 1 - i);
+ int bit = typeInfoBits.at(typeInfoBits.size() - 1 - i);
// Type info bits at the left top corner. See 8.9 of JISX0510:2004 (p.46).
- final int x1 = TYPE_INFO_COORDINATES[i][0];
- final int y1 = TYPE_INFO_COORDINATES[i][1];
+ int x1 = TYPE_INFO_COORDINATES[i][0];
+ int y1 = TYPE_INFO_COORDINATES[i][1];
matrix.set(y1, x1, bit);
if (i < 8) {
// Right top corner.
- final int x2 = matrix.width() - i - 1;
- final int y2 = 8;
+ int x2 = matrix.width() - i - 1;
+ int y2 = 8;
matrix.set(y2, x2, bit);
} else {
// Left bottom corner.
- final int x2 = 8;
- final int y2 = matrix.height() - 7 + (i - 8);
+ int x2 = 8;
+ int y2 = matrix.height() - 7 + (i - 8);
matrix.set(y2, x2, bit);
}
}
for (int i = 0; i < 6; ++i) {
for (int j = 0; j < 3; ++j) {
// Place bits in LSB (least significant bit) to MSB order.
- final int bit = versionInfoBits.at(bitIndex);
+ int bit = versionInfoBits.at(bitIndex);
bitIndex--;
// Left bottom corner.
matrix.set(matrix.height() - 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(final BitVector dataBits, int maskPattern, ByteMatrix matrix)
+ public static void embedDataBits(BitVector dataBits, int maskPattern, ByteMatrix matrix)
throws WriterException {
int bitIndex = 0;
int direction = -1;
}
while (y >= 0 && y < matrix.height()) {
for (int i = 0; i < 2; ++i) {
- final int xx = x - i;
+ int xx = x - i;
// Skip the cell if it's not empty.
if (!isEmpty(matrix.get(y, xx))) {
continue;
// Skip masking if mask_pattern is -1.
if (maskPattern != -1) {
- final int mask = MaskUtil.getDataMaskBit(maskPattern, xx, y);
+ int mask = MaskUtil.getDataMaskBit(maskPattern, xx, y);
bit ^= mask;
}
matrix.set(y, xx, bit);
}
// All bits should be consumed.
if (bitIndex != dataBits.size()) {
- throw new WriterException("Not all bits consumed: " + bitIndex + "/" + dataBits.size());
+ throw new WriterException("Not all bits consumed: " + bitIndex + '/' + dataBits.size());
}
}
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.
- final int msbSetInPoly = findMSBSet(poly);
+ int msbSetInPoly = findMSBSet(poly);
value <<= msbSetInPoly - 1;
// Do the division business using exclusive-or operations.
while (findMSBSet(value) >= msbSetInPoly) {
// 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, final int maskPattern, BitVector bits)
+ public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, int maskPattern, BitVector bits)
throws WriterException {
if (!QRCode.isValidMaskPattern(maskPattern)) {
throw new WriterException("Invalid mask pattern");
}
- final int typeInfo = (ecLevel.getBits() << 3) | maskPattern;
+ int typeInfo = (ecLevel.getBits() << 3) | maskPattern;
bits.appendBits(typeInfo, 5);
- final int bchCode = MatrixUtil.calculateBCHCode(typeInfo, TYPE_INFO_POLY);
+ int bchCode = calculateBCHCode(typeInfo, TYPE_INFO_POLY);
bits.appendBits(bchCode, 10);
BitVector maskBits = new BitVector();
// See 8.10 of JISX0510:2004 (p.45) for details.
public static void makeVersionInfoBits(int version, BitVector bits) throws WriterException {
bits.appendBits(version, 6);
- final int bchCode = MatrixUtil.calculateBCHCode(version, VERSION_INFO_POLY);
+ int bchCode = calculateBCHCode(version, VERSION_INFO_POLY);
bits.appendBits(bchCode, 12);
if (bits.size() != 18) { // Just in case.
}
// Check if "value" is empty.
- private static boolean isEmpty(final int value) {
+ private static boolean isEmpty(int value) {
return value == -1;
}
// Check if "value" is valid.
- private static boolean isValidValue(final int value) {
+ private static boolean isValidValue(int value) {
return (value == -1 || // Empty.
value == 0 || // Light (white).
value == 1); // Dark (black).
// -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.width() - 8; ++i) {
- final int bit = (i + 1) % 2;
+ int bit = (i + 1) % 2;
// Horizontal line.
if (!isValidValue(matrix.get(6, i))) {
throw new WriterException();
matrix.set(matrix.height() - 8, 8, 1);
}
- private static void embedHorizontalSeparationPattern(final int xStart, final int yStart,
+ 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) {
}
}
- private static void embedVerticalSeparationPattern(final int xStart, final int yStart,
+ 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) {
// 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(final int xStart, final int yStart,
+ 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) {
}
}
- private static void embedPositionDetectionPattern(final int xStart, final int yStart,
+ 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) {
// Embed position detection patterns and surrounding vertical/horizontal separators.
private static void embedPositionDetectionPatternsAndSeparators(ByteMatrix matrix) throws WriterException {
// Embed three big squares at corners.
- final int pdpWidth = POSITION_DETECTION_PATTERN[0].length;
+ int pdpWidth = POSITION_DETECTION_PATTERN[0].length;
// Left top corner.
embedPositionDetectionPattern(0, 0, matrix);
// Right top corner.
embedPositionDetectionPattern(0, matrix.width() - pdpWidth, matrix);
// Embed horizontal separation patterns around the squares.
- final int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].length;
+ int hspWidth = HORIZONTAL_SEPARATION_PATTERN[0].length;
// Left top corner.
embedHorizontalSeparationPattern(0, hspWidth - 1, matrix);
// Right top corner.
embedHorizontalSeparationPattern(0, matrix.width() - hspWidth, matrix);
// Embed vertical separation patterns around the squares.
- final int vspSize = VERTICAL_SEPARATION_PATTERN.length;
+ int vspSize = VERTICAL_SEPARATION_PATTERN.length;
// Left top corner.
embedVerticalSeparationPattern(vspSize, 0, matrix);
// Right top corner.
}
// Embed position adjustment patterns if need be.
- private static void maybeEmbedPositionAdjustmentPatterns(final int version, ByteMatrix matrix)
+ private static void maybeEmbedPositionAdjustmentPatterns(int version, ByteMatrix matrix)
throws WriterException {
if (version < 2) { // The patterns appear if version >= 2
return;
}
- final int index = version - 1;
- final int[] coordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index];
- final int numCoordinates = POSITION_ADJUSTMENT_PATTERN_COORDINATE_TABLE[index].length;
+ 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) {
- final int y = coordinates[i];
- final int x = coordinates[j];
+ int y = coordinates[i];
+ int x = coordinates[j];
if (x == -1 || y == -1) {
continue;
}
*/
public final class QRCode {
- // Magic numbers.
- private static final int MIN_VERSION = 1;
- private static final int MAX_VERSION = 40;
- // For matrix width, see 7.3.1 of JISX0510:2004 (p.5).
- private static final int MIN_MATRIX_WIDTH = 21; // Version 1
- private static final int MAX_MATRIX_WIDTH = 177; // Version 40 (21 + 4 * (40 -1)).
public static final int NUM_MASK_PATTERNS = 8;
private Mode mode;
}
// ByteMatrix data of the QR Code.
- public final ByteMatrix getMatrix() {
+ public ByteMatrix getMatrix() {
return matrix;
}
numECBytes != -1 &&
numRSBlocks != -1 &&
// Then check them in other ways..
- isValidVersion(version) &&
- isValidMatrixWidth(matrixWidth) &&
isValidMaskPattern(maskPattern) &&
numTotalBytes == numDataBytes + numECBytes &&
// ByteMatrix stuff.
matrix != null &&
matrixWidth == matrix.width() &&
// See 7.3.1 of JISX0510:2004 (p.5).
- matrixWidth == MIN_MATRIX_WIDTH + (version - 1) * 4 &&
matrix.width() == matrix.height(); // Must be square.
}
// Return debug String.
public String toString() {
- StringBuffer result = new StringBuffer();
+ StringBuffer result = new StringBuffer(200);
result.append("<<\n");
result.append(" mode: ");
result.append(mode);
matrix = value;
}
- // Check if "version" is valid.
- public static boolean isValidVersion(final int version) {
- return version >= MIN_VERSION && version <= MAX_VERSION;
- }
-
- // Check if "width" is valid.
- public static boolean isValidMatrixWidth(int width) {
- return width >= MIN_MATRIX_WIDTH && width <= MAX_MATRIX_WIDTH;
- }
-
// Check if "mask_pattern" is valid.
public static boolean isValidMaskPattern(int maskPattern) {
return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;
public void testQRCodeWriter() throws WriterException {
// The QR should be multiplied up to fit, with extra padding if necessary
- final int bigEnough = 256;
+ int bigEnough = 256;
QRCodeWriter writer = new QRCodeWriter();
ByteMatrix matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, bigEnough,
bigEnough, null);
- assertTrue(matrix != null);
+ assertNotNull(matrix);
assertEquals(bigEnough, matrix.width());
assertEquals(bigEnough, matrix.height());
// The QR will not fit in this size, so the matrix should come back bigger
- final int tooSmall = 20;
+ int tooSmall = 20;
matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, tooSmall,
tooSmall, null);
- assertTrue(matrix != null);
+ assertNotNull(matrix);
assertTrue(tooSmall < matrix.width());
assertTrue(tooSmall < matrix.height());
// We should also be able to handle non-square requests by padding them
- final int strangeWidth = 500;
- final int strangeHeight = 100;
+ int strangeWidth = 500;
+ int strangeHeight = 100;
matrix = writer.encode("http://www.google.com/", BarcodeFormat.QR_CODE, strangeWidth,
strangeHeight, null);
- assertTrue(matrix != null);
+ assertNotNull(matrix);
assertEquals(strangeWidth, matrix.width());
assertEquals(strangeHeight, matrix.height());
}
- private static boolean compareToGoldenFile(final String contents, final ErrorCorrectionLevel ecLevel,
- final int resolution, final String fileName) throws WriterException {
+ private static void compareToGoldenFile(String contents, ErrorCorrectionLevel ecLevel,
+ int resolution, String fileName) throws WriterException {
BufferedImage image = loadImage(fileName);
assertNotNull(image);
resolution, generatedResult.height());
assertTrue("Expected " + goldenResult.toString() + " but got " + generatedResult.toString(),
Arrays.deepEquals(goldenResult.getArray(), generatedResult.getArray()));
- return true;
}
// Golden images are generated with "qrcode_sample.cc". The images are checked with both eye balls
// and cell phones. We expect pixel-perfect results, because the error correction level is known,
// and the pixel dimensions matches exactly.
- public void testRegressionTest() throws WriterException {
- assertTrue(compareToGoldenFile("http://www.google.com/", ErrorCorrectionLevel.M, 99,
- "renderer-test-01.png"));
+ public void testRegressionTest() throws WriterException, IOException {
+ compareToGoldenFile("http://www.google.com/", ErrorCorrectionLevel.M, 99,
+ "renderer-test-01.png");
- assertTrue(compareToGoldenFile("12345", ErrorCorrectionLevel.L, 58, "renderer-test-02.png"));
+ compareToGoldenFile("12345", ErrorCorrectionLevel.L, 58, "renderer-test-02.png");
// Test in Katakana in Shift_JIS.
- final byte[] KATAKANA_INPUT = {
- (byte)0x83, 0x65, (byte)0x83, 0x58, (byte)0x83, 0x67
- };
- assertTrue(compareToGoldenFile(new String(KATAKANA_INPUT), ErrorCorrectionLevel.H, 145,
- "renderer-test-03.png"));
+ // TODO: this test is bogus now that byte mode has been basically fixed to assuming ISO-8859-1 encoding
+ // The real solution is to implement Kanji mode, in which case the golden file will be wrong again
+ /*
+ compareToGoldenFile(
+ new String(new byte[] {(byte)0x83, 0x65, (byte)0x83, 0x58, (byte)0x83, 0x67}, "Shift_JIS"),
+ ErrorCorrectionLevel.H, 145,
+ "renderer-test-03.png");
+ */
}
}
import com.google.zxing.qrcode.decoder.Mode;
import junit.framework.TestCase;
+import java.io.UnsupportedEncodingException;
+
/**
* @author satorux@google.com (Satoru Takabayashi) - creator
* @author mysen@google.com (Chris Mysen) - ported from C++
*/
public final class EncoderTestCase extends TestCase {
- public void testGetAlphanumericCode() throws WriterException {
+ public void testGetAlphanumericCode() {
// The first ten code points are numbers.
for (int i = 0; i < 10; ++i) {
assertEquals(i, Encoder.getAlphanumericCode('0' + i));
public void testChooseMode() throws WriterException {
// Numeric mode.
- assertEquals(Mode.NUMERIC, Encoder.chooseMode(new ByteArray("0")));
- assertEquals(Mode.NUMERIC, Encoder.chooseMode(new ByteArray("0123456789")));
+ assertEquals(Mode.NUMERIC, Encoder.chooseMode("0"));
+ assertEquals(Mode.NUMERIC, Encoder.chooseMode("0123456789"));
// Alphanumeric mode.
- assertEquals(Mode.ALPHANUMERIC, Encoder.chooseMode(new ByteArray("A")));
+ assertEquals(Mode.ALPHANUMERIC, Encoder.chooseMode("A"));
assertEquals(Mode.ALPHANUMERIC,
- Encoder.chooseMode(new ByteArray("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:")));
+ Encoder.chooseMode("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ $%*+-./:"));
// 8-bit byte mode.
- assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("a")));
- assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("#")));
- assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray("")));
+ assertEquals(Mode.BYTE, Encoder.chooseMode("a"));
+ assertEquals(Mode.BYTE, Encoder.chooseMode("#"));
+ assertEquals(Mode.BYTE, Encoder.chooseMode(""));
// Kanji mode. We used to use MODE_KANJI for these, but we stopped
// doing that as we cannot distinguish Shift_JIS from other encodings
// from data bytes alone. See also comments in qrcode_encoder.h.
// AIUE in Hiragana in Shift_JIS
- byte[] dat1 = {0x8,0xa,0x8,0xa,0x8,0xa,0x8,(byte)0xa6};
- assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat1)));
+ assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0x8,0xa,0x8,0xa,0x8,0xa,0x8,(byte)0xa6})));
// Nihon in Kanji in Shift_JIS.
- byte[] dat2 = {0x9,0xf,0x9,0x7b};
- assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat2)));
+ assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0x9,0xf,0x9,0x7b})));
// Sou-Utsu-Byou in Kanji in Shift_JIS.
- byte[] dat3 = {0xe,0x4,0x9,0x5,0x9,0x61};
- assertEquals(Mode.BYTE, Encoder.chooseMode(new ByteArray(dat3)));
+ assertEquals(Mode.BYTE, Encoder.chooseMode(shiftJISString(new byte[] {0xe,0x4,0x9,0x5,0x9,0x61})));
}
public void testEncode() throws WriterException {
QRCode qrCode = new QRCode();
- Encoder.encode(new ByteArray("ABCDEF"), ErrorCorrectionLevel.H, qrCode);
+ Encoder.encode("ABCDEF", ErrorCorrectionLevel.H, qrCode);
// The following is a valid QR Code that can be read by cell phones.
String expected =
"<<\n" +
}
{
BitVector bits = new BitVector();
- Encoder.appendLengthInfo(1024, // 512 letters (1024/2).
+ Encoder.appendLengthInfo(512, // 512 letters (1024/2).
40, // version 40.
Mode.KANJI,
bits);
// Should use appendNumericBytes.
// 1 = 01 = 0001 in 4 bits.
BitVector bits = new BitVector();
- Encoder.appendBytes(new ByteArray("1"), Mode.NUMERIC, bits);
+ Encoder.appendBytes("1", Mode.NUMERIC, bits);
assertEquals("0001" , bits.toString());
- // 'A' cannot be encoded in MODE_NUMERIC.
- try {
- Encoder.appendBytes(new ByteArray("A"), Mode.NUMERIC, bits);
- fail("Should have thrown exception");
- } catch (WriterException we) {
- // good
- }
}
{
// Should use appendAlphanumericBytes.
// A = 10 = 0xa = 001010 in 6 bits
BitVector bits = new BitVector();
- Encoder.appendBytes(new ByteArray("A"), Mode.ALPHANUMERIC, bits);
+ Encoder.appendBytes("A", Mode.ALPHANUMERIC, bits);
assertEquals("001010" , bits.toString());
// Lower letters such as 'a' cannot be encoded in MODE_ALPHANUMERIC.
try {
- Encoder.appendBytes(new ByteArray("a"), Mode.ALPHANUMERIC, bits);
+ Encoder.appendBytes("a", Mode.ALPHANUMERIC, bits);
} catch (WriterException we) {
// good
}
// Should use append8BitBytes.
// 0x61, 0x62, 0x63
BitVector bits = new BitVector();
- Encoder.appendBytes(new ByteArray("abc"), Mode.BYTE, bits);
- assertEquals("01100001" + "01100010" + "01100011", bits.toString());
+ Encoder.appendBytes("abc", Mode.BYTE, bits);
+ assertEquals("011000010110001001100011", bits.toString());
// Anything can be encoded in QRCode.MODE_8BIT_BYTE.
- byte[] bytes = {0x00};
- Encoder.appendBytes(new ByteArray(bytes), Mode.BYTE, bits);
+ Encoder.appendBytes("\0", Mode.BYTE, bits);
}
{
// Should use appendKanjiBytes.
// 0x93, 0x5f
BitVector bits = new BitVector();
- byte[] bytes = {(byte)0x93,0x5f};
- Encoder.appendBytes(new ByteArray(bytes), Mode.KANJI, bits);
+ Encoder.appendBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), Mode.KANJI, bits);
assertEquals("0110110011111", bits.toString());
- // ASCII characters can not be encoded in QRCode.MODE_KANJI.
-
- try {
- Encoder.appendBytes(new ByteArray("a"), Mode.KANJI, bits);
- } catch (WriterException we) {
- // good
- }
}
}
- public void testInit() {
- // TODO: should be implemented.
- }
-
public void testTerminateBits() throws WriterException {
{
BitVector v = new BitVector();
public void testInterleaveWithECBytes() throws WriterException {
{
- final byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
+ byte[] dataBytes = {32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236};
BitVector in = new BitVector();
for (byte dataByte: dataBytes) {
in.appendBits(dataByte, 8);
}
BitVector out = new BitVector();
Encoder.interleaveWithECBytes(in, 26, 9, 1, out);
- final byte[] expected = {
+ byte[] expected = {
// Data bytes.
32, 65, (byte)205, 69, 41, (byte)220, 46, (byte)128, (byte)236,
// Error correction bytes.
(byte)237, 85, (byte)224, 96, 74, (byte)219, 61,
};
assertEquals(expected.length, out.sizeInBytes());
- final byte[] outArray = out.getArray();
+ byte[] outArray = out.getArray();
// Can't use Arrays.equals(), because outArray may be longer than out.sizeInBytes()
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[x]);
}
// Numbers are from http://www.swetake.com/qr/qr8.html
{
- final byte[] dataBytes = {
+ byte[] dataBytes = {
67, 70, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166, (byte)182,
(byte)198, (byte)214, (byte)230, (byte)247, 7, 23, 39, 55, 71, 87, 103, 119, (byte)135,
(byte)151, (byte)166, 22, 38, 54, 70, 86, 102, 118, (byte)134, (byte)150, (byte)166,
}
BitVector out = new BitVector();
Encoder.interleaveWithECBytes(in, 134, 62, 4, out);
- final byte[] expected = {
+ byte[] expected = {
// Data bytes.
67, (byte)230, 54, 55, 70, (byte)247, 70, 71, 22, 7, 86, 87, 38, 23, 102, 103, 54, 39,
118, 119, 70, 55, (byte)134, (byte)135, 86, 71, (byte)150, (byte)151, 102, 87, (byte)166,
(byte)187, 49, (byte)156, (byte)214,
};
assertEquals(expected.length, out.sizeInBytes());
- final byte[] outArray = out.getArray();
+ byte[] outArray = out.getArray();
for (int x = 0; x < expected.length; x++) {
assertEquals(expected[x], outArray[x]);
}
}
}
- public void testAppendNumericBytes() throws WriterException {
+ public void testAppendNumericBytes() {
{
// 1 = 01 = 0001 in 4 bits.
BitVector bits = new BitVector();
- Encoder.appendNumericBytes(new ByteArray("1"), bits);
+ Encoder.appendNumericBytes("1", bits);
assertEquals("0001" , bits.toString());
}
{
// 12 = 0xc = 0001100 in 7 bits.
BitVector bits = new BitVector();
- Encoder.appendNumericBytes(new ByteArray("12"), bits);
+ Encoder.appendNumericBytes("12", bits);
assertEquals("0001100" , bits.toString());
}
{
// 123 = 0x7b = 0001111011 in 10 bits.
BitVector bits = new BitVector();
- Encoder.appendNumericBytes(new ByteArray("123"), bits);
+ Encoder.appendNumericBytes("123", bits);
assertEquals("0001111011" , bits.toString());
}
{
// 1234 = "123" + "4" = 0001111011 + 0100
BitVector bits = new BitVector();
- Encoder.appendNumericBytes(new ByteArray("1234"), bits);
+ Encoder.appendNumericBytes("1234", bits);
assertEquals("0001111011" + "0100" , bits.toString());
}
{
// Empty.
BitVector bits = new BitVector();
- Encoder.appendNumericBytes(new ByteArray(""), bits);
+ Encoder.appendNumericBytes("", bits);
assertEquals("" , bits.toString());
}
- {
- // Invalid data.
- BitVector bits = new BitVector();
- try {
- Encoder.appendNumericBytes(new ByteArray("abc"), bits);
- } catch (WriterException we) {
- // good
- }
- }
}
public void testAppendAlphanumericBytes() throws WriterException {
{
// A = 10 = 0xa = 001010 in 6 bits
BitVector bits = new BitVector();
- Encoder.appendAlphanumericBytes(new ByteArray("A"), bits);
+ Encoder.appendAlphanumericBytes("A", bits);
assertEquals("001010" , bits.toString());
}
{
// AB = 10 * 45 + 11 = 461 = 0x1cd = 00111001101 in 11 bits
BitVector bits = new BitVector();
- Encoder.appendAlphanumericBytes(new ByteArray("AB"), bits);
+ Encoder.appendAlphanumericBytes("AB", bits);
assertEquals("00111001101", bits.toString());
}
{
// ABC = "AB" + "C" = 00111001101 + 001100
BitVector bits = new BitVector();
- Encoder.appendAlphanumericBytes(new ByteArray("ABC"), bits);
+ Encoder.appendAlphanumericBytes("ABC", bits);
assertEquals("00111001101" + "001100" , bits.toString());
}
{
// Empty.
BitVector bits = new BitVector();
- Encoder.appendAlphanumericBytes(new ByteArray(""), bits);
+ Encoder.appendAlphanumericBytes("", bits);
assertEquals("" , bits.toString());
}
{
// Invalid data.
BitVector bits = new BitVector();
try {
- Encoder.appendAlphanumericBytes(new ByteArray("abc"), bits);
+ Encoder.appendAlphanumericBytes("abc", bits);
} catch (WriterException we) {
// good
}
{
// 0x61, 0x62, 0x63
BitVector bits = new BitVector();
- Encoder.append8BitBytes(new ByteArray("abc"), bits);
+ Encoder.append8BitBytes("abc", bits);
assertEquals("01100001" + "01100010" + "01100011", bits.toString());
}
{
// Empty.
BitVector bits = new BitVector();
- Encoder.append8BitBytes(new ByteArray(""), bits);
+ Encoder.append8BitBytes("", bits);
assertEquals("", bits.toString());
}
}
// Numbers are from page 21 of JISX0510:2004
public void testAppendKanjiBytes() throws WriterException {
- {
BitVector bits = new BitVector();
- byte[] dat1 = {(byte)0x93,0x5f};
- Encoder.appendKanjiBytes(new ByteArray(dat1), bits);
+ Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0x93,0x5f}), bits);
assertEquals("0110110011111", bits.toString());
- byte[] dat2 = {(byte)0xe4,(byte)0xaa};
- Encoder.appendKanjiBytes(new ByteArray(dat2), bits);
+ Encoder.appendKanjiBytes(shiftJISString(new byte[] {(byte)0xe4,(byte)0xaa}), bits);
assertEquals("0110110011111" + "1101010101010", bits.toString());
- }
}
- // JAVAPORT: Uncomment and fix up with new Reed Solomon objects
-// static boolean ComparePoly(final int[] expected, final int size, final GF_Poly poly) {
-// if (size != poly.degree() + 1) {
-// return false;
-// }
-// for (int i = 0; i < size; ++i) {
-// // "expected" is ordered in a reverse order. We reverse the coeff
-// // index for comparison.
-// final int coeff = GaloisField.GetField(8).Log(
-// poly.coeff(size - i - 1));
-// if (expected[i] != coeff) {
-// Debug.LOG_ERROR("values don't match at " + i + ": " +
-// expected[i] + " vs. " + coeff);
-// return false;
-// }
-// }
-// return true;
-// }
-//
-// // Numbers are from Appendix A of JISX0510 2004 (p.59).
-// public void testGetECPoly() {
-// {
-// final GF_Poly poly = Encoder.GetECPoly(7);
-// final int[] expected = {0, 87, 229, 146, 149, 238, 102, 21};
-// assertTrue(ComparePoly(expected, expected.length, poly));
-// }
-// {
-// final GF_Poly poly = Encoder.GetECPoly(17);
-// final int[] expected = {
-// 0, 43, 139, 206, 78, 43, 239, 123, 206, 214, 147, 24, 99, 150,
-// 39, 243, 163, 136
-// };
-// assertTrue(ComparePoly(expected, expected.length, poly));
-// }
-// {
-// final GF_Poly poly = Encoder.GetECPoly(34);
-// final int[] expected = {
-// 0, 111, 77, 146, 94, 26, 21, 108, 19,
-// 105, 94, 113, 193, 86, 140, 163, 125,
-// 58,
-// 158, 229, 239, 218, 103, 56, 70, 114,
-// 61, 183, 129, 167, 13, 98, 62, 129, 51
-// };
-// assertTrue(ComparePoly(expected, expected.length, poly));
-// }
-// {
-// final GF_Poly poly = Encoder.GetECPoly(68);
-// final int[] expected = {
-// 0, 247, 159, 223, 33, 224, 93, 77, 70,
-// 90, 160, 32, 254, 43, 150, 84, 101,
-// 190,
-// 205, 133, 52, 60, 202, 165, 220, 203,
-// 151, 93, 84, 15, 84, 253, 173, 160,
-// 89, 227, 52, 199, 97, 95, 231, 52,
-// 177, 41, 125, 137, 241, 166, 225, 118,
-// 2, 54,
-// 32, 82, 215, 175, 198, 43, 238, 235,
-// 27, 101, 184, 127, 3, 5, 8, 163, 238
-// };
-// assertTrue(ComparePoly(expected, expected.length, poly));
-// }
-// }
-
// Numbers are from http://www.swetake.com/qr/qr3.html and
// http://www.swetake.com/qr/qr9.html
public void testGenerateECBytes() {
}
}
- public void testIsValidKanji() {
- assertTrue(Encoder.isValidKanji(0x82, 0xa0)); // Hiragana "A".
- assertTrue(Encoder.isValidKanji(0x93, 0xfa)); // Nichi in Kanji.
- assertTrue(Encoder.isValidKanji(0x8a, 0xbf)); // Kan in Kanji.
- assertTrue(Encoder.isValidKanji(0xe7, 0x4e)); // Sou in Kanji.
- assertTrue(Encoder.isValidKanji(0xea, 0xa2)); // Haruka in Kanji.
-
- assertFalse(Encoder.isValidKanji('0', '1'));
- assertFalse(Encoder.isValidKanji(0x82, 0x7f));
- assertFalse(Encoder.isValidKanji(0xa0, 0xa0));
- }
-
- public void testIsValidKanjiSequence() {
- // AIUEO in Katakana
- byte[] dat1 = {
- (byte)0x83, 0x41, (byte)0x83, 0x43, (byte)0x83, 0x45, (byte)0x83, 0x47, (byte)0x83, 0x49
- };
- assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat1)));
- // 012345 in multi-byte letters.
- byte[] dat2 = {
- (byte)0x82, 0x4f, (byte)0x82, 0x50, (byte)0x82, 0x51, (byte)0x82, 0x52, (byte)0x82, 0x53,
- (byte)0x82, 0x54
- };
- assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat2)));
- // Yoroshiku in Kanji.
- byte[] dat3 = {
- (byte)0x96, (byte)0xe9, (byte)0x98, 0x49, (byte)0x8e, (byte)0x80, (byte)0x8b, (byte)0xea
- };
- assertTrue(Encoder.isValidKanjiSequence(new ByteArray(dat3)));
- assertFalse(Encoder.isValidKanjiSequence(new ByteArray("0123")));
- assertFalse(Encoder.isValidKanjiSequence(new ByteArray("ABC")));
- }
-
public void testBugInBitVectorNumBytes() throws WriterException {
// There was a bug in BitVector.sizeInBytes() that caused it to return a
// smaller-by-one value (ex. 1465 instead of 1466) if the number of bits
// - To be precise, it needs 11727 + 4 (getMode info) + 14 (length info) =
// 11745 bits = 1468.125 bytes are needed (i.e. cannot fit in 1468
// bytes).
- final int arraySize = 3518;
- byte[] dataBytes = new byte[arraySize];
- for (int x = 0; x < arraySize; x++) {
- dataBytes[x] = '0';
+ StringBuilder builder = new StringBuilder(3518);
+ for (int x = 0; x < 3518; x++) {
+ builder.append('0');
}
QRCode qrCode = new QRCode();
- Encoder.encode(new ByteArray(dataBytes), ErrorCorrectionLevel.L, qrCode);
+ Encoder.encode(builder.toString(), ErrorCorrectionLevel.L, qrCode);
}
+
+ private static String shiftJISString(byte[] bytes) throws WriterException {
+ try {
+ return new String(bytes, "Shift_JIS");
+ } catch (UnsupportedEncodingException uee) {
+ throw new WriterException(uee.toString());
+ }
+ }
+
}
" 1 0 1 1 1 0 1 0 1 1 1 1 0 0 0 0 1 1 1 0 0\n" +
" 1 0 0 0 0 0 1 0 0 0 0 0 0 0 0 0 1 0 1 0 0\n" +
" 1 1 1 1 1 1 1 0 0 0 1 1 1 1 1 0 1 0 0 1 0\n";
- char bytes[] = {32, 65, 205, 69, 41, 220, 46, 128, 236,
+ char[] bytes = {32, 65, 205, 69, 41, 220, 46, 128, 236,
42, 159, 74, 221, 244, 169, 239, 150, 138,
70, 237, 85, 224, 96, 74, 219 , 61};
BitVector bits = new BitVector();
}
}
- public void testIsValidVersion() {
- assertFalse(QRCode.isValidVersion(0));
- assertTrue(QRCode.isValidVersion(1));
- assertTrue(QRCode.isValidVersion(40));
- assertFalse(QRCode.isValidVersion(0));
- }
-
- public void testIsValidMatrixWidth() {
- assertFalse(QRCode.isValidMatrixWidth(20));
- assertTrue(QRCode.isValidMatrixWidth(21));
- assertTrue(QRCode.isValidMatrixWidth(177));
- assertFalse(QRCode.isValidMatrixWidth(178));
- }
-
public void testIsValidMaskPattern() {
assertFalse(QRCode.isValidMaskPattern(-1));
assertTrue(QRCode.isValidMaskPattern(0));