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);
169 cout << "version " << versionNumber_ << " built function pattern:\n";
170 cout << *functionPattern;
172 return functionPattern;
175 static valarray<int> *intArray(size_t n ...) {
178 valarray<int> *result = new valarray<int>(n);
179 for (size_t i = 0; i < n; i++) {
180 (*result)[i] = va_arg(ap, int);
186 int Version::buildVersions() {
187 VERSIONS.push_back(new Version(1, intArray(0),
188 new ECBlocks(7, new ECB(1, 19)),
189 new ECBlocks(10, new ECB(1, 16)),
190 new ECBlocks(13, new ECB(1, 13)),
191 new ECBlocks(17, new ECB(1, 9))));
192 VERSIONS.push_back(new Version(2, intArray(2, 6, 18),
193 new ECBlocks(10, new ECB(1, 34)),
194 new ECBlocks(16, new ECB(1, 28)),
195 new ECBlocks(22, new ECB(1, 22)),
196 new ECBlocks(28, new ECB(1, 16))));
197 VERSIONS.push_back(new Version(3, intArray(2, 6, 22),
198 new ECBlocks(15, new ECB(1, 55)),
199 new ECBlocks(26, new ECB(1, 44)),
200 new ECBlocks(18, new ECB(2, 17)),
201 new ECBlocks(22, new ECB(2, 13))));
202 VERSIONS.push_back(new Version(4, intArray(2, 6, 26),
203 new ECBlocks(20, new ECB(1, 80)),
204 new ECBlocks(18, new ECB(2, 32)),
205 new ECBlocks(26, new ECB(2, 24)),
206 new ECBlocks(16, new ECB(4, 9))));
207 VERSIONS.push_back(new Version(5, intArray(2, 6, 30),
208 new ECBlocks(26, new ECB(1, 108)),
209 new ECBlocks(24, new ECB(2, 43)),
210 new ECBlocks(18, new ECB(2, 15),
212 new ECBlocks(22, new ECB(2, 11),
214 VERSIONS.push_back(new Version(6, intArray(2, 6, 34),
215 new ECBlocks(18, new ECB(2, 68)),
216 new ECBlocks(16, new ECB(4, 27)),
217 new ECBlocks(24, new ECB(4, 19)),
218 new ECBlocks(28, new ECB(4, 15))));
219 VERSIONS.push_back(new Version(7, intArray(3, 6, 22, 38),
220 new ECBlocks(20, new ECB(2, 78)),
221 new ECBlocks(18, new ECB(4, 31)),
222 new ECBlocks(18, new ECB(2, 14),
224 new ECBlocks(26, new ECB(4, 13),
226 VERSIONS.push_back(new Version(8, intArray(3, 6, 24, 42),
227 new ECBlocks(24, new ECB(2, 97)),
228 new ECBlocks(22, new ECB(2, 38),
230 new ECBlocks(22, new ECB(4, 18),
232 new ECBlocks(26, new ECB(4, 14),
234 VERSIONS.push_back(new Version(9, intArray(3, 6, 26, 46),
235 new ECBlocks(30, new ECB(2, 116)),
236 new ECBlocks(22, new ECB(3, 36),
238 new ECBlocks(20, new ECB(4, 16),
240 new ECBlocks(24, new ECB(4, 12),
242 VERSIONS.push_back(new Version(10, intArray(3, 6, 28, 50),
243 new ECBlocks(18, new ECB(2, 68),
245 new ECBlocks(26, new ECB(4, 43),
247 new ECBlocks(24, new ECB(6, 19),
249 new ECBlocks(28, new ECB(6, 15),
251 VERSIONS.push_back(new Version(11, intArray(3, 6, 30, 54),
252 new ECBlocks(20, new ECB(4, 81)),
253 new ECBlocks(30, new ECB(1, 50),
255 new ECBlocks(28, new ECB(4, 22),
257 new ECBlocks(24, new ECB(3, 12),
259 VERSIONS.push_back(new Version(12, intArray(3, 6, 32, 58),
260 new ECBlocks(24, new ECB(2, 92),
262 new ECBlocks(22, new ECB(6, 36),
264 new ECBlocks(26, new ECB(4, 20),
266 new ECBlocks(28, new ECB(7, 14),
268 VERSIONS.push_back(new Version(13, intArray(3, 6, 34, 62),
269 new ECBlocks(26, new ECB(4, 107)),
270 new ECBlocks(22, new ECB(8, 37),
272 new ECBlocks(24, new ECB(8, 20),
274 new ECBlocks(22, new ECB(12, 11),
276 VERSIONS.push_back(new Version(14, intArray(4, 6, 26, 46, 66),
277 new ECBlocks(30, new ECB(3, 115),
279 new ECBlocks(24, new ECB(4, 40),
281 new ECBlocks(20, new ECB(11, 16),
283 new ECBlocks(24, new ECB(11, 12),
285 VERSIONS.push_back(new Version(15, intArray(4, 6, 26, 48, 70),
286 new ECBlocks(22, new ECB(5, 87),
288 new ECBlocks(24, new ECB(5, 41),
290 new ECBlocks(30, new ECB(5, 24),
292 new ECBlocks(24, new ECB(11, 12),
294 VERSIONS.push_back(new Version(16, intArray(4, 6, 26, 50, 74),
295 new ECBlocks(24, new ECB(5, 98),
297 new ECBlocks(28, new ECB(7, 45),
299 new ECBlocks(24, new ECB(15, 19),
301 new ECBlocks(30, new ECB(3, 15),
303 VERSIONS.push_back(new Version(17, intArray(4, 6, 30, 54, 78),
304 new ECBlocks(28, new ECB(1, 107),
306 new ECBlocks(28, new ECB(10, 46),
308 new ECBlocks(28, new ECB(1, 22),
310 new ECBlocks(28, new ECB(2, 14),
312 VERSIONS.push_back(new Version(18, intArray(4, 6, 30, 56, 82),
313 new ECBlocks(30, new ECB(5, 120),
315 new ECBlocks(26, new ECB(9, 43),
317 new ECBlocks(28, new ECB(17, 22),
319 new ECBlocks(28, new ECB(2, 14),
321 VERSIONS.push_back(new Version(19, intArray(4, 6, 30, 58, 86),
322 new ECBlocks(28, new ECB(3, 113),
324 new ECBlocks(26, new ECB(3, 44),
326 new ECBlocks(26, new ECB(17, 21),
328 new ECBlocks(26, new ECB(9, 13),
330 VERSIONS.push_back(new Version(20, intArray(4, 6, 34, 62, 90),
331 new ECBlocks(28, new ECB(3, 107),
333 new ECBlocks(26, new ECB(3, 41),
335 new ECBlocks(30, new ECB(15, 24),
337 new ECBlocks(28, new ECB(15, 15),
339 VERSIONS.push_back(new Version(21, intArray(5, 6, 28, 50, 72, 94),
340 new ECBlocks(28, new ECB(4, 116),
342 new ECBlocks(26, new ECB(17, 42)),
343 new ECBlocks(28, new ECB(17, 22),
345 new ECBlocks(30, new ECB(19, 16),
347 VERSIONS.push_back(new Version(22, intArray(5, 6, 26, 50, 74, 98),
348 new ECBlocks(28, new ECB(2, 111),
350 new ECBlocks(28, new ECB(17, 46)),
351 new ECBlocks(30, new ECB(7, 24),
353 new ECBlocks(24, new ECB(34, 13))));
354 VERSIONS.push_back(new Version(23, intArray(5, 6, 30, 54, 74, 102),
355 new ECBlocks(30, new ECB(4, 121),
357 new ECBlocks(28, new ECB(4, 47),
359 new ECBlocks(30, new ECB(11, 24),
361 new ECBlocks(30, new ECB(16, 15),
363 VERSIONS.push_back(new Version(24, intArray(5, 6, 28, 54, 80, 106),
364 new ECBlocks(30, new ECB(6, 117),
366 new ECBlocks(28, new ECB(6, 45),
368 new ECBlocks(30, new ECB(11, 24),
370 new ECBlocks(30, new ECB(30, 16),
372 VERSIONS.push_back(new Version(25, intArray(5, 6, 32, 58, 84, 110),
373 new ECBlocks(26, new ECB(8, 106),
375 new ECBlocks(28, new ECB(8, 47),
377 new ECBlocks(30, new ECB(7, 24),
379 new ECBlocks(30, new ECB(22, 15),
381 VERSIONS.push_back(new Version(26, intArray(5, 6, 30, 58, 86, 114),
382 new ECBlocks(28, new ECB(10, 114),
384 new ECBlocks(28, new ECB(19, 46),
386 new ECBlocks(28, new ECB(28, 22),
388 new ECBlocks(30, new ECB(33, 16),
390 VERSIONS.push_back(new Version(27, intArray(5, 6, 34, 62, 90, 118),
391 new ECBlocks(30, new ECB(8, 122),
393 new ECBlocks(28, new ECB(22, 45),
395 new ECBlocks(30, new ECB(8, 23),
397 new ECBlocks(30, new ECB(12, 15),
399 VERSIONS.push_back(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122),
400 new ECBlocks(30, new ECB(3, 117),
402 new ECBlocks(28, new ECB(3, 45),
404 new ECBlocks(30, new ECB(4, 24),
406 new ECBlocks(30, new ECB(11, 15),
408 VERSIONS.push_back(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126),
409 new ECBlocks(30, new ECB(7, 116),
411 new ECBlocks(28, new ECB(21, 45),
413 new ECBlocks(30, new ECB(1, 23),
415 new ECBlocks(30, new ECB(19, 15),
417 VERSIONS.push_back(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130),
418 new ECBlocks(30, new ECB(5, 115),
420 new ECBlocks(28, new ECB(19, 47),
422 new ECBlocks(30, new ECB(15, 24),
424 new ECBlocks(30, new ECB(23, 15),
426 VERSIONS.push_back(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134),
427 new ECBlocks(30, new ECB(13, 115),
429 new ECBlocks(28, new ECB(2, 46),
431 new ECBlocks(30, new ECB(42, 24),
433 new ECBlocks(30, new ECB(23, 15),
435 VERSIONS.push_back(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138),
436 new ECBlocks(30, new ECB(17, 115)),
437 new ECBlocks(28, new ECB(10, 46),
439 new ECBlocks(30, new ECB(10, 24),
441 new ECBlocks(30, new ECB(19, 15),
443 VERSIONS.push_back(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142),
444 new ECBlocks(30, new ECB(17, 115),
446 new ECBlocks(28, new ECB(14, 46),
448 new ECBlocks(30, new ECB(29, 24),
450 new ECBlocks(30, new ECB(11, 15),
452 VERSIONS.push_back(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146),
453 new ECBlocks(30, new ECB(13, 115),
455 new ECBlocks(28, new ECB(14, 46),
457 new ECBlocks(30, new ECB(44, 24),
459 new ECBlocks(30, new ECB(59, 16),
461 VERSIONS.push_back(new Version(35, intArray(7, 6, 30, 54, 78,
463 new ECBlocks(30, new ECB(12, 121),
465 new ECBlocks(28, new ECB(12, 47),
467 new ECBlocks(30, new ECB(39, 24),
469 new ECBlocks(30, new ECB(22, 15),
471 VERSIONS.push_back(new Version(36, intArray(7, 6, 24, 50, 76,
473 new ECBlocks(30, new ECB(6, 121),
475 new ECBlocks(28, new ECB(6, 47),
477 new ECBlocks(30, new ECB(46, 24),
479 new ECBlocks(30, new ECB(2, 15),
481 VERSIONS.push_back(new Version(37, intArray(7, 6, 28, 54, 80,
483 new ECBlocks(30, new ECB(17, 122),
485 new ECBlocks(28, new ECB(29, 46),
487 new ECBlocks(30, new ECB(49, 24),
489 new ECBlocks(30, new ECB(24, 15),
491 VERSIONS.push_back(new Version(38, intArray(7, 6, 32, 58, 84,
493 new ECBlocks(30, new ECB(4, 122),
495 new ECBlocks(28, new ECB(13, 46),
497 new ECBlocks(30, new ECB(48, 24),
499 new ECBlocks(30, new ECB(42, 15),
501 VERSIONS.push_back(new Version(39, intArray(7, 6, 26, 54, 82,
503 new ECBlocks(30, new ECB(20, 117),
505 new ECBlocks(28, new ECB(40, 47),
507 new ECBlocks(30, new ECB(43, 24),
509 new ECBlocks(30, new ECB(10, 15),
511 VERSIONS.push_back(new Version(40, intArray(7, 6, 30, 58, 86,
513 new ECBlocks(30, new ECB(19, 118),
515 new ECBlocks(28, new ECB(18, 47),
517 new ECBlocks(30, new ECB(34, 24),
519 new ECBlocks(30, new ECB(20, 15),
521 return VERSIONS.size();