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 import com.google.zxing.common.ByteMatrix;
20 import com.google.zxing.WriterException;
23 * @author satorux@google.com (Satoru Takabayashi) - creator
24 * @author dswitkin@google.com (Daniel Switkin) - ported from C++
26 public final class QRCode {
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;
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
44 // JAVAPORT: Do not remove trailing slashes yet. There are very likely conflicts with local
45 // variables and parameters which will introduce insidious bugs.
47 private int ec_level_;
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_;
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().
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.
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.
78 public static final int NUM_MODES = 4;
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().
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;
94 mode_ = MODE_UNDEFINED;
95 ec_level_ = EC_LEVEL_UNDEFINED;
99 num_total_bytes_ = -1;
100 num_data_bytes_ = -1;
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_; }
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");
139 // Checks all the member variables are set properly. Returns true on success. Otherwise, returns
141 // JAVAPORT: Do not call EverythingIsBinary(matrix_) here as it is very expensive.
142 public boolean IsValid() {
144 // First check if all version are not uninitialized.
145 mode_ != MODE_UNDEFINED &&
146 ec_level_ != EC_LEVEL_UNDEFINED &&
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_ &&
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.
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");
194 result.append("\n matrix:\n");
195 result.append(matrix_.toString());
197 result.append(">>\n");
198 return result.toString();
201 public void set_mode(int value) {
205 public void set_ec_level(int value) {
209 public void set_version(int value) {
213 public void set_matrix_width(int value) {
214 matrix_width_ = value;
217 public void set_mask_pattern(int value) {
218 mask_pattern_ = value;
221 public void set_num_total_bytes(int value) {
222 num_total_bytes_ = value;
225 public void set_num_data_bytes(int value) {
226 num_data_bytes_ = value;
229 public void set_num_ec_bytes(int value) {
230 num_ec_bytes_ = value;
233 public void set_num_rs_blocks(int value) {
234 num_rs_blocks_ = value;
237 // This takes ownership of the 2D array.
238 public void set_matrix(ByteMatrix value) {
242 // Check if "version" is valid.
243 public static boolean IsValidVersion(final int version) {
244 return version >= kMinVersion && version <= kMaxVersion;
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;
252 // Check if "mode" is valid.
253 public static boolean IsValidMode(final int mode) {
254 return mode >= 0 && mode < NUM_MODES;
257 // Check if "width" is valid.
258 public static boolean IsValidMatrixWidth(int width) {
259 return width >= kMinMatrixWidth && width <= kMaxMatrixWidth;
262 // Check if "mask_pattern" is valid.
263 public static boolean IsValidMaskPattern(int mask_pattern) {
264 return mask_pattern >= 0 && mask_pattern < kNumMaskPatterns;
267 // Convert "ec_level" to String for debugging.
268 public static String ECLevelToString(int ec_level) {
270 case QRCode.EC_LEVEL_UNDEFINED:
272 case QRCode.EC_LEVEL_L:
274 case QRCode.EC_LEVEL_M:
276 case QRCode.EC_LEVEL_Q:
278 case QRCode.EC_LEVEL_H:
286 // Convert "mode" to String for debugging.
287 public static String ModeToString(int mode) {
289 case QRCode.MODE_UNDEFINED:
291 case QRCode.MODE_NUMERIC:
293 case QRCode.MODE_ALPHANUMERIC:
294 return "ALPHANUMERIC";
295 case QRCode.MODE_8BIT_BYTE:
297 case QRCode.MODE_KANJI:
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 {
309 case QRCode.EC_LEVEL_L:
311 case QRCode.EC_LEVEL_M:
313 case QRCode.EC_LEVEL_Q:
315 case QRCode.EC_LEVEL_H:
318 throw new WriterException("Unknown EC level");
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 {
326 case QRCode.MODE_NUMERIC:
328 case QRCode.MODE_ALPHANUMERIC:
330 case QRCode.MODE_8BIT_BYTE:
332 case QRCode.MODE_KANJI:
335 throw new WriterException("Unknown mode: " + mode);
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);
345 if (!IsValidMode(mode)) {
346 throw new IllegalArgumentException("Invalid mode: " + mode);
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];
355 throw new IllegalArgumentException("Bad version: " + version);
358 // Return true if the all values in the matrix are binary numbers. Otherwise, return false.
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.