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.
21 #include <zxing/qrcode/Version.h>
22 #include <zxing/qrcode/FormatInformation.h>
31 ECB::ECB(int count, int dataCodewords) :
32 count_(count), dataCodewords_(dataCodewords) {
39 int ECB::getDataCodewords() {
40 return dataCodewords_;
43 ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks) :
44 ecCodewords_(ecCodewords) {
45 ecBlocks_.push_back(ecBlocks);
48 ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) :
49 ecCodewords_(ecCodewords) {
50 ecBlocks_.push_back(ecBlocks1);
51 ecBlocks_.push_back(ecBlocks2);
54 int ECBlocks::getECCodewords() {
58 std::vector<ECB*>& ECBlocks::getECBlocks() {
62 ECBlocks::~ECBlocks() {
63 for (size_t i = 0; i < ecBlocks_.size(); i++) {
68 unsigned int Version::VERSION_DECODE_INFO[] = { 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D,
69 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
70 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64,
73 int Version::N_VERSION_DECODE_INFOS = 34;
74 vector<Ref<Version> > Version::VERSIONS;
75 static int N_VERSIONS = Version::buildVersions();
77 int Version::getVersionNumber() {
78 return versionNumber_;
81 valarray<int> &Version::getAlignmentPatternCenters() {
82 return alignmentPatternCenters_;
85 int Version::getTotalCodewords() {
86 return totalCodewords_;
89 int Version::getDimensionForVersion() {
90 return 17 + 4 * versionNumber_;
93 ECBlocks& Version::getECBlocksForLevel(ErrorCorrectionLevel &ecLevel) {
94 return *ecBlocks_[ecLevel.ordinal()];
97 Version *Version::getProvisionalVersionForDimension(int dimension) {
98 if (dimension % 4 != 1) {
99 throw ReaderException("Dimension must be 1 mod 4");
101 return Version::getVersionForNumber((dimension - 17) >> 2);
104 Version *Version::getVersionForNumber(int versionNumber) {
105 if (versionNumber < 1 || versionNumber > 40) {
106 throw ReaderException("versionNumber must be between 1 and 40");
109 return VERSIONS[versionNumber - 1];
112 Version::Version(int versionNumber, valarray<int> *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2,
113 ECBlocks *ecBlocks3, ECBlocks *ecBlocks4) :
114 versionNumber_(versionNumber), alignmentPatternCenters_(*alignmentPatternCenters), ecBlocks_(4) {
115 ecBlocks_[0] = ecBlocks1;
116 ecBlocks_[1] = ecBlocks2;
117 ecBlocks_[2] = ecBlocks3;
118 ecBlocks_[3] = ecBlocks4;
121 int ecCodewords = ecBlocks1->getECCodewords();
122 vector<ECB*> &ecbArray = ecBlocks1->getECBlocks();
123 for (size_t i = 0; i < ecbArray.size(); i++) {
124 ECB *ecBlock = ecbArray[i];
125 total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);
127 totalCodewords_ = total;
130 Version::~Version() {
131 delete &alignmentPatternCenters_;
132 for (size_t i = 0; i < ecBlocks_.size(); i++) {
137 Version *Version::decodeVersionInformation(unsigned int versionBits) {
138 int bestDifference = numeric_limits<int>::max();
139 size_t bestVersion = 0;
140 for (int i = 0; i < N_VERSION_DECODE_INFOS; i++) {
141 unsigned targetVersion = VERSION_DECODE_INFO[i];
142 // Do the version info bits match exactly? done.
143 if (targetVersion == versionBits) {
144 return getVersionForNumber(i + 7);
146 // Otherwise see if this is the closest to a real version info bit
147 // string we have seen so far
148 int bitsDifference = FormatInformation::numBitsDiffering(versionBits, targetVersion);
149 if (bitsDifference < bestDifference) {
151 bestDifference = bitsDifference;
154 // We can tolerate up to 3 bits of error since no two version info codewords will
155 // differ in less than 4 bits.
156 if (bestDifference <= 3) {
157 return getVersionForNumber(bestVersion);
159 // If we didn't find a close enough match, fail
163 Ref<BitMatrix> Version::buildFunctionPattern() {
164 int dimension = getDimensionForVersion();
165 Ref<BitMatrix> functionPattern(new BitMatrix(dimension));
168 // Top left finder pattern + separator + format
169 functionPattern->setRegion(0, 0, 9, 9);
170 // Top right finder pattern + separator + format
171 functionPattern->setRegion(dimension - 8, 0, 8, 9);
172 // Bottom left finder pattern + separator + format
173 functionPattern->setRegion(0, dimension - 8, 9, 8);
176 // Alignment patterns
177 size_t max = alignmentPatternCenters_.size();
178 for (size_t x = 0; x < max; x++) {
179 int i = alignmentPatternCenters_[x] - 2;
180 for (size_t y = 0; y < max; y++) {
181 if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
182 // No alignment patterns near the three finder patterns
185 functionPattern->setRegion(alignmentPatternCenters_[y] - 2, i, 5, 5);
189 // Vertical timing pattern
190 functionPattern->setRegion(6, 9, 1, dimension - 17);
191 // Horizontal timing pattern
192 functionPattern->setRegion(9, 6, dimension - 17, 1);
194 if (versionNumber_ > 6) {
195 // Version info, top right
196 functionPattern->setRegion(dimension - 11, 0, 3, 6);
197 // Version info, bottom left
198 functionPattern->setRegion(0, dimension - 11, 6, 3);
203 // cout << "version " << versionNumber_ << " built function pattern:\n";
204 // cout << *functionPattern;
207 return functionPattern;
210 static valarray<int> *intArray(size_t n...) {
213 valarray<int> *result = new valarray<int>(n);
214 for (size_t i = 0; i < n; i++) {
215 (*result)[i] = va_arg(ap, int);
221 int Version::buildVersions() {
222 VERSIONS.push_back(Ref<Version>(new Version(1, intArray(0),
223 new ECBlocks(7, new ECB(1, 19)),
224 new ECBlocks(10, new ECB(1, 16)),
225 new ECBlocks(13, new ECB(1, 13)),
226 new ECBlocks(17, new ECB(1, 9)))));
227 VERSIONS.push_back(Ref<Version>(new Version(2, intArray(2, 6, 18),
228 new ECBlocks(10, new ECB(1, 34)),
229 new ECBlocks(16, new ECB(1, 28)),
230 new ECBlocks(22, new ECB(1, 22)),
231 new ECBlocks(28, new ECB(1, 16)))));
232 VERSIONS.push_back(Ref<Version>(new Version(3, intArray(2, 6, 22),
233 new ECBlocks(15, new ECB(1, 55)),
234 new ECBlocks(26, new ECB(1, 44)),
235 new ECBlocks(18, new ECB(2, 17)),
236 new ECBlocks(22, new ECB(2, 13)))));
237 VERSIONS.push_back(Ref<Version>(new Version(4, intArray(2, 6, 26),
238 new ECBlocks(20, new ECB(1, 80)),
239 new ECBlocks(18, new ECB(2, 32)),
240 new ECBlocks(26, new ECB(2, 24)),
241 new ECBlocks(16, new ECB(4, 9)))));
242 VERSIONS.push_back(Ref<Version>(new Version(5, intArray(2, 6, 30),
243 new ECBlocks(26, new ECB(1, 108)),
244 new ECBlocks(24, new ECB(2, 43)),
245 new ECBlocks(18, new ECB(2, 15),
247 new ECBlocks(22, new ECB(2, 11),
249 VERSIONS.push_back(Ref<Version>(new Version(6, intArray(2, 6, 34),
250 new ECBlocks(18, new ECB(2, 68)),
251 new ECBlocks(16, new ECB(4, 27)),
252 new ECBlocks(24, new ECB(4, 19)),
253 new ECBlocks(28, new ECB(4, 15)))));
254 VERSIONS.push_back(Ref<Version>(new Version(7, intArray(3, 6, 22, 38),
255 new ECBlocks(20, new ECB(2, 78)),
256 new ECBlocks(18, new ECB(4, 31)),
257 new ECBlocks(18, new ECB(2, 14),
259 new ECBlocks(26, new ECB(4, 13),
261 VERSIONS.push_back(Ref<Version>(new Version(8, intArray(3, 6, 24, 42),
262 new ECBlocks(24, new ECB(2, 97)),
263 new ECBlocks(22, new ECB(2, 38),
265 new ECBlocks(22, new ECB(4, 18),
267 new ECBlocks(26, new ECB(4, 14),
269 VERSIONS.push_back(Ref<Version>(new Version(9, intArray(3, 6, 26, 46),
270 new ECBlocks(30, new ECB(2, 116)),
271 new ECBlocks(22, new ECB(3, 36),
273 new ECBlocks(20, new ECB(4, 16),
275 new ECBlocks(24, new ECB(4, 12),
277 VERSIONS.push_back(Ref<Version>(new Version(10, intArray(3, 6, 28, 50),
278 new ECBlocks(18, new ECB(2, 68),
280 new ECBlocks(26, new ECB(4, 43),
282 new ECBlocks(24, new ECB(6, 19),
284 new ECBlocks(28, new ECB(6, 15),
286 VERSIONS.push_back(Ref<Version>(new Version(11, intArray(3, 6, 30, 54),
287 new ECBlocks(20, new ECB(4, 81)),
288 new ECBlocks(30, new ECB(1, 50),
290 new ECBlocks(28, new ECB(4, 22),
292 new ECBlocks(24, new ECB(3, 12),
294 VERSIONS.push_back(Ref<Version>(new Version(12, intArray(3, 6, 32, 58),
295 new ECBlocks(24, new ECB(2, 92),
297 new ECBlocks(22, new ECB(6, 36),
299 new ECBlocks(26, new ECB(4, 20),
301 new ECBlocks(28, new ECB(7, 14),
303 VERSIONS.push_back(Ref<Version>(new Version(13, intArray(3, 6, 34, 62),
304 new ECBlocks(26, new ECB(4, 107)),
305 new ECBlocks(22, new ECB(8, 37),
307 new ECBlocks(24, new ECB(8, 20),
309 new ECBlocks(22, new ECB(12, 11),
311 VERSIONS.push_back(Ref<Version>(new Version(14, intArray(4, 6, 26, 46, 66),
312 new ECBlocks(30, new ECB(3, 115),
314 new ECBlocks(24, new ECB(4, 40),
316 new ECBlocks(20, new ECB(11, 16),
318 new ECBlocks(24, new ECB(11, 12),
320 VERSIONS.push_back(Ref<Version>(new Version(15, intArray(4, 6, 26, 48, 70),
321 new ECBlocks(22, new ECB(5, 87),
323 new ECBlocks(24, new ECB(5, 41),
325 new ECBlocks(30, new ECB(5, 24),
327 new ECBlocks(24, new ECB(11, 12),
329 VERSIONS.push_back(Ref<Version>(new Version(16, intArray(4, 6, 26, 50, 74),
330 new ECBlocks(24, new ECB(5, 98),
332 new ECBlocks(28, new ECB(7, 45),
334 new ECBlocks(24, new ECB(15, 19),
336 new ECBlocks(30, new ECB(3, 15),
338 VERSIONS.push_back(Ref<Version>(new Version(17, intArray(4, 6, 30, 54, 78),
339 new ECBlocks(28, new ECB(1, 107),
341 new ECBlocks(28, new ECB(10, 46),
343 new ECBlocks(28, new ECB(1, 22),
345 new ECBlocks(28, new ECB(2, 14),
347 VERSIONS.push_back(Ref<Version>(new Version(18, intArray(4, 6, 30, 56, 82),
348 new ECBlocks(30, new ECB(5, 120),
350 new ECBlocks(26, new ECB(9, 43),
352 new ECBlocks(28, new ECB(17, 22),
354 new ECBlocks(28, new ECB(2, 14),
356 VERSIONS.push_back(Ref<Version>(new Version(19, intArray(4, 6, 30, 58, 86),
357 new ECBlocks(28, new ECB(3, 113),
359 new ECBlocks(26, new ECB(3, 44),
361 new ECBlocks(26, new ECB(17, 21),
363 new ECBlocks(26, new ECB(9, 13),
365 VERSIONS.push_back(Ref<Version>(new Version(20, intArray(4, 6, 34, 62, 90),
366 new ECBlocks(28, new ECB(3, 107),
368 new ECBlocks(26, new ECB(3, 41),
370 new ECBlocks(30, new ECB(15, 24),
372 new ECBlocks(28, new ECB(15, 15),
374 VERSIONS.push_back(Ref<Version>(new Version(21, intArray(5, 6, 28, 50, 72, 94),
375 new ECBlocks(28, new ECB(4, 116),
377 new ECBlocks(26, new ECB(17, 42)),
378 new ECBlocks(28, new ECB(17, 22),
380 new ECBlocks(30, new ECB(19, 16),
382 VERSIONS.push_back(Ref<Version>(new Version(22, intArray(5, 6, 26, 50, 74, 98),
383 new ECBlocks(28, new ECB(2, 111),
385 new ECBlocks(28, new ECB(17, 46)),
386 new ECBlocks(30, new ECB(7, 24),
388 new ECBlocks(24, new ECB(34, 13)))));
389 VERSIONS.push_back(Ref<Version>(new Version(23, intArray(5, 6, 30, 54, 74, 102),
390 new ECBlocks(30, new ECB(4, 121),
392 new ECBlocks(28, new ECB(4, 47),
394 new ECBlocks(30, new ECB(11, 24),
396 new ECBlocks(30, new ECB(16, 15),
398 VERSIONS.push_back(Ref<Version>(new Version(24, intArray(5, 6, 28, 54, 80, 106),
399 new ECBlocks(30, new ECB(6, 117),
401 new ECBlocks(28, new ECB(6, 45),
403 new ECBlocks(30, new ECB(11, 24),
405 new ECBlocks(30, new ECB(30, 16),
407 VERSIONS.push_back(Ref<Version>(new Version(25, intArray(5, 6, 32, 58, 84, 110),
408 new ECBlocks(26, new ECB(8, 106),
410 new ECBlocks(28, new ECB(8, 47),
412 new ECBlocks(30, new ECB(7, 24),
414 new ECBlocks(30, new ECB(22, 15),
416 VERSIONS.push_back(Ref<Version>(new Version(26, intArray(5, 6, 30, 58, 86, 114),
417 new ECBlocks(28, new ECB(10, 114),
419 new ECBlocks(28, new ECB(19, 46),
421 new ECBlocks(28, new ECB(28, 22),
423 new ECBlocks(30, new ECB(33, 16),
425 VERSIONS.push_back(Ref<Version>(new Version(27, intArray(5, 6, 34, 62, 90, 118),
426 new ECBlocks(30, new ECB(8, 122),
428 new ECBlocks(28, new ECB(22, 45),
430 new ECBlocks(30, new ECB(8, 23),
432 new ECBlocks(30, new ECB(12, 15),
434 VERSIONS.push_back(Ref<Version>(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122),
435 new ECBlocks(30, new ECB(3, 117),
437 new ECBlocks(28, new ECB(3, 45),
439 new ECBlocks(30, new ECB(4, 24),
441 new ECBlocks(30, new ECB(11, 15),
443 VERSIONS.push_back(Ref<Version>(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126),
444 new ECBlocks(30, new ECB(7, 116),
446 new ECBlocks(28, new ECB(21, 45),
448 new ECBlocks(30, new ECB(1, 23),
450 new ECBlocks(30, new ECB(19, 15),
452 VERSIONS.push_back(Ref<Version>(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130),
453 new ECBlocks(30, new ECB(5, 115),
455 new ECBlocks(28, new ECB(19, 47),
457 new ECBlocks(30, new ECB(15, 24),
459 new ECBlocks(30, new ECB(23, 15),
461 VERSIONS.push_back(Ref<Version>(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134),
462 new ECBlocks(30, new ECB(13, 115),
464 new ECBlocks(28, new ECB(2, 46),
466 new ECBlocks(30, new ECB(42, 24),
468 new ECBlocks(30, new ECB(23, 15),
470 VERSIONS.push_back(Ref<Version>(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138),
471 new ECBlocks(30, new ECB(17, 115)),
472 new ECBlocks(28, new ECB(10, 46),
474 new ECBlocks(30, new ECB(10, 24),
476 new ECBlocks(30, new ECB(19, 15),
478 VERSIONS.push_back(Ref<Version>(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142),
479 new ECBlocks(30, new ECB(17, 115),
481 new ECBlocks(28, new ECB(14, 46),
483 new ECBlocks(30, new ECB(29, 24),
485 new ECBlocks(30, new ECB(11, 15),
487 VERSIONS.push_back(Ref<Version>(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146),
488 new ECBlocks(30, new ECB(13, 115),
490 new ECBlocks(28, new ECB(14, 46),
492 new ECBlocks(30, new ECB(44, 24),
494 new ECBlocks(30, new ECB(59, 16),
496 VERSIONS.push_back(Ref<Version>(new Version(35, intArray(7, 6, 30, 54, 78,
498 new ECBlocks(30, new ECB(12, 121),
500 new ECBlocks(28, new ECB(12, 47),
502 new ECBlocks(30, new ECB(39, 24),
504 new ECBlocks(30, new ECB(22, 15),
506 VERSIONS.push_back(Ref<Version>(new Version(36, intArray(7, 6, 24, 50, 76,
508 new ECBlocks(30, new ECB(6, 121),
510 new ECBlocks(28, new ECB(6, 47),
512 new ECBlocks(30, new ECB(46, 24),
514 new ECBlocks(30, new ECB(2, 15),
516 VERSIONS.push_back(Ref<Version>(new Version(37, intArray(7, 6, 28, 54, 80,
518 new ECBlocks(30, new ECB(17, 122),
520 new ECBlocks(28, new ECB(29, 46),
522 new ECBlocks(30, new ECB(49, 24),
524 new ECBlocks(30, new ECB(24, 15),
526 VERSIONS.push_back(Ref<Version>(new Version(38, intArray(7, 6, 32, 58, 84,
528 new ECBlocks(30, new ECB(4, 122),
530 new ECBlocks(28, new ECB(13, 46),
532 new ECBlocks(30, new ECB(48, 24),
534 new ECBlocks(30, new ECB(42, 15),
536 VERSIONS.push_back(Ref<Version>(new Version(39, intArray(7, 6, 26, 54, 82,
538 new ECBlocks(30, new ECB(20, 117),
540 new ECBlocks(28, new ECB(40, 47),
542 new ECBlocks(30, new ECB(43, 24),
544 new ECBlocks(30, new ECB(10, 15),
546 VERSIONS.push_back(Ref<Version>(new Version(40, intArray(7, 6, 30, 58, 86,
548 new ECBlocks(30, new ECB(19, 118),
550 new ECBlocks(28, new ECB(18, 47),
552 new ECBlocks(30, new ECB(34, 24),
554 new ECBlocks(30, new ECB(20, 15),
556 return VERSIONS.size();