2 * Copyright 2008 ZXing authors
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
8 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 package com.google.zxing.qrcode.encoder;
20 * @author satorux@google.com (Satoru Takabayashi) - creator
21 * @author dswitkin@google.com (Daniel Switkin) - ported from C++
23 public final class QRCode {
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;
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
41 // JAVAPORT: Do not remove trailing slashes yet. There are very likely conflicts with local
42 // variables and parameters which will introduce insidious bugs.
44 private int ec_level_;
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_;
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().
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.
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.
75 public static final int NUM_MODES = 4;
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().
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;
91 mode_ = MODE_UNDEFINED;
92 ec_level_ = EC_LEVEL_UNDEFINED;
96 num_total_bytes_ = -1;
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_; }
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
129 // Note that the class internally used Array2D. You should access
130 // cells in row-major order for cache efficiency. Example:
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));
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);
145 // Checks all the member variables are set properly. Returns true on success. Otherwise, returns
147 // JAVAPORT: Do not call EverythingIsBinary(matrix_) here as it is very expensive.
148 public boolean IsValid() {
150 // First check if all version are not uninitialized.
151 mode_ != MODE_UNDEFINED &&
152 ec_level_ != EC_LEVEL_UNDEFINED &&
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_ &&
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.
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");
200 result.append("\n matrix:");
201 result.append(MatrixUtil.ToASCII(matrix_));
203 result.append("\n>>\n");
204 return result.toString();
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; }
221 // Check if "version" is valid.
222 public static boolean IsValidVersion(final int version) {
223 return version >= kMinVersion && version <= kMaxVersion;
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;
229 // Check if "mode" is valid.
230 public static boolean IsValidMode(final int mode) {
231 return mode >= 0 && mode < NUM_MODES;
233 // Check if "width" is valid.
234 public static boolean IsValidMatrixWidth(int width) {
235 return width >= kMinMatrixWidth && width <= kMaxMatrixWidth;
237 // Check if "mask_pattern" is valid.
238 public static boolean IsValidMaskPattern(int mask_pattern) {
239 return mask_pattern >= 0 && mask_pattern < kNumMaskPatterns;
242 // Convert "ec_level" to String for debugging.
243 public static final String ECLevelToString(int ec_level) {
245 case QRCode.EC_LEVEL_UNDEFINED:
247 case QRCode.EC_LEVEL_L:
249 case QRCode.EC_LEVEL_M:
251 case QRCode.EC_LEVEL_Q:
253 case QRCode.EC_LEVEL_H:
261 // Convert "mode" to String for debugging.
262 public static final String ModeToString(int mode) {
264 case QRCode.MODE_UNDEFINED:
266 case QRCode.MODE_NUMERIC:
268 case QRCode.MODE_ALPHANUMERIC:
269 return "ALPHANUMERIC";
270 case QRCode.MODE_8BIT_BYTE:
272 case QRCode.MODE_KANJI:
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) {
285 case QRCode.EC_LEVEL_L:
287 case QRCode.EC_LEVEL_M:
289 case QRCode.EC_LEVEL_Q:
291 case QRCode.EC_LEVEL_H:
296 return -1; // Unknown error correction level.
299 // Return the code of mode. On error, return -1.
300 // The codes of modes are defined in the table 2 of JISX0510:2004
302 public static int GetModeCode(final int mode) {
304 case QRCode.MODE_NUMERIC:
306 case QRCode.MODE_ALPHANUMERIC:
308 case QRCode.MODE_8BIT_BYTE:
310 case QRCode.MODE_KANJI:
315 return -1; // Unknown mode.
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);
325 if (!IsValidMode(mode)) {
326 Debug.LOG_ERROR("Invalid mode: " + mode);
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];
336 Debug.LOG_ERROR("Should not reach");
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.