Wrote a Matrix class and fixed all uses of it, as well as other small fixes like...
[zxing.git] / core / src / com / google / zxing / qrcode / encoder / QRCode.java
1 /*
2  * Copyright 2008 ZXing authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package com.google.zxing.qrcode.encoder;
18
19 /**
20  * @author satorux@google.com (Satoru Takabayashi) - creator
21  * @author dswitkin@google.com (Daniel Switkin) - ported from C++
22  */
23 public final class QRCode {
24
25   // Magic numbers.
26   public static final int kMinVersion = 1;
27   public static final int kMaxVersion = 40;
28   // For matrix width, see 7.3.1 of JISX0510:2004 (p.5).
29   public static final int kMinMatrixWidth = 21;  // Version 1
30   public static final int kMaxMatrixWidth = 177;  // Version 40 (21 + 4 * (40 -1)).
31   public static final int kNumMaskPatterns = 8;
32
33   // See table 3 of JISX0510:2004 (p.16)
34   private static final int kNumBitsTable[][] = {
35       // NUMERIC  ALPHANUMERIC  8BIT_BYTE  KANJI
36       {       10,            9,         8,     8 },  // Version 1-9
37       {       12,           11,        16,    10 },  // Version 10-26
38       {       14,           13,        16,    12 },  // Version 27-40
39   };
40
41   // JAVAPORT: Do not remove trailing slashes yet. There are very likely conflicts with local
42   // variables and parameters which will introduce insidious bugs.
43   private int mode_;
44   private int ec_level_;
45   private int version_;
46   private int matrix_width_;
47   private int mask_pattern_;
48   private int num_total_bytes_;
49   private int num_data_bytes_;
50   private int num_ec_bytes_;
51   private int num_rs_blocks_;
52   private Matrix matrix_;
53
54
55   // They call encoding "mode".  The modes are defined in 8.3 of JISX0510:2004 (p.14). It's unlikely
56   // (probably we will not support complicated modes) but if you add an item to this, please also
57   // add it to ModeToString(), GetModeCode(), GetNumBitsForLength(), Encoder.AppendBytes(), and
58   // Encoder.ChooseMode().
59   //
60   // JAVAPORT: These used to be C++ enums, but the code evaluates them as integers, and requires
61   // negative values. I don't want to take the ParsedResultType approach of a class full of statics
62   // of that class's type. The best compromise here is integer constants.
63   //
64   // Formerly enum Mode
65   public static final int MODE_UNDEFINED = -1;
66   public static final int MODE_NUMERIC = 0;
67   public static final int MODE_ALPHANUMERIC = 1;
68   public static final int MODE_8BIT_BYTE = 2;
69   public static final int MODE_KANJI = 3;  // Shift_JIS
70   // The following modes are unimplemented.
71   // MODE_ECI,
72   // MODE_MIXED,
73   // MODE_CONCATENATED,
74   // MODE_FNC1,
75   public static final int NUM_MODES = 4;
76
77   // The error correction levels are defined in the table 22 of JISX0510:2004 (p.45). It's very
78   // unlikely (we've already covered all of them!)  but if you add an item to this, please also add
79   // it to ECLevelToString() and GetECLevelCode().
80   //
81   // Formerly enum ECLevel
82   public static final int EC_LEVEL_UNDEFINED  = -1;
83   // They don't have names in the standard!
84   public static final int EC_LEVEL_L = 0;  //  7% of corruption can be recovered.
85   public static final int EC_LEVEL_M = 1;  // 15%
86   public static final int EC_LEVEL_Q = 2;  // 25%
87   public static final int EC_LEVEL_H = 3;  // 30%
88   public static final int NUM_EC_LEVELS = 4;
89
90   public QRCode() {
91     mode_ = MODE_UNDEFINED;
92     ec_level_ = EC_LEVEL_UNDEFINED;
93     version_ = -1;
94     matrix_width_ = -1;
95     mask_pattern_ = -1;
96     num_total_bytes_ = -1;
97     num_data_bytes_ = -1;
98     num_ec_bytes_ = -1;
99     num_rs_blocks_ = -1;
100     matrix_ = null;
101   }
102
103   // Mode of the QR Code.
104   public int mode() { return mode_; }
105   // Error correction level of the QR Code.
106   public int ec_level() { return ec_level_; }
107   // Version of the QR Code.  The bigger size, the bigger version.
108   public int version() { return version_; }
109   // Matrix width of the QR Code.
110   public int matrix_width() { return matrix_width_; }
111   // Mask pattern of the QR Code.
112   public int mask_pattern() { return mask_pattern_; }
113   // Number of total bytes in the QR Code.
114   public int num_total_bytes() { return num_total_bytes_; }
115   // Number of data bytes in the QR Code.
116   public int num_data_bytes() { return num_data_bytes_; }
117   // Number of error correction bytes in the QR Code.
118   public int num_ec_bytes() { return num_ec_bytes_; }
119   // Number of Reedsolomon blocks in the QR Code.
120   public int num_rs_blocks() { return num_rs_blocks_; }
121   // Matrix data of the QR Code.
122   public final Matrix matrix() { return matrix_; }
123
124   // Return the value of the module (cell) pointed by "x" and "y" in
125   // the matrix of the QR Code.  They call cells in the matrix
126   // "modules".  1 represents a black cell, and 0 represents a white
127   // cell.
128   //
129   // Note that the class internally used Array2D.  You should access
130   // cells in row-major order for cache efficiency.  Example:
131   //
132   //   for (int y = 0; y < qrcode.matrix_width(); ++y) {
133   //     for (int x = 0; x < qrcode.matrix_width(); ++x) {
134   //       DoSomething(qrcode.at(x, y));
135   //     }
136   //   }
137   //
138   public int at(int x, int y) {
139     // The value must be zero or one.
140     int value = matrix_.get(y, x);
141     Debug.DCHECK(value == 0 || value == 1);
142     return value;
143   }
144
145   // Checks all the member variables are set properly.  Returns true on success.  Otherwise, returns
146   // false.
147   // JAVAPORT: Do not call EverythingIsBinary(matrix_) here as it is very expensive.
148   public boolean IsValid() {
149     return (
150         // First check if all version are not uninitialized.
151         mode_ != MODE_UNDEFINED &&
152             ec_level_ != EC_LEVEL_UNDEFINED &&
153             version_ != -1 &&
154             matrix_width_ != -1 &&
155             mask_pattern_ != -1 &&
156             num_total_bytes_ != -1 &&
157             num_data_bytes_ != -1 &&
158             num_ec_bytes_ != -1 &&
159             num_rs_blocks_ != -1 &&
160             // Then check them in other ways..
161             IsValidVersion(version_) &&
162             IsValidMode(mode_) &&
163             IsValidECLevel(ec_level_) &&
164             IsValidMatrixWidth(matrix_width_) &&
165             IsValidMaskPattern(mask_pattern_) &&
166             num_total_bytes_ == num_data_bytes_ + num_ec_bytes_ &&
167             // Matrix stuff.
168             matrix_ != null &&
169             matrix_width_ == matrix_.width() &&
170             // See 7.3.1 of JISX0510:2004 (p.5).
171             matrix_width_ == kMinMatrixWidth + (version_ - 1) * 4 &&
172             matrix_.width() == matrix_.height()); // Must be square.
173   }
174
175   // Return debug String.
176   public String DebugString() {
177     StringBuffer result = new StringBuffer();
178     result.append("<<QRCode\n");
179     result.append(" mode: ");
180     result.append(ModeToString(mode_));
181     result.append("\n ec_level: ");
182     result.append(ECLevelToString(ec_level_));
183     result.append("\n version: ");
184     result.append(version_);
185     result.append("\n matrix_width: ");
186     result.append(matrix_width_);
187     result.append("\n mask_pattern: ");
188     result.append(mask_pattern_);
189     result.append("\n num_total_bytes_: ");
190     result.append(num_total_bytes_);
191     result.append("\n num_data_bytes: ");
192     result.append(num_data_bytes_);
193     result.append("\n num_ec_bytes: ");
194     result.append(num_ec_bytes_);
195     result.append("\n num_rs_blocks: ");
196     result.append(num_rs_blocks_);
197     if (matrix_ == null) {
198       result.append("\n matrix: null");
199     } else {
200       result.append("\n matrix:");
201       result.append(MatrixUtil.ToASCII(matrix_));
202     }
203     result.append("\n>>\n");
204     return result.toString();
205   }
206
207   public void set_mode(int value) { mode_ = value; }
208   public void set_ec_level(int value) { ec_level_ = value; }
209   public void set_version(int value) { version_ = value; }
210   public void set_matrix_width(int value) { matrix_width_ = value; }
211   public void set_mask_pattern(int value) { mask_pattern_ = value; }
212   public void set_num_total_bytes(int value) { num_total_bytes_ = value; }
213   public void set_num_data_bytes(int value) { num_data_bytes_ = value; }
214   public void set_num_ec_bytes(int value) { num_ec_bytes_ = value; }
215   public void set_num_rs_blocks(int value) { num_rs_blocks_ = value; }
216   // This takes ownership of the 2D array.  The 2D array will be
217   // deleted in the destructor of the class.
218   public void set_matrix(Matrix value) { matrix_ = value; }
219
220
221   // Check if "version" is valid.
222   public static boolean IsValidVersion(final int version) {
223     return version >= kMinVersion && version <= kMaxVersion;
224   }
225   // Check if "mask_pattern" is valid.
226   public static boolean IsValidECLevel(int ec_level) {
227     return ec_level >= 0 && ec_level < NUM_EC_LEVELS;
228   }
229   // Check if "mode" is valid.
230   public static boolean IsValidMode(final int mode) {
231     return mode >= 0 && mode < NUM_MODES;
232   }
233   // Check if "width" is valid.
234   public static boolean IsValidMatrixWidth(int width) {
235     return width >= kMinMatrixWidth && width <= kMaxMatrixWidth;
236   }
237   // Check if "mask_pattern" is valid.
238   public static boolean IsValidMaskPattern(int mask_pattern) {
239     return mask_pattern >= 0 && mask_pattern < kNumMaskPatterns;
240   }
241
242   // Convert "ec_level" to String for debugging.
243   public static final String ECLevelToString(int ec_level) {
244     switch (ec_level) {
245       case QRCode.EC_LEVEL_UNDEFINED:
246         return "UNDEFINED";
247       case QRCode.EC_LEVEL_L:
248         return "L";
249       case QRCode.EC_LEVEL_M:
250         return "M";
251       case QRCode.EC_LEVEL_Q:
252         return "Q";
253       case QRCode.EC_LEVEL_H:
254         return "H";
255       default:
256         break;
257     }
258     return "UNKNOWN";
259   }
260
261   // Convert "mode" to String for debugging.
262   public static final String ModeToString(int mode) {
263     switch (mode) {
264       case QRCode.MODE_UNDEFINED:
265         return "UNDEFINED";
266       case QRCode.MODE_NUMERIC:
267         return "NUMERIC";
268       case QRCode.MODE_ALPHANUMERIC:
269         return "ALPHANUMERIC";
270       case QRCode.MODE_8BIT_BYTE:
271         return "8BIT_BYTE";
272       case QRCode.MODE_KANJI:
273         return "KANJI";
274       default:
275         break;
276     }
277     return "UNKNOWN";
278   }
279
280   // Return the code of error correction level.  On error, return -1.
281   // The codes of error correction levels are defined in the table 22
282   // of JISX0510:2004 (p.45).
283   public static int GetECLevelCode(final int ec_level) {
284     switch (ec_level) {
285       case QRCode.EC_LEVEL_L:
286         return 1;
287       case QRCode.EC_LEVEL_M:
288         return 0;
289       case QRCode.EC_LEVEL_Q:
290         return 3;
291       case QRCode.EC_LEVEL_H:
292         return 2;
293       default:
294         break;
295     }
296     return -1;  // Unknown error correction level.
297   }
298
299   // Return the code of mode.  On error, return -1.
300   // The codes of modes are defined in the table 2 of JISX0510:2004
301   // (p.16).
302   public static int GetModeCode(final int mode) {
303     switch (mode) {
304       case QRCode.MODE_NUMERIC:
305         return 1;
306       case QRCode.MODE_ALPHANUMERIC:
307         return 2;
308       case QRCode.MODE_8BIT_BYTE:
309         return 4;
310       case QRCode.MODE_KANJI:
311         return 8;
312       default:
313         break;
314     }
315     return -1;  // Unknown mode.
316   }
317
318   // Return the number of bits needed for representing the length info
319   // of QR Code with "version" and "mode".  On error, return -1.
320   public static int GetNumBitsForLength(int version, int mode) {
321     if (!IsValidVersion(version)) {
322       Debug.LOG_ERROR("Invalid version: " + version);
323       return -1;
324     }
325     if (!IsValidMode(mode)) {
326       Debug.LOG_ERROR("Invalid mode: " + mode);
327       return -1;
328     }
329     if (version >= 1 && version <= 9) {
330       return kNumBitsTable[0][mode];
331     } else if (version >= 10 && version <= 26) {
332       return kNumBitsTable[1][mode];
333     } else if (version >= 27 && version <= 40) {
334       return kNumBitsTable[2][mode];
335     } else {
336       Debug.LOG_ERROR("Should not reach");
337     }
338     return -1;
339   }
340
341   // Return true if the all values in the matrix are binary numbers. Otherwise, return false.
342   // JAVAPORT: This is going to be super expensive and unnecessary, we should not call this in
343   // production. I'm leaving it because it may be useful for testing.
344   private static boolean EverythingIsBinary(final Matrix matrix) {
345     for (int y = 0; y < matrix.height(); ++y) {
346       for (int x = 0; x < matrix.width(); ++x) {
347         int value = matrix.get(y, x);
348         if (!(value == 0 || value == 1)) {
349           // Found non zero/one value.
350           return false;
351         }
352       }
353     }
354     return true;
355   }
356
357 }