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.FormatException;
\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 FormatException if dimension is not 1 mod 4
\r
96 public static Version getProvisionalVersionForDimension(int dimension) throws FormatException {
\r
97 if (dimension % 4 != 1) {
\r
98 throw FormatException.getFormatInstance();
\r
101 return getVersionForNumber((dimension - 17) >> 2);
\r
102 } catch (IllegalArgumentException iae) {
\r
103 throw FormatException.getFormatInstance();
\r
107 public static Version getVersionForNumber(int versionNumber) {
\r
108 if (versionNumber < 1 || versionNumber > 40) {
\r
109 throw new IllegalArgumentException();
\r
111 return VERSIONS[versionNumber - 1];
\r
114 static Version decodeVersionInformation(int versionBits) {
\r
115 int bestDifference = Integer.MAX_VALUE;
\r
116 int bestVersion = 0;
\r
117 for (int i = 0; i < VERSION_DECODE_INFO.length; i++) {
\r
118 int targetVersion = VERSION_DECODE_INFO[i];
\r
119 // Do the version info bits match exactly? done.
\r
120 if (targetVersion == versionBits) {
\r
121 return getVersionForNumber(i + 7);
\r
123 // Otherwise see if this is the closest to a real version info bit string
\r
124 // we have seen so far
\r
125 int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
\r
126 if (bitsDifference < bestDifference) {
\r
127 bestVersion = i + 7;
\r
128 bestDifference = bitsDifference;
\r
131 // We can tolerate up to 3 bits of error since no two version info codewords will
\r
132 // differ in less than 4 bits.
\r
133 if (bestDifference <= 3) {
\r
134 return getVersionForNumber(bestVersion);
\r
136 // If we didn't find a close enough match, fail
\r
141 * See ISO 18004:2006 Annex E
\r
143 BitMatrix buildFunctionPattern() {
\r
144 int dimension = getDimensionForVersion();
\r
145 BitMatrix bitMatrix = new BitMatrix(dimension);
\r
147 // Top left finder pattern + separator + format
\r
148 bitMatrix.setRegion(0, 0, 9, 9);
\r
149 // Top right finder pattern + separator + format
\r
150 bitMatrix.setRegion(dimension - 8, 0, 8, 9);
\r
151 // Bottom left finder pattern + separator + format
\r
152 bitMatrix.setRegion(0, dimension - 8, 9, 8);
\r
154 // Alignment patterns
\r
155 int max = alignmentPatternCenters.length;
\r
156 for (int x = 0; x < max; x++) {
\r
157 int i = alignmentPatternCenters[x] - 2;
\r
158 for (int y = 0; y < max; y++) {
\r
159 if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
\r
160 // No alignment patterns near the three finder paterns
\r
163 bitMatrix.setRegion(alignmentPatternCenters[y] - 2, i, 5, 5);
\r
167 // Vertical timing pattern
\r
168 bitMatrix.setRegion(6, 9, 1, dimension - 17);
\r
169 // Horizontal timing pattern
\r
170 bitMatrix.setRegion(9, 6, dimension - 17, 1);
\r
172 if (versionNumber > 6) {
\r
173 // Version info, top right
\r
174 bitMatrix.setRegion(dimension - 11, 0, 3, 6);
\r
175 // Version info, bottom left
\r
176 bitMatrix.setRegion(0, dimension - 11, 6, 3);
\r
183 * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
\r
184 * use blocks of differing sizes within one version, so, this encapsulates the parameters for
\r
185 * each set of blocks. It also holds the number of error-correction codewords per block since it
\r
186 * will be the same across all blocks within one version.</p>
\r
188 public static final class ECBlocks {
\r
189 private final int ecCodewordsPerBlock;
\r
190 private final ECB[] ecBlocks;
\r
192 ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) {
\r
193 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
194 this.ecBlocks = new ECB[]{ecBlocks};
\r
197 ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) {
\r
198 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
199 this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};
\r
202 public int getECCodewordsPerBlock() {
\r
203 return ecCodewordsPerBlock;
\r
206 public int getNumBlocks() {
\r
208 for (int i = 0; i < ecBlocks.length; i++) {
\r
209 total += ecBlocks[i].getCount();
\r
214 public int getTotalECCodewords() {
\r
215 return ecCodewordsPerBlock * getNumBlocks();
\r
218 public ECB[] getECBlocks() {
\r
224 * <p>Encapsualtes the parameters for one error-correction block in one symbol version.
\r
225 * This includes the number of data codewords, and the number of times a block with these
\r
226 * parameters is used consecutively in the QR code version's format.</p>
\r
228 public static final class ECB {
\r
229 private final int count;
\r
230 private final int dataCodewords;
\r
232 ECB(int count, int dataCodewords) {
\r
233 this.count = count;
\r
234 this.dataCodewords = dataCodewords;
\r
237 public int getCount() {
\r
241 public int getDataCodewords() {
\r
242 return dataCodewords;
\r
246 public String toString() {
\r
247 return String.valueOf(versionNumber);
\r
251 * See ISO 18004:2006 6.5.1 Table 9
\r
253 private static Version[] buildVersions() {
\r
254 return new Version[]{
\r
255 new Version(1, new int[]{},
\r
256 new ECBlocks(7, new ECB(1, 19)),
\r
257 new ECBlocks(10, new ECB(1, 16)),
\r
258 new ECBlocks(13, new ECB(1, 13)),
\r
259 new ECBlocks(17, new ECB(1, 9))),
\r
260 new Version(2, new int[]{6, 18},
\r
261 new ECBlocks(10, new ECB(1, 34)),
\r
262 new ECBlocks(16, new ECB(1, 28)),
\r
263 new ECBlocks(22, new ECB(1, 22)),
\r
264 new ECBlocks(28, new ECB(1, 16))),
\r
265 new Version(3, new int[]{6, 22},
\r
266 new ECBlocks(15, new ECB(1, 55)),
\r
267 new ECBlocks(26, new ECB(1, 44)),
\r
268 new ECBlocks(18, new ECB(2, 17)),
\r
269 new ECBlocks(22, new ECB(2, 13))),
\r
270 new Version(4, new int[]{6, 26},
\r
271 new ECBlocks(20, new ECB(1, 80)),
\r
272 new ECBlocks(18, new ECB(2, 32)),
\r
273 new ECBlocks(26, new ECB(2, 24)),
\r
274 new ECBlocks(16, new ECB(4, 9))),
\r
275 new Version(5, new int[]{6, 30},
\r
276 new ECBlocks(26, new ECB(1, 108)),
\r
277 new ECBlocks(24, new ECB(2, 43)),
\r
278 new ECBlocks(18, new ECB(2, 15),
\r
280 new ECBlocks(22, new ECB(2, 11),
\r
282 new Version(6, new int[]{6, 34},
\r
283 new ECBlocks(18, new ECB(2, 68)),
\r
284 new ECBlocks(16, new ECB(4, 27)),
\r
285 new ECBlocks(24, new ECB(4, 19)),
\r
286 new ECBlocks(28, new ECB(4, 15))),
\r
287 new Version(7, new int[]{6, 22, 38},
\r
288 new ECBlocks(20, new ECB(2, 78)),
\r
289 new ECBlocks(18, new ECB(4, 31)),
\r
290 new ECBlocks(18, new ECB(2, 14),
\r
292 new ECBlocks(26, new ECB(4, 13),
\r
294 new Version(8, new int[]{6, 24, 42},
\r
295 new ECBlocks(24, new ECB(2, 97)),
\r
296 new ECBlocks(22, new ECB(2, 38),
\r
298 new ECBlocks(22, new ECB(4, 18),
\r
300 new ECBlocks(26, new ECB(4, 14),
\r
302 new Version(9, new int[]{6, 26, 46},
\r
303 new ECBlocks(30, new ECB(2, 116)),
\r
304 new ECBlocks(22, new ECB(3, 36),
\r
306 new ECBlocks(20, new ECB(4, 16),
\r
308 new ECBlocks(24, new ECB(4, 12),
\r
310 new Version(10, new int[]{6, 28, 50},
\r
311 new ECBlocks(18, new ECB(2, 68),
\r
313 new ECBlocks(26, new ECB(4, 43),
\r
315 new ECBlocks(24, new ECB(6, 19),
\r
317 new ECBlocks(28, new ECB(6, 15),
\r
319 new Version(11, new int[]{6, 30, 54},
\r
320 new ECBlocks(20, new ECB(4, 81)),
\r
321 new ECBlocks(30, new ECB(1, 50),
\r
323 new ECBlocks(28, new ECB(4, 22),
\r
325 new ECBlocks(24, new ECB(3, 12),
\r
327 new Version(12, new int[]{6, 32, 58},
\r
328 new ECBlocks(24, new ECB(2, 92),
\r
330 new ECBlocks(22, new ECB(6, 36),
\r
332 new ECBlocks(26, new ECB(4, 20),
\r
334 new ECBlocks(28, new ECB(7, 14),
\r
336 new Version(13, new int[]{6, 34, 62},
\r
337 new ECBlocks(26, new ECB(4, 107)),
\r
338 new ECBlocks(22, new ECB(8, 37),
\r
340 new ECBlocks(24, new ECB(8, 20),
\r
342 new ECBlocks(22, new ECB(12, 11),
\r
344 new Version(14, new int[]{6, 26, 46, 66},
\r
345 new ECBlocks(30, new ECB(3, 115),
\r
347 new ECBlocks(24, new ECB(4, 40),
\r
349 new ECBlocks(20, new ECB(11, 16),
\r
351 new ECBlocks(24, new ECB(11, 12),
\r
353 new Version(15, new int[]{6, 26, 48, 70},
\r
354 new ECBlocks(22, new ECB(5, 87),
\r
356 new ECBlocks(24, new ECB(5, 41),
\r
358 new ECBlocks(30, new ECB(5, 24),
\r
360 new ECBlocks(24, new ECB(11, 12),
\r
362 new Version(16, new int[]{6, 26, 50, 74},
\r
363 new ECBlocks(24, new ECB(5, 98),
\r
365 new ECBlocks(28, new ECB(7, 45),
\r
367 new ECBlocks(24, new ECB(15, 19),
\r
369 new ECBlocks(30, new ECB(3, 15),
\r
371 new Version(17, new int[]{6, 30, 54, 78},
\r
372 new ECBlocks(28, new ECB(1, 107),
\r
374 new ECBlocks(28, new ECB(10, 46),
\r
376 new ECBlocks(28, new ECB(1, 22),
\r
378 new ECBlocks(28, new ECB(2, 14),
\r
380 new Version(18, new int[]{6, 30, 56, 82},
\r
381 new ECBlocks(30, new ECB(5, 120),
\r
383 new ECBlocks(26, new ECB(9, 43),
\r
385 new ECBlocks(28, new ECB(17, 22),
\r
387 new ECBlocks(28, new ECB(2, 14),
\r
389 new Version(19, new int[]{6, 30, 58, 86},
\r
390 new ECBlocks(28, new ECB(3, 113),
\r
392 new ECBlocks(26, new ECB(3, 44),
\r
394 new ECBlocks(26, new ECB(17, 21),
\r
396 new ECBlocks(26, new ECB(9, 13),
\r
398 new Version(20, new int[]{6, 34, 62, 90},
\r
399 new ECBlocks(28, new ECB(3, 107),
\r
401 new ECBlocks(26, new ECB(3, 41),
\r
403 new ECBlocks(30, new ECB(15, 24),
\r
405 new ECBlocks(28, new ECB(15, 15),
\r
407 new Version(21, new int[]{6, 28, 50, 72, 94},
\r
408 new ECBlocks(28, new ECB(4, 116),
\r
410 new ECBlocks(26, new ECB(17, 42)),
\r
411 new ECBlocks(28, new ECB(17, 22),
\r
413 new ECBlocks(30, new ECB(19, 16),
\r
415 new Version(22, new int[]{6, 26, 50, 74, 98},
\r
416 new ECBlocks(28, new ECB(2, 111),
\r
418 new ECBlocks(28, new ECB(17, 46)),
\r
419 new ECBlocks(30, new ECB(7, 24),
\r
421 new ECBlocks(24, new ECB(34, 13))),
\r
422 new Version(23, new int[]{6, 30, 54, 74, 102},
\r
423 new ECBlocks(30, new ECB(4, 121),
\r
425 new ECBlocks(28, new ECB(4, 47),
\r
427 new ECBlocks(30, new ECB(11, 24),
\r
429 new ECBlocks(30, new ECB(16, 15),
\r
431 new Version(24, new int[]{6, 28, 54, 80, 106},
\r
432 new ECBlocks(30, new ECB(6, 117),
\r
434 new ECBlocks(28, new ECB(6, 45),
\r
436 new ECBlocks(30, new ECB(11, 24),
\r
438 new ECBlocks(30, new ECB(30, 16),
\r
440 new Version(25, new int[]{6, 32, 58, 84, 110},
\r
441 new ECBlocks(26, new ECB(8, 106),
\r
443 new ECBlocks(28, new ECB(8, 47),
\r
445 new ECBlocks(30, new ECB(7, 24),
\r
447 new ECBlocks(30, new ECB(22, 15),
\r
449 new Version(26, new int[]{6, 30, 58, 86, 114},
\r
450 new ECBlocks(28, new ECB(10, 114),
\r
452 new ECBlocks(28, new ECB(19, 46),
\r
454 new ECBlocks(28, new ECB(28, 22),
\r
456 new ECBlocks(30, new ECB(33, 16),
\r
458 new Version(27, new int[]{6, 34, 62, 90, 118},
\r
459 new ECBlocks(30, new ECB(8, 122),
\r
461 new ECBlocks(28, new ECB(22, 45),
\r
463 new ECBlocks(30, new ECB(8, 23),
\r
465 new ECBlocks(30, new ECB(12, 15),
\r
467 new Version(28, new int[]{6, 26, 50, 74, 98, 122},
\r
468 new ECBlocks(30, new ECB(3, 117),
\r
470 new ECBlocks(28, new ECB(3, 45),
\r
472 new ECBlocks(30, new ECB(4, 24),
\r
474 new ECBlocks(30, new ECB(11, 15),
\r
476 new Version(29, new int[]{6, 30, 54, 78, 102, 126},
\r
477 new ECBlocks(30, new ECB(7, 116),
\r
479 new ECBlocks(28, new ECB(21, 45),
\r
481 new ECBlocks(30, new ECB(1, 23),
\r
483 new ECBlocks(30, new ECB(19, 15),
\r
485 new Version(30, new int[]{6, 26, 52, 78, 104, 130},
\r
486 new ECBlocks(30, new ECB(5, 115),
\r
488 new ECBlocks(28, new ECB(19, 47),
\r
490 new ECBlocks(30, new ECB(15, 24),
\r
492 new ECBlocks(30, new ECB(23, 15),
\r
494 new Version(31, new int[]{6, 30, 56, 82, 108, 134},
\r
495 new ECBlocks(30, new ECB(13, 115),
\r
497 new ECBlocks(28, new ECB(2, 46),
\r
499 new ECBlocks(30, new ECB(42, 24),
\r
501 new ECBlocks(30, new ECB(23, 15),
\r
503 new Version(32, new int[]{6, 34, 60, 86, 112, 138},
\r
504 new ECBlocks(30, new ECB(17, 115)),
\r
505 new ECBlocks(28, new ECB(10, 46),
\r
507 new ECBlocks(30, new ECB(10, 24),
\r
509 new ECBlocks(30, new ECB(19, 15),
\r
511 new Version(33, new int[]{6, 30, 58, 86, 114, 142},
\r
512 new ECBlocks(30, new ECB(17, 115),
\r
514 new ECBlocks(28, new ECB(14, 46),
\r
516 new ECBlocks(30, new ECB(29, 24),
\r
518 new ECBlocks(30, new ECB(11, 15),
\r
520 new Version(34, new int[]{6, 34, 62, 90, 118, 146},
\r
521 new ECBlocks(30, new ECB(13, 115),
\r
523 new ECBlocks(28, new ECB(14, 46),
\r
525 new ECBlocks(30, new ECB(44, 24),
\r
527 new ECBlocks(30, new ECB(59, 16),
\r
529 new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150},
\r
530 new ECBlocks(30, new ECB(12, 121),
\r
532 new ECBlocks(28, new ECB(12, 47),
\r
534 new ECBlocks(30, new ECB(39, 24),
\r
536 new ECBlocks(30, new ECB(22, 15),
\r
538 new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154},
\r
539 new ECBlocks(30, new ECB(6, 121),
\r
541 new ECBlocks(28, new ECB(6, 47),
\r
543 new ECBlocks(30, new ECB(46, 24),
\r
545 new ECBlocks(30, new ECB(2, 15),
\r
547 new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158},
\r
548 new ECBlocks(30, new ECB(17, 122),
\r
550 new ECBlocks(28, new ECB(29, 46),
\r
552 new ECBlocks(30, new ECB(49, 24),
\r
554 new ECBlocks(30, new ECB(24, 15),
\r
556 new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162},
\r
557 new ECBlocks(30, new ECB(4, 122),
\r
559 new ECBlocks(28, new ECB(13, 46),
\r
561 new ECBlocks(30, new ECB(48, 24),
\r
563 new ECBlocks(30, new ECB(42, 15),
\r
565 new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166},
\r
566 new ECBlocks(30, new ECB(20, 117),
\r
568 new ECBlocks(28, new ECB(40, 47),
\r
570 new ECBlocks(30, new ECB(43, 24),
\r
572 new ECBlocks(30, new ECB(10, 15),
\r
574 new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170},
\r
575 new ECBlocks(30, new ECB(19, 118),
\r
577 new ECBlocks(28, new ECB(18, 47),
\r
579 new ECBlocks(30, new ECB(34, 24),
\r
581 new ECBlocks(30, new ECB(20, 15),
\r