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 using com.google.zxing;
\r
18 using com.google.zxing.common;
\r
20 namespace com.google.zxing.qrcode.decoder
\r
22 public sealed class Version
\r
25 * See ISO 18004:2006 Annex D.
\r
26 * Element i represents the raw version bits that specify version i + 7
\r
28 private static int[] VERSION_DECODE_INFO = {
\r
29 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
\r
30 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
\r
31 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
\r
32 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
\r
33 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
\r
34 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
\r
35 0x2542E, 0x26A64, 0x27541, 0x28C69
\r
38 private static Version[] VERSIONS = buildVersions();
\r
40 private int versionNumber;
\r
41 private int[] alignmentPatternCenters;
\r
42 private ECBlocks[] ecBlocks;
\r
43 private int totalCodewords;
\r
45 private Version(int versionNumber,
\r
46 int[] alignmentPatternCenters,
\r
50 ECBlocks ecBlocks4) {
\r
51 this.versionNumber = versionNumber;
\r
52 this.alignmentPatternCenters = alignmentPatternCenters;
\r
53 this.ecBlocks = new ECBlocks[]{ecBlocks1, ecBlocks2, ecBlocks3, ecBlocks4};
\r
55 int ecCodewords = ecBlocks1.getECCodewordsPerBlock();
\r
56 ECB[] ecbArray = ecBlocks1.getECBlocks();
\r
57 for (int i = 0; i < ecbArray.Length; i++) {
\r
58 ECB ecBlock = ecbArray[i];
\r
59 total += ecBlock.getCount() * (ecBlock.getDataCodewords() + ecCodewords);
\r
61 this.totalCodewords = total;
\r
64 public int getVersionNumber() {
\r
65 return versionNumber;
\r
68 public int[] getAlignmentPatternCenters() {
\r
69 return alignmentPatternCenters;
\r
72 public int getTotalCodewords() {
\r
73 return totalCodewords;
\r
76 public int getDimensionForVersion() {
\r
77 return 17 + 4 * versionNumber;
\r
80 public ECBlocks getECBlocksForLevel(ErrorCorrectionLevel ecLevel) {
\r
81 return ecBlocks[ecLevel.ordinal()];
\r
85 * <p>Deduces version information purely from QR Code dimensions.</p>
\r
87 * @param dimension dimension in modules
\r
88 * @return {@link Version} for a QR Code of that dimension
\r
89 * @throws ReaderException if dimension is not 1 mod 4
\r
91 public static Version getProvisionalVersionForDimension(int dimension) {
\r
92 if (dimension % 4 != 1) {
\r
93 throw new ReaderException();
\r
95 return getVersionForNumber((dimension - 17) >> 2);
\r
98 public static Version getVersionForNumber(int versionNumber) {
\r
99 if (versionNumber < 1 || versionNumber > 40) {
\r
100 throw new ArgumentException();
\r
102 return VERSIONS[versionNumber - 1];
\r
105 public static Version decodeVersionInformation(int versionBits) {
\r
106 int bestDifference = int.MaxValue;
\r
107 int bestVersion = 0;
\r
108 for (int i = 0; i < VERSION_DECODE_INFO.Length; i++) {
\r
109 int targetVersion = VERSION_DECODE_INFO[i];
\r
110 // Do the version info bits match exactly? done.
\r
111 if (targetVersion == versionBits) {
\r
112 return getVersionForNumber(i + 7);
\r
114 // Otherwise see if this is the closest to a real version info bit string
\r
115 // we have seen so far
\r
116 int bitsDifference = FormatInformation.numBitsDiffering(versionBits, targetVersion);
\r
117 if (bitsDifference < bestDifference) {
\r
118 bestVersion = i + 7;
\r
121 // We can tolerate up to 3 bits of error since no two version info codewords will
\r
122 // differ in less than 4 bits.
\r
123 if (bestDifference <= 3) {
\r
124 return getVersionForNumber(bestVersion);
\r
126 // If we didn't find a close enough match, fail
\r
131 * See ISO 18004:2006 Annex E
\r
133 public BitMatrix buildFunctionPattern() {
\r
134 int dimension = getDimensionForVersion();
\r
135 BitMatrix bitMatrix = new BitMatrix(dimension);
\r
137 // Top left finder pattern + separator + format
\r
138 bitMatrix.setRegion(0, 0, 9, 9);
\r
139 // Top right finder pattern + separator + format
\r
140 bitMatrix.setRegion(0, dimension - 8, 9, 8);
\r
141 // Bottom left finder pattern + separator + format
\r
142 bitMatrix.setRegion(dimension - 8, 0, 8, 9);
\r
144 // Alignment patterns
\r
145 int max = alignmentPatternCenters.Length;
\r
146 for (int x = 0; x < max; x++) {
\r
147 int i = alignmentPatternCenters[x] - 2;
\r
148 for (int y = 0; y < max; y++) {
\r
149 if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
\r
150 // No alignment patterns near the three finder paterns
\r
153 bitMatrix.setRegion(i, alignmentPatternCenters[y] - 2, 5, 5);
\r
157 // Vertical timing pattern
\r
158 bitMatrix.setRegion(9, 6, dimension - 17, 1);
\r
159 // Horizontal timing pattern
\r
160 bitMatrix.setRegion(6, 9, 1, dimension - 17);
\r
162 if (versionNumber > 6) {
\r
163 // Version info, top right
\r
164 bitMatrix.setRegion(0, dimension - 11, 6, 3);
\r
165 // Version info, bottom left
\r
166 bitMatrix.setRegion(dimension - 11, 0, 3, 6);
\r
173 * <p>Encapsulates a set of error-correction blocks in one symbol version. Most versions will
\r
174 * use blocks of differing sizes within one version, so, this encapsulates the parameters for
\r
175 * each set of blocks. It also holds the number of error-correction codewords per block since it
\r
176 * will be the same across all blocks within one version.</p>
\r
178 public class ECBlocks {
\r
179 private int ecCodewordsPerBlock;
\r
180 private ECB[] ecBlocks;
\r
182 public ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks) {
\r
183 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
184 this.ecBlocks = new ECB[]{ecBlocks};
\r
187 public ECBlocks(int ecCodewordsPerBlock, ECB ecBlocks1, ECB ecBlocks2)
\r
189 this.ecCodewordsPerBlock = ecCodewordsPerBlock;
\r
190 this.ecBlocks = new ECB[]{ecBlocks1, ecBlocks2};
\r
193 public int getECCodewordsPerBlock() {
\r
194 return ecCodewordsPerBlock;
\r
197 public int getNumBlocks() {
\r
199 for (int i = 0; i < ecBlocks.Length; i++) {
\r
200 total += ecBlocks[i].getCount();
\r
205 public int getTotalECCodewords() {
\r
206 return ecCodewordsPerBlock * getNumBlocks();
\r
209 public ECB[] getECBlocks() {
\r
215 * <p>Encapsualtes the parameters for one error-correction block in one symbol version.
\r
216 * This includes the number of data codewords, and the number of times a block with these
\r
217 * parameters is used consecutively in the QR code version's format.</p>
\r
221 private int dataCodewords;
\r
223 public ECB(int count, int dataCodewords) {
\r
224 this.count = count;
\r
225 this.dataCodewords = dataCodewords;
\r
228 public int getCount() {
\r
232 public int getDataCodewords() {
\r
233 return dataCodewords;
\r
237 public String toString() {
\r
238 return versionNumber.ToString();
\r
239 //return String.valueOf(versionNumber);
\r
243 * See ISO 18004:2006 6.5.1 Table 9
\r
245 private static Version[] buildVersions() {
\r
246 return new Version[]{
\r
247 new Version(1, new int[]{},
\r
248 new ECBlocks(7, new ECB(1, 19)),
\r
249 new ECBlocks(10, new ECB(1, 16)),
\r
250 new ECBlocks(13, new ECB(1, 13)),
\r
251 new ECBlocks(17, new ECB(1, 9))),
\r
252 new Version(2, new int[]{6, 18},
\r
253 new ECBlocks(10, new ECB(1, 34)),
\r
254 new ECBlocks(16, new ECB(1, 28)),
\r
255 new ECBlocks(22, new ECB(1, 22)),
\r
256 new ECBlocks(28, new ECB(1, 16))),
\r
257 new Version(3, new int[]{6, 22},
\r
258 new ECBlocks(15, new ECB(1, 55)),
\r
259 new ECBlocks(26, new ECB(1, 44)),
\r
260 new ECBlocks(18, new ECB(2, 17)),
\r
261 new ECBlocks(22, new ECB(2, 13))),
\r
262 new Version(4, new int[]{6, 26},
\r
263 new ECBlocks(20, new ECB(1, 80)),
\r
264 new ECBlocks(18, new ECB(2, 32)),
\r
265 new ECBlocks(26, new ECB(2, 24)),
\r
266 new ECBlocks(16, new ECB(4, 9))),
\r
267 new Version(5, new int[]{6, 30},
\r
268 new ECBlocks(26, new ECB(1, 108)),
\r
269 new ECBlocks(24, new ECB(2, 43)),
\r
270 new ECBlocks(18, new ECB(2, 15),
\r
272 new ECBlocks(22, new ECB(2, 11),
\r
274 new Version(6, new int[]{6, 34},
\r
275 new ECBlocks(18, new ECB(2, 68)),
\r
276 new ECBlocks(16, new ECB(4, 27)),
\r
277 new ECBlocks(24, new ECB(4, 19)),
\r
278 new ECBlocks(28, new ECB(4, 15))),
\r
279 new Version(7, new int[]{6, 22, 38},
\r
280 new ECBlocks(20, new ECB(2, 78)),
\r
281 new ECBlocks(18, new ECB(4, 31)),
\r
282 new ECBlocks(18, new ECB(2, 14),
\r
284 new ECBlocks(26, new ECB(4, 13),
\r
286 new Version(8, new int[]{6, 24, 42},
\r
287 new ECBlocks(24, new ECB(2, 97)),
\r
288 new ECBlocks(22, new ECB(2, 38),
\r
290 new ECBlocks(22, new ECB(4, 18),
\r
292 new ECBlocks(26, new ECB(4, 14),
\r
294 new Version(9, new int[]{6, 26, 46},
\r
295 new ECBlocks(30, new ECB(2, 116)),
\r
296 new ECBlocks(22, new ECB(3, 36),
\r
298 new ECBlocks(20, new ECB(4, 16),
\r
300 new ECBlocks(24, new ECB(4, 12),
\r
302 new Version(10, new int[]{6, 28, 50},
\r
303 new ECBlocks(18, new ECB(2, 68),
\r
305 new ECBlocks(26, new ECB(4, 43),
\r
307 new ECBlocks(24, new ECB(6, 19),
\r
309 new ECBlocks(28, new ECB(6, 15),
\r
311 new Version(11, new int[]{6, 30, 54},
\r
312 new ECBlocks(20, new ECB(4, 81)),
\r
313 new ECBlocks(30, new ECB(1, 50),
\r
315 new ECBlocks(28, new ECB(4, 22),
\r
317 new ECBlocks(24, new ECB(3, 12),
\r
319 new Version(12, new int[]{6, 32, 58},
\r
320 new ECBlocks(24, new ECB(2, 92),
\r
322 new ECBlocks(22, new ECB(6, 36),
\r
324 new ECBlocks(26, new ECB(4, 20),
\r
326 new ECBlocks(28, new ECB(7, 14),
\r
328 new Version(13, new int[]{6, 34, 62},
\r
329 new ECBlocks(26, new ECB(4, 107)),
\r
330 new ECBlocks(22, new ECB(8, 37),
\r
332 new ECBlocks(24, new ECB(8, 20),
\r
334 new ECBlocks(22, new ECB(12, 11),
\r
336 new Version(14, new int[]{6, 26, 46, 66},
\r
337 new ECBlocks(30, new ECB(3, 115),
\r
339 new ECBlocks(24, new ECB(4, 40),
\r
341 new ECBlocks(20, new ECB(11, 16),
\r
343 new ECBlocks(24, new ECB(11, 12),
\r
345 new Version(15, new int[]{6, 26, 48, 70},
\r
346 new ECBlocks(22, new ECB(5, 87),
\r
348 new ECBlocks(24, new ECB(5, 41),
\r
350 new ECBlocks(30, new ECB(5, 24),
\r
352 new ECBlocks(24, new ECB(11, 12),
\r
354 new Version(16, new int[]{6, 26, 50, 74},
\r
355 new ECBlocks(24, new ECB(5, 98),
\r
357 new ECBlocks(28, new ECB(7, 45),
\r
359 new ECBlocks(24, new ECB(15, 19),
\r
361 new ECBlocks(30, new ECB(3, 15),
\r
363 new Version(17, new int[]{6, 30, 54, 78},
\r
364 new ECBlocks(28, new ECB(1, 107),
\r
366 new ECBlocks(28, new ECB(10, 46),
\r
368 new ECBlocks(28, new ECB(1, 22),
\r
370 new ECBlocks(28, new ECB(2, 14),
\r
372 new Version(18, new int[]{6, 30, 56, 82},
\r
373 new ECBlocks(30, new ECB(5, 120),
\r
375 new ECBlocks(26, new ECB(9, 43),
\r
377 new ECBlocks(28, new ECB(17, 22),
\r
379 new ECBlocks(28, new ECB(2, 14),
\r
381 new Version(19, new int[]{6, 30, 58, 86},
\r
382 new ECBlocks(28, new ECB(3, 113),
\r
384 new ECBlocks(26, new ECB(3, 44),
\r
386 new ECBlocks(26, new ECB(17, 21),
\r
388 new ECBlocks(26, new ECB(9, 13),
\r
390 new Version(20, new int[]{6, 34, 62, 90},
\r
391 new ECBlocks(28, new ECB(3, 107),
\r
393 new ECBlocks(26, new ECB(3, 41),
\r
395 new ECBlocks(30, new ECB(15, 24),
\r
397 new ECBlocks(28, new ECB(15, 15),
\r
399 new Version(21, new int[]{6, 28, 50, 72, 94},
\r
400 new ECBlocks(28, new ECB(4, 116),
\r
402 new ECBlocks(26, new ECB(17, 42)),
\r
403 new ECBlocks(28, new ECB(17, 22),
\r
405 new ECBlocks(30, new ECB(19, 16),
\r
407 new Version(22, new int[]{6, 26, 50, 74, 98},
\r
408 new ECBlocks(28, new ECB(2, 111),
\r
410 new ECBlocks(28, new ECB(17, 46)),
\r
411 new ECBlocks(30, new ECB(7, 24),
\r
413 new ECBlocks(24, new ECB(34, 13))),
\r
414 new Version(23, new int[]{6, 30, 54, 74, 102},
\r
415 new ECBlocks(30, new ECB(4, 121),
\r
417 new ECBlocks(28, new ECB(4, 47),
\r
419 new ECBlocks(30, new ECB(11, 24),
\r
421 new ECBlocks(30, new ECB(16, 15),
\r
423 new Version(24, new int[]{6, 28, 54, 80, 106},
\r
424 new ECBlocks(30, new ECB(6, 117),
\r
426 new ECBlocks(28, new ECB(6, 45),
\r
428 new ECBlocks(30, new ECB(11, 24),
\r
430 new ECBlocks(30, new ECB(30, 16),
\r
432 new Version(25, new int[]{6, 32, 58, 84, 110},
\r
433 new ECBlocks(26, new ECB(8, 106),
\r
435 new ECBlocks(28, new ECB(8, 47),
\r
437 new ECBlocks(30, new ECB(7, 24),
\r
439 new ECBlocks(30, new ECB(22, 15),
\r
441 new Version(26, new int[]{6, 30, 58, 86, 114},
\r
442 new ECBlocks(28, new ECB(10, 114),
\r
444 new ECBlocks(28, new ECB(19, 46),
\r
446 new ECBlocks(28, new ECB(28, 22),
\r
448 new ECBlocks(30, new ECB(33, 16),
\r
450 new Version(27, new int[]{6, 34, 62, 90, 118},
\r
451 new ECBlocks(30, new ECB(8, 122),
\r
453 new ECBlocks(28, new ECB(22, 45),
\r
455 new ECBlocks(30, new ECB(8, 23),
\r
457 new ECBlocks(30, new ECB(12, 15),
\r
459 new Version(28, new int[]{6, 26, 50, 74, 98, 122},
\r
460 new ECBlocks(30, new ECB(3, 117),
\r
462 new ECBlocks(28, new ECB(3, 45),
\r
464 new ECBlocks(30, new ECB(4, 24),
\r
466 new ECBlocks(30, new ECB(11, 15),
\r
468 new Version(29, new int[]{6, 30, 54, 78, 102, 126},
\r
469 new ECBlocks(30, new ECB(7, 116),
\r
471 new ECBlocks(28, new ECB(21, 45),
\r
473 new ECBlocks(30, new ECB(1, 23),
\r
475 new ECBlocks(30, new ECB(19, 15),
\r
477 new Version(30, new int[]{6, 26, 52, 78, 104, 130},
\r
478 new ECBlocks(30, new ECB(5, 115),
\r
480 new ECBlocks(28, new ECB(19, 47),
\r
482 new ECBlocks(30, new ECB(15, 24),
\r
484 new ECBlocks(30, new ECB(23, 15),
\r
486 new Version(31, new int[]{6, 30, 56, 82, 108, 134},
\r
487 new ECBlocks(30, new ECB(13, 115),
\r
489 new ECBlocks(28, new ECB(2, 46),
\r
491 new ECBlocks(30, new ECB(42, 24),
\r
493 new ECBlocks(30, new ECB(23, 15),
\r
495 new Version(32, new int[]{6, 34, 60, 86, 112, 138},
\r
496 new ECBlocks(30, new ECB(17, 115)),
\r
497 new ECBlocks(28, new ECB(10, 46),
\r
499 new ECBlocks(30, new ECB(10, 24),
\r
501 new ECBlocks(30, new ECB(19, 15),
\r
503 new Version(33, new int[]{6, 30, 58, 86, 114, 142},
\r
504 new ECBlocks(30, new ECB(17, 115),
\r
506 new ECBlocks(28, new ECB(14, 46),
\r
508 new ECBlocks(30, new ECB(29, 24),
\r
510 new ECBlocks(30, new ECB(11, 15),
\r
512 new Version(34, new int[]{6, 34, 62, 90, 118, 146},
\r
513 new ECBlocks(30, new ECB(13, 115),
\r
515 new ECBlocks(28, new ECB(14, 46),
\r
517 new ECBlocks(30, new ECB(44, 24),
\r
519 new ECBlocks(30, new ECB(59, 16),
\r
521 new Version(35, new int[]{6, 30, 54, 78, 102, 126, 150},
\r
522 new ECBlocks(30, new ECB(12, 121),
\r
524 new ECBlocks(28, new ECB(12, 47),
\r
526 new ECBlocks(30, new ECB(39, 24),
\r
528 new ECBlocks(30, new ECB(22, 15),
\r
530 new Version(36, new int[]{6, 24, 50, 76, 102, 128, 154},
\r
531 new ECBlocks(30, new ECB(6, 121),
\r
533 new ECBlocks(28, new ECB(6, 47),
\r
535 new ECBlocks(30, new ECB(46, 24),
\r
537 new ECBlocks(30, new ECB(2, 15),
\r
539 new Version(37, new int[]{6, 28, 54, 80, 106, 132, 158},
\r
540 new ECBlocks(30, new ECB(17, 122),
\r
542 new ECBlocks(28, new ECB(29, 46),
\r
544 new ECBlocks(30, new ECB(49, 24),
\r
546 new ECBlocks(30, new ECB(24, 15),
\r
548 new Version(38, new int[]{6, 32, 58, 84, 110, 136, 162},
\r
549 new ECBlocks(30, new ECB(4, 122),
\r
551 new ECBlocks(28, new ECB(13, 46),
\r
553 new ECBlocks(30, new ECB(48, 24),
\r
555 new ECBlocks(30, new ECB(42, 15),
\r
557 new Version(39, new int[]{6, 26, 54, 82, 110, 138, 166},
\r
558 new ECBlocks(30, new ECB(20, 117),
\r
560 new ECBlocks(28, new ECB(40, 47),
\r
562 new ECBlocks(30, new ECB(43, 24),
\r
564 new ECBlocks(30, new ECB(10, 15),
\r
566 new Version(40, new int[]{6, 30, 58, 86, 114, 142, 170},
\r
567 new ECBlocks(30, new ECB(19, 118),
\r
569 new ECBlocks(28, new ECB(18, 47),
\r
571 new ECBlocks(30, new ECB(34, 24),
\r
573 new ECBlocks(30, new ECB(20, 15),
\r