Created the base Writer object for all barcode encoding, then wrote a QR Code version...
[zxing.git] / core / src / com / google / zxing / qrcode / encoder / QRCode.java
index 48aca02..80d8266 100644 (file)
 
 package com.google.zxing.qrcode.encoder;
 
-// JAVAPORT: QRCodeMatrix needs to be renamed Matrix and built as a new class.
-//
-// template <typename T> class Array2D;
-// typedef Array2D<int> QRCodeMatrix;
-// #include "util/array/array2d-inl.h"
+import com.google.zxing.common.ByteMatrix;
 
 /**
  * @author satorux@google.com (Satoru Takabayashi) - creator
@@ -46,8 +42,8 @@ public final class QRCode {
 
   // JAVAPORT: Do not remove trailing slashes yet. There are very likely conflicts with local
   // variables and parameters which will introduce insidious bugs.
-  private Mode mode_;
-  private ECLevel ec_level_;
+  private int mode_;
+  private int ec_level_;
   private int version_;
   private int matrix_width_;
   private int mask_pattern_;
@@ -55,42 +51,43 @@ public final class QRCode {
   private int num_data_bytes_;
   private int num_ec_bytes_;
   private int num_rs_blocks_;
-  private QRCodeMatrix *matrix_;
+  private ByteMatrix matrix_;
 
 
-  // They call encoding "mode".  The modes are defined in 8.3 of
-  // JISX0510:2004 (p.14).  It's unlikely (probably we will not
-  // support complicated modes) but if you add an item to this, please
-  // also add it to ModeToString(), GetModeCode(),
-  // GetNumBitsForLength(), Encoder.AppendBytes(),
+  // They call encoding "mode". The modes are defined in 8.3 of JISX0510:2004 (p.14). It's unlikely
+  // (probably we will not support complicated modes) but if you add an item to this, please also
+  // add it to ModeToString(), GetModeCode(), GetNumBitsForLength(), Encoder.AppendBytes(), and
   // Encoder.ChooseMode().
-  public enum Mode {
-    MODE_UNDEFINED = -1,
-    MODE_NUMERIC,
-    MODE_ALPHANUMERIC,
-    MODE_8BIT_BYTE,
-    MODE_KANJI,  // Shift_JIS
-    // The following modes are unimplemented.
-    // MODE_ECI,
-    // MODE_MIXED,
-    // MODE_CONCATENATED,
-    // MODE_FNC1,
-    NUM_MODES,  // Always keep this at the end.
-  };
+  //
+  // JAVAPORT: These used to be C++ enums, but the code evaluates them as integers, and requires
+  // negative values. I don't want to take the ParsedResultType approach of a class full of statics
+  // of that class's type. The best compromise here is integer constants.
+  //
+  // Formerly enum Mode
+  public static final int MODE_UNDEFINED = -1;
+  public static final int MODE_NUMERIC = 0;
+  public static final int MODE_ALPHANUMERIC = 1;
+  public static final int MODE_8BIT_BYTE = 2;
+  public static final int MODE_KANJI = 3;  // Shift_JIS
+  // The following modes are unimplemented.
+  // MODE_ECI,
+  // MODE_MIXED,
+  // MODE_CONCATENATED,
+  // MODE_FNC1,
+  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().
-  public enum ECLevel {
-    EC_LEVEL_UNDEFINED  = -1,
-    // They don't have names in the standard!
-    EC_LEVEL_L,  //  7% of corruption can be recovered.
-    EC_LEVEL_M,  // 15%
-    EC_LEVEL_Q,  // 25%
-    EC_LEVEL_H,  // 30%
-    NUM_EC_LEVELS,  // Always keep this at the end.
-  };
+  // 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() {
     mode_ = MODE_UNDEFINED;
@@ -106,12 +103,12 @@ public final class QRCode {
   }
 
   // Mode of the QR Code.
-  public Mode mode() { return mode_; }
+  public int mode() { return mode_; }
   // Error correction level of the QR Code.
-  public ECLevel ec_level() { return ec_level_; }
+  public int ec_level() { return ec_level_; }
   // Version of the QR Code.  The bigger size, the bigger version.
   public int version() { return version_; }
-  // Matrix width of the QR Code.
+  // ByteMatrix width of the QR Code.
   public int matrix_width() { return matrix_width_; }
   // Mask pattern of the QR Code.
   public int mask_pattern() { return mask_pattern_; }
@@ -123,31 +120,21 @@ public final class QRCode {
   public int num_ec_bytes() { return num_ec_bytes_; }
   // Number of Reedsolomon blocks in the QR Code.
   public int num_rs_blocks() { return num_rs_blocks_; }
-  // Matrix data of the QR Code.
-  public final QRCodeMatrix* matrix() { return matrix_; }
+  // ByteMatrix data of the QR Code.
+  public final ByteMatrix matrix() { return matrix_; }
 
-  // Return the value of the module (cell) pointed by "x" and "y" in
-  // the matrix of the QR Code.  They call cells in the matrix
-  // "modules".  1 represents a black cell, and 0 represents a white
-  // cell.
-  //
-  // Note that the class internally used Array2D.  You should access
-  // cells in row-major order for cache efficiency.  Example:
-  //
-  //   for (int y = 0; y < qrcode.matrix_width(); ++y) {
-  //     for (int x = 0; x < qrcode.matrix_width(); ++x) {
-  //       DoSomething(qrcode.at(x, y));
-  //     }
-  //   }
-  //
+  // Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They
+  // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell.
   public int at(int x, int y) {
     // The value must be zero or one.
-    Debug.DCHECK((*matrix_)(y, x) == 0 || (*matrix_)(y, x) == 1);
-    return (*matrix_)(y, x);
+    int value = matrix_.get(y, x);
+    Debug.DCHECK(value == 0 || value == 1);
+    return value;
   }
 
-  // Checks all the member variables are set properly.  Returns true
-  // on success.  Otherwise, returns false.
+  // Checks all the member variables are set properly. Returns true on success. Otherwise, returns
+  // false.
+  // JAVAPORT: Do not call EverythingIsBinary(matrix_) here as it is very expensive.
   public boolean IsValid() {
     return (
         // First check if all version are not uninitialized.
@@ -167,115 +154,154 @@ public final class QRCode {
             IsValidMatrixWidth(matrix_width_) &&
             IsValidMaskPattern(mask_pattern_) &&
             num_total_bytes_ == num_data_bytes_ + num_ec_bytes_ &&
-            // Matrix stuff.
+            // ByteMatrix stuff.
             matrix_ != null &&
             matrix_width_ == matrix_.width() &&
             // See 7.3.1 of JISX0510:2004 (p.5).
             matrix_width_ == kMinMatrixWidth + (version_ - 1) * 4 &&
-            matrix_.width() == matrix_.height() &&  // Must be square.
-            EverythingIsBinary(*matrix_));
+            matrix_.width() == matrix_.height()); // Must be square.
   }
 
   // Return debug String.
-  public String DebugString() {
-    String result;
-    StringAppendF(&result, "<<QRCode\n");
-    StringAppendF(&result, " mode: %s\n", ModeToString(mode_));
-    StringAppendF(&result, " ec_level: %s\n", ECLevelToString(ec_level_));
-    StringAppendF(&result, " version: %d\n", version_);
-    StringAppendF(&result, " matrix_width: %d\n", matrix_width_);
-    StringAppendF(&result, " mask_pattern: %d\n", mask_pattern_);
-    StringAppendF(&result, " num_total_bytes_: %d\n", num_total_bytes_);
-    StringAppendF(&result, " num_data_bytes: %d\n", num_data_bytes_);
-    StringAppendF(&result, " num_ec_bytes: %d\n", num_ec_bytes_);
-    StringAppendF(&result, " num_rs_blocks: %d\n", num_rs_blocks_);
+  public String toString() {
+    StringBuffer result = new StringBuffer();
+    result.append("<<QRCode\n");
+    result.append(" mode: ");
+    result.append(ModeToString(mode_));
+    result.append("\n ec_level: ");
+    result.append(ECLevelToString(ec_level_));
+    result.append("\n version: ");
+    result.append(version_);
+    result.append("\n matrix_width: ");
+    result.append(matrix_width_);
+    result.append("\n mask_pattern: ");
+    result.append(mask_pattern_);
+    result.append("\n num_total_bytes_: ");
+    result.append(num_total_bytes_);
+    result.append("\n num_data_bytes: ");
+    result.append(num_data_bytes_);
+    result.append("\n num_ec_bytes: ");
+    result.append(num_ec_bytes_);
+    result.append("\n num_rs_blocks: ");
+    result.append(num_rs_blocks_);
     if (matrix_ == null) {
-      StringAppendF(&result, " matrix: null\n");
+      result.append("\n matrix: null");
     } else {
-      StringAppendF(&result, " matrix:\n%s",
-          MatrixUtil.ToASCII(*matrix_).c_str());
+      result.append("\n matrix:");
+      result.append(matrix_.toString());
     }
-    StringAppendF(&result, ">>\n");
-    return result;
+    result.append("\n>>\n");
+    return result.toString();
+  }
+
+  public void set_mode(int value) {
+    mode_ = value;
+  }
+
+  public void set_ec_level(int value) {
+    ec_level_ = value;
+  }
+
+  public void set_version(int value) {
+    version_ = value;
+  }
+
+  public void set_matrix_width(int value) {
+    matrix_width_ = value;
+  }
+
+  public void set_mask_pattern(int value) {
+    mask_pattern_ = value;
+  }
+
+  public void set_num_total_bytes(int value) {
+    num_total_bytes_ = value;
+  }
+
+  public void set_num_data_bytes(int value) {
+    num_data_bytes_ = value;
+  }
+
+  public void set_num_ec_bytes(int value) {
+    num_ec_bytes_ = value;
+  }
+
+  public void set_num_rs_blocks(int value) {
+    num_rs_blocks_ = value;
   }
 
-  public void set_mode(Mode value) { mode_ = value; }
-  public void set_ec_level(ECLevel value) { ec_level_ = value; }
-  public void set_version(int value) { version_ = value; }
-  public void set_matrix_width(int value) { matrix_width_ = value; }
-  public void set_mask_pattern(int value) { mask_pattern_ = value; }
-  public void set_num_total_bytes(int value) { num_total_bytes_ = value; }
-  public void set_num_data_bytes(int value) { num_data_bytes_ = value; }
-  public void set_num_ec_bytes(int value) { num_ec_bytes_ = value; }
-  public void set_num_rs_blocks(int value) { num_rs_blocks_ = value; }
   // This takes ownership of the 2D array.  The 2D array will be
   // deleted in the destructor of the class.
-  public void set_matrix(QRCodeMatrix *value) { matrix_ = value; }
-
+  public void set_matrix(ByteMatrix value) {
+    matrix_ = value;
+  }
 
   // Check if "version" is valid.
   public static boolean IsValidVersion(final int version) {
     return version >= kMinVersion && version <= kMaxVersion;
   }
+
   // Check if "mask_pattern" is valid.
-  public static boolean IsValidECLevel(ECLevel ec_level) {
+  public static boolean IsValidECLevel(int ec_level) {
     return ec_level >= 0 && ec_level < NUM_EC_LEVELS;
   }
+
   // Check if "mode" is valid.
-  public static boolean IsValidMode(final QRCode.Mode mode) {
+  public static boolean IsValidMode(final int mode) {
     return mode >= 0 && mode < NUM_MODES;
   }
+
   // Check if "width" is valid.
   public static boolean IsValidMatrixWidth(int width) {
     return width >= kMinMatrixWidth && width <= kMaxMatrixWidth;
   }
+
   // Check if "mask_pattern" is valid.
   public static boolean IsValidMaskPattern(int mask_pattern) {
     return mask_pattern >= 0 && mask_pattern < kNumMaskPatterns;
   }
 
   // Convert "ec_level" to String for debugging.
-  public static final char *ECLevelToString(QRCode.ECLevel ec_level) {
-  switch (ec_level) {
-    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;
+  public static final String ECLevelToString(int ec_level) {
+    switch (ec_level) {
+      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";
   }
-  return "UNKNOWN";
-}
 
   // Convert "mode" to String for debugging.
-  public static final char *ModeToString(QRCode.Mode mode) {
-  switch (mode) {
-    case QRCode.MODE_UNDEFINED:
-      return "UNDEFINED";
-    case QRCode.MODE_NUMERIC:
-      return "NUMERIC";
-    case QRCode.MODE_ALPHANUMERIC:
-      return "ALPHANUMERIC";
-    case QRCode.MODE_8BIT_BYTE:
-      return "8BIT_BYTE";
-    case QRCode.MODE_KANJI:
-      return "KANJI";
-    default:
-      break;
+  public static final String ModeToString(int mode) {
+    switch (mode) {
+      case QRCode.MODE_UNDEFINED:
+        return "UNDEFINED";
+      case QRCode.MODE_NUMERIC:
+        return "NUMERIC";
+      case QRCode.MODE_ALPHANUMERIC:
+        return "ALPHANUMERIC";
+      case QRCode.MODE_8BIT_BYTE:
+        return "8BIT_BYTE";
+      case QRCode.MODE_KANJI:
+        return "KANJI";
+      default:
+        break;
+    }
+    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 QRCode.ECLevel ec_level) {
+  // 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 ec_level) {
     switch (ec_level) {
       case QRCode.EC_LEVEL_L:
         return 1;
@@ -291,10 +317,9 @@ public final class QRCode {
     return -1;  // Unknown error correction level.
   }
 
-  // Return the code of mode.  On error, return -1.
-  // The codes of modes are defined in the table 2 of JISX0510:2004
-  // (p.16).
-  public static int GetModeCode(final QRCode.Mode mode) {
+  // Return the code of mode. On error, return -1. The codes of modes are defined in the table 2 of
+  // JISX0510:2004 (p.16).
+  public static int GetModeCode(final int mode) {
     switch (mode) {
       case QRCode.MODE_NUMERIC:
         return 1;
@@ -310,9 +335,9 @@ public final class QRCode {
     return -1;  // Unknown mode.
   }
 
-  // Return the number of bits needed for representing the length info
-  // of QR Code with "version" and "mode".  On error, return -1.
-  public static int GetNumBitsForLength(int version, QRCode.Mode mode) {
+  // Return the number of bits needed for representing the length info of QR Code with "version" and
+  // "mode". On error, return -1.
+  public static int GetNumBitsForLength(int version, int mode) {
     if (!IsValidVersion(version)) {
       Debug.LOG_ERROR("Invalid version: " + version);
       return -1;
@@ -333,12 +358,16 @@ public final class QRCode {
     return -1;
   }
 
-  // Return true if the all values in the matrix are binary numbers.
-  // Otherwise, return false.
-  private static boolean EverythingIsBinary(final Array2D<int> &matrix) {
+  // Return true if the all values in the matrix are binary numbers. Otherwise, return false.
+  //
+  // JAVAPORT: This is going to be super expensive and unnecessary, we should not call this in
+  // production. I'm leaving it because it may be useful for testing. It should be removed entirely
+  // if ByteMatrix is changed never to contain a -1.
+  private static boolean EverythingIsBinary(final ByteMatrix matrix) {
     for (int y = 0; y < matrix.height(); ++y) {
       for (int x = 0; x < matrix.width(); ++x) {
-        if (!(matrix(y, x) == 0 || matrix(y, x) == 1)) {
+        int value = matrix.get(y, x);
+        if (!(value == 0 || value == 1)) {
           // Found non zero/one value.
           return false;
         }