2 * Copyright 2007 ZXing authors
\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
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 = {
\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 int ecCodewords = ecBlocks1.getECCodewordsPerBlock();
\r
61 ECB[] ecbArray = ecBlocks1.getECBlocks();
\r
62 for (int i = 0; i < ecbArray.length; i++) {
\r
63 ECB ecBlock = ecbArray[i];
\r
64 total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords);
\r
66 this.totalCodewords = total;
\r
69 public int getVersionNumber() {
\r
70 return versionNumber;
\r
73 public int[] getAlignmentPatternCenters() {
\r
74 return alignmentPatternCenters;
\r
77 public int getTotalCodewords() {
\r
78 return totalCodewords;
\r
81 public int getDimensionForVersion() {
\r
82 return 17 + 4 * versionNumber;
\r
85 public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {
\r
86 return ecBlocks[ecLevel.ordinal()];
\r
90 * <p>Deduces version information purely from QR Code dimensions.</p>
\r
92 * @param dimension dimension in modules
\r
93 * @return {@link Version} for a QR Code of that dimension
\r
94 * @throws ReaderException if dimension is not 1 mod 4
\r
96 public static Version getProvisionalVersionForDimension(int dimension) throws ReaderException {
\r
97 if (dimension % 4 != 1) {
\r
98 throw ReaderException.getInstance();
\r
100 return getVersionForNumber((dimension - 17) >> 2);
\r
103 public static Version getVersionForNumber(int versionNumber) {
\r
104 if (versionNumber < 1 || versionNumber > 40) {
\r
105 throw new IllegalArgumentException();
\r
107 return VERSIONS[versionNumber - 1];
\r
110 static Version decodeVersionInformation(int versionBits) {
\r
111 int bestDifference = Integer.MAX_VALUE;
\r
112 int bestVersion = 0;
\r
113 for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {
\r
114 int targetVersion = VERSION_DECODE_INFO[i];
\r
115 // Do the version info bits match exactly? done.
\r
116 if (targetVersion == versionBits) {
\r
117 return getVersionForNumber(i + 7);
\r
119 // Otherwise see if this is the closest to a real version info bit string
\r
120 // we have seen so far
\r
121 int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
\r
122 if (bitsDifference < bestDifference) {
\r
123 bestVersion = i + 7;
\r
124 bestDifference = bitsDifference;
\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 public static final class ECBlocks {
\r
185 private final int ecCodewordsPerBlock;
\r
186 private final ECB[] ecBlocks;
\r
188 private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) {
\r
189 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
190 this.ecBlocks = new ECB[]{ecBlocks};
\r
193 private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) {
\r
194 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
195 this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};
\r
198 public int getECCodewordsPerBlock() {
\r
199 return ecCodewordsPerBlock;
\r
202 public int getNumBlocks() {
\r
204 for (int i = 0; i < ecBlocks.length; i++) {
\r
205 total += ecBlocks[i].getCount();
\r
210 public int getTotalECCodewords() {
\r
211 return ecCodewordsPerBlock * getNumBlocks();
\r
214 public ECB[] getECBlocks() {
\r
220 * <p>Encapsualtes the parameters for one error-correction block in one symbol version.
\r
221 * This includes the number of data codewords, and the number of times a block with these
\r
222 * parameters is used consecutively in the QR code version's format.</p>
\r
224 public static final class ECB {
\r
225 private final int count;
\r
226 private final int dataCodewords;
\r
228 ECB(int count, int dataCodewords) {
\r
229 this.count = count;
\r
230 this.dataCodewords = dataCodewords;
\r
233 public int getCount() {
\r
237 public int getDataCodewords() {
\r
238 return dataCodewords;
\r
242 public String toString() {
\r
243 return String.valueOf(versionNumber);
\r
247 * See ISO 18004:2006 6.5.1 Table 9
\r
249 private static Version[] buildVersions() {
\r
250 return new Version[]{
\r
251 new Version(1, new int[]{},
\r
252 new ECBlocks(7, new ECB(1, 19)),
\r
253 new ECBlocks(10, new ECB(1, 16)),
\r
254 new ECBlocks(13, new ECB(1, 13)),
\r
255 new ECBlocks(17, new ECB(1, 9))),
\r
256 new Version(2, new int[]{6, 18},
\r
257 new ECBlocks(10, new ECB(1, 34)),
\r
258 new ECBlocks(16, new ECB(1, 28)),
\r
259 new ECBlocks(22, new ECB(1, 22)),
\r
260 new ECBlocks(28, new ECB(1, 16))),
\r
261 new Version(3, new int[]{6, 22},
\r
262 new ECBlocks(15, new ECB(1, 55)),
\r
263 new ECBlocks(26, new ECB(1, 44)),
\r
264 new ECBlocks(18, new ECB(2, 17)),
\r
265 new ECBlocks(22, new ECB(2, 13))),
\r
266 new Version(4, new int[]{6, 26},
\r
267 new ECBlocks(20, new ECB(1, 80)),
\r
268 new ECBlocks(18, new ECB(2, 32)),
\r
269 new ECBlocks(26, new ECB(2, 24)),
\r
270 new ECBlocks(16, new ECB(4, 9))),
\r
271 new Version(5, new int[]{6, 30},
\r
272 new ECBlocks(26, new ECB(1, 108)),
\r
273 new ECBlocks(24, new ECB(2, 43)),
\r
274 new ECBlocks(18, new ECB(2, 15),
\r
276 new ECBlocks(22, new ECB(2, 11),
\r
278 new Version(6, new int[]{6, 34},
\r
279 new ECBlocks(18, new ECB(2, 68)),
\r
280 new ECBlocks(16, new ECB(4, 27)),
\r
281 new ECBlocks(24, new ECB(4, 19)),
\r
282 new ECBlocks(28, new ECB(4, 15))),
\r
283 new Version(7, new int[]{6, 22, 38},
\r
284 new ECBlocks(20, new ECB(2, 78)),
\r
285 new ECBlocks(18, new ECB(4, 31)),
\r
286 new ECBlocks(18, new ECB(2, 14),
\r
288 new ECBlocks(26, new ECB(4, 13),
\r
290 new Version(8, new int[]{6, 24, 42},
\r
291 new ECBlocks(24, new ECB(2, 97)),
\r
292 new ECBlocks(22, new ECB(2, 38),
\r
294 new ECBlocks(22, new ECB(4, 18),
\r
296 new ECBlocks(26, new ECB(4, 14),
\r
298 new Version(9, new int[]{6, 26, 46},
\r
299 new ECBlocks(30, new ECB(2, 116)),
\r
300 new ECBlocks(22, new ECB(3, 36),
\r
302 new ECBlocks(20, new ECB(4, 16),
\r
304 new ECBlocks(24, new ECB(4, 12),
\r
306 new Version(10, new int[]{6, 28, 50},
\r
307 new ECBlocks(18, new ECB(2, 68),
\r
309 new ECBlocks(26, new ECB(4, 43),
\r
311 new ECBlocks(24, new ECB(6, 19),
\r
313 new ECBlocks(28, new ECB(6, 15),
\r
315 new Version(11, new int[]{6, 30, 54},
\r
316 new ECBlocks(20, new ECB(4, 81)),
\r
317 new ECBlocks(30, new ECB(1, 50),
\r
319 new ECBlocks(28, new ECB(4, 22),
\r
321 new ECBlocks(24, new ECB(3, 12),
\r
323 new Version(12, new int[]{6, 32, 58},
\r
324 new ECBlocks(24, new ECB(2, 92),
\r
326 new ECBlocks(22, new ECB(6, 36),
\r
328 new ECBlocks(26, new ECB(4, 20),
\r
330 new ECBlocks(28, new ECB(7, 14),
\r
332 new Version(13, new int[]{6, 34, 62},
\r
333 new ECBlocks(26, new ECB(4, 107)),
\r
334 new ECBlocks(22, new ECB(8, 37),
\r
336 new ECBlocks(24, new ECB(8, 20),
\r
338 new ECBlocks(22, new ECB(12, 11),
\r
340 new Version(14, new int[]{6, 26, 46, 66},
\r
341 new ECBlocks(30, new ECB(3, 115),
\r
343 new ECBlocks(24, new ECB(4, 40),
\r
345 new ECBlocks(20, new ECB(11, 16),
\r
347 new ECBlocks(24, new ECB(11, 12),
\r
349 new Version(15, new int[]{6, 26, 48, 70},
\r
350 new ECBlocks(22, new ECB(5, 87),
\r
352 new ECBlocks(24, new ECB(5, 41),
\r
354 new ECBlocks(30, new ECB(5, 24),
\r
356 new ECBlocks(24, new ECB(11, 12),
\r
358 new Version(16, new int[]{6, 26, 50, 74},
\r
359 new ECBlocks(24, new ECB(5, 98),
\r
361 new ECBlocks(28, new ECB(7, 45),
\r
363 new ECBlocks(24, new ECB(15, 19),
\r
365 new ECBlocks(30, new ECB(3, 15),
\r
367 new Version(17, new int[]{6, 30, 54, 78},
\r
368 new ECBlocks(28, new ECB(1, 107),
\r
370 new ECBlocks(28, new ECB(10, 46),
\r
372 new ECBlocks(28, new ECB(1, 22),
\r
374 new ECBlocks(28, new ECB(2, 14),
\r
376 new Version(18, new int[]{6, 30, 56, 82},
\r
377 new ECBlocks(30, new ECB(5, 120),
\r
379 new ECBlocks(26, new ECB(9, 43),
\r
381 new ECBlocks(28, new ECB(17, 22),
\r
383 new ECBlocks(28, new ECB(2, 14),
\r
385 new Version(19, new int[]{6, 30, 58, 86},
\r
386 new ECBlocks(28, new ECB(3, 113),
\r
388 new ECBlocks(26, new ECB(3, 44),
\r
390 new ECBlocks(26, new ECB(17, 21),
\r
392 new ECBlocks(26, new ECB(9, 13),
\r
394 new Version(20, new int[]{6, 34, 62, 90},
\r
395 new ECBlocks(28, new ECB(3, 107),
\r
397 new ECBlocks(26, new ECB(3, 41),
\r
399 new ECBlocks(30, new ECB(15, 24),
\r
401 new ECBlocks(28, new ECB(15, 15),
\r
403 new Version(21, new int[]{6, 28, 50, 72, 94},
\r
404 new ECBlocks(28, new ECB(4, 116),
\r
406 new ECBlocks(26, new ECB(17, 42)),
\r
407 new ECBlocks(28, new ECB(17, 22),
\r
409 new ECBlocks(30, new ECB(19, 16),
\r
411 new Version(22, new int[]{6, 26, 50, 74, 98},
\r
412 new ECBlocks(28, new ECB(2, 111),
\r
414 new ECBlocks(28, new ECB(17, 46)),
\r
415 new ECBlocks(30, new ECB(7, 24),
\r
417 new ECBlocks(24, new ECB(34, 13))),
\r
418 new Version(23, new int[]{6, 30, 54, 74, 102},
\r
419 new ECBlocks(30, new ECB(4, 121),
\r
421 new ECBlocks(28, new ECB(4, 47),
\r
423 new ECBlocks(30, new ECB(11, 24),
\r
425 new ECBlocks(30, new ECB(16, 15),
\r
427 new Version(24, new int[]{6, 28, 54, 80, 106},
\r
428 new ECBlocks(30, new ECB(6, 117),
\r
430 new ECBlocks(28, new ECB(6, 45),
\r
432 new ECBlocks(30, new ECB(11, 24),
\r
434 new ECBlocks(30, new ECB(30, 16),
\r
436 new Version(25, new int[]{6, 32, 58, 84, 110},
\r
437 new ECBlocks(26, new ECB(8, 106),
\r
439 new ECBlocks(28, new ECB(8, 47),
\r
441 new ECBlocks(30, new ECB(7, 24),
\r
443 new ECBlocks(30, new ECB(22, 15),
\r
445 new Version(26, new int[]{6, 30, 58, 86, 114},
\r
446 new ECBlocks(28, new ECB(10, 114),
\r
448 new ECBlocks(28, new ECB(19, 46),
\r
450 new ECBlocks(28, new ECB(28, 22),
\r
452 new ECBlocks(30, new ECB(33, 16),
\r
454 new Version(27, new int[]{6, 34, 62, 90, 118},
\r
455 new ECBlocks(30, new ECB(8, 122),
\r
457 new ECBlocks(28, new ECB(22, 45),
\r
459 new ECBlocks(30, new ECB(8, 23),
\r
461 new ECBlocks(30, new ECB(12, 15),
\r
463 new Version(28, new int[]{6, 26, 50, 74, 98, 122},
\r
464 new ECBlocks(30, new ECB(3, 117),
\r
466 new ECBlocks(28, new ECB(3, 45),
\r
468 new ECBlocks(30, new ECB(4, 24),
\r
470 new ECBlocks(30, new ECB(11, 15),
\r
472 new Version(29, new int[]{6, 30, 54, 78, 102, 126},
\r
473 new ECBlocks(30, new ECB(7, 116),
\r
475 new ECBlocks(28, new ECB(21, 45),
\r
477 new ECBlocks(30, new ECB(1, 23),
\r
479 new ECBlocks(30, new ECB(19, 15),
\r
481 new Version(30, new int[]{6, 26, 52, 78, 104, 130},
\r
482 new ECBlocks(30, new ECB(5, 115),
\r
484 new ECBlocks(28, new ECB(19, 47),
\r
486 new ECBlocks(30, new ECB(15, 24),
\r
488 new ECBlocks(30, new ECB(23, 15),
\r
490 new Version(31, new int[]{6, 30, 56, 82, 108, 134},
\r
491 new ECBlocks(30, new ECB(13, 115),
\r
493 new ECBlocks(28, new ECB(2, 46),
\r
495 new ECBlocks(30, new ECB(42, 24),
\r
497 new ECBlocks(30, new ECB(23, 15),
\r
499 new Version(32, new int[]{6, 34, 60, 86, 112, 138},
\r
500 new ECBlocks(30, new ECB(17, 115)),
\r
501 new ECBlocks(28, new ECB(10, 46),
\r
503 new ECBlocks(30, new ECB(10, 24),
\r
505 new ECBlocks(30, new ECB(19, 15),
\r
507 new Version(33, new int[]{6, 30, 58, 86, 114, 142},
\r
508 new ECBlocks(30, new ECB(17, 115),
\r
510 new ECBlocks(28, new ECB(14, 46),
\r
512 new ECBlocks(30, new ECB(29, 24),
\r
514 new ECBlocks(30, new ECB(11, 15),
\r
516 new Version(34, new int[]{6, 34, 62, 90, 118, 146},
\r
517 new ECBlocks(30, new ECB(13, 115),
\r
519 new ECBlocks(28, new ECB(14, 46),
\r
521 new ECBlocks(30, new ECB(44, 24),
\r
523 new ECBlocks(30, new ECB(59, 16),
\r
525 new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150},
\r
526 new ECBlocks(30, new ECB(12, 121),
\r
528 new ECBlocks(28, new ECB(12, 47),
\r
530 new ECBlocks(30, new ECB(39, 24),
\r
532 new ECBlocks(30, new ECB(22, 15),
\r
534 new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154},
\r
535 new ECBlocks(30, new ECB(6, 121),
\r
537 new ECBlocks(28, new ECB(6, 47),
\r
539 new ECBlocks(30, new ECB(46, 24),
\r
541 new ECBlocks(30, new ECB(2, 15),
\r
543 new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158},
\r
544 new ECBlocks(30, new ECB(17, 122),
\r
546 new ECBlocks(28, new ECB(29, 46),
\r
548 new ECBlocks(30, new ECB(49, 24),
\r
550 new ECBlocks(30, new ECB(24, 15),
\r
552 new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162},
\r
553 new ECBlocks(30, new ECB(4, 122),
\r
555 new ECBlocks(28, new ECB(13, 46),
\r
557 new ECBlocks(30, new ECB(48, 24),
\r
559 new ECBlocks(30, new ECB(42, 15),
\r
561 new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166},
\r
562 new ECBlocks(30, new ECB(20, 117),
\r
564 new ECBlocks(28, new ECB(40, 47),
\r
566 new ECBlocks(30, new ECB(43, 24),
\r
568 new ECBlocks(30, new ECB(10, 15),
\r
570 new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170},
\r
571 new ECBlocks(30, new ECB(19, 118),
\r
573 new ECBlocks(28, new ECB(18, 47),
\r
575 new ECBlocks(30, new ECB(34, 24),
\r
577 new ECBlocks(30, new ECB(20, 15),
\r