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;
19 // JAVAPORT: QRCodeMatrix needs to be renamed Matrix and built as a new class.
21 // template <typename T> class Array2D;
22 // typedef Array2D<int> QRCodeMatrix;
23 // #include "util/array/array2d-inl.h"
26 * @author satorux@google.com (Satoru Takabayashi) - creator
27 * @author dswitkin@google.com (Daniel Switkin) - ported from C++
29 public final class QRCode {
32 public static final int kMinVersion = 1;
33 public static final int kMaxVersion = 40;
34 // For matrix width, see 7.3.1 of JISX0510:2004 (p.5).
35 public static final int kMinMatrixWidth = 21; // Version 1
36 public static final int kMaxMatrixWidth = 177; // Version 40 (21 + 4 * (40 -1)).
37 public static final int kNumMaskPatterns = 8;
39 // See table 3 of JISX0510:2004 (p.16)
40 private static final int kNumBitsTable[][] = {
41 // NUMERIC ALPHANUMERIC 8BIT_BYTE KANJI
42 { 10, 9, 8, 8 }, // Version 1-9
43 { 12, 11, 16, 10 }, // Version 10-26
44 { 14, 13, 16, 12 }, // Version 27-40
47 // JAVAPORT: Do not remove trailing slashes yet. There are very likely conflicts with local
48 // variables and parameters which will introduce insidious bugs.
50 private ECLevel ec_level_;
52 private int matrix_width_;
53 private int mask_pattern_;
54 private int num_total_bytes_;
55 private int num_data_bytes_;
56 private int num_ec_bytes_;
57 private int num_rs_blocks_;
58 private QRCodeMatrix *matrix_;
61 // They call encoding "mode". The modes are defined in 8.3 of
62 // JISX0510:2004 (p.14). It's unlikely (probably we will not
63 // support complicated modes) but if you add an item to this, please
64 // also add it to ModeToString(), GetModeCode(),
65 // GetNumBitsForLength(), Encoder.AppendBytes(),
66 // Encoder.ChooseMode().
72 MODE_KANJI, // Shift_JIS
73 // The following modes are unimplemented.
78 NUM_MODES, // Always keep this at the end.
81 // The error correction levels are defined in the table 22 of
82 // JISX0510:2004 (p.45). It's very unlikely (we've already covered
83 // all of them!) but if you add an item to this, please also add it
84 // to ECLevelToString() and GetECLevelCode().
86 EC_LEVEL_UNDEFINED = -1,
87 // They don't have names in the standard!
88 EC_LEVEL_L, // 7% of corruption can be recovered.
92 NUM_EC_LEVELS, // Always keep this at the end.
96 mode_ = MODE_UNDEFINED;
97 ec_level_ = EC_LEVEL_UNDEFINED;
101 num_total_bytes_ = -1;
102 num_data_bytes_ = -1;
108 // Mode of the QR Code.
109 public Mode mode() { return mode_; }
110 // Error correction level of the QR Code.
111 public ECLevel ec_level() { return ec_level_; }
112 // Version of the QR Code. The bigger size, the bigger version.
113 public int version() { return version_; }
114 // Matrix width of the QR Code.
115 public int matrix_width() { return matrix_width_; }
116 // Mask pattern of the QR Code.
117 public int mask_pattern() { return mask_pattern_; }
118 // Number of total bytes in the QR Code.
119 public int num_total_bytes() { return num_total_bytes_; }
120 // Number of data bytes in the QR Code.
121 public int num_data_bytes() { return num_data_bytes_; }
122 // Number of error correction bytes in the QR Code.
123 public int num_ec_bytes() { return num_ec_bytes_; }
124 // Number of Reedsolomon blocks in the QR Code.
125 public int num_rs_blocks() { return num_rs_blocks_; }
126 // Matrix data of the QR Code.
127 public final QRCodeMatrix* matrix() { return matrix_; }
129 // Return the value of the module (cell) pointed by "x" and "y" in
130 // the matrix of the QR Code. They call cells in the matrix
131 // "modules". 1 represents a black cell, and 0 represents a white
134 // Note that the class internally used Array2D. You should access
135 // cells in row-major order for cache efficiency. Example:
137 // for (int y = 0; y < qrcode.matrix_width(); ++y) {
138 // for (int x = 0; x < qrcode.matrix_width(); ++x) {
139 // DoSomething(qrcode.at(x, y));
143 public int at(int x, int y) {
144 // The value must be zero or one.
145 Debug.DCHECK((*matrix_)(y, x) == 0 || (*matrix_)(y, x) == 1);
146 return (*matrix_)(y, x);
149 // Checks all the member variables are set properly. Returns true
150 // on success. Otherwise, returns false.
151 public boolean IsValid() {
153 // First check if all version are not uninitialized.
154 mode_ != MODE_UNDEFINED &&
155 ec_level_ != EC_LEVEL_UNDEFINED &&
157 matrix_width_ != -1 &&
158 mask_pattern_ != -1 &&
159 num_total_bytes_ != -1 &&
160 num_data_bytes_ != -1 &&
161 num_ec_bytes_ != -1 &&
162 num_rs_blocks_ != -1 &&
163 // Then check them in other ways..
164 IsValidVersion(version_) &&
165 IsValidMode(mode_) &&
166 IsValidECLevel(ec_level_) &&
167 IsValidMatrixWidth(matrix_width_) &&
168 IsValidMaskPattern(mask_pattern_) &&
169 num_total_bytes_ == num_data_bytes_ + num_ec_bytes_ &&
172 matrix_width_ == matrix_.width() &&
173 // See 7.3.1 of JISX0510:2004 (p.5).
174 matrix_width_ == kMinMatrixWidth + (version_ - 1) * 4 &&
175 matrix_.width() == matrix_.height() && // Must be square.
176 EverythingIsBinary(*matrix_));
179 // Return debug String.
180 public String DebugString() {
182 StringAppendF(&result, "<<QRCode\n");
183 StringAppendF(&result, " mode: %s\n", ModeToString(mode_));
184 StringAppendF(&result, " ec_level: %s\n", ECLevelToString(ec_level_));
185 StringAppendF(&result, " version: %d\n", version_);
186 StringAppendF(&result, " matrix_width: %d\n", matrix_width_);
187 StringAppendF(&result, " mask_pattern: %d\n", mask_pattern_);
188 StringAppendF(&result, " num_total_bytes_: %d\n", num_total_bytes_);
189 StringAppendF(&result, " num_data_bytes: %d\n", num_data_bytes_);
190 StringAppendF(&result, " num_ec_bytes: %d\n", num_ec_bytes_);
191 StringAppendF(&result, " num_rs_blocks: %d\n", num_rs_blocks_);
192 if (matrix_ == null) {
193 StringAppendF(&result, " matrix: null\n");
195 StringAppendF(&result, " matrix:\n%s",
196 MatrixUtil.ToASCII(*matrix_).c_str());
198 StringAppendF(&result, ">>\n");
202 public void set_mode(Mode value) { mode_ = value; }
203 public void set_ec_level(ECLevel value) { ec_level_ = value; }
204 public void set_version(int value) { version_ = value; }
205 public void set_matrix_width(int value) { matrix_width_ = value; }
206 public void set_mask_pattern(int value) { mask_pattern_ = value; }
207 public void set_num_total_bytes(int value) { num_total_bytes_ = value; }
208 public void set_num_data_bytes(int value) { num_data_bytes_ = value; }
209 public void set_num_ec_bytes(int value) { num_ec_bytes_ = value; }
210 public void set_num_rs_blocks(int value) { num_rs_blocks_ = value; }
211 // This takes ownership of the 2D array. The 2D array will be
212 // deleted in the destructor of the class.
213 public void set_matrix(QRCodeMatrix *value) { matrix_ = value; }
216 // Check if "version" is valid.
217 public static boolean IsValidVersion(final int version) {
218 return version >= kMinVersion && version <= kMaxVersion;
220 // Check if "mask_pattern" is valid.
221 public static boolean IsValidECLevel(ECLevel ec_level) {
222 return ec_level >= 0 && ec_level < NUM_EC_LEVELS;
224 // Check if "mode" is valid.
225 public static boolean IsValidMode(final QRCode.Mode mode) {
226 return mode >= 0 && mode < NUM_MODES;
228 // Check if "width" is valid.
229 public static boolean IsValidMatrixWidth(int width) {
230 return width >= kMinMatrixWidth && width <= kMaxMatrixWidth;
232 // Check if "mask_pattern" is valid.
233 public static boolean IsValidMaskPattern(int mask_pattern) {
234 return mask_pattern >= 0 && mask_pattern < kNumMaskPatterns;
237 // Convert "ec_level" to String for debugging.
238 public static final char *ECLevelToString(QRCode.ECLevel ec_level) {
240 case QRCode.EC_LEVEL_UNDEFINED:
242 case QRCode.EC_LEVEL_L:
244 case QRCode.EC_LEVEL_M:
246 case QRCode.EC_LEVEL_Q:
248 case QRCode.EC_LEVEL_H:
256 // Convert "mode" to String for debugging.
257 public static final char *ModeToString(QRCode.Mode mode) {
259 case QRCode.MODE_UNDEFINED:
261 case QRCode.MODE_NUMERIC:
263 case QRCode.MODE_ALPHANUMERIC:
264 return "ALPHANUMERIC";
265 case QRCode.MODE_8BIT_BYTE:
267 case QRCode.MODE_KANJI:
275 // Return the code of error correction level. On error, return -1.
276 // The codes of error correction levels are defined in the table 22
277 // of JISX0510:2004 (p.45).
278 public static int GetECLevelCode(final QRCode.ECLevel ec_level) {
280 case QRCode.EC_LEVEL_L:
282 case QRCode.EC_LEVEL_M:
284 case QRCode.EC_LEVEL_Q:
286 case QRCode.EC_LEVEL_H:
291 return -1; // Unknown error correction level.
294 // Return the code of mode. On error, return -1.
295 // The codes of modes are defined in the table 2 of JISX0510:2004
297 public static int GetModeCode(final QRCode.Mode mode) {
299 case QRCode.MODE_NUMERIC:
301 case QRCode.MODE_ALPHANUMERIC:
303 case QRCode.MODE_8BIT_BYTE:
305 case QRCode.MODE_KANJI:
310 return -1; // Unknown mode.
313 // Return the number of bits needed for representing the length info
314 // of QR Code with "version" and "mode". On error, return -1.
315 public static int GetNumBitsForLength(int version, QRCode.Mode mode) {
316 if (!IsValidVersion(version)) {
317 Debug.LOG_ERROR("Invalid version: " + version);
320 if (!IsValidMode(mode)) {
321 Debug.LOG_ERROR("Invalid mode: " + mode);
324 if (version >= 1 && version <= 9) {
325 return kNumBitsTable[0][mode];
326 } else if (version >= 10 && version <= 26) {
327 return kNumBitsTable[1][mode];
328 } else if (version >= 27 && version <= 40) {
329 return kNumBitsTable[2][mode];
331 Debug.LOG_ERROR("Should not reach");
336 // Return true if the all values in the matrix are binary numbers.
337 // Otherwise, return false.
338 private static boolean EverythingIsBinary(final Array2D<int> &matrix) {
339 for (int y = 0; y < matrix.height(); ++y) {
340 for (int x = 0; x < matrix.width(); ++x) {
341 if (!(matrix(y, x) == 0 || matrix(y, x) == 1)) {
342 // Found non zero/one value.