Big rename of variables and method to have more standard Java names
[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 MIN_VERSION = 1;
30   private static final int MAX_VERSION = 40;
31   // For matrix width, see 7.3.1 of JISX0510:2004 (p.5).
32   private static final int MIN_MATRIX_WIDTH = 21;  // Version 1
33   private static final int MAX_MATRIX_WIDTH = 177;  // Version 40 (21 + 4 * (40 -1)).
34   public static final int NUM_MASK_PATTERNS = 8;
35
36   // See table 3 of JISX0510:2004 (p.16)
37   private static final int[][] NUM_BITS_TABLE = {
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   private int mode;
45   private int ecLevel;
46   private int version;
47   private int matrixWidth;
48   private int maskPattern;
49   private int numTotalBytes;
50   private int numDataBytes;
51   private int numECBytes;
52   private int numRSBlocks;
53   private ByteMatrix matrix;
54
55
56   // They call encoding "mode". The modes are defined in 8.3 of JISX0510:2004 (p.14). It's unlikely
57   // (probably we will not support complicated modes) but if you add an item to this, please also
58   // add it to modeToString(), getModeCode(), getNumBitsForLength(), Encoder.appendBytes(), and
59   // Encoder.chooseMode().
60   //
61   // JAVAPORT: These used to be C++ enums, but the code evaluates them as integers, and requires
62   // negative values. I don't want to take the ParsedResultType approach of a class full of statics
63   // of that class's type. The best compromise here is integer constants.
64   //
65   // Formerly enum Mode
66   public static final int MODE_UNDEFINED = -1;
67   public static final int MODE_NUMERIC = 0;
68   public static final int MODE_ALPHANUMERIC = 1;
69   public static final int MODE_8BIT_BYTE = 2;
70   public static final int MODE_KANJI = 3;  // Shift_JIS
71   // The following modes are unimplemented.
72   // MODE_ECI,
73   // MODE_MIXED,
74   // MODE_CONCATENATED,
75   // MODE_FNC1,
76   public static final int NUM_MODES = 4;
77
78   // The error correction levels are defined in the table 22 of JISX0510:2004 (p.45). It's very
79   // unlikely (we've already covered all of them!)  but if you add an item to this, please also add
80   // it to ecLevelToString() and getECLevelCode().
81   //
82   // Formerly enum ECLevel
83   public static final int EC_LEVEL_UNDEFINED  = -1;
84   // They don't have names in the standard!
85   public static final int EC_LEVEL_L = 0;  //  7% of corruption can be recovered.
86   public static final int EC_LEVEL_M = 1;  // 15%
87   public static final int EC_LEVEL_Q = 2;  // 25%
88   public static final int EC_LEVEL_H = 3;  // 30%
89   public static final int NUM_EC_LEVELS = 4;
90
91   public QRCode() {
92     mode = MODE_UNDEFINED;
93     ecLevel = EC_LEVEL_UNDEFINED;
94     version = -1;
95     matrixWidth = -1;
96     maskPattern = -1;
97     numTotalBytes = -1;
98     numDataBytes = -1;
99     numECBytes = -1;
100     numRSBlocks = -1;
101     matrix = null;
102   }
103
104   // Mode of the QR Code.
105   public int getMode() { return mode; }
106   // Error correction level of the QR Code.
107   public int getECLevel() { return ecLevel; }
108   // Version of the QR Code.  The bigger size, the bigger version.
109   public int getVersion() { return version; }
110   // ByteMatrix width of the QR Code.
111   public int getMatrixWidth() { return matrixWidth; }
112   // Mask pattern of the QR Code.
113   public int getMaskPattern() { return maskPattern; }
114   // Number of total bytes in the QR Code.
115   public int getNumTotalBytes() { return numTotalBytes; }
116   // Number of data bytes in the QR Code.
117   public int getNumDataBytes() { return numDataBytes; }
118   // Number of error correction bytes in the QR Code.
119   public int getNumECBytes() { return numECBytes; }
120   // Number of Reedsolomon blocks in the QR Code.
121   public int getNumRSBlocks() { return numRSBlocks; }
122   // ByteMatrix data of the QR Code.
123   public final ByteMatrix getMatrix() { return matrix; }
124
125   // Return the value of the module (cell) pointed by "x" and "y" in the matrix of the QR Code. They
126   // call cells in the matrix "modules". 1 represents a black cell, and 0 represents a white cell.
127   public int at(int x, int y) {
128     // The value must be zero or one.
129     int value = matrix.get(y, x);
130     if (!(value == 0 || value == 1)) {
131       // this is really like an assert... not sure what better exception to use?
132       throw new RuntimeException("Bad value");
133     }
134     return value;
135   }
136
137   // Checks all the member variables are set properly. Returns true on success. Otherwise, returns
138   // false.
139   public boolean isValid() {
140     return (
141         // First check if all version are not uninitialized.
142         mode != MODE_UNDEFINED &&
143             ecLevel != EC_LEVEL_UNDEFINED &&
144             version != -1 &&
145             matrixWidth != -1 &&
146             maskPattern != -1 &&
147             numTotalBytes != -1 &&
148             numDataBytes != -1 &&
149             numECBytes != -1 &&
150             numRSBlocks != -1 &&
151             // Then check them in other ways..
152             isValidVersion(version) &&
153             isValidMode(mode) &&
154             isValidECLevel(ecLevel) &&
155             isValidMatrixWidth(matrixWidth) &&
156             isValidMaskPattern(maskPattern) &&
157             numTotalBytes == numDataBytes + numECBytes &&
158             // ByteMatrix stuff.
159             matrix != null &&
160             matrixWidth == matrix.width() &&
161             // See 7.3.1 of JISX0510:2004 (p.5).
162             matrixWidth == MIN_MATRIX_WIDTH + (version - 1) * 4 &&
163             matrix.width() == matrix.height()); // Must be square.
164   }
165
166   // Return debug String.
167   public String toString() {
168     StringBuffer result = new StringBuffer();
169     result.append("<<\n");
170     result.append(" mode: ");
171     result.append(modeToString(mode));
172     result.append("\n ecLevel: ");
173     result.append(ecLevelToString(ecLevel));
174     result.append("\n version: ");
175     result.append(version);
176     result.append("\n matrixWidth: ");
177     result.append(matrixWidth);
178     result.append("\n maskPattern: ");
179     result.append(maskPattern);
180     result.append("\n numTotalBytes: ");
181     result.append(numTotalBytes);
182     result.append("\n numDataBytes: ");
183     result.append(numDataBytes);
184     result.append("\n numECBytes: ");
185     result.append(numECBytes);
186     result.append("\n numRSBlocks: ");
187     result.append(numRSBlocks);
188     if (matrix == null) {
189       result.append("\n matrix: null\n");
190     } else {
191       result.append("\n matrix:\n");
192       result.append(matrix.toString());
193     }
194     result.append(">>\n");
195     return result.toString();
196   }
197
198   public void setMode(int value) {
199     mode = value;
200   }
201
202   public void setECLevel(int value) {
203     ecLevel = value;
204   }
205
206   public void setVersion(int value) {
207     version = value;
208   }
209
210   public void setMatrixWidth(int value) {
211     matrixWidth = value;
212   }
213
214   public void setMaskPattern(int value) {
215     maskPattern = value;
216   }
217
218   public void setNumTotalBytes(int value) {
219     numTotalBytes = value;
220   }
221
222   public void setNumDataBytes(int value) {
223     numDataBytes = value;
224   }
225
226   public void setNumECBytes(int value) {
227     numECBytes = value;
228   }
229
230   public void setNumRSBlocks(int value) {
231     numRSBlocks = value;
232   }
233
234   // This takes ownership of the 2D array.
235   public void setMatrix(ByteMatrix value) {
236     matrix = value;
237   }
238
239   // Check if "version" is valid.
240   public static boolean isValidVersion(final int version) {
241     return version >= MIN_VERSION && version <= MAX_VERSION;
242   }
243
244   // Check if "ecLevel" is valid.
245   public static boolean isValidECLevel(int ecLevel) {
246     return ecLevel >= 0 && ecLevel < NUM_EC_LEVELS;
247   }
248
249   // Check if "mode" is valid.
250   public static boolean isValidMode(final int mode) {
251     return mode >= 0 && mode < NUM_MODES;
252   }
253
254   // Check if "width" is valid.
255   public static boolean isValidMatrixWidth(int width) {
256     return width >= MIN_MATRIX_WIDTH && width <= MAX_MATRIX_WIDTH;
257   }
258
259   // Check if "mask_pattern" is valid.
260   public static boolean isValidMaskPattern(int maskPattern) {
261     return maskPattern >= 0 && maskPattern < NUM_MASK_PATTERNS;
262   }
263
264   // Convert "getECLevel" to String for debugging.
265   public static String ecLevelToString(int ecLevel) {
266     switch (ecLevel) {
267       case QRCode.EC_LEVEL_UNDEFINED:
268         return "UNDEFINED";
269       case QRCode.EC_LEVEL_L:
270         return "L";
271       case QRCode.EC_LEVEL_M:
272         return "M";
273       case QRCode.EC_LEVEL_Q:
274         return "Q";
275       case QRCode.EC_LEVEL_H:
276         return "H";
277       default:
278         break;
279     }
280     return "UNKNOWN";
281   }
282
283   // Convert "mode" to String for debugging.
284   public static String modeToString(int mode) {
285     switch (mode) {
286       case QRCode.MODE_UNDEFINED:
287         return "UNDEFINED";
288       case QRCode.MODE_NUMERIC:
289         return "NUMERIC";
290       case QRCode.MODE_ALPHANUMERIC:
291         return "ALPHANUMERIC";
292       case QRCode.MODE_8BIT_BYTE:
293         return "8BIT_BYTE";
294       case QRCode.MODE_KANJI:
295         return "KANJI";
296       default:
297         break;
298     }
299     return "UNKNOWN";
300   }
301
302   // Return the code of error correction level. On error, return -1. The codes of error correction
303   // levels are defined in the table 22 of JISX0510:2004 (p.45).
304   public static int getECLevelCode(final int ecLevel) throws WriterException {
305     switch (ecLevel) {
306       case QRCode.EC_LEVEL_L:
307         return 1;
308       case QRCode.EC_LEVEL_M:
309         return 0;
310       case QRCode.EC_LEVEL_Q:
311         return 3;
312       case QRCode.EC_LEVEL_H:
313         return 2;
314       default:
315         throw new WriterException("Unknown EC level");
316     }
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) throws WriterException {
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         throw new WriterException("Unknown mode: " + mode);
333     }
334   }
335
336   // Return the number of bits needed for representing the length info of QR Code with "version" and
337   // "mode". On error, return -1.
338   static int getNumBitsForLength(int version, int mode) {
339     if (!isValidVersion(version)) {
340       throw new IllegalArgumentException("Invalid version: " + version);
341     }
342     if (!isValidMode(mode)) {
343       throw new IllegalArgumentException("Invalid mode: " + mode);
344     }
345     if (version >= 1 && version <= 9) {
346       return NUM_BITS_TABLE[0][mode];
347     } else if (version >= 10 && version <= 26) {
348       return NUM_BITS_TABLE[1][mode];
349     } else if (version >= 27 && version <= 40) {
350       return NUM_BITS_TABLE[2][mode];
351     }
352     throw new IllegalArgumentException("Bad version: " + version);
353   }
354
355   // Return true if the all values in the matrix are binary numbers. Otherwise, return false.
356   //
357   // JAVAPORT: This is going to be super expensive and unnecessary, we should not call this in
358   // production. I'm leaving it because it may be useful for testing. It should be removed entirely
359   // if ByteMatrix is changed never to contain a -1.
360   /*
361   private static boolean EverythingIsBinary(final ByteMatrix matrix) {
362     for (int y = 0; y < matrix.height(); ++y) {
363       for (int x = 0; x < matrix.width(); ++x) {
364         int value = matrix.get(y, x);
365         if (!(value == 0 || value == 1)) {
366           // Found non zero/one value.
367           return false;
368         }
369       }
370     }
371     return true;
372   }
373    */
374
375 }