2 * Copyright 2007 Google Inc.
\r
4 * Licensed under the Apache License, Version 2.0 (the "License");
\r
5 * you may not use this file except in compliance with the License.
\r
6 * You may obtain a copy of the License at
\r
8 * http://www.apache.org/licenses/LICENSE-2.0
\r
10 * Unless required by applicable law or agreed to in writing, software
\r
11 * distributed under the License is distributed on an "AS IS" BASIS,
\r
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
\r
13 * See the License for the specific language governing permissions and
\r
14 * limitations under the License.
\r
17 package com.google.zxing.qrcode.decoder;
\r
19 import com.google.zxing.ReaderException;
\r
20 import com.google.zxing.common.BitMatrix;
\r
23 * See ISO 18004:2006 Annex D
\r
25 * @author srowen@google.com (Sean Owen)
\r
27 public final class Version {
\r
30 * See ISO 18004:2006 Annex D.
\r
31 * Element i represents the raw version bits that specify version i + 7
\r
33 private static final int[] VERSION_DECODE_INFO = new int[]{
\r
34 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
\r
35 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
\r
36 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
\r
37 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
\r
38 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
\r
39 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
\r
40 0x2542E, 0x26A64, 0x27541, 0x28C69
\r
43 private static final Version[] VERSIONS = buildVersions();
\r
45 private final int versionNumber;
\r
46 private final int[] alignmentPatternCenters;
\r
47 private final ECBlocks[] ecBlocks;
\r
48 private final int totalCodewords;
\r
50 private Version(int versionNumber,
\r
51 int[] alignmentPatternCenters,
\r
55 ECBlocks ecBlocks4) {
\r
56 this.versionNumber = versionNumber;
\r
57 this.alignmentPatternCenters = alignmentPatternCenters;
\r
58 this.ecBlocks = new ECBlocks[]{ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4};
\r
60 ECBlocks levelLECBlocks = ecBlocks1; // L,M,Q,H -- all the same total
\r
61 int ecCodewords = levelLECBlocks.ecCodewords;
\r
62 ECB[] ecbArray = levelLECBlocks.ecBlocks;
\r
63 for (int i = 0; i < ecbArray.length; i++) {
\r
64 ECB ecBlock = ecbArray[i];
\r
65 total += ecBlock.count * (ecBlock.dataCodewords + ecCodewords);
\r
67 this.totalCodewords = total;
\r
70 public int getVersionNumber() {
\r
71 return versionNumber;
\r
74 public int[] getAlignmentPatternCenters() {
\r
75 return alignmentPatternCenters;
\r
78 public int getTotalCodewords() {
\r
79 return totalCodewords;
\r
82 public int getDimensionForVersion() {
\r
83 return 17 + 4 * versionNumber;
\r
86 ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {
\r
87 return ecBlocks[ecLevel.ordinal()];
\r
91 * <p>Deduces version information purely from QR Code dimensions.</p>
\r
93 * @param dimension dimension in modules
\r
94 * @return {@link Version} for a QR Code of that dimension
\r
95 * @throws ReaderException if dimension is not 1 mod 4
\r
97 public static Version getProvisionalVersionForDimension(int dimension) throws ReaderException {
\r
98 if (dimension % 4 != 1) {
\r
99 throw new ReaderException("Dimension must be 1 mod 4");
\r
101 return getVersionForNumber((dimension - 17) >> 2);
\r
104 public static Version getVersionForNumber(int versionNumber) throws ReaderException {
\r
105 if (versionNumber < 1 || versionNumber > 40) {
\r
106 throw new ReaderException("versionNumber must be between 1 and 40");
\r
108 return VERSIONS[versionNumber - 1];
\r
111 static Version decodeVersionInformation(int versionBits) throws ReaderException {
\r
112 int bestDifference = Integer.MAX_VALUE;
\r
113 int bestVersion = 0;
\r
114 for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {
\r
115 int targetVersion = VERSION_DECODE_INFO[i];
\r
116 // Do the version info bits match exactly? done.
\r
117 if (targetVersion == versionBits) {
\r
118 return getVersionForNumber(i + 7);
\r
120 // Otherwise see if this is the closest to a real version info bit string
\r
121 // we have seen so far
\r
122 int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
\r
123 if (bitsDifference < bestDifference) {
\r
124 bestVersion = i + 7;
\r
127 // We can tolerate up to 3 bits of error since no two version info codewords will
\r
128 // differ in less than 4 bits.
\r
129 if (bestDifference <= 3) {
\r
130 return getVersionForNumber(bestVersion);
\r
132 // If we didn't find a close enough match, fail
\r
137 * See ISO 18004:2006 Annex E
\r
139 BitMatrix buildFunctionPattern() {
\r
140 int dimension = getDimensionForVersion();
\r
141 BitMatrix bitMatrix = new BitMatrix(dimension);
\r
143 // Top left finder pattern + separator + format
\r
144 bitMatrix.setRegion(0, 0, 9, 9);
\r
145 // Top right finder pattern + separator + format
\r
146 bitMatrix.setRegion(0, dimension - 8, 9, 8);
\r
147 // Bottom left finder pattern + separator + format
\r
148 bitMatrix.setRegion(dimension - 8, 0, 8, 9);
\r
150 // Alignment patterns
\r
151 int max = alignmentPatternCenters.length;
\r
152 for (int x = 0; x < max; x++) {
\r
153 int i = alignmentPatternCenters[x] - 2;
\r
154 for (int y = 0; y < max; y++) {
\r
155 if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
\r
156 // No alignment patterns near the three finder paterns
\r
159 bitMatrix.setRegion(i, alignmentPatternCenters[y] - 2, 5, 5);
\r
163 // Vertical timing pattern
\r
164 bitMatrix.setRegion(9, 6, dimension - 17, 1);
\r
165 // Horizontal timing pattern
\r
166 bitMatrix.setRegion(6, 9, 1, dimension - 17);
\r
168 if (versionNumber > 6) {
\r
169 // Version info, top right
\r
170 bitMatrix.setRegion(0, dimension - 11, 6, 3);
\r
171 // Version info, bottom left
\r
172 bitMatrix.setRegion(dimension - 11, 0, 3, 6);
\r
179 * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
\r
180 * use blocks of differing sizes within one version, so, this encapsulates the parameters for
\r
181 * each set of blocks. It also holds the number of error-correction codewords per block since it
\r
182 * will be the same across all blocks within one version.</p>
\r
184 static final class ECBlocks {
\r
185 private int ecCodewords;
\r
186 private ECB[] ecBlocks;
\r
188 private ECBlocks(int ecCodewords, ECB ecBlocks) {
\r
189 this.ecCodewords = ecCodewords;
\r
190 this.ecBlocks = new ECB[]{ecBlocks};
\r
193 private ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) {
\r
194 this.ecCodewords = ecCodewords;
\r
195 this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};
\r
198 int getECCodewords() {
\r
199 return ecCodewords;
\r
202 ECB[] getECBlocks() {
\r
208 * <p>Encapsualtes the parameters for one error-correction block in one symbol version.
\r
209 * This includes the number of data codewords, and the number of times a block with these
\r
210 * parameters is used consecutively in the QR code version's format.</p>
\r
212 static final class ECB {
\r
214 private int dataCodewords;
\r
216 private ECB(int count, int dataCodewords) {
\r
217 this.count = count;
\r
218 this.dataCodewords = dataCodewords;
\r
225 int getDataCodewords() {
\r
226 return dataCodewords;
\r
230 public String toString() {
\r
231 return String.valueOf(versionNumber);
\r
235 * See ISO 18004:2006 6.5.1 Table 9
\r
237 private static Version[] buildVersions() {
\r
238 return new Version[]{
\r
239 new Version(1, new int[]{},
\r
240 new ECBlocks(7, new ECB(1, 19)),
\r
241 new ECBlocks(10, new ECB(1, 16)),
\r
242 new ECBlocks(13, new ECB(1, 13)),
\r
243 new ECBlocks(17, new ECB(1, 9))),
\r
244 new Version(2, new int[]{6, 18},
\r
245 new ECBlocks(10, new ECB(1, 34)),
\r
246 new ECBlocks(16, new ECB(1, 28)),
\r
247 new ECBlocks(22, new ECB(1, 22)),
\r
248 new ECBlocks(28, new ECB(1, 16))),
\r
249 new Version(3, new int[]{6, 22},
\r
250 new ECBlocks(15, new ECB(1, 55)),
\r
251 new ECBlocks(26, new ECB(1, 44)),
\r
252 new ECBlocks(18, new ECB(2, 17)),
\r
253 new ECBlocks(22, new ECB(2, 13))),
\r
254 new Version(4, new int[]{6, 26},
\r
255 new ECBlocks(20, new ECB(1, 80)),
\r
256 new ECBlocks(18, new ECB(2, 32)),
\r
257 new ECBlocks(26, new ECB(2, 24)),
\r
258 new ECBlocks(16, new ECB(4, 9))),
\r
259 new Version(5, new int[]{6, 30},
\r
260 new ECBlocks(26, new ECB(1, 108)),
\r
261 new ECBlocks(24, new ECB(2, 43)),
\r
262 new ECBlocks(18, new ECB(2, 15),
\r
264 new ECBlocks(22, new ECB(2, 11),
\r
266 new Version(6, new int[]{6, 34},
\r
267 new ECBlocks(18, new ECB(2, 68)),
\r
268 new ECBlocks(16, new ECB(4, 27)),
\r
269 new ECBlocks(24, new ECB(4, 19)),
\r
270 new ECBlocks(28, new ECB(4, 15))),
\r
271 new Version(7, new int[]{6, 22, 38},
\r
272 new ECBlocks(20, new ECB(2, 78)),
\r
273 new ECBlocks(18, new ECB(4, 31)),
\r
274 new ECBlocks(18, new ECB(2, 14),
\r
276 new ECBlocks(26, new ECB(4, 13),
\r
278 new Version(8, new int[]{6, 24, 42},
\r
279 new ECBlocks(24, new ECB(2, 97)),
\r
280 new ECBlocks(22, new ECB(2, 38),
\r
282 new ECBlocks(22, new ECB(4, 18),
\r
284 new ECBlocks(26, new ECB(4, 14),
\r
286 new Version(9, new int[]{6, 26, 46},
\r
287 new ECBlocks(30, new ECB(2, 116)),
\r
288 new ECBlocks(22, new ECB(3, 36),
\r
290 new ECBlocks(20, new ECB(4, 16),
\r
292 new ECBlocks(24, new ECB(4, 12),
\r
294 new Version(10, new int[]{6, 28, 50},
\r
295 new ECBlocks(18, new ECB(2, 68),
\r
297 new ECBlocks(26, new ECB(4, 43),
\r
299 new ECBlocks(24, new ECB(6, 19),
\r
301 new ECBlocks(28, new ECB(6, 15),
\r
303 new Version(11, new int[]{6, 30, 54},
\r
304 new ECBlocks(20, new ECB(4, 81)),
\r
305 new ECBlocks(30, new ECB(1, 50),
\r
307 new ECBlocks(28, new ECB(4, 22),
\r
309 new ECBlocks(24, new ECB(3, 12),
\r
311 new Version(12, new int[]{6, 32, 58},
\r
312 new ECBlocks(24, new ECB(2, 92),
\r
314 new ECBlocks(22, new ECB(6, 36),
\r
316 new ECBlocks(26, new ECB(4, 20),
\r
318 new ECBlocks(28, new ECB(7, 14),
\r
320 new Version(13, new int[]{6, 34, 62},
\r
321 new ECBlocks(26, new ECB(4, 107)),
\r
322 new ECBlocks(22, new ECB(8, 37),
\r
324 new ECBlocks(24, new ECB(8, 20),
\r
326 new ECBlocks(22, new ECB(12, 11),
\r
328 new Version(14, new int[]{6, 26, 46, 66},
\r
329 new ECBlocks(30, new ECB(3, 115),
\r
331 new ECBlocks(24, new ECB(4, 40),
\r
333 new ECBlocks(20, new ECB(11, 16),
\r
335 new ECBlocks(24, new ECB(11, 12),
\r
337 new Version(15, new int[]{6, 26, 48, 70},
\r
338 new ECBlocks(22, new ECB(5, 87),
\r
340 new ECBlocks(24, new ECB(5, 41),
\r
342 new ECBlocks(30, new ECB(5, 24),
\r
344 new ECBlocks(24, new ECB(11, 12),
\r
346 new Version(16, new int[]{6, 26, 50, 74},
\r
347 new ECBlocks(24, new ECB(5, 98),
\r
349 new ECBlocks(28, new ECB(7, 45),
\r
351 new ECBlocks(24, new ECB(15, 19),
\r
353 new ECBlocks(30, new ECB(3, 15),
\r
355 new Version(17, new int[]{6, 30, 54, 78},
\r
356 new ECBlocks(28, new ECB(1, 107),
\r
358 new ECBlocks(28, new ECB(10, 46),
\r
360 new ECBlocks(28, new ECB(1, 22),
\r
362 new ECBlocks(28, new ECB(2, 14),
\r
364 new Version(18, new int[]{6, 30, 56, 82},
\r
365 new ECBlocks(30, new ECB(5, 120),
\r
367 new ECBlocks(26, new ECB(9, 43),
\r
369 new ECBlocks(28, new ECB(17, 22),
\r
371 new ECBlocks(28, new ECB(2, 14),
\r
373 new Version(19, new int[]{6, 30, 58, 86},
\r
374 new ECBlocks(28, new ECB(3, 113),
\r
376 new ECBlocks(26, new ECB(3, 44),
\r
378 new ECBlocks(26, new ECB(17, 21),
\r
380 new ECBlocks(26, new ECB(9, 13),
\r
382 new Version(20, new int[]{6, 34, 62, 90},
\r
383 new ECBlocks(28, new ECB(3, 107),
\r
385 new ECBlocks(26, new ECB(3, 41),
\r
387 new ECBlocks(30, new ECB(15, 24),
\r
389 new ECBlocks(28, new ECB(15, 15),
\r
391 new Version(21, new int[]{6, 28, 50, 72, 94},
\r
392 new ECBlocks(28, new ECB(4, 116),
\r
394 new ECBlocks(26, new ECB(17, 42)),
\r
395 new ECBlocks(28, new ECB(17, 22),
\r
397 new ECBlocks(30, new ECB(19, 16),
\r
399 new Version(22, new int[]{6, 26, 50, 74, 98},
\r
400 new ECBlocks(28, new ECB(2, 111),
\r
402 new ECBlocks(28, new ECB(17, 46)),
\r
403 new ECBlocks(30, new ECB(7, 24),
\r
405 new ECBlocks(24, new ECB(34, 13))),
\r
406 new Version(23, new int[]{6, 30, 54, 74, 102},
\r
407 new ECBlocks(30, new ECB(4, 121),
\r
409 new ECBlocks(28, new ECB(4, 47),
\r
411 new ECBlocks(30, new ECB(11, 24),
\r
413 new ECBlocks(30, new ECB(16, 15),
\r
415 new Version(24, new int[]{6, 28, 54, 80, 106},
\r
416 new ECBlocks(30, new ECB(6, 117),
\r
418 new ECBlocks(28, new ECB(6, 45),
\r
420 new ECBlocks(30, new ECB(11, 24),
\r
422 new ECBlocks(30, new ECB(30, 16),
\r
424 new Version(25, new int[]{6, 32, 58, 84, 110},
\r
425 new ECBlocks(26, new ECB(8, 106),
\r
427 new ECBlocks(28, new ECB(8, 47),
\r
429 new ECBlocks(30, new ECB(7, 24),
\r
431 new ECBlocks(30, new ECB(22, 15),
\r
433 new Version(26, new int[]{6, 30, 58, 86, 114},
\r
434 new ECBlocks(28, new ECB(10, 114),
\r
436 new ECBlocks(28, new ECB(19, 46),
\r
438 new ECBlocks(28, new ECB(28, 22),
\r
440 new ECBlocks(30, new ECB(33, 16),
\r
442 new Version(27, new int[]{6, 34, 62, 90, 118},
\r
443 new ECBlocks(30, new ECB(8, 122),
\r
445 new ECBlocks(28, new ECB(22, 45),
\r
447 new ECBlocks(30, new ECB(8, 23),
\r
449 new ECBlocks(30, new ECB(12, 15),
\r
451 new Version(28, new int[]{6, 26, 50, 74, 98, 122},
\r
452 new ECBlocks(30, new ECB(3, 117),
\r
454 new ECBlocks(28, new ECB(3, 45),
\r
456 new ECBlocks(30, new ECB(4, 24),
\r
458 new ECBlocks(30, new ECB(11, 15),
\r
460 new Version(29, new int[]{6, 30, 54, 78, 102, 126},
\r
461 new ECBlocks(30, new ECB(7, 116),
\r
463 new ECBlocks(28, new ECB(21, 45),
\r
465 new ECBlocks(30, new ECB(1, 23),
\r
467 new ECBlocks(30, new ECB(19, 15),
\r
469 new Version(30, new int[]{6, 26, 52, 78, 104, 130},
\r
470 new ECBlocks(30, new ECB(5, 115),
\r
472 new ECBlocks(28, new ECB(19, 47),
\r
474 new ECBlocks(30, new ECB(15, 24),
\r
476 new ECBlocks(30, new ECB(23, 15),
\r
478 new Version(31, new int[]{6, 30, 56, 82, 108, 134},
\r
479 new ECBlocks(30, new ECB(13, 115),
\r
481 new ECBlocks(28, new ECB(2, 46),
\r
483 new ECBlocks(30, new ECB(42, 24),
\r
485 new ECBlocks(30, new ECB(23, 15),
\r
487 new Version(32, new int[]{6, 34, 60, 86, 112, 138},
\r
488 new ECBlocks(30, new ECB(17, 115)),
\r
489 new ECBlocks(28, new ECB(10, 46),
\r
491 new ECBlocks(30, new ECB(10, 24),
\r
493 new ECBlocks(30, new ECB(19, 15),
\r
495 new Version(33, new int[]{6, 30, 58, 86, 114, 142},
\r
496 new ECBlocks(30, new ECB(17, 115),
\r
498 new ECBlocks(28, new ECB(14, 46),
\r
500 new ECBlocks(30, new ECB(29, 24),
\r
502 new ECBlocks(30, new ECB(11, 15),
\r
504 new Version(34, new int[]{6, 34, 62, 90, 118, 146},
\r
505 new ECBlocks(30, new ECB(13, 115),
\r
507 new ECBlocks(28, new ECB(14, 46),
\r
509 new ECBlocks(30, new ECB(44, 24),
\r
511 new ECBlocks(30, new ECB(59, 16),
\r
513 new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150},
\r
514 new ECBlocks(30, new ECB(12, 121),
\r
516 new ECBlocks(28, new ECB(12, 47),
\r
518 new ECBlocks(30, new ECB(39, 24),
\r
520 new ECBlocks(30, new ECB(22, 15),
\r
522 new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154},
\r
523 new ECBlocks(30, new ECB(6, 121),
\r
525 new ECBlocks(28, new ECB(6, 47),
\r
527 new ECBlocks(30, new ECB(46, 24),
\r
529 new ECBlocks(30, new ECB(2, 15),
\r
531 new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158},
\r
532 new ECBlocks(30, new ECB(17, 122),
\r
534 new ECBlocks(28, new ECB(29, 46),
\r
536 new ECBlocks(30, new ECB(49, 24),
\r
538 new ECBlocks(30, new ECB(24, 15),
\r
540 new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162},
\r
541 new ECBlocks(30, new ECB(4, 122),
\r
543 new ECBlocks(28, new ECB(13, 46),
\r
545 new ECBlocks(30, new ECB(48, 24),
\r
547 new ECBlocks(30, new ECB(42, 15),
\r
549 new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166},
\r
550 new ECBlocks(30, new ECB(20, 117),
\r
552 new ECBlocks(28, new ECB(40, 47),
\r
554 new ECBlocks(30, new ECB(43, 24),
\r
556 new ECBlocks(30, new ECB(10, 15),
\r
558 new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170},
\r
559 new ECBlocks(30, new ECB(19, 118),
\r
561 new ECBlocks(28, new ECB(18, 47),
\r
563 new ECBlocks(30, new ECB(34, 24),
\r
565 new ECBlocks(30, new ECB(20, 15),
\r