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) {
121 bestDifference = bitsDifference;
124 // We can tolerate up to 3 bits of error since no two version info codewords will
125 // differ in less than 4 bits.
126 if (bestDifference <= 3) {
127 return getVersionForNumber(bestVersion);
129 // If we didn't find a close enough match, fail
133 Ref<BitMatrix> Version::buildFunctionPattern() {
134 int dimension = getDimensionForVersion();
135 Ref<BitMatrix> functionPattern(new BitMatrix(dimension));
137 // Top left finder pattern + separator + format
138 functionPattern->setRegion(0, 0, 9, 9);
139 // Top right finder pattern + separator + format
140 functionPattern->setRegion(0, dimension - 8, 9, 8);
141 // Bottom left finder pattern + separator + format
142 functionPattern->setRegion(dimension - 8, 0, 8, 9);
144 // Alignment patterns
145 size_t max = alignmentPatternCenters_.size();
146 for (size_t x = 0; x < max; x++) {
147 int i = alignmentPatternCenters_[x] - 2;
148 for (size_t y = 0; y < max; y++) {
149 if ((x == 0 && (y == 0 || y == max - 1)) ||
150 (x == max - 1 && y == 0)) {
151 // No alignment patterns near the three finder patterns
154 functionPattern->setRegion(i, alignmentPatternCenters_[y] - 2, 5, 5);
158 // Vertical timing pattern
159 functionPattern->setRegion(9, 6, dimension - 17, 1);
160 // Horizontal timing pattern
161 functionPattern->setRegion(6, 9, 1, dimension - 17);
163 if (versionNumber_ > 6) {
164 // Version info, top right
165 functionPattern->setRegion(0, dimension - 11, 6, 3);
166 // Version info, bottom left
167 functionPattern->setRegion(dimension - 11, 0, 3, 6);
171 cout << "version " << versionNumber_ << " built function pattern:\n";
172 cout << *functionPattern;
175 return functionPattern;
178 static valarray<int> *intArray(size_t n ...) {
181 valarray<int> *result = new valarray<int>(n);
182 for (size_t i = 0; i < n; i++) {
183 (*result)[i] = va_arg(ap, int);
189 int Version::buildVersions() {
190 VERSIONS.push_back(new Version(1, intArray(0),
191 new ECBlocks(7, new ECB(1, 19)),
192 new ECBlocks(10, new ECB(1, 16)),
193 new ECBlocks(13, new ECB(1, 13)),
194 new ECBlocks(17, new ECB(1, 9))));
195 VERSIONS.push_back(new Version(2, intArray(2, 6, 18),
196 new ECBlocks(10, new ECB(1, 34)),
197 new ECBlocks(16, new ECB(1, 28)),
198 new ECBlocks(22, new ECB(1, 22)),
199 new ECBlocks(28, new ECB(1, 16))));
200 VERSIONS.push_back(new Version(3, intArray(2, 6, 22),
201 new ECBlocks(15, new ECB(1, 55)),
202 new ECBlocks(26, new ECB(1, 44)),
203 new ECBlocks(18, new ECB(2, 17)),
204 new ECBlocks(22, new ECB(2, 13))));
205 VERSIONS.push_back(new Version(4, intArray(2, 6, 26),
206 new ECBlocks(20, new ECB(1, 80)),
207 new ECBlocks(18, new ECB(2, 32)),
208 new ECBlocks(26, new ECB(2, 24)),
209 new ECBlocks(16, new ECB(4, 9))));
210 VERSIONS.push_back(new Version(5, intArray(2, 6, 30),
211 new ECBlocks(26, new ECB(1, 108)),
212 new ECBlocks(24, new ECB(2, 43)),
213 new ECBlocks(18, new ECB(2, 15),
215 new ECBlocks(22, new ECB(2, 11),
217 VERSIONS.push_back(new Version(6, intArray(2, 6, 34),
218 new ECBlocks(18, new ECB(2, 68)),
219 new ECBlocks(16, new ECB(4, 27)),
220 new ECBlocks(24, new ECB(4, 19)),
221 new ECBlocks(28, new ECB(4, 15))));
222 VERSIONS.push_back(new Version(7, intArray(3, 6, 22, 38),
223 new ECBlocks(20, new ECB(2, 78)),
224 new ECBlocks(18, new ECB(4, 31)),
225 new ECBlocks(18, new ECB(2, 14),
227 new ECBlocks(26, new ECB(4, 13),
229 VERSIONS.push_back(new Version(8, intArray(3, 6, 24, 42),
230 new ECBlocks(24, new ECB(2, 97)),
231 new ECBlocks(22, new ECB(2, 38),
233 new ECBlocks(22, new ECB(4, 18),
235 new ECBlocks(26, new ECB(4, 14),
237 VERSIONS.push_back(new Version(9, intArray(3, 6, 26, 46),
238 new ECBlocks(30, new ECB(2, 116)),
239 new ECBlocks(22, new ECB(3, 36),
241 new ECBlocks(20, new ECB(4, 16),
243 new ECBlocks(24, new ECB(4, 12),
245 VERSIONS.push_back(new Version(10, intArray(3, 6, 28, 50),
246 new ECBlocks(18, new ECB(2, 68),
248 new ECBlocks(26, new ECB(4, 43),
250 new ECBlocks(24, new ECB(6, 19),
252 new ECBlocks(28, new ECB(6, 15),
254 VERSIONS.push_back(new Version(11, intArray(3, 6, 30, 54),
255 new ECBlocks(20, new ECB(4, 81)),
256 new ECBlocks(30, new ECB(1, 50),
258 new ECBlocks(28, new ECB(4, 22),
260 new ECBlocks(24, new ECB(3, 12),
262 VERSIONS.push_back(new Version(12, intArray(3, 6, 32, 58),
263 new ECBlocks(24, new ECB(2, 92),
265 new ECBlocks(22, new ECB(6, 36),
267 new ECBlocks(26, new ECB(4, 20),
269 new ECBlocks(28, new ECB(7, 14),
271 VERSIONS.push_back(new Version(13, intArray(3, 6, 34, 62),
272 new ECBlocks(26, new ECB(4, 107)),
273 new ECBlocks(22, new ECB(8, 37),
275 new ECBlocks(24, new ECB(8, 20),
277 new ECBlocks(22, new ECB(12, 11),
279 VERSIONS.push_back(new Version(14, intArray(4, 6, 26, 46, 66),
280 new ECBlocks(30, new ECB(3, 115),
282 new ECBlocks(24, new ECB(4, 40),
284 new ECBlocks(20, new ECB(11, 16),
286 new ECBlocks(24, new ECB(11, 12),
288 VERSIONS.push_back(new Version(15, intArray(4, 6, 26, 48, 70),
289 new ECBlocks(22, new ECB(5, 87),
291 new ECBlocks(24, new ECB(5, 41),
293 new ECBlocks(30, new ECB(5, 24),
295 new ECBlocks(24, new ECB(11, 12),
297 VERSIONS.push_back(new Version(16, intArray(4, 6, 26, 50, 74),
298 new ECBlocks(24, new ECB(5, 98),
300 new ECBlocks(28, new ECB(7, 45),
302 new ECBlocks(24, new ECB(15, 19),
304 new ECBlocks(30, new ECB(3, 15),
306 VERSIONS.push_back(new Version(17, intArray(4, 6, 30, 54, 78),
307 new ECBlocks(28, new ECB(1, 107),
309 new ECBlocks(28, new ECB(10, 46),
311 new ECBlocks(28, new ECB(1, 22),
313 new ECBlocks(28, new ECB(2, 14),
315 VERSIONS.push_back(new Version(18, intArray(4, 6, 30, 56, 82),
316 new ECBlocks(30, new ECB(5, 120),
318 new ECBlocks(26, new ECB(9, 43),
320 new ECBlocks(28, new ECB(17, 22),
322 new ECBlocks(28, new ECB(2, 14),
324 VERSIONS.push_back(new Version(19, intArray(4, 6, 30, 58, 86),
325 new ECBlocks(28, new ECB(3, 113),
327 new ECBlocks(26, new ECB(3, 44),
329 new ECBlocks(26, new ECB(17, 21),
331 new ECBlocks(26, new ECB(9, 13),
333 VERSIONS.push_back(new Version(20, intArray(4, 6, 34, 62, 90),
334 new ECBlocks(28, new ECB(3, 107),
336 new ECBlocks(26, new ECB(3, 41),
338 new ECBlocks(30, new ECB(15, 24),
340 new ECBlocks(28, new ECB(15, 15),
342 VERSIONS.push_back(new Version(21, intArray(5, 6, 28, 50, 72, 94),
343 new ECBlocks(28, new ECB(4, 116),
345 new ECBlocks(26, new ECB(17, 42)),
346 new ECBlocks(28, new ECB(17, 22),
348 new ECBlocks(30, new ECB(19, 16),
350 VERSIONS.push_back(new Version(22, intArray(5, 6, 26, 50, 74, 98),
351 new ECBlocks(28, new ECB(2, 111),
353 new ECBlocks(28, new ECB(17, 46)),
354 new ECBlocks(30, new ECB(7, 24),
356 new ECBlocks(24, new ECB(34, 13))));
357 VERSIONS.push_back(new Version(23, intArray(5, 6, 30, 54, 74, 102),
358 new ECBlocks(30, new ECB(4, 121),
360 new ECBlocks(28, new ECB(4, 47),
362 new ECBlocks(30, new ECB(11, 24),
364 new ECBlocks(30, new ECB(16, 15),
366 VERSIONS.push_back(new Version(24, intArray(5, 6, 28, 54, 80, 106),
367 new ECBlocks(30, new ECB(6, 117),
369 new ECBlocks(28, new ECB(6, 45),
371 new ECBlocks(30, new ECB(11, 24),
373 new ECBlocks(30, new ECB(30, 16),
375 VERSIONS.push_back(new Version(25, intArray(5, 6, 32, 58, 84, 110),
376 new ECBlocks(26, new ECB(8, 106),
378 new ECBlocks(28, new ECB(8, 47),
380 new ECBlocks(30, new ECB(7, 24),
382 new ECBlocks(30, new ECB(22, 15),
384 VERSIONS.push_back(new Version(26, intArray(5, 6, 30, 58, 86, 114),
385 new ECBlocks(28, new ECB(10, 114),
387 new ECBlocks(28, new ECB(19, 46),
389 new ECBlocks(28, new ECB(28, 22),
391 new ECBlocks(30, new ECB(33, 16),
393 VERSIONS.push_back(new Version(27, intArray(5, 6, 34, 62, 90, 118),
394 new ECBlocks(30, new ECB(8, 122),
396 new ECBlocks(28, new ECB(22, 45),
398 new ECBlocks(30, new ECB(8, 23),
400 new ECBlocks(30, new ECB(12, 15),
402 VERSIONS.push_back(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122),
403 new ECBlocks(30, new ECB(3, 117),
405 new ECBlocks(28, new ECB(3, 45),
407 new ECBlocks(30, new ECB(4, 24),
409 new ECBlocks(30, new ECB(11, 15),
411 VERSIONS.push_back(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126),
412 new ECBlocks(30, new ECB(7, 116),
414 new ECBlocks(28, new ECB(21, 45),
416 new ECBlocks(30, new ECB(1, 23),
418 new ECBlocks(30, new ECB(19, 15),
420 VERSIONS.push_back(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130),
421 new ECBlocks(30, new ECB(5, 115),
423 new ECBlocks(28, new ECB(19, 47),
425 new ECBlocks(30, new ECB(15, 24),
427 new ECBlocks(30, new ECB(23, 15),
429 VERSIONS.push_back(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134),
430 new ECBlocks(30, new ECB(13, 115),
432 new ECBlocks(28, new ECB(2, 46),
434 new ECBlocks(30, new ECB(42, 24),
436 new ECBlocks(30, new ECB(23, 15),
438 VERSIONS.push_back(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138),
439 new ECBlocks(30, new ECB(17, 115)),
440 new ECBlocks(28, new ECB(10, 46),
442 new ECBlocks(30, new ECB(10, 24),
444 new ECBlocks(30, new ECB(19, 15),
446 VERSIONS.push_back(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142),
447 new ECBlocks(30, new ECB(17, 115),
449 new ECBlocks(28, new ECB(14, 46),
451 new ECBlocks(30, new ECB(29, 24),
453 new ECBlocks(30, new ECB(11, 15),
455 VERSIONS.push_back(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146),
456 new ECBlocks(30, new ECB(13, 115),
458 new ECBlocks(28, new ECB(14, 46),
460 new ECBlocks(30, new ECB(44, 24),
462 new ECBlocks(30, new ECB(59, 16),
464 VERSIONS.push_back(new Version(35, intArray(7, 6, 30, 54, 78,
466 new ECBlocks(30, new ECB(12, 121),
468 new ECBlocks(28, new ECB(12, 47),
470 new ECBlocks(30, new ECB(39, 24),
472 new ECBlocks(30, new ECB(22, 15),
474 VERSIONS.push_back(new Version(36, intArray(7, 6, 24, 50, 76,
476 new ECBlocks(30, new ECB(6, 121),
478 new ECBlocks(28, new ECB(6, 47),
480 new ECBlocks(30, new ECB(46, 24),
482 new ECBlocks(30, new ECB(2, 15),
484 VERSIONS.push_back(new Version(37, intArray(7, 6, 28, 54, 80,
486 new ECBlocks(30, new ECB(17, 122),
488 new ECBlocks(28, new ECB(29, 46),
490 new ECBlocks(30, new ECB(49, 24),
492 new ECBlocks(30, new ECB(24, 15),
494 VERSIONS.push_back(new Version(38, intArray(7, 6, 32, 58, 84,
496 new ECBlocks(30, new ECB(4, 122),
498 new ECBlocks(28, new ECB(13, 46),
500 new ECBlocks(30, new ECB(48, 24),
502 new ECBlocks(30, new ECB(42, 15),
504 VERSIONS.push_back(new Version(39, intArray(7, 6, 26, 54, 82,
506 new ECBlocks(30, new ECB(20, 117),
508 new ECBlocks(28, new ECB(40, 47),
510 new ECBlocks(30, new ECB(43, 24),
512 new ECBlocks(30, new ECB(10, 15),
514 VERSIONS.push_back(new Version(40, intArray(7, 6, 30, 58, 86,
516 new ECBlocks(30, new ECB(19, 118),
518 new ECBlocks(28, new ECB(18, 47),
520 new ECBlocks(30, new ECB(34, 24),
522 new ECBlocks(30, new ECB(20, 15),
524 return VERSIONS.size();