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
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 = {
\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.getECCodewords();
\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 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 new ReaderException("Dimension must be 1 mod 4");
\r
100 return getVersionForNumber((dimension - 17) >> 2);
\r
103 public static Version getVersionForNumber(int versionNumber) throws ReaderException {
\r
104 if (versionNumber < 1 || versionNumber > 40) {
\r
105 throw new ReaderException("versionNumber must be between 1 and 40");
\r
107 return VERSIONS[versionNumber - 1];
\r
110 static Version decodeVersionInformation(int versionBits) throws ReaderException {
\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
126 // We can tolerate up to 3 bits of error since no two version info codewords will
\r
127 // differ in less than 4 bits.
\r
128 if (bestDifference <= 3) {
\r
129 return getVersionForNumber(bestVersion);
\r
131 // If we didn't find a close enough match, fail
\r
136 * See ISO 18004:2006 Annex E
\r
138 BitMatrix buildFunctionPattern() {
\r
139 int dimension = getDimensionForVersion();
\r
140 BitMatrix bitMatrix = new BitMatrix(dimension);
\r
142 // Top left finder pattern + separator + format
\r
143 bitMatrix.setRegion(0, 0, 9, 9);
\r
144 // Top right finder pattern + separator + format
\r
145 bitMatrix.setRegion(0, dimension - 8, 9, 8);
\r
146 // Bottom left finder pattern + separator + format
\r
147 bitMatrix.setRegion(dimension - 8, 0, 8, 9);
\r
149 // Alignment patterns
\r
150 int max = alignmentPatternCenters.length;
\r
151 for (int x = 0; x < max; x++) {
\r
152 int i = alignmentPatternCenters[x] - 2;
\r
153 for (int y = 0; y < max; y++) {
\r
154 if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
\r
155 // No alignment patterns near the three finder paterns
\r
158 bitMatrix.setRegion(i, alignmentPatternCenters[y] - 2, 5, 5);
\r
162 // Vertical timing pattern
\r
163 bitMatrix.setRegion(9, 6, dimension - 17, 1);
\r
164 // Horizontal timing pattern
\r
165 bitMatrix.setRegion(6, 9, 1, dimension - 17);
\r
167 if (versionNumber > 6) {
\r
168 // Version info, top right
\r
169 bitMatrix.setRegion(0, dimension - 11, 6, 3);
\r
170 // Version info, bottom left
\r
171 bitMatrix.setRegion(dimension - 11, 0, 3, 6);
\r
178 * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
\r
179 * use blocks of differing sizes within one version, so, this encapsulates the parameters for
\r
180 * each set of blocks. It also holds the number of error-correction codewords per block since it
\r
181 * will be the same across all blocks within one version.</p>
\r
183 static final class ECBlocks {
\r
184 private final int ecCodewords;
\r
185 private final ECB[] ecBlocks;
\r
187 private ECBlocks(int ecCodewords, ECB ecBlocks) {
\r
188 this.ecCodewords = ecCodewords;
\r
189 this.ecBlocks = new ECB[]{ecBlocks};
\r
192 private ECBlocks(int ecCodewords, ECB ecBlocks1, ECB ecBlocks2) {
\r
193 this.ecCodewords = ecCodewords;
\r
194 this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};
\r
197 int getECCodewords() {
\r
198 return ecCodewords;
\r
201 ECB[] getECBlocks() {
\r
207 * <p>Encapsualtes the parameters for one error-correction block in one symbol version.
\r
208 * This includes the number of data codewords, and the number of times a block with these
\r
209 * parameters is used consecutively in the QR code version's format.</p>
\r
211 static final class ECB {
\r
213 final int dataCodewords;
\r
215 ECB(int count, int dataCodewords) {
\r
216 this.count = count;
\r
217 this.dataCodewords = dataCodewords;
\r
224 int getDataCodewords() {
\r
225 return dataCodewords;
\r
229 public String toString() {
\r
230 return String.valueOf(versionNumber);
\r
234 * See ISO 18004:2006 6.5.1 Table 9
\r
236 private static Version[] buildVersions() {
\r
237 return new Version[]{
\r
238 new Version(1, new int[]{},
\r
239 new ECBlocks(7, new ECB(1, 19)),
\r
240 new ECBlocks(10, new ECB(1, 16)),
\r
241 new ECBlocks(13, new ECB(1, 13)),
\r
242 new ECBlocks(17, new ECB(1, 9))),
\r
243 new Version(2, new int[]{6, 18},
\r
244 new ECBlocks(10, new ECB(1, 34)),
\r
245 new ECBlocks(16, new ECB(1, 28)),
\r
246 new ECBlocks(22, new ECB(1, 22)),
\r
247 new ECBlocks(28, new ECB(1, 16))),
\r
248 new Version(3, new int[]{6, 22},
\r
249 new ECBlocks(15, new ECB(1, 55)),
\r
250 new ECBlocks(26, new ECB(1, 44)),
\r
251 new ECBlocks(18, new ECB(2, 17)),
\r
252 new ECBlocks(22, new ECB(2, 13))),
\r
253 new Version(4, new int[]{6, 26},
\r
254 new ECBlocks(20, new ECB(1, 80)),
\r
255 new ECBlocks(18, new ECB(2, 32)),
\r
256 new ECBlocks(26, new ECB(2, 24)),
\r
257 new ECBlocks(16, new ECB(4, 9))),
\r
258 new Version(5, new int[]{6, 30},
\r
259 new ECBlocks(26, new ECB(1, 108)),
\r
260 new ECBlocks(24, new ECB(2, 43)),
\r
261 new ECBlocks(18, new ECB(2, 15),
\r
263 new ECBlocks(22, new ECB(2, 11),
\r
265 new Version(6, new int[]{6, 34},
\r
266 new ECBlocks(18, new ECB(2, 68)),
\r
267 new ECBlocks(16, new ECB(4, 27)),
\r
268 new ECBlocks(24, new ECB(4, 19)),
\r
269 new ECBlocks(28, new ECB(4, 15))),
\r
270 new Version(7, new int[]{6, 22, 38},
\r
271 new ECBlocks(20, new ECB(2, 78)),
\r
272 new ECBlocks(18, new ECB(4, 31)),
\r
273 new ECBlocks(18, new ECB(2, 14),
\r
275 new ECBlocks(26, new ECB(4, 13),
\r
277 new Version(8, new int[]{6, 24, 42},
\r
278 new ECBlocks(24, new ECB(2, 97)),
\r
279 new ECBlocks(22, new ECB(2, 38),
\r
281 new ECBlocks(22, new ECB(4, 18),
\r
283 new ECBlocks(26, new ECB(4, 14),
\r
285 new Version(9, new int[]{6, 26, 46},
\r
286 new ECBlocks(30, new ECB(2, 116)),
\r
287 new ECBlocks(22, new ECB(3, 36),
\r
289 new ECBlocks(20, new ECB(4, 16),
\r
291 new ECBlocks(24, new ECB(4, 12),
\r
293 new Version(10, new int[]{6, 28, 50},
\r
294 new ECBlocks(18, new ECB(2, 68),
\r
296 new ECBlocks(26, new ECB(4, 43),
\r
298 new ECBlocks(24, new ECB(6, 19),
\r
300 new ECBlocks(28, new ECB(6, 15),
\r
302 new Version(11, new int[]{6, 30, 54},
\r
303 new ECBlocks(20, new ECB(4, 81)),
\r
304 new ECBlocks(30, new ECB(1, 50),
\r
306 new ECBlocks(28, new ECB(4, 22),
\r
308 new ECBlocks(24, new ECB(3, 12),
\r
310 new Version(12, new int[]{6, 32, 58},
\r
311 new ECBlocks(24, new ECB(2, 92),
\r
313 new ECBlocks(22, new ECB(6, 36),
\r
315 new ECBlocks(26, new ECB(4, 20),
\r
317 new ECBlocks(28, new ECB(7, 14),
\r
319 new Version(13, new int[]{6, 34, 62},
\r
320 new ECBlocks(26, new ECB(4, 107)),
\r
321 new ECBlocks(22, new ECB(8, 37),
\r
323 new ECBlocks(24, new ECB(8, 20),
\r
325 new ECBlocks(22, new ECB(12, 11),
\r
327 new Version(14, new int[]{6, 26, 46, 66},
\r
328 new ECBlocks(30, new ECB(3, 115),
\r
330 new ECBlocks(24, new ECB(4, 40),
\r
332 new ECBlocks(20, new ECB(11, 16),
\r
334 new ECBlocks(24, new ECB(11, 12),
\r
336 new Version(15, new int[]{6, 26, 48, 70},
\r
337 new ECBlocks(22, new ECB(5, 87),
\r
339 new ECBlocks(24, new ECB(5, 41),
\r
341 new ECBlocks(30, new ECB(5, 24),
\r
343 new ECBlocks(24, new ECB(11, 12),
\r
345 new Version(16, new int[]{6, 26, 50, 74},
\r
346 new ECBlocks(24, new ECB(5, 98),
\r
348 new ECBlocks(28, new ECB(7, 45),
\r
350 new ECBlocks(24, new ECB(15, 19),
\r
352 new ECBlocks(30, new ECB(3, 15),
\r
354 new Version(17, new int[]{6, 30, 54, 78},
\r
355 new ECBlocks(28, new ECB(1, 107),
\r
357 new ECBlocks(28, new ECB(10, 46),
\r
359 new ECBlocks(28, new ECB(1, 22),
\r
361 new ECBlocks(28, new ECB(2, 14),
\r
363 new Version(18, new int[]{6, 30, 56, 82},
\r
364 new ECBlocks(30, new ECB(5, 120),
\r
366 new ECBlocks(26, new ECB(9, 43),
\r
368 new ECBlocks(28, new ECB(17, 22),
\r
370 new ECBlocks(28, new ECB(2, 14),
\r
372 new Version(19, new int[]{6, 30, 58, 86},
\r
373 new ECBlocks(28, new ECB(3, 113),
\r
375 new ECBlocks(26, new ECB(3, 44),
\r
377 new ECBlocks(26, new ECB(17, 21),
\r
379 new ECBlocks(26, new ECB(9, 13),
\r
381 new Version(20, new int[]{6, 34, 62, 90},
\r
382 new ECBlocks(28, new ECB(3, 107),
\r
384 new ECBlocks(26, new ECB(3, 41),
\r
386 new ECBlocks(30, new ECB(15, 24),
\r
388 new ECBlocks(28, new ECB(15, 15),
\r
390 new Version(21, new int[]{6, 28, 50, 72, 94},
\r
391 new ECBlocks(28, new ECB(4, 116),
\r
393 new ECBlocks(26, new ECB(17, 42)),
\r
394 new ECBlocks(28, new ECB(17, 22),
\r
396 new ECBlocks(30, new ECB(19, 16),
\r
398 new Version(22, new int[]{6, 26, 50, 74, 98},
\r
399 new ECBlocks(28, new ECB(2, 111),
\r
401 new ECBlocks(28, new ECB(17, 46)),
\r
402 new ECBlocks(30, new ECB(7, 24),
\r
404 new ECBlocks(24, new ECB(34, 13))),
\r
405 new Version(23, new int[]{6, 30, 54, 74, 102},
\r
406 new ECBlocks(30, new ECB(4, 121),
\r
408 new ECBlocks(28, new ECB(4, 47),
\r
410 new ECBlocks(30, new ECB(11, 24),
\r
412 new ECBlocks(30, new ECB(16, 15),
\r
414 new Version(24, new int[]{6, 28, 54, 80, 106},
\r
415 new ECBlocks(30, new ECB(6, 117),
\r
417 new ECBlocks(28, new ECB(6, 45),
\r
419 new ECBlocks(30, new ECB(11, 24),
\r
421 new ECBlocks(30, new ECB(30, 16),
\r
423 new Version(25, new int[]{6, 32, 58, 84, 110},
\r
424 new ECBlocks(26, new ECB(8, 106),
\r
426 new ECBlocks(28, new ECB(8, 47),
\r
428 new ECBlocks(30, new ECB(7, 24),
\r
430 new ECBlocks(30, new ECB(22, 15),
\r
432 new Version(26, new int[]{6, 30, 58, 86, 114},
\r
433 new ECBlocks(28, new ECB(10, 114),
\r
435 new ECBlocks(28, new ECB(19, 46),
\r
437 new ECBlocks(28, new ECB(28, 22),
\r
439 new ECBlocks(30, new ECB(33, 16),
\r
441 new Version(27, new int[]{6, 34, 62, 90, 118},
\r
442 new ECBlocks(30, new ECB(8, 122),
\r
444 new ECBlocks(28, new ECB(22, 45),
\r
446 new ECBlocks(30, new ECB(8, 23),
\r
448 new ECBlocks(30, new ECB(12, 15),
\r
450 new Version(28, new int[]{6, 26, 50, 74, 98, 122},
\r
451 new ECBlocks(30, new ECB(3, 117),
\r
453 new ECBlocks(28, new ECB(3, 45),
\r
455 new ECBlocks(30, new ECB(4, 24),
\r
457 new ECBlocks(30, new ECB(11, 15),
\r
459 new Version(29, new int[]{6, 30, 54, 78, 102, 126},
\r
460 new ECBlocks(30, new ECB(7, 116),
\r
462 new ECBlocks(28, new ECB(21, 45),
\r
464 new ECBlocks(30, new ECB(1, 23),
\r
466 new ECBlocks(30, new ECB(19, 15),
\r
468 new Version(30, new int[]{6, 26, 52, 78, 104, 130},
\r
469 new ECBlocks(30, new ECB(5, 115),
\r
471 new ECBlocks(28, new ECB(19, 47),
\r
473 new ECBlocks(30, new ECB(15, 24),
\r
475 new ECBlocks(30, new ECB(23, 15),
\r
477 new Version(31, new int[]{6, 30, 56, 82, 108, 134},
\r
478 new ECBlocks(30, new ECB(13, 115),
\r
480 new ECBlocks(28, new ECB(2, 46),
\r
482 new ECBlocks(30, new ECB(42, 24),
\r
484 new ECBlocks(30, new ECB(23, 15),
\r
486 new Version(32, new int[]{6, 34, 60, 86, 112, 138},
\r
487 new ECBlocks(30, new ECB(17, 115)),
\r
488 new ECBlocks(28, new ECB(10, 46),
\r
490 new ECBlocks(30, new ECB(10, 24),
\r
492 new ECBlocks(30, new ECB(19, 15),
\r
494 new Version(33, new int[]{6, 30, 58, 86, 114, 142},
\r
495 new ECBlocks(30, new ECB(17, 115),
\r
497 new ECBlocks(28, new ECB(14, 46),
\r
499 new ECBlocks(30, new ECB(29, 24),
\r
501 new ECBlocks(30, new ECB(11, 15),
\r
503 new Version(34, new int[]{6, 34, 62, 90, 118, 146},
\r
504 new ECBlocks(30, new ECB(13, 115),
\r
506 new ECBlocks(28, new ECB(14, 46),
\r
508 new ECBlocks(30, new ECB(44, 24),
\r
510 new ECBlocks(30, new ECB(59, 16),
\r
512 new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150},
\r
513 new ECBlocks(30, new ECB(12, 121),
\r
515 new ECBlocks(28, new ECB(12, 47),
\r
517 new ECBlocks(30, new ECB(39, 24),
\r
519 new ECBlocks(30, new ECB(22, 15),
\r
521 new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154},
\r
522 new ECBlocks(30, new ECB(6, 121),
\r
524 new ECBlocks(28, new ECB(6, 47),
\r
526 new ECBlocks(30, new ECB(46, 24),
\r
528 new ECBlocks(30, new ECB(2, 15),
\r
530 new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158},
\r
531 new ECBlocks(30, new ECB(17, 122),
\r
533 new ECBlocks(28, new ECB(29, 46),
\r
535 new ECBlocks(30, new ECB(49, 24),
\r
537 new ECBlocks(30, new ECB(24, 15),
\r
539 new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162},
\r
540 new ECBlocks(30, new ECB(4, 122),
\r
542 new ECBlocks(28, new ECB(13, 46),
\r
544 new ECBlocks(30, new ECB(48, 24),
\r
546 new ECBlocks(30, new ECB(42, 15),
\r
548 new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166},
\r
549 new ECBlocks(30, new ECB(20, 117),
\r
551 new ECBlocks(28, new ECB(40, 47),
\r
553 new ECBlocks(30, new ECB(43, 24),
\r
555 new ECBlocks(30, new ECB(10, 15),
\r
557 new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170},
\r
558 new ECBlocks(30, new ECB(19, 118),
\r
560 new ECBlocks(28, new ECB(18, 47),
\r
562 new ECBlocks(30, new ECB(34, 24),
\r
564 new ECBlocks(30, new ECB(20, 15),
\r