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
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 public static final class ECBlocks {
\r
184 private final int ecCodewordsPerBlock;
\r
185 private final ECB[] ecBlocks;
\r
187 private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) {
\r
188 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
189 this.ecBlocks = new ECB[]{ecBlocks};
\r
192 private ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2) {
\r
193 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
194 this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};
\r
197 public int getECCodewordsPerBlock() {
\r
198 return ecCodewordsPerBlock;
\r
201 public int getNumBlocks() {
\r
203 for (int i = 0; i < ecBlocks.length; i++) {
\r
204 total += ecBlocks[i].getCount();
\r
209 public int getTotalECCodewords() {
\r
210 return ecCodewordsPerBlock * getNumBlocks();
\r
213 public ECB[] getECBlocks() {
\r
219 * <p>Encapsualtes the parameters for one error-correction block in one symbol version.
\r
220 * This includes the number of data codewords, and the number of times a block with these
\r
221 * parameters is used consecutively in the QR code version's format.</p>
\r
223 public static final class ECB {
\r
224 private final int count;
\r
225 private final int dataCodewords;
\r
227 ECB(int count, int dataCodewords) {
\r
228 this.count = count;
\r
229 this.dataCodewords = dataCodewords;
\r
232 public int getCount() {
\r
236 public int getDataCodewords() {
\r
237 return dataCodewords;
\r
241 public String toString() {
\r
242 return String.valueOf(versionNumber);
\r
246 * See ISO 18004:2006 6.5.1 Table 9
\r
248 private static Version[] buildVersions() {
\r
249 return new Version[]{
\r
250 new Version(1, new int[]{},
\r
251 new ECBlocks(7, new ECB(1, 19)),
\r
252 new ECBlocks(10, new ECB(1, 16)),
\r
253 new ECBlocks(13, new ECB(1, 13)),
\r
254 new ECBlocks(17, new ECB(1, 9))),
\r
255 new Version(2, new int[]{6, 18},
\r
256 new ECBlocks(10, new ECB(1, 34)),
\r
257 new ECBlocks(16, new ECB(1, 28)),
\r
258 new ECBlocks(22, new ECB(1, 22)),
\r
259 new ECBlocks(28, new ECB(1, 16))),
\r
260 new Version(3, new int[]{6, 22},
\r
261 new ECBlocks(15, new ECB(1, 55)),
\r
262 new ECBlocks(26, new ECB(1, 44)),
\r
263 new ECBlocks(18, new ECB(2, 17)),
\r
264 new ECBlocks(22, new ECB(2, 13))),
\r
265 new Version(4, new int[]{6, 26},
\r
266 new ECBlocks(20, new ECB(1, 80)),
\r
267 new ECBlocks(18, new ECB(2, 32)),
\r
268 new ECBlocks(26, new ECB(2, 24)),
\r
269 new ECBlocks(16, new ECB(4, 9))),
\r
270 new Version(5, new int[]{6, 30},
\r
271 new ECBlocks(26, new ECB(1, 108)),
\r
272 new ECBlocks(24, new ECB(2, 43)),
\r
273 new ECBlocks(18, new ECB(2, 15),
\r
275 new ECBlocks(22, new ECB(2, 11),
\r
277 new Version(6, new int[]{6, 34},
\r
278 new ECBlocks(18, new ECB(2, 68)),
\r
279 new ECBlocks(16, new ECB(4, 27)),
\r
280 new ECBlocks(24, new ECB(4, 19)),
\r
281 new ECBlocks(28, new ECB(4, 15))),
\r
282 new Version(7, new int[]{6, 22, 38},
\r
283 new ECBlocks(20, new ECB(2, 78)),
\r
284 new ECBlocks(18, new ECB(4, 31)),
\r
285 new ECBlocks(18, new ECB(2, 14),
\r
287 new ECBlocks(26, new ECB(4, 13),
\r
289 new Version(8, new int[]{6, 24, 42},
\r
290 new ECBlocks(24, new ECB(2, 97)),
\r
291 new ECBlocks(22, new ECB(2, 38),
\r
293 new ECBlocks(22, new ECB(4, 18),
\r
295 new ECBlocks(26, new ECB(4, 14),
\r
297 new Version(9, new int[]{6, 26, 46},
\r
298 new ECBlocks(30, new ECB(2, 116)),
\r
299 new ECBlocks(22, new ECB(3, 36),
\r
301 new ECBlocks(20, new ECB(4, 16),
\r
303 new ECBlocks(24, new ECB(4, 12),
\r
305 new Version(10, new int[]{6, 28, 50},
\r
306 new ECBlocks(18, new ECB(2, 68),
\r
308 new ECBlocks(26, new ECB(4, 43),
\r
310 new ECBlocks(24, new ECB(6, 19),
\r
312 new ECBlocks(28, new ECB(6, 15),
\r
314 new Version(11, new int[]{6, 30, 54},
\r
315 new ECBlocks(20, new ECB(4, 81)),
\r
316 new ECBlocks(30, new ECB(1, 50),
\r
318 new ECBlocks(28, new ECB(4, 22),
\r
320 new ECBlocks(24, new ECB(3, 12),
\r
322 new Version(12, new int[]{6, 32, 58},
\r
323 new ECBlocks(24, new ECB(2, 92),
\r
325 new ECBlocks(22, new ECB(6, 36),
\r
327 new ECBlocks(26, new ECB(4, 20),
\r
329 new ECBlocks(28, new ECB(7, 14),
\r
331 new Version(13, new int[]{6, 34, 62},
\r
332 new ECBlocks(26, new ECB(4, 107)),
\r
333 new ECBlocks(22, new ECB(8, 37),
\r
335 new ECBlocks(24, new ECB(8, 20),
\r
337 new ECBlocks(22, new ECB(12, 11),
\r
339 new Version(14, new int[]{6, 26, 46, 66},
\r
340 new ECBlocks(30, new ECB(3, 115),
\r
342 new ECBlocks(24, new ECB(4, 40),
\r
344 new ECBlocks(20, new ECB(11, 16),
\r
346 new ECBlocks(24, new ECB(11, 12),
\r
348 new Version(15, new int[]{6, 26, 48, 70},
\r
349 new ECBlocks(22, new ECB(5, 87),
\r
351 new ECBlocks(24, new ECB(5, 41),
\r
353 new ECBlocks(30, new ECB(5, 24),
\r
355 new ECBlocks(24, new ECB(11, 12),
\r
357 new Version(16, new int[]{6, 26, 50, 74},
\r
358 new ECBlocks(24, new ECB(5, 98),
\r
360 new ECBlocks(28, new ECB(7, 45),
\r
362 new ECBlocks(24, new ECB(15, 19),
\r
364 new ECBlocks(30, new ECB(3, 15),
\r
366 new Version(17, new int[]{6, 30, 54, 78},
\r
367 new ECBlocks(28, new ECB(1, 107),
\r
369 new ECBlocks(28, new ECB(10, 46),
\r
371 new ECBlocks(28, new ECB(1, 22),
\r
373 new ECBlocks(28, new ECB(2, 14),
\r
375 new Version(18, new int[]{6, 30, 56, 82},
\r
376 new ECBlocks(30, new ECB(5, 120),
\r
378 new ECBlocks(26, new ECB(9, 43),
\r
380 new ECBlocks(28, new ECB(17, 22),
\r
382 new ECBlocks(28, new ECB(2, 14),
\r
384 new Version(19, new int[]{6, 30, 58, 86},
\r
385 new ECBlocks(28, new ECB(3, 113),
\r
387 new ECBlocks(26, new ECB(3, 44),
\r
389 new ECBlocks(26, new ECB(17, 21),
\r
391 new ECBlocks(26, new ECB(9, 13),
\r
393 new Version(20, new int[]{6, 34, 62, 90},
\r
394 new ECBlocks(28, new ECB(3, 107),
\r
396 new ECBlocks(26, new ECB(3, 41),
\r
398 new ECBlocks(30, new ECB(15, 24),
\r
400 new ECBlocks(28, new ECB(15, 15),
\r
402 new Version(21, new int[]{6, 28, 50, 72, 94},
\r
403 new ECBlocks(28, new ECB(4, 116),
\r
405 new ECBlocks(26, new ECB(17, 42)),
\r
406 new ECBlocks(28, new ECB(17, 22),
\r
408 new ECBlocks(30, new ECB(19, 16),
\r
410 new Version(22, new int[]{6, 26, 50, 74, 98},
\r
411 new ECBlocks(28, new ECB(2, 111),
\r
413 new ECBlocks(28, new ECB(17, 46)),
\r
414 new ECBlocks(30, new ECB(7, 24),
\r
416 new ECBlocks(24, new ECB(34, 13))),
\r
417 new Version(23, new int[]{6, 30, 54, 74, 102},
\r
418 new ECBlocks(30, new ECB(4, 121),
\r
420 new ECBlocks(28, new ECB(4, 47),
\r
422 new ECBlocks(30, new ECB(11, 24),
\r
424 new ECBlocks(30, new ECB(16, 15),
\r
426 new Version(24, new int[]{6, 28, 54, 80, 106},
\r
427 new ECBlocks(30, new ECB(6, 117),
\r
429 new ECBlocks(28, new ECB(6, 45),
\r
431 new ECBlocks(30, new ECB(11, 24),
\r
433 new ECBlocks(30, new ECB(30, 16),
\r
435 new Version(25, new int[]{6, 32, 58, 84, 110},
\r
436 new ECBlocks(26, new ECB(8, 106),
\r
438 new ECBlocks(28, new ECB(8, 47),
\r
440 new ECBlocks(30, new ECB(7, 24),
\r
442 new ECBlocks(30, new ECB(22, 15),
\r
444 new Version(26, new int[]{6, 30, 58, 86, 114},
\r
445 new ECBlocks(28, new ECB(10, 114),
\r
447 new ECBlocks(28, new ECB(19, 46),
\r
449 new ECBlocks(28, new ECB(28, 22),
\r
451 new ECBlocks(30, new ECB(33, 16),
\r
453 new Version(27, new int[]{6, 34, 62, 90, 118},
\r
454 new ECBlocks(30, new ECB(8, 122),
\r
456 new ECBlocks(28, new ECB(22, 45),
\r
458 new ECBlocks(30, new ECB(8, 23),
\r
460 new ECBlocks(30, new ECB(12, 15),
\r
462 new Version(28, new int[]{6, 26, 50, 74, 98, 122},
\r
463 new ECBlocks(30, new ECB(3, 117),
\r
465 new ECBlocks(28, new ECB(3, 45),
\r
467 new ECBlocks(30, new ECB(4, 24),
\r
469 new ECBlocks(30, new ECB(11, 15),
\r
471 new Version(29, new int[]{6, 30, 54, 78, 102, 126},
\r
472 new ECBlocks(30, new ECB(7, 116),
\r
474 new ECBlocks(28, new ECB(21, 45),
\r
476 new ECBlocks(30, new ECB(1, 23),
\r
478 new ECBlocks(30, new ECB(19, 15),
\r
480 new Version(30, new int[]{6, 26, 52, 78, 104, 130},
\r
481 new ECBlocks(30, new ECB(5, 115),
\r
483 new ECBlocks(28, new ECB(19, 47),
\r
485 new ECBlocks(30, new ECB(15, 24),
\r
487 new ECBlocks(30, new ECB(23, 15),
\r
489 new Version(31, new int[]{6, 30, 56, 82, 108, 134},
\r
490 new ECBlocks(30, new ECB(13, 115),
\r
492 new ECBlocks(28, new ECB(2, 46),
\r
494 new ECBlocks(30, new ECB(42, 24),
\r
496 new ECBlocks(30, new ECB(23, 15),
\r
498 new Version(32, new int[]{6, 34, 60, 86, 112, 138},
\r
499 new ECBlocks(30, new ECB(17, 115)),
\r
500 new ECBlocks(28, new ECB(10, 46),
\r
502 new ECBlocks(30, new ECB(10, 24),
\r
504 new ECBlocks(30, new ECB(19, 15),
\r
506 new Version(33, new int[]{6, 30, 58, 86, 114, 142},
\r
507 new ECBlocks(30, new ECB(17, 115),
\r
509 new ECBlocks(28, new ECB(14, 46),
\r
511 new ECBlocks(30, new ECB(29, 24),
\r
513 new ECBlocks(30, new ECB(11, 15),
\r
515 new Version(34, new int[]{6, 34, 62, 90, 118, 146},
\r
516 new ECBlocks(30, new ECB(13, 115),
\r
518 new ECBlocks(28, new ECB(14, 46),
\r
520 new ECBlocks(30, new ECB(44, 24),
\r
522 new ECBlocks(30, new ECB(59, 16),
\r
524 new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150},
\r
525 new ECBlocks(30, new ECB(12, 121),
\r
527 new ECBlocks(28, new ECB(12, 47),
\r
529 new ECBlocks(30, new ECB(39, 24),
\r
531 new ECBlocks(30, new ECB(22, 15),
\r
533 new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154},
\r
534 new ECBlocks(30, new ECB(6, 121),
\r
536 new ECBlocks(28, new ECB(6, 47),
\r
538 new ECBlocks(30, new ECB(46, 24),
\r
540 new ECBlocks(30, new ECB(2, 15),
\r
542 new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158},
\r
543 new ECBlocks(30, new ECB(17, 122),
\r
545 new ECBlocks(28, new ECB(29, 46),
\r
547 new ECBlocks(30, new ECB(49, 24),
\r
549 new ECBlocks(30, new ECB(24, 15),
\r
551 new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162},
\r
552 new ECBlocks(30, new ECB(4, 122),
\r
554 new ECBlocks(28, new ECB(13, 46),
\r
556 new ECBlocks(30, new ECB(48, 24),
\r
558 new ECBlocks(30, new ECB(42, 15),
\r
560 new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166},
\r
561 new ECBlocks(30, new ECB(20, 117),
\r
563 new ECBlocks(28, new ECB(40, 47),
\r
565 new ECBlocks(30, new ECB(43, 24),
\r
567 new ECBlocks(30, new ECB(10, 15),
\r
569 new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170},
\r
570 new ECBlocks(30, new ECB(19, 118),
\r
572 new ECBlocks(28, new ECB(18, 47),
\r
574 new ECBlocks(30, new ECB(34, 24),
\r
576 new ECBlocks(30, new ECB(20, 15),
\r