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