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