5 * Created by Christian Brunschen on 14/05/2008.
6 * Copyright 2008 ZXing authors All rights reserved.
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
12 * http://www.apache.org/licenses/LICENSE-2.0
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
24 #include "FormatInformation.h"
29 unsigned int Version::VERSION_DECODE_INFO[] = {
30 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6,
31 0x0C762, 0x0D847, 0x0E60D, 0x0F928, 0x10B78,
32 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683,
33 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
34 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250,
35 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B,
36 0x2542E, 0x26A64, 0x27541, 0x28C69
38 int Version::N_VERSION_DECODE_INFOS = 34;
39 vector<Version*> Version::VERSIONS;
40 static int N_VERSIONS = Version::buildVersions();
43 int Version::getVersionNumber() {
44 return versionNumber_;
47 valarray<int> &Version::getAlignmentPatternCenters() {
48 return alignmentPatternCenters_;
51 int Version::getTotalCodewords() {
52 return totalCodewords_;
55 int Version::getDimensionForVersion() {
56 return 17 + 4 * versionNumber_;
60 Version::getECBlocksForLevel(ErrorCorrectionLevel &ecLevel) {
61 return *ecBlocks_[ecLevel.ordinal()];
64 Version *Version::getProvisionalVersionForDimension(int dimension) {
65 if (dimension %4 != 1) {
66 throw new ReaderException("Dimension must be 1 mod 4");
68 return Version::getVersionForNumber((dimension - 17) >> 2);
71 Version *Version::getVersionForNumber(int versionNumber) {
72 if (versionNumber < 1 || versionNumber > 40) {
73 throw new ReaderException("versionNumber must be between 1 and 40");
76 return VERSIONS[versionNumber - 1];
79 Version::Version(int versionNumber,
80 valarray<int> *alignmentPatternCenters,
84 ECBlocks *ecBlocks4) :
85 versionNumber_(versionNumber),
86 alignmentPatternCenters_(*alignmentPatternCenters),
89 ecBlocks_[0] = ecBlocks1;
90 ecBlocks_[1] = ecBlocks2;
91 ecBlocks_[2] = ecBlocks3;
92 ecBlocks_[3] = ecBlocks4;
95 int ecCodewords = ecBlocks1->getECCodewords();
96 vector<ECB*> &ecbArray = ecBlocks1->getECBlocks();
97 for (size_t i = 0; i < ecbArray.size(); i++) {
98 ECB *ecBlock = ecbArray[i];
99 total += ecBlock->getCount() *
100 (ecBlock->getDataCodewords() + ecCodewords);
102 totalCodewords_ = total;
106 Version *Version::decodeVersionInformation(unsigned int versionBits) {
107 int bestDifference = numeric_limits<int>::max();
108 size_t bestVersion = 0;
109 for (int i = 0; i < N_VERSION_DECODE_INFOS; i++) {
110 unsigned targetVersion = VERSION_DECODE_INFO[i];
111 // Do the version info bits match exactly? done.
112 if (targetVersion == versionBits) {
113 return getVersionForNumber(i + 7);
115 // Otherwise see if this is the closest to a real version info bit
116 // string we have seen so far
118 FormatInformation::numBitsDiffering(versionBits, targetVersion);
119 if (bitsDifference < bestDifference) {
123 // We can tolerate up to 3 bits of error since no two version info codewords will
124 // differ in less than 4 bits.
125 if (bestDifference <= 3) {
126 return getVersionForNumber(bestVersion);
128 // If we didn't find a close enough match, fail
132 Ref<BitMatrix> Version::buildFunctionPattern() {
133 int dimension = getDimensionForVersion();
134 Ref<BitMatrix> functionPattern(new BitMatrix(dimension));
136 // Top left finder pattern + separator + format
137 functionPattern->setRegion(0, 0, 9, 9);
138 // Top right finder pattern + separator + format
139 functionPattern->setRegion(0, dimension - 8, 9, 8);
140 // Bottom left finder pattern + separator + format
141 functionPattern->setRegion(dimension - 8, 0, 8, 9);
143 // Alignment patterns
144 size_t max = alignmentPatternCenters_.size();
145 for (size_t x = 0; x < max; x++) {
146 int i = alignmentPatternCenters_[x] - 2;
147 for (size_t y = 0; y < max; y++) {
148 if ((x == 0 && (y == 0 || y == max - 1)) ||
149 (x == max - 1 && y == 0)) {
150 // No alignment patterns near the three finder patterns
153 functionPattern->setRegion(i, alignmentPatternCenters_[y] - 2, 5, 5);
157 // Vertical timing pattern
158 functionPattern->setRegion(9, 6, dimension - 17, 1);
159 // Horizontal timing pattern
160 functionPattern->setRegion(6, 9, 1, dimension - 17);
162 if (versionNumber_ > 6) {
163 // Version info, top right
164 functionPattern->setRegion(0, dimension - 11, 6, 3);
165 // Version info, bottom left
166 functionPattern->setRegion(dimension - 11, 0, 3, 6);
170 cout << "version " << versionNumber_ << " built function pattern:\n";
171 cout << *functionPattern;
174 return functionPattern;
177 static valarray<int> *intArray(size_t n ...) {
180 valarray<int> *result = new valarray<int>(n);
181 for (size_t i = 0; i < n; i++) {
182 (*result)[i] = va_arg(ap, int);
188 int Version::buildVersions() {
189 VERSIONS.push_back(new Version(1, intArray(0),
190 new ECBlocks(7, new ECB(1, 19)),
191 new ECBlocks(10, new ECB(1, 16)),
192 new ECBlocks(13, new ECB(1, 13)),
193 new ECBlocks(17, new ECB(1, 9))));
194 VERSIONS.push_back(new Version(2, intArray(2, 6, 18),
195 new ECBlocks(10, new ECB(1, 34)),
196 new ECBlocks(16, new ECB(1, 28)),
197 new ECBlocks(22, new ECB(1, 22)),
198 new ECBlocks(28, new ECB(1, 16))));
199 VERSIONS.push_back(new Version(3, intArray(2, 6, 22),
200 new ECBlocks(15, new ECB(1, 55)),
201 new ECBlocks(26, new ECB(1, 44)),
202 new ECBlocks(18, new ECB(2, 17)),
203 new ECBlocks(22, new ECB(2, 13))));
204 VERSIONS.push_back(new Version(4, intArray(2, 6, 26),
205 new ECBlocks(20, new ECB(1, 80)),
206 new ECBlocks(18, new ECB(2, 32)),
207 new ECBlocks(26, new ECB(2, 24)),
208 new ECBlocks(16, new ECB(4, 9))));
209 VERSIONS.push_back(new Version(5, intArray(2, 6, 30),
210 new ECBlocks(26, new ECB(1, 108)),
211 new ECBlocks(24, new ECB(2, 43)),
212 new ECBlocks(18, new ECB(2, 15),
214 new ECBlocks(22, new ECB(2, 11),
216 VERSIONS.push_back(new Version(6, intArray(2, 6, 34),
217 new ECBlocks(18, new ECB(2, 68)),
218 new ECBlocks(16, new ECB(4, 27)),
219 new ECBlocks(24, new ECB(4, 19)),
220 new ECBlocks(28, new ECB(4, 15))));
221 VERSIONS.push_back(new Version(7, intArray(3, 6, 22, 38),
222 new ECBlocks(20, new ECB(2, 78)),
223 new ECBlocks(18, new ECB(4, 31)),
224 new ECBlocks(18, new ECB(2, 14),
226 new ECBlocks(26, new ECB(4, 13),
228 VERSIONS.push_back(new Version(8, intArray(3, 6, 24, 42),
229 new ECBlocks(24, new ECB(2, 97)),
230 new ECBlocks(22, new ECB(2, 38),
232 new ECBlocks(22, new ECB(4, 18),
234 new ECBlocks(26, new ECB(4, 14),
236 VERSIONS.push_back(new Version(9, intArray(3, 6, 26, 46),
237 new ECBlocks(30, new ECB(2, 116)),
238 new ECBlocks(22, new ECB(3, 36),
240 new ECBlocks(20, new ECB(4, 16),
242 new ECBlocks(24, new ECB(4, 12),
244 VERSIONS.push_back(new Version(10, intArray(3, 6, 28, 50),
245 new ECBlocks(18, new ECB(2, 68),
247 new ECBlocks(26, new ECB(4, 43),
249 new ECBlocks(24, new ECB(6, 19),
251 new ECBlocks(28, new ECB(6, 15),
253 VERSIONS.push_back(new Version(11, intArray(3, 6, 30, 54),
254 new ECBlocks(20, new ECB(4, 81)),
255 new ECBlocks(30, new ECB(1, 50),
257 new ECBlocks(28, new ECB(4, 22),
259 new ECBlocks(24, new ECB(3, 12),
261 VERSIONS.push_back(new Version(12, intArray(3, 6, 32, 58),
262 new ECBlocks(24, new ECB(2, 92),
264 new ECBlocks(22, new ECB(6, 36),
266 new ECBlocks(26, new ECB(4, 20),
268 new ECBlocks(28, new ECB(7, 14),
270 VERSIONS.push_back(new Version(13, intArray(3, 6, 34, 62),
271 new ECBlocks(26, new ECB(4, 107)),
272 new ECBlocks(22, new ECB(8, 37),
274 new ECBlocks(24, new ECB(8, 20),
276 new ECBlocks(22, new ECB(12, 11),
278 VERSIONS.push_back(new Version(14, intArray(4, 6, 26, 46, 66),
279 new ECBlocks(30, new ECB(3, 115),
281 new ECBlocks(24, new ECB(4, 40),
283 new ECBlocks(20, new ECB(11, 16),
285 new ECBlocks(24, new ECB(11, 12),
287 VERSIONS.push_back(new Version(15, intArray(4, 6, 26, 48, 70),
288 new ECBlocks(22, new ECB(5, 87),
290 new ECBlocks(24, new ECB(5, 41),
292 new ECBlocks(30, new ECB(5, 24),
294 new ECBlocks(24, new ECB(11, 12),
296 VERSIONS.push_back(new Version(16, intArray(4, 6, 26, 50, 74),
297 new ECBlocks(24, new ECB(5, 98),
299 new ECBlocks(28, new ECB(7, 45),
301 new ECBlocks(24, new ECB(15, 19),
303 new ECBlocks(30, new ECB(3, 15),
305 VERSIONS.push_back(new Version(17, intArray(4, 6, 30, 54, 78),
306 new ECBlocks(28, new ECB(1, 107),
308 new ECBlocks(28, new ECB(10, 46),
310 new ECBlocks(28, new ECB(1, 22),
312 new ECBlocks(28, new ECB(2, 14),
314 VERSIONS.push_back(new Version(18, intArray(4, 6, 30, 56, 82),
315 new ECBlocks(30, new ECB(5, 120),
317 new ECBlocks(26, new ECB(9, 43),
319 new ECBlocks(28, new ECB(17, 22),
321 new ECBlocks(28, new ECB(2, 14),
323 VERSIONS.push_back(new Version(19, intArray(4, 6, 30, 58, 86),
324 new ECBlocks(28, new ECB(3, 113),
326 new ECBlocks(26, new ECB(3, 44),
328 new ECBlocks(26, new ECB(17, 21),
330 new ECBlocks(26, new ECB(9, 13),
332 VERSIONS.push_back(new Version(20, intArray(4, 6, 34, 62, 90),
333 new ECBlocks(28, new ECB(3, 107),
335 new ECBlocks(26, new ECB(3, 41),
337 new ECBlocks(30, new ECB(15, 24),
339 new ECBlocks(28, new ECB(15, 15),
341 VERSIONS.push_back(new Version(21, intArray(5, 6, 28, 50, 72, 94),
342 new ECBlocks(28, new ECB(4, 116),
344 new ECBlocks(26, new ECB(17, 42)),
345 new ECBlocks(28, new ECB(17, 22),
347 new ECBlocks(30, new ECB(19, 16),
349 VERSIONS.push_back(new Version(22, intArray(5, 6, 26, 50, 74, 98),
350 new ECBlocks(28, new ECB(2, 111),
352 new ECBlocks(28, new ECB(17, 46)),
353 new ECBlocks(30, new ECB(7, 24),
355 new ECBlocks(24, new ECB(34, 13))));
356 VERSIONS.push_back(new Version(23, intArray(5, 6, 30, 54, 74, 102),
357 new ECBlocks(30, new ECB(4, 121),
359 new ECBlocks(28, new ECB(4, 47),
361 new ECBlocks(30, new ECB(11, 24),
363 new ECBlocks(30, new ECB(16, 15),
365 VERSIONS.push_back(new Version(24, intArray(5, 6, 28, 54, 80, 106),
366 new ECBlocks(30, new ECB(6, 117),
368 new ECBlocks(28, new ECB(6, 45),
370 new ECBlocks(30, new ECB(11, 24),
372 new ECBlocks(30, new ECB(30, 16),
374 VERSIONS.push_back(new Version(25, intArray(5, 6, 32, 58, 84, 110),
375 new ECBlocks(26, new ECB(8, 106),
377 new ECBlocks(28, new ECB(8, 47),
379 new ECBlocks(30, new ECB(7, 24),
381 new ECBlocks(30, new ECB(22, 15),
383 VERSIONS.push_back(new Version(26, intArray(5, 6, 30, 58, 86, 114),
384 new ECBlocks(28, new ECB(10, 114),
386 new ECBlocks(28, new ECB(19, 46),
388 new ECBlocks(28, new ECB(28, 22),
390 new ECBlocks(30, new ECB(33, 16),
392 VERSIONS.push_back(new Version(27, intArray(5, 6, 34, 62, 90, 118),
393 new ECBlocks(30, new ECB(8, 122),
395 new ECBlocks(28, new ECB(22, 45),
397 new ECBlocks(30, new ECB(8, 23),
399 new ECBlocks(30, new ECB(12, 15),
401 VERSIONS.push_back(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122),
402 new ECBlocks(30, new ECB(3, 117),
404 new ECBlocks(28, new ECB(3, 45),
406 new ECBlocks(30, new ECB(4, 24),
408 new ECBlocks(30, new ECB(11, 15),
410 VERSIONS.push_back(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126),
411 new ECBlocks(30, new ECB(7, 116),
413 new ECBlocks(28, new ECB(21, 45),
415 new ECBlocks(30, new ECB(1, 23),
417 new ECBlocks(30, new ECB(19, 15),
419 VERSIONS.push_back(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130),
420 new ECBlocks(30, new ECB(5, 115),
422 new ECBlocks(28, new ECB(19, 47),
424 new ECBlocks(30, new ECB(15, 24),
426 new ECBlocks(30, new ECB(23, 15),
428 VERSIONS.push_back(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134),
429 new ECBlocks(30, new ECB(13, 115),
431 new ECBlocks(28, new ECB(2, 46),
433 new ECBlocks(30, new ECB(42, 24),
435 new ECBlocks(30, new ECB(23, 15),
437 VERSIONS.push_back(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138),
438 new ECBlocks(30, new ECB(17, 115)),
439 new ECBlocks(28, new ECB(10, 46),
441 new ECBlocks(30, new ECB(10, 24),
443 new ECBlocks(30, new ECB(19, 15),
445 VERSIONS.push_back(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142),
446 new ECBlocks(30, new ECB(17, 115),
448 new ECBlocks(28, new ECB(14, 46),
450 new ECBlocks(30, new ECB(29, 24),
452 new ECBlocks(30, new ECB(11, 15),
454 VERSIONS.push_back(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146),
455 new ECBlocks(30, new ECB(13, 115),
457 new ECBlocks(28, new ECB(14, 46),
459 new ECBlocks(30, new ECB(44, 24),
461 new ECBlocks(30, new ECB(59, 16),
463 VERSIONS.push_back(new Version(35, intArray(7, 6, 30, 54, 78,
465 new ECBlocks(30, new ECB(12, 121),
467 new ECBlocks(28, new ECB(12, 47),
469 new ECBlocks(30, new ECB(39, 24),
471 new ECBlocks(30, new ECB(22, 15),
473 VERSIONS.push_back(new Version(36, intArray(7, 6, 24, 50, 76,
475 new ECBlocks(30, new ECB(6, 121),
477 new ECBlocks(28, new ECB(6, 47),
479 new ECBlocks(30, new ECB(46, 24),
481 new ECBlocks(30, new ECB(2, 15),
483 VERSIONS.push_back(new Version(37, intArray(7, 6, 28, 54, 80,
485 new ECBlocks(30, new ECB(17, 122),
487 new ECBlocks(28, new ECB(29, 46),
489 new ECBlocks(30, new ECB(49, 24),
491 new ECBlocks(30, new ECB(24, 15),
493 VERSIONS.push_back(new Version(38, intArray(7, 6, 32, 58, 84,
495 new ECBlocks(30, new ECB(4, 122),
497 new ECBlocks(28, new ECB(13, 46),
499 new ECBlocks(30, new ECB(48, 24),
501 new ECBlocks(30, new ECB(42, 15),
503 VERSIONS.push_back(new Version(39, intArray(7, 6, 26, 54, 82,
505 new ECBlocks(30, new ECB(20, 117),
507 new ECBlocks(28, new ECB(40, 47),
509 new ECBlocks(30, new ECB(43, 24),
511 new ECBlocks(30, new ECB(10, 15),
513 VERSIONS.push_back(new Version(40, intArray(7, 6, 30, 58, 86,
515 new ECBlocks(30, new ECB(19, 118),
517 new ECBlocks(28, new ECB(18, 47),
519 new ECBlocks(30, new ECB(34, 24),
521 new ECBlocks(30, new ECB(20, 15),
523 return VERSIONS.size();