Unify handling of EC level between encoder and decoder

git-svn-id: https://zxing.googlecode.com/svn/trunk@770 59b500cc-1b3d-0410-9834-0bbf25fbcc57
This commit is contained in:
srowen 2008-12-02 01:00:18 +00:00
parent 416193ff9a
commit 784673a241
10 changed files with 132 additions and 166 deletions

View file

@ -24,6 +24,7 @@ import com.google.zxing.common.ByteArray;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.ByteMatrix;
import com.google.zxing.qrcode.encoder.Encoder; import com.google.zxing.qrcode.encoder.Encoder;
import com.google.zxing.qrcode.encoder.QRCode; import com.google.zxing.qrcode.encoder.QRCode;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.util.Hashtable; import java.util.Hashtable;
@ -58,11 +59,11 @@ public final class QRCodeWriter implements Writer {
height); height);
} }
int errorCorrectionLevel = QRCode.EC_LEVEL_L; ErrorCorrectionLevel errorCorrectionLevel = ErrorCorrectionLevel.L;
if (hints != null) { if (hints != null) {
Integer requestedECLevel = (Integer) hints.get(EncodeHintType.ERROR_CORRECTION); ErrorCorrectionLevel requestedECLevel = (ErrorCorrectionLevel) hints.get(EncodeHintType.ERROR_CORRECTION);
if (requestedECLevel != null) { if (requestedECLevel != null) {
errorCorrectionLevel = requestedECLevel.intValue(); errorCorrectionLevel = requestedECLevel;
} }
} }

View file

@ -24,46 +24,62 @@ import com.google.zxing.ReaderException;
* *
* @author Sean Owen * @author Sean Owen
*/ */
final class ErrorCorrectionLevel { public final class ErrorCorrectionLevel {
// No, we can't use an enum here. J2ME doesn't support it. // No, we can't use an enum here. J2ME doesn't support it.
/** /**
* L = ~7% correction * L = ~7% correction
*/ */
static final ErrorCorrectionLevel L = new ErrorCorrectionLevel(0); public static final ErrorCorrectionLevel L = new ErrorCorrectionLevel(0, 0x01, "L");
/** /**
* M = ~15% correction * M = ~15% correction
*/ */
static final ErrorCorrectionLevel M = new ErrorCorrectionLevel(1); public static final ErrorCorrectionLevel M = new ErrorCorrectionLevel(1, 0x00, "M");
/** /**
* Q = ~25% correction * Q = ~25% correction
*/ */
static final ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2); public static final ErrorCorrectionLevel Q = new ErrorCorrectionLevel(2, 0x03, "Q");
/** /**
* H = ~30% correction * H = ~30% correction
*/ */
static final ErrorCorrectionLevel H = new ErrorCorrectionLevel(3); public static final ErrorCorrectionLevel H = new ErrorCorrectionLevel(3, 0x02, "H");
private static final ErrorCorrectionLevel[] FOR_BITS = {M, L, H, Q}; private static final ErrorCorrectionLevel[] FOR_BITS = {M, L, H, Q};
private final int ordinal; private final int ordinal;
private final int bits;
private final String name;
private ErrorCorrectionLevel(int ordinal) { private ErrorCorrectionLevel(int ordinal, int bits, String name) {
this.ordinal = ordinal; this.ordinal = ordinal;
this.bits = bits;
this.name = name;
} }
int ordinal() { public int ordinal() {
return ordinal; return ordinal;
} }
public int getBits() {
return bits;
}
public String getName() {
return name;
}
public String toString() {
return name;
}
/** /**
* @param bits int containing the two bits encoding a QR Code's error correction level * @param bits int containing the two bits encoding a QR Code's error correction level
* @return {@link ErrorCorrectionLevel} representing the encoded error correction level * @return {@link ErrorCorrectionLevel} representing the encoded error correction level
*/ */
static ErrorCorrectionLevel forBits(int bits) throws ReaderException { public static ErrorCorrectionLevel forBits(int bits) {
if (bits < 0 || bits >= FOR_BITS.length) { if (bits < 0 || bits >= FOR_BITS.length) {
throw ReaderException.getInstance(); throw new IllegalArgumentException();
} }
return FOR_BITS[bits]; return FOR_BITS[bits];
} }

View file

@ -21,6 +21,7 @@ import com.google.zxing.common.ByteArray;
import com.google.zxing.common.reedsolomon.GF256; import com.google.zxing.common.reedsolomon.GF256;
import com.google.zxing.common.reedsolomon.ReedSolomonEncoder; import com.google.zxing.common.reedsolomon.ReedSolomonEncoder;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import java.util.Vector; import java.util.Vector;
@ -119,14 +120,15 @@ public final class Encoder {
} }
// Encode "bytes" with the error correction level "getECLevel". The encoding mode will be chosen // Encode "bytes" with the error correction level "getECLevel". The encoding mode will be chosen
// internally by chooseMode(). On success, store the result in "qrCode" and return true. On // internally by chooseMode(). On success, store the result in "qrCode" and return true.
// error, return false. We recommend you to use QRCode.EC_LEVEL_L (the lowest level) for // 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 // "getECLevel" since our primary use is to show QR code on desktop screens. We don't need very
// strong error correction for this purpose. // strong error correction for this purpose.
// //
// Note that there is no way to encode bytes in MODE_KANJI. We might want to add EncodeWithMode() // 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. // with which clients can specify the encoding mode. For now, we don't need the functionality.
public static void encode(final ByteArray bytes, int ecLevel, QRCode qrCode) throws WriterException { public static void encode(final ByteArray bytes, ErrorCorrectionLevel ecLevel, QRCode qrCode)
throws WriterException {
// Step 1: Choose the mode (encoding). // Step 1: Choose the mode (encoding).
final int mode = chooseMode(bytes); final int mode = chooseMode(bytes);
@ -211,7 +213,7 @@ public final class Encoder {
return QRCode.MODE_8BIT_BYTE; return QRCode.MODE_8BIT_BYTE;
} }
private static int chooseMaskPattern(final BitVector bits, int ecLevel, int version, private static int chooseMaskPattern(final BitVector bits, ErrorCorrectionLevel ecLevel, int version,
ByteMatrix matrix) throws WriterException { ByteMatrix matrix) throws WriterException {
if (!QRCode.isValidMatrixWidth(matrix.width())) { if (!QRCode.isValidMatrixWidth(matrix.width())) {
throw new WriterException("Invalid matrix width: " + matrix.width()); throw new WriterException("Invalid matrix width: " + matrix.width());
@ -231,25 +233,22 @@ public final class Encoder {
return bestMaskPattern; return bestMaskPattern;
} }
// Initialize "qrCode" according to "numInputBytes", "getECLevel", and "mode". On success, modify // Initialize "qrCode" according to "numInputBytes", "ecLevel", and "mode". On success, modify
// "qrCode" and return true. On error, return false. // "qrCode" and return true.
private static void initQRCode(int numInputBytes, int ecLevel, int mode, QRCode qrCode) throws WriterException { private static void initQRCode(int numInputBytes, ErrorCorrectionLevel ecLevel, int mode, QRCode qrCode)
throws WriterException {
qrCode.setECLevel(ecLevel); qrCode.setECLevel(ecLevel);
qrCode.setMode(mode); qrCode.setMode(mode);
if (!QRCode.isValidECLevel(ecLevel)) {
throw new WriterException("Invalid EC level: " + ecLevel);
}
// In the following comments, we use numbers of Version 7-H. // In the following comments, we use numbers of Version 7-H.
for (int i = 0; i < RS_BLOCK_TABLE.length; ++i) { for (int i = 0; i < RS_BLOCK_TABLE.length; ++i) {
final RSBlockInfo row = RS_BLOCK_TABLE[i]; final RSBlockInfo row = RS_BLOCK_TABLE[i];
// numBytes = 196 // numBytes = 196
final int numBytes = row.numBytes; final int numBytes = row.numBytes;
// getNumECBytes = 130 // getNumECBytes = 130
final int numEcBytes = row.blockInfo[ecLevel][0]; final int numEcBytes = row.blockInfo[ecLevel.ordinal()][0];
// getNumRSBlocks = 5 // getNumRSBlocks = 5
final int numRSBlocks = row.blockInfo[ecLevel][1]; final int numRSBlocks = row.blockInfo[ecLevel.ordinal()][1];
// getNumDataBytes = 196 - 130 = 66 // getNumDataBytes = 196 - 130 = 66
final int numDataBytes = numBytes - numEcBytes; final int numDataBytes = numBytes - numEcBytes;
// We want to choose the smallest version which can contain data of "numInputBytes" + some // We want to choose the smallest version which can contain data of "numInputBytes" + some
@ -360,7 +359,7 @@ public final class Encoder {
} }
// Interleave "bits" with corresponding error correction bytes. On success, store the result in // Interleave "bits" with corresponding error correction bytes. On success, store the result in
// "result" and return true. On error, return false. The interleave rule is complicated. See 8.6 // "result" and return true. The interleave rule is complicated. See 8.6
// of JISX0510:2004 (p.37) for details. // of JISX0510:2004 (p.37) for details.
static void interleaveWithECBytes(final BitVector bits, int numTotalBytes, static void interleaveWithECBytes(final BitVector bits, int numTotalBytes,
int numDataBytes, int numRSBlocks, BitVector result) throws WriterException { int numDataBytes, int numRSBlocks, BitVector result) throws WriterException {
@ -466,7 +465,7 @@ public final class Encoder {
} }
// Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits" // Append "bytes" in "mode" mode (encoding) into "bits". On success, store the result in "bits"
// and return true. On error, return false. // and return true.
static void appendBytes(final ByteArray bytes, int mode, BitVector bits) throws WriterException { static void appendBytes(final ByteArray bytes, int mode, BitVector bits) throws WriterException {
switch (mode) { switch (mode) {
case QRCode.MODE_NUMERIC: case QRCode.MODE_NUMERIC:
@ -487,7 +486,7 @@ public final class Encoder {
} }
// Append "bytes" to "bits" using QRCode.MODE_NUMERIC mode. On success, store the result in "bits" // Append "bytes" to "bits" using QRCode.MODE_NUMERIC mode. On success, store the result in "bits"
// and return true. On error, return false. // and return true.
static void appendNumericBytes(final ByteArray bytes, BitVector bits) throws WriterException { static void appendNumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
// Validate all the bytes first. // Validate all the bytes first.
for (int i = 0; i < bytes.size(); ++i) { for (int i = 0; i < bytes.size(); ++i) {
@ -518,7 +517,7 @@ public final class Encoder {
} }
// Append "bytes" to "bits" using QRCode.MODE_ALPHANUMERIC mode. On success, store the result in // Append "bytes" to "bits" using QRCode.MODE_ALPHANUMERIC mode. On success, store the result in
// "bits" and return true. On error, return false. // "bits" and return true.
static void appendAlphanumericBytes(final ByteArray bytes, BitVector bits) throws WriterException { static void appendAlphanumericBytes(final ByteArray bytes, BitVector bits) throws WriterException {
for (int i = 0; i < bytes.size();) { for (int i = 0; i < bytes.size();) {
final int code1 = getAlphanumericCode(bytes.at(i)); final int code1 = getAlphanumericCode(bytes.at(i));
@ -542,7 +541,7 @@ public final class Encoder {
} }
// Append "bytes" to "bits" using QRCode.MODE_8BIT_BYTE mode. On success, store the result in // Append "bytes" to "bits" using QRCode.MODE_8BIT_BYTE mode. On success, store the result in
// "bits" and return true. On error, return false. // "bits" and return true.
static void append8BitBytes(final ByteArray bytes, BitVector bits) { static void append8BitBytes(final ByteArray bytes, BitVector bits) {
for (int i = 0; i < bytes.size(); ++i) { for (int i = 0; i < bytes.size(); ++i) {
bits.appendBits(bytes.at(i), 8); bits.appendBits(bytes.at(i), 8);
@ -550,7 +549,7 @@ public final class Encoder {
} }
// Append "bytes" to "bits" using QRCode.MODE_KANJI mode. On success, store the result in "bits" // Append "bytes" to "bits" using QRCode.MODE_KANJI mode. On success, store the result in "bits"
// and return true. On error, return false. See 8.4.5 of JISX0510:2004 (p.21) for how to encode // and return true. See 8.4.5 of JISX0510:2004 (p.21) for how to encode
// Kanji bytes. // Kanji bytes.
static void appendKanjiBytes(final ByteArray bytes, BitVector bits) throws WriterException { static void appendKanjiBytes(final ByteArray bytes, BitVector bits) throws WriterException {
if (bytes.size() % 2 != 0) { if (bytes.size() % 2 != 0) {

View file

@ -18,6 +18,7 @@ package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.ByteMatrix;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/** /**
* @author satorux@google.com (Satoru Takabayashi) - creator * @author satorux@google.com (Satoru Takabayashi) - creator
@ -133,9 +134,9 @@ public final class MatrixUtil {
matrix.clear((byte) -1); matrix.clear((byte) -1);
} }
// Build 2D matrix of QR Code from "dataBits" with "getECLevel", "version" and "getMaskPattern". On // Build 2D matrix of QR Code from "dataBits" with "ecLevel", "version" and "getMaskPattern". On
// success, store the result in "matrix" and return true. On error, return false. // success, store the result in "matrix" and return true.
public static void buildMatrix(final BitVector dataBits, int ecLevel, int version, public static void buildMatrix(final BitVector dataBits, ErrorCorrectionLevel ecLevel, int version,
int maskPattern, ByteMatrix matrix) throws WriterException { int maskPattern, ByteMatrix matrix) throws WriterException {
MatrixUtil.clearMatrix(matrix); MatrixUtil.clearMatrix(matrix);
embedBasicPatterns(version, matrix); embedBasicPatterns(version, matrix);
@ -147,7 +148,7 @@ public final class MatrixUtil {
embedDataBits(dataBits, maskPattern, matrix); embedDataBits(dataBits, maskPattern, matrix);
} }
// Embed basic patterns. On success, modify the matrix and return true. On error, return false. // Embed basic patterns. On success, modify the matrix and return true.
// The basic patterns are: // The basic patterns are:
// - Position detection patterns // - Position detection patterns
// - Timing patterns // - Timing patterns
@ -166,7 +167,8 @@ public final class MatrixUtil {
} }
// Embed type information. On success, modify the matrix. // Embed type information. On success, modify the matrix.
public static void embedTypeInfo(int ecLevel, int maskPattern, ByteMatrix matrix) throws WriterException { public static void embedTypeInfo(ErrorCorrectionLevel ecLevel, int maskPattern, ByteMatrix matrix)
throws WriterException {
BitVector typeInfoBits = new BitVector(); BitVector typeInfoBits = new BitVector();
makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits); makeTypeInfoBits(ecLevel, maskPattern, typeInfoBits);
@ -194,9 +196,8 @@ public final class MatrixUtil {
} }
} }
// Embed version information if need be. On success, modify the matrix and return true. On error, // Embed version information if need be. On success, modify the matrix and return true.
// return false. See 8.10 of JISX0510:2004 (p.47) for how to embed version information. Return // See 8.10 of JISX0510:2004 (p.47) for how to embed version information.
// true on success, otherwise return false.
public static void maybeEmbedVersionInfo(int version, ByteMatrix matrix) throws WriterException { public static void maybeEmbedVersionInfo(int version, ByteMatrix matrix) throws WriterException {
if (version < 7) { // Version info is necessary if version >= 7. if (version < 7) { // Version info is necessary if version >= 7.
return; // Don't need version info. return; // Don't need version info.
@ -218,8 +219,8 @@ public final class MatrixUtil {
} }
} }
// Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true. On // Embed "dataBits" using "getMaskPattern". On success, modify the matrix and return true.
// error, return false. For debugging purposes, it skips masking process if "getMaskPattern" is -1. // 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. // 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(final BitVector dataBits, int maskPattern, ByteMatrix matrix)
throws WriterException { throws WriterException {
@ -322,14 +323,14 @@ public final class MatrixUtil {
} }
// Make bit vector of type information. On success, store the result in "bits" and return true. // Make bit vector of type information. On success, store the result in "bits" and return true.
// On error, return false. Encode error correction level and mask pattern. See 8.9 of // Encode error correction level and mask pattern. See 8.9 of
// JISX0510:2004 (p.45) for details. // JISX0510:2004 (p.45) for details.
public static void makeTypeInfoBits(int ecLevel, final int maskPattern, BitVector bits) throws WriterException { public static void makeTypeInfoBits(ErrorCorrectionLevel ecLevel, final int maskPattern, BitVector bits)
final int ecCode = QRCode.getECLevelCode(ecLevel); throws WriterException {
if (!QRCode.isValidMaskPattern(maskPattern)) { if (!QRCode.isValidMaskPattern(maskPattern)) {
throw new WriterException("Invalid mask pattern"); throw new WriterException("Invalid mask pattern");
} }
final int typeInfo = (ecCode << 3) | maskPattern; final int typeInfo = (ecLevel.getBits() << 3) | maskPattern;
bits.appendBits(typeInfo, 5); bits.appendBits(typeInfo, 5);
final int bchCode = MatrixUtil.calculateBCHCode(typeInfo, TYPE_INFO_POLY); final int bchCode = MatrixUtil.calculateBCHCode(typeInfo, TYPE_INFO_POLY);
@ -345,7 +346,7 @@ public final class MatrixUtil {
} }
// Make bit vector of version information. On success, store the result in "bits" and return true. // Make bit vector of version information. On success, store the result in "bits" and return true.
// On error, return false. See 8.10 of JISX0510:2004 (p.45) for details. // See 8.10 of JISX0510:2004 (p.45) for details.
public static void makeVersionInfoBits(int version, BitVector bits) throws WriterException { public static void makeVersionInfoBits(int version, BitVector bits) throws WriterException {
bits.appendBits(version, 6); bits.appendBits(version, 6);
final int bchCode = MatrixUtil.calculateBCHCode(version, VERSION_INFO_POLY); final int bchCode = MatrixUtil.calculateBCHCode(version, VERSION_INFO_POLY);
@ -494,7 +495,8 @@ public final class MatrixUtil {
} }
// Embed position adjustment patterns if need be. // Embed position adjustment patterns if need be.
private static void maybeEmbedPositionAdjustmentPatterns(final int version, ByteMatrix matrix) throws WriterException { private static void maybeEmbedPositionAdjustmentPatterns(final int version, ByteMatrix matrix)
throws WriterException {
if (version < 2) { // The patterns appear if version >= 2 if (version < 2) { // The patterns appear if version >= 2
return; return;
} }

View file

@ -18,6 +18,7 @@ package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.ByteMatrix;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
/** /**
* @author satorux@google.com (Satoru Takabayashi) - creator * @author satorux@google.com (Satoru Takabayashi) - creator
@ -42,7 +43,7 @@ public final class QRCode {
}; };
private int mode; private int mode;
private int ecLevel; private ErrorCorrectionLevel ecLevel;
private int version; private int version;
private int matrixWidth; private int matrixWidth;
private int maskPattern; private int maskPattern;
@ -75,22 +76,9 @@ public final class QRCode {
// MODE_FNC1, // MODE_FNC1,
public static final int NUM_MODES = 4; public static final int NUM_MODES = 4;
// The error correction levels are defined in the table 22 of JISX0510:2004 (p.45). It's very
// unlikely (we've already covered all of them!) but if you add an item to this, please also add
// it to ecLevelToString() and getECLevelCode().
//
// Formerly enum ECLevel
public static final int EC_LEVEL_UNDEFINED = -1;
// They don't have names in the standard!
public static final int EC_LEVEL_L = 0; // 7% of corruption can be recovered.
public static final int EC_LEVEL_M = 1; // 15%
public static final int EC_LEVEL_Q = 2; // 25%
public static final int EC_LEVEL_H = 3; // 30%
public static final int NUM_EC_LEVELS = 4;
public QRCode() { public QRCode() {
mode = MODE_UNDEFINED; mode = MODE_UNDEFINED;
ecLevel = EC_LEVEL_UNDEFINED; ecLevel = null;
version = -1; version = -1;
matrixWidth = -1; matrixWidth = -1;
maskPattern = -1; maskPattern = -1;
@ -102,25 +90,55 @@ public final class QRCode {
} }
// Mode of the QR Code. // Mode of the QR Code.
public int getMode() { return mode; } public int getMode() {
return mode;
}
// Error correction level of the QR Code. // Error correction level of the QR Code.
public int getECLevel() { return ecLevel; } public ErrorCorrectionLevel getECLevel() {
return ecLevel;
}
// Version of the QR Code. The bigger size, the bigger version. // Version of the QR Code. The bigger size, the bigger version.
public int getVersion() { return version; } public int getVersion() {
return version;
}
// ByteMatrix width of the QR Code. // ByteMatrix width of the QR Code.
public int getMatrixWidth() { return matrixWidth; } public int getMatrixWidth() {
return matrixWidth;
}
// Mask pattern of the QR Code. // Mask pattern of the QR Code.
public int getMaskPattern() { return maskPattern; } public int getMaskPattern() {
return maskPattern;
}
// Number of total bytes in the QR Code. // Number of total bytes in the QR Code.
public int getNumTotalBytes() { return numTotalBytes; } public int getNumTotalBytes() {
return numTotalBytes;
}
// Number of data bytes in the QR Code. // Number of data bytes in the QR Code.
public int getNumDataBytes() { return numDataBytes; } public int getNumDataBytes() {
return numDataBytes;
}
// Number of error correction bytes in the QR Code. // Number of error correction bytes in the QR Code.
public int getNumECBytes() { return numECBytes; } public int getNumECBytes() {
return numECBytes;
}
// Number of Reedsolomon blocks in the QR Code. // Number of Reedsolomon blocks in the QR Code.
public int getNumRSBlocks() { return numRSBlocks; } public int getNumRSBlocks() {
return numRSBlocks;
}
// ByteMatrix data of the QR Code. // ByteMatrix data of the QR Code.
public final ByteMatrix getMatrix() { return matrix; } public final ByteMatrix getMatrix() {
return matrix;
}
// Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They // 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. // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell.
@ -140,7 +158,7 @@ public final class QRCode {
return ( return (
// First check if all version are not uninitialized. // First check if all version are not uninitialized.
mode != MODE_UNDEFINED && mode != MODE_UNDEFINED &&
ecLevel != EC_LEVEL_UNDEFINED && ecLevel != null &&
version != -1 && version != -1 &&
matrixWidth != -1 && matrixWidth != -1 &&
maskPattern != -1 && maskPattern != -1 &&
@ -151,7 +169,6 @@ public final class QRCode {
// Then check them in other ways.. // Then check them in other ways..
isValidVersion(version) && isValidVersion(version) &&
isValidMode(mode) && isValidMode(mode) &&
isValidECLevel(ecLevel) &&
isValidMatrixWidth(matrixWidth) && isValidMatrixWidth(matrixWidth) &&
isValidMaskPattern(maskPattern) && isValidMaskPattern(maskPattern) &&
numTotalBytes == numDataBytes + numECBytes && numTotalBytes == numDataBytes + numECBytes &&
@ -170,7 +187,7 @@ public final class QRCode {
result.append(" mode: "); result.append(" mode: ");
result.append(modeToString(mode)); result.append(modeToString(mode));
result.append("\n ecLevel: "); result.append("\n ecLevel: ");
result.append(ecLevelToString(ecLevel)); result.append(ecLevel);
result.append("\n version: "); result.append("\n version: ");
result.append(version); result.append(version);
result.append("\n matrixWidth: "); result.append("\n matrixWidth: ");
@ -199,7 +216,7 @@ public final class QRCode {
mode = value; mode = value;
} }
public void setECLevel(int value) { public void setECLevel(ErrorCorrectionLevel value) {
ecLevel = value; ecLevel = value;
} }
@ -241,11 +258,6 @@ public final class QRCode {
return version >= MIN_VERSION && version <= MAX_VERSION; return version >= MIN_VERSION && version <= MAX_VERSION;
} }
// Check if "ecLevel" is valid.
public static boolean isValidECLevel(int ecLevel) {
return ecLevel >= 0 && ecLevel < NUM_EC_LEVELS;
}
// Check if "mode" is valid. // Check if "mode" is valid.
public static boolean isValidMode(final int mode) { public static boolean isValidMode(final int mode) {
return mode >= 0 && mode < NUM_MODES; return mode >= 0 && mode < NUM_MODES;
@ -261,25 +273,6 @@ public final class QRCode {
return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS; return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;
} }
// Convert "getECLevel" to String for debugging.
public static String ecLevelToString(int ecLevel) {
switch (ecLevel) {
case QRCode.EC_LEVEL_UNDEFINED:
return "UNDEFINED";
case QRCode.EC_LEVEL_L:
return "L";
case QRCode.EC_LEVEL_M:
return "M";
case QRCode.EC_LEVEL_Q:
return "Q";
case QRCode.EC_LEVEL_H:
return "H";
default:
break;
}
return "UNKNOWN";
}
// Convert "mode" to String for debugging. // Convert "mode" to String for debugging.
public static String modeToString(int mode) { public static String modeToString(int mode) {
switch (mode) { switch (mode) {
@ -299,23 +292,6 @@ public final class QRCode {
return "UNKNOWN"; return "UNKNOWN";
} }
// Return the code of error correction level. On error, return -1. The codes of error correction
// levels are defined in the table 22 of JISX0510:2004 (p.45).
public static int getECLevelCode(final int ecLevel) throws WriterException {
switch (ecLevel) {
case QRCode.EC_LEVEL_L:
return 1;
case QRCode.EC_LEVEL_M:
return 0;
case QRCode.EC_LEVEL_Q:
return 3;
case QRCode.EC_LEVEL_H:
return 2;
default:
throw new WriterException("Unknown EC level");
}
}
// Return the code of mode. On error, return -1. The codes of modes are defined in the table 2 of // Return the code of mode. On error, return -1. The codes of modes are defined in the table 2 of
// JISX0510:2004 (p.16). // JISX0510:2004 (p.16).
public static int getModeCode(final int mode) throws WriterException { public static int getModeCode(final int mode) throws WriterException {
@ -352,7 +328,7 @@ public final class QRCode {
throw new IllegalArgumentException("Bad version: " + version); throw new IllegalArgumentException("Bad version: " + version);
} }
// Return true if the all values in the matrix are binary numbers. Otherwise, return false. // 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 // 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 // production. I'm leaving it because it may be useful for testing. It should be removed entirely

View file

@ -20,7 +20,7 @@ import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType; import com.google.zxing.EncodeHintType;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.ByteMatrix;
import com.google.zxing.qrcode.encoder.QRCode; import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase; import junit.framework.TestCase;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
@ -96,7 +96,7 @@ public final class QRCodeWriterTestCase extends TestCase {
assertEquals(strangeHeight, matrix.height()); assertEquals(strangeHeight, matrix.height());
} }
private static boolean compareToGoldenFile(final String contents, final int ecLevel, private static boolean compareToGoldenFile(final String contents, final ErrorCorrectionLevel ecLevel,
final int resolution, final String fileName) throws WriterException { final int resolution, final String fileName) throws WriterException {
BufferedImage image = loadImage(fileName); BufferedImage image = loadImage(fileName);
@ -106,7 +106,7 @@ public final class QRCodeWriterTestCase extends TestCase {
QRCodeWriter writer = new QRCodeWriter(); QRCodeWriter writer = new QRCodeWriter();
Hashtable hints = new Hashtable(); Hashtable hints = new Hashtable();
hints.put(EncodeHintType.ERROR_CORRECTION, new Integer(ecLevel)); hints.put(EncodeHintType.ERROR_CORRECTION, ecLevel);
ByteMatrix generatedResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution, ByteMatrix generatedResult = writer.encode(contents, BarcodeFormat.QR_CODE, resolution,
resolution, hints); resolution, hints);
@ -123,16 +123,16 @@ public final class QRCodeWriterTestCase extends TestCase {
// and cell phones. We expect pixel-perfect results, because the error correction level is known, // and cell phones. We expect pixel-perfect results, because the error correction level is known,
// and the pixel dimensions matches exactly. // and the pixel dimensions matches exactly.
public void testRegressionTest() throws WriterException { public void testRegressionTest() throws WriterException {
assertTrue(compareToGoldenFile("http://www.google.com/", QRCode.EC_LEVEL_M, 99, assertTrue(compareToGoldenFile("http://www.google.com/", ErrorCorrectionLevel.M, 99,
"renderer-test-01.png")); "renderer-test-01.png"));
assertTrue(compareToGoldenFile("12345", QRCode.EC_LEVEL_L, 58, "renderer-test-02.png")); assertTrue(compareToGoldenFile("12345", ErrorCorrectionLevel.L, 58, "renderer-test-02.png"));
// Test in Katakana in Shift_JIS. // Test in Katakana in Shift_JIS.
final byte[] KATAKANA_INPUT = { final byte[] KATAKANA_INPUT = {
(byte)0x83, 0x65, (byte)0x83, 0x58, (byte)0x83, 0x67 (byte)0x83, 0x65, (byte)0x83, 0x58, (byte)0x83, 0x67
}; };
assertTrue(compareToGoldenFile(new String(KATAKANA_INPUT), QRCode.EC_LEVEL_H, 145, assertTrue(compareToGoldenFile(new String(KATAKANA_INPUT), ErrorCorrectionLevel.H, 145,
"renderer-test-03.png")); "renderer-test-03.png"));
} }

View file

@ -16,7 +16,6 @@
package com.google.zxing.qrcode.decoder; package com.google.zxing.qrcode.decoder;
import com.google.zxing.ReaderException;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -24,7 +23,7 @@ import junit.framework.TestCase;
*/ */
public final class ErrorCorrectionLevelTestCase extends TestCase { public final class ErrorCorrectionLevelTestCase extends TestCase {
public void testForBits() throws ReaderException { public void testForBits() {
assertEquals(ErrorCorrectionLevel.M, ErrorCorrectionLevel.forBits(0)); assertEquals(ErrorCorrectionLevel.M, ErrorCorrectionLevel.forBits(0));
assertEquals(ErrorCorrectionLevel.L, ErrorCorrectionLevel.forBits(1)); assertEquals(ErrorCorrectionLevel.L, ErrorCorrectionLevel.forBits(1));
assertEquals(ErrorCorrectionLevel.H, ErrorCorrectionLevel.forBits(2)); assertEquals(ErrorCorrectionLevel.H, ErrorCorrectionLevel.forBits(2));
@ -32,7 +31,7 @@ public final class ErrorCorrectionLevelTestCase extends TestCase {
try { try {
ErrorCorrectionLevel.forBits(4); ErrorCorrectionLevel.forBits(4);
fail("Should have thrown an exception"); fail("Should have thrown an exception");
} catch (ReaderException re) { } catch (IllegalArgumentException iae) {
// good // good
} }
} }

View file

@ -18,6 +18,7 @@ package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteArray; import com.google.zxing.common.ByteArray;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -85,7 +86,7 @@ public final class EncoderTestCase extends TestCase {
public void testEncode() throws WriterException { public void testEncode() throws WriterException {
QRCode qrCode = new QRCode(); QRCode qrCode = new QRCode();
Encoder.encode(new ByteArray("ABCDEF"), QRCode.EC_LEVEL_H, qrCode); Encoder.encode(new ByteArray("ABCDEF"), ErrorCorrectionLevel.H, qrCode);
// The following is a valid QR Code that can be read by cell phones. // The following is a valid QR Code that can be read by cell phones.
String expected = String expected =
"<<\n" + "<<\n" +
@ -643,6 +644,6 @@ public final class EncoderTestCase extends TestCase {
dataBytes[x] = '0'; dataBytes[x] = '0';
} }
QRCode qrCode = new QRCode(); QRCode qrCode = new QRCode();
Encoder.encode(new ByteArray(dataBytes), QRCode.EC_LEVEL_L, qrCode); Encoder.encode(new ByteArray(dataBytes), ErrorCorrectionLevel.L, qrCode);
} }
} }

View file

@ -18,6 +18,7 @@ package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.ByteMatrix;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -141,7 +142,7 @@ public final class MatrixUtilTestCase extends TestCase {
" 1 \n"; " 1 \n";
ByteMatrix matrix = new ByteMatrix(21, 21); ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.clearMatrix(matrix); MatrixUtil.clearMatrix(matrix);
MatrixUtil.embedTypeInfo(QRCode.EC_LEVEL_M, 5, matrix); MatrixUtil.embedTypeInfo(ErrorCorrectionLevel.M, 5, matrix);
assertEquals(expected, matrix.toString()); assertEquals(expected, matrix.toString());
} }
@ -242,7 +243,7 @@ public final class MatrixUtilTestCase extends TestCase {
} }
ByteMatrix matrix = new ByteMatrix(21, 21); ByteMatrix matrix = new ByteMatrix(21, 21);
MatrixUtil.buildMatrix(bits, MatrixUtil.buildMatrix(bits,
QRCode.EC_LEVEL_H, ErrorCorrectionLevel.H,
1, // Version 1 1, // Version 1
3, // Mask pattern 3 3, // Mask pattern 3
matrix); matrix);
@ -289,7 +290,7 @@ public final class MatrixUtilTestCase extends TestCase {
public void testMakeTypeInfoInfoBits() throws WriterException { public void testMakeTypeInfoInfoBits() throws WriterException {
// From Appendix C in JISX0510:2004 (p 65) // From Appendix C in JISX0510:2004 (p 65)
BitVector bits = new BitVector(); BitVector bits = new BitVector();
MatrixUtil.makeTypeInfoBits(QRCode.EC_LEVEL_M, MatrixUtil.makeTypeInfoBits(ErrorCorrectionLevel.M,
5, bits); 5, bits);
assertEquals("100000011001110", bits.toString()); assertEquals("100000011001110", bits.toString());
} }

View file

@ -18,6 +18,7 @@ package com.google.zxing.qrcode.encoder;
import com.google.zxing.common.ByteMatrix; import com.google.zxing.common.ByteMatrix;
import com.google.zxing.WriterException; import com.google.zxing.WriterException;
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel;
import junit.framework.TestCase; import junit.framework.TestCase;
/** /**
@ -33,7 +34,7 @@ public final class QRCodeTestCase extends TestCase {
// First, test simple setters and getters. // First, test simple setters and getters.
// We use numbers of version 7-H. // We use numbers of version 7-H.
qrCode.setMode(QRCode.MODE_8BIT_BYTE); qrCode.setMode(QRCode.MODE_8BIT_BYTE);
qrCode.setECLevel(QRCode.EC_LEVEL_H); qrCode.setECLevel(ErrorCorrectionLevel.H);
qrCode.setVersion(7); qrCode.setVersion(7);
qrCode.setMatrixWidth(45); qrCode.setMatrixWidth(45);
qrCode.setMaskPattern(3); qrCode.setMaskPattern(3);
@ -43,7 +44,7 @@ public final class QRCodeTestCase extends TestCase {
qrCode.setNumRSBlocks(5); qrCode.setNumRSBlocks(5);
assertEquals(QRCode.MODE_8BIT_BYTE, qrCode.getMode()); assertEquals(QRCode.MODE_8BIT_BYTE, qrCode.getMode());
assertEquals(QRCode.EC_LEVEL_H, qrCode.getECLevel()); assertEquals(ErrorCorrectionLevel.H, qrCode.getECLevel());
assertEquals(7, qrCode.getVersion()); assertEquals(7, qrCode.getVersion());
assertEquals(45, qrCode.getMatrixWidth()); assertEquals(45, qrCode.getMatrixWidth());
assertEquals(3, qrCode.getMaskPattern()); assertEquals(3, qrCode.getMaskPattern());
@ -85,7 +86,7 @@ public final class QRCodeTestCase extends TestCase {
String expected = String expected =
"<<\n" + "<<\n" +
" mode: UNDEFINED\n" + " mode: UNDEFINED\n" +
" ecLevel: UNDEFINED\n" + " ecLevel: null\n" +
" version: -1\n" + " version: -1\n" +
" matrixWidth: -1\n" + " matrixWidth: -1\n" +
" maskPattern: -1\n" + " maskPattern: -1\n" +
@ -134,7 +135,7 @@ public final class QRCodeTestCase extends TestCase {
">>\n"; ">>\n";
QRCode qrCode = new QRCode(); QRCode qrCode = new QRCode();
qrCode.setMode(QRCode.MODE_8BIT_BYTE); qrCode.setMode(QRCode.MODE_8BIT_BYTE);
qrCode.setECLevel(QRCode.EC_LEVEL_H); qrCode.setECLevel(ErrorCorrectionLevel.H);
qrCode.setVersion(1); qrCode.setVersion(1);
qrCode.setMatrixWidth(21); qrCode.setMatrixWidth(21);
qrCode.setMaskPattern(3); qrCode.setMaskPattern(3);
@ -161,15 +162,6 @@ public final class QRCodeTestCase extends TestCase {
assertFalse(QRCode.isValidVersion(0)); assertFalse(QRCode.isValidVersion(0));
} }
public void testIsValidECLevel() {
assertFalse(QRCode.isValidECLevel(QRCode.EC_LEVEL_UNDEFINED));
assertTrue(QRCode.isValidECLevel(QRCode.EC_LEVEL_L));
assertTrue(QRCode.isValidECLevel(QRCode.EC_LEVEL_Q));
assertTrue(QRCode.isValidECLevel(QRCode.EC_LEVEL_M));
assertTrue(QRCode.isValidECLevel(QRCode.EC_LEVEL_H));
assertFalse(QRCode.isValidECLevel(QRCode.NUM_EC_LEVELS));
}
public void testIsValidMode() { public void testIsValidMode() {
assertFalse(QRCode.isValidMode(QRCode.MODE_UNDEFINED)); assertFalse(QRCode.isValidMode(QRCode.MODE_UNDEFINED));
assertTrue(QRCode.isValidMode(QRCode.MODE_NUMERIC)); assertTrue(QRCode.isValidMode(QRCode.MODE_NUMERIC));
@ -200,15 +192,6 @@ public final class QRCodeTestCase extends TestCase {
assertEquals("UNKNOWN", QRCode.modeToString(QRCode.NUM_MODES)); assertEquals("UNKNOWN", QRCode.modeToString(QRCode.NUM_MODES));
} }
public void testECLevelToString() {
assertEquals("UNDEFINED", QRCode.ecLevelToString(QRCode.EC_LEVEL_UNDEFINED));
assertEquals("L", QRCode.ecLevelToString(QRCode.EC_LEVEL_L));
assertEquals("M", QRCode.ecLevelToString(QRCode.EC_LEVEL_M));
assertEquals("Q", QRCode.ecLevelToString(QRCode.EC_LEVEL_Q));
assertEquals("H", QRCode.ecLevelToString(QRCode.EC_LEVEL_H));
assertEquals("UNKNOWN", QRCode.ecLevelToString(QRCode.NUM_EC_LEVELS));
}
public void testGetModeCode() throws WriterException { public void testGetModeCode() throws WriterException {
assertEquals(1, QRCode.getModeCode(QRCode.MODE_NUMERIC)); assertEquals(1, QRCode.getModeCode(QRCode.MODE_NUMERIC));
assertEquals(2, QRCode.getModeCode(QRCode.MODE_ALPHANUMERIC)); assertEquals(2, QRCode.getModeCode(QRCode.MODE_ALPHANUMERIC));
@ -222,16 +205,4 @@ public final class QRCodeTestCase extends TestCase {
} }
} }
public void testGetECLevelCode() throws WriterException {
assertEquals(1, QRCode.getECLevelCode(QRCode.EC_LEVEL_L));
assertEquals(0, QRCode.getECLevelCode(QRCode.EC_LEVEL_M));
assertEquals(3, QRCode.getECLevelCode(QRCode.EC_LEVEL_Q));
assertEquals(2, QRCode.getECLevelCode(QRCode.EC_LEVEL_H));
try {
QRCode.getECLevelCode(QRCode.EC_LEVEL_UNDEFINED);
fail("Should have thrown exception");
} catch (WriterException we) {
// good
}
}
} }