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), ecBlocks_(1, ecBlocks) {
47 ECBlocks::ECBlocks(int ecCodewords, ECB *ecBlocks1, ECB *ecBlocks2) :
48 ecCodewords_(ecCodewords), ecBlocks_(1, ecBlocks1) {
49 ecBlocks_.push_back(ecBlocks2);
52 int ECBlocks::getECCodewords() {
56 std::vector<ECB*>& ECBlocks::getECBlocks() {
60 ECBlocks::~ECBlocks() {
61 for (size_t i = 0; i < ecBlocks_.size(); i++) {
66 unsigned int Version::VERSION_DECODE_INFO[] = { 0x07C94, 0x085BC, 0x09A99, 0x0A4D3, 0x0BBF6, 0x0C762, 0x0D847, 0x0E60D,
67 0x0F928, 0x10B78, 0x1145D, 0x12A17, 0x13532, 0x149A6, 0x15683, 0x168C9, 0x177EC, 0x18EC4, 0x191E1, 0x1AFAB,
68 0x1B08E, 0x1CC1A, 0x1D33F, 0x1ED75, 0x1F250, 0x209D5, 0x216F0, 0x228BA, 0x2379F, 0x24B0B, 0x2542E, 0x26A64,
71 int Version::N_VERSION_DECODE_INFOS = 34;
72 vector<Ref<Version> > Version::VERSIONS;
73 static int N_VERSIONS = Version::buildVersions();
75 int Version::getVersionNumber() {
76 return versionNumber_;
79 vector<int> &Version::getAlignmentPatternCenters() {
80 return alignmentPatternCenters_;
83 int Version::getTotalCodewords() {
84 return totalCodewords_;
87 int Version::getDimensionForVersion() {
88 return 17 + 4 * versionNumber_;
91 ECBlocks& Version::getECBlocksForLevel(ErrorCorrectionLevel &ecLevel) {
92 return *ecBlocks_[ecLevel.ordinal()];
95 Version *Version::getProvisionalVersionForDimension(int dimension) {
96 if (dimension % 4 != 1) {
97 throw ReaderException("Dimension must be 1 mod 4");
99 return Version::getVersionForNumber((dimension - 17) >> 2);
102 Version *Version::getVersionForNumber(int versionNumber) {
103 if (versionNumber < 1 || versionNumber > N_VERSIONS) {
104 throw ReaderException("versionNumber must be between 1 and 40");
107 return VERSIONS[versionNumber - 1];
110 Version::Version(int versionNumber, vector<int> *alignmentPatternCenters, ECBlocks *ecBlocks1, ECBlocks *ecBlocks2,
111 ECBlocks *ecBlocks3, ECBlocks *ecBlocks4) :
112 versionNumber_(versionNumber), alignmentPatternCenters_(*alignmentPatternCenters), ecBlocks_(4), totalCodewords_(0) {
113 ecBlocks_[0] = ecBlocks1;
114 ecBlocks_[1] = ecBlocks2;
115 ecBlocks_[2] = ecBlocks3;
116 ecBlocks_[3] = ecBlocks4;
119 int ecCodewords = ecBlocks1->getECCodewords();
120 vector<ECB*> &ecbArray = ecBlocks1->getECBlocks();
121 for (size_t i = 0; i < ecbArray.size(); i++) {
122 ECB *ecBlock = ecbArray[i];
123 total += ecBlock->getCount() * (ecBlock->getDataCodewords() + ecCodewords);
125 totalCodewords_ = total;
128 Version::~Version() {
129 delete &alignmentPatternCenters_;
130 for (size_t i = 0; i < ecBlocks_.size(); i++) {
135 Version *Version::decodeVersionInformation(unsigned int versionBits) {
136 int bestDifference = numeric_limits<int>::max();
137 size_t bestVersion = 0;
138 for (int i = 0; i < N_VERSION_DECODE_INFOS; i++) {
139 unsigned targetVersion = VERSION_DECODE_INFO[i];
140 // Do the version info bits match exactly? done.
141 if (targetVersion == versionBits) {
142 return getVersionForNumber(i + 7);
144 // Otherwise see if this is the closest to a real version info bit
145 // string we have seen so far
146 int bitsDifference = FormatInformation::numBitsDiffering(versionBits, targetVersion);
147 if (bitsDifference < bestDifference) {
149 bestDifference = bitsDifference;
152 // We can tolerate up to 3 bits of error since no two version info codewords will
153 // differ in less than 4 bits.
154 if (bestDifference <= 3) {
155 return getVersionForNumber(bestVersion);
157 // If we didn't find a close enough match, fail
161 Ref<BitMatrix> Version::buildFunctionPattern() {
162 int dimension = getDimensionForVersion();
163 Ref<BitMatrix> functionPattern(new BitMatrix(dimension));
166 // Top left finder pattern + separator + format
167 functionPattern->setRegion(0, 0, 9, 9);
168 // Top right finder pattern + separator + format
169 functionPattern->setRegion(dimension - 8, 0, 8, 9);
170 // Bottom left finder pattern + separator + format
171 functionPattern->setRegion(0, dimension - 8, 9, 8);
174 // Alignment patterns
175 size_t max = alignmentPatternCenters_.size();
176 for (size_t x = 0; x < max; x++) {
177 int i = alignmentPatternCenters_[x] - 2;
178 for (size_t y = 0; y < max; y++) {
179 if ((x == 0 && (y == 0 || y == max - 1)) || (x == max - 1 && y == 0)) {
180 // No alignment patterns near the three finder patterns
183 functionPattern->setRegion(alignmentPatternCenters_[y] - 2, i, 5, 5);
187 // Vertical timing pattern
188 functionPattern->setRegion(6, 9, 1, dimension - 17);
189 // Horizontal timing pattern
190 functionPattern->setRegion(9, 6, dimension - 17, 1);
192 if (versionNumber_ > 6) {
193 // Version info, top right
194 functionPattern->setRegion(dimension - 11, 0, 3, 6);
195 // Version info, bottom left
196 functionPattern->setRegion(0, dimension - 11, 6, 3);
201 // cout << "version " << versionNumber_ << " built function pattern:\n";
202 // cout << *functionPattern;
205 return functionPattern;
208 static vector<int> *intArray(size_t n...) {
211 vector<int> *result = new vector<int>(n);
212 for (size_t i = 0; i < n; i++) {
213 (*result)[i] = va_arg(ap, int);
219 int Version::buildVersions() {
220 VERSIONS.push_back(Ref<Version>(new Version(1, intArray(0),
221 new ECBlocks(7, new ECB(1, 19)),
222 new ECBlocks(10, new ECB(1, 16)),
223 new ECBlocks(13, new ECB(1, 13)),
224 new ECBlocks(17, new ECB(1, 9)))));
225 VERSIONS.push_back(Ref<Version>(new Version(2, intArray(2, 6, 18),
226 new ECBlocks(10, new ECB(1, 34)),
227 new ECBlocks(16, new ECB(1, 28)),
228 new ECBlocks(22, new ECB(1, 22)),
229 new ECBlocks(28, new ECB(1, 16)))));
230 VERSIONS.push_back(Ref<Version>(new Version(3, intArray(2, 6, 22),
231 new ECBlocks(15, new ECB(1, 55)),
232 new ECBlocks(26, new ECB(1, 44)),
233 new ECBlocks(18, new ECB(2, 17)),
234 new ECBlocks(22, new ECB(2, 13)))));
235 VERSIONS.push_back(Ref<Version>(new Version(4, intArray(2, 6, 26),
236 new ECBlocks(20, new ECB(1, 80)),
237 new ECBlocks(18, new ECB(2, 32)),
238 new ECBlocks(26, new ECB(2, 24)),
239 new ECBlocks(16, new ECB(4, 9)))));
240 VERSIONS.push_back(Ref<Version>(new Version(5, intArray(2, 6, 30),
241 new ECBlocks(26, new ECB(1, 108)),
242 new ECBlocks(24, new ECB(2, 43)),
243 new ECBlocks(18, new ECB(2, 15),
245 new ECBlocks(22, new ECB(2, 11),
247 VERSIONS.push_back(Ref<Version>(new Version(6, intArray(2, 6, 34),
248 new ECBlocks(18, new ECB(2, 68)),
249 new ECBlocks(16, new ECB(4, 27)),
250 new ECBlocks(24, new ECB(4, 19)),
251 new ECBlocks(28, new ECB(4, 15)))));
252 VERSIONS.push_back(Ref<Version>(new Version(7, intArray(3, 6, 22, 38),
253 new ECBlocks(20, new ECB(2, 78)),
254 new ECBlocks(18, new ECB(4, 31)),
255 new ECBlocks(18, new ECB(2, 14),
257 new ECBlocks(26, new ECB(4, 13),
259 VERSIONS.push_back(Ref<Version>(new Version(8, intArray(3, 6, 24, 42),
260 new ECBlocks(24, new ECB(2, 97)),
261 new ECBlocks(22, new ECB(2, 38),
263 new ECBlocks(22, new ECB(4, 18),
265 new ECBlocks(26, new ECB(4, 14),
267 VERSIONS.push_back(Ref<Version>(new Version(9, intArray(3, 6, 26, 46),
268 new ECBlocks(30, new ECB(2, 116)),
269 new ECBlocks(22, new ECB(3, 36),
271 new ECBlocks(20, new ECB(4, 16),
273 new ECBlocks(24, new ECB(4, 12),
275 VERSIONS.push_back(Ref<Version>(new Version(10, intArray(3, 6, 28, 50),
276 new ECBlocks(18, new ECB(2, 68),
278 new ECBlocks(26, new ECB(4, 43),
280 new ECBlocks(24, new ECB(6, 19),
282 new ECBlocks(28, new ECB(6, 15),
284 VERSIONS.push_back(Ref<Version>(new Version(11, intArray(3, 6, 30, 54),
285 new ECBlocks(20, new ECB(4, 81)),
286 new ECBlocks(30, new ECB(1, 50),
288 new ECBlocks(28, new ECB(4, 22),
290 new ECBlocks(24, new ECB(3, 12),
292 VERSIONS.push_back(Ref<Version>(new Version(12, intArray(3, 6, 32, 58),
293 new ECBlocks(24, new ECB(2, 92),
295 new ECBlocks(22, new ECB(6, 36),
297 new ECBlocks(26, new ECB(4, 20),
299 new ECBlocks(28, new ECB(7, 14),
301 VERSIONS.push_back(Ref<Version>(new Version(13, intArray(3, 6, 34, 62),
302 new ECBlocks(26, new ECB(4, 107)),
303 new ECBlocks(22, new ECB(8, 37),
305 new ECBlocks(24, new ECB(8, 20),
307 new ECBlocks(22, new ECB(12, 11),
309 VERSIONS.push_back(Ref<Version>(new Version(14, intArray(4, 6, 26, 46, 66),
310 new ECBlocks(30, new ECB(3, 115),
312 new ECBlocks(24, new ECB(4, 40),
314 new ECBlocks(20, new ECB(11, 16),
316 new ECBlocks(24, new ECB(11, 12),
318 VERSIONS.push_back(Ref<Version>(new Version(15, intArray(4, 6, 26, 48, 70),
319 new ECBlocks(22, new ECB(5, 87),
321 new ECBlocks(24, new ECB(5, 41),
323 new ECBlocks(30, new ECB(5, 24),
325 new ECBlocks(24, new ECB(11, 12),
327 VERSIONS.push_back(Ref<Version>(new Version(16, intArray(4, 6, 26, 50, 74),
328 new ECBlocks(24, new ECB(5, 98),
330 new ECBlocks(28, new ECB(7, 45),
332 new ECBlocks(24, new ECB(15, 19),
334 new ECBlocks(30, new ECB(3, 15),
336 VERSIONS.push_back(Ref<Version>(new Version(17, intArray(4, 6, 30, 54, 78),
337 new ECBlocks(28, new ECB(1, 107),
339 new ECBlocks(28, new ECB(10, 46),
341 new ECBlocks(28, new ECB(1, 22),
343 new ECBlocks(28, new ECB(2, 14),
345 VERSIONS.push_back(Ref<Version>(new Version(18, intArray(4, 6, 30, 56, 82),
346 new ECBlocks(30, new ECB(5, 120),
348 new ECBlocks(26, new ECB(9, 43),
350 new ECBlocks(28, new ECB(17, 22),
352 new ECBlocks(28, new ECB(2, 14),
354 VERSIONS.push_back(Ref<Version>(new Version(19, intArray(4, 6, 30, 58, 86),
355 new ECBlocks(28, new ECB(3, 113),
357 new ECBlocks(26, new ECB(3, 44),
359 new ECBlocks(26, new ECB(17, 21),
361 new ECBlocks(26, new ECB(9, 13),
363 VERSIONS.push_back(Ref<Version>(new Version(20, intArray(4, 6, 34, 62, 90),
364 new ECBlocks(28, new ECB(3, 107),
366 new ECBlocks(26, new ECB(3, 41),
368 new ECBlocks(30, new ECB(15, 24),
370 new ECBlocks(28, new ECB(15, 15),
372 VERSIONS.push_back(Ref<Version>(new Version(21, intArray(5, 6, 28, 50, 72, 94),
373 new ECBlocks(28, new ECB(4, 116),
375 new ECBlocks(26, new ECB(17, 42)),
376 new ECBlocks(28, new ECB(17, 22),
378 new ECBlocks(30, new ECB(19, 16),
380 VERSIONS.push_back(Ref<Version>(new Version(22, intArray(5, 6, 26, 50, 74, 98),
381 new ECBlocks(28, new ECB(2, 111),
383 new ECBlocks(28, new ECB(17, 46)),
384 new ECBlocks(30, new ECB(7, 24),
386 new ECBlocks(24, new ECB(34, 13)))));
387 VERSIONS.push_back(Ref<Version>(new Version(23, intArray(5, 6, 30, 54, 74, 102),
388 new ECBlocks(30, new ECB(4, 121),
390 new ECBlocks(28, new ECB(4, 47),
392 new ECBlocks(30, new ECB(11, 24),
394 new ECBlocks(30, new ECB(16, 15),
396 VERSIONS.push_back(Ref<Version>(new Version(24, intArray(5, 6, 28, 54, 80, 106),
397 new ECBlocks(30, new ECB(6, 117),
399 new ECBlocks(28, new ECB(6, 45),
401 new ECBlocks(30, new ECB(11, 24),
403 new ECBlocks(30, new ECB(30, 16),
405 VERSIONS.push_back(Ref<Version>(new Version(25, intArray(5, 6, 32, 58, 84, 110),
406 new ECBlocks(26, new ECB(8, 106),
408 new ECBlocks(28, new ECB(8, 47),
410 new ECBlocks(30, new ECB(7, 24),
412 new ECBlocks(30, new ECB(22, 15),
414 VERSIONS.push_back(Ref<Version>(new Version(26, intArray(5, 6, 30, 58, 86, 114),
415 new ECBlocks(28, new ECB(10, 114),
417 new ECBlocks(28, new ECB(19, 46),
419 new ECBlocks(28, new ECB(28, 22),
421 new ECBlocks(30, new ECB(33, 16),
423 VERSIONS.push_back(Ref<Version>(new Version(27, intArray(5, 6, 34, 62, 90, 118),
424 new ECBlocks(30, new ECB(8, 122),
426 new ECBlocks(28, new ECB(22, 45),
428 new ECBlocks(30, new ECB(8, 23),
430 new ECBlocks(30, new ECB(12, 15),
432 VERSIONS.push_back(Ref<Version>(new Version(28, intArray(6, 6, 26, 50, 74, 98, 122),
433 new ECBlocks(30, new ECB(3, 117),
435 new ECBlocks(28, new ECB(3, 45),
437 new ECBlocks(30, new ECB(4, 24),
439 new ECBlocks(30, new ECB(11, 15),
441 VERSIONS.push_back(Ref<Version>(new Version(29, intArray(6, 6, 30, 54, 78, 102, 126),
442 new ECBlocks(30, new ECB(7, 116),
444 new ECBlocks(28, new ECB(21, 45),
446 new ECBlocks(30, new ECB(1, 23),
448 new ECBlocks(30, new ECB(19, 15),
450 VERSIONS.push_back(Ref<Version>(new Version(30, intArray(6, 6, 26, 52, 78, 104, 130),
451 new ECBlocks(30, new ECB(5, 115),
453 new ECBlocks(28, new ECB(19, 47),
455 new ECBlocks(30, new ECB(15, 24),
457 new ECBlocks(30, new ECB(23, 15),
459 VERSIONS.push_back(Ref<Version>(new Version(31, intArray(6, 6, 30, 56, 82, 108, 134),
460 new ECBlocks(30, new ECB(13, 115),
462 new ECBlocks(28, new ECB(2, 46),
464 new ECBlocks(30, new ECB(42, 24),
466 new ECBlocks(30, new ECB(23, 15),
468 VERSIONS.push_back(Ref<Version>(new Version(32, intArray(6, 6, 34, 60, 86, 112, 138),
469 new ECBlocks(30, new ECB(17, 115)),
470 new ECBlocks(28, new ECB(10, 46),
472 new ECBlocks(30, new ECB(10, 24),
474 new ECBlocks(30, new ECB(19, 15),
476 VERSIONS.push_back(Ref<Version>(new Version(33, intArray(6, 6, 30, 58, 86, 114, 142),
477 new ECBlocks(30, new ECB(17, 115),
479 new ECBlocks(28, new ECB(14, 46),
481 new ECBlocks(30, new ECB(29, 24),
483 new ECBlocks(30, new ECB(11, 15),
485 VERSIONS.push_back(Ref<Version>(new Version(34, intArray(6, 6, 34, 62, 90, 118, 146),
486 new ECBlocks(30, new ECB(13, 115),
488 new ECBlocks(28, new ECB(14, 46),
490 new ECBlocks(30, new ECB(44, 24),
492 new ECBlocks(30, new ECB(59, 16),
494 VERSIONS.push_back(Ref<Version>(new Version(35, intArray(7, 6, 30, 54, 78,
496 new ECBlocks(30, new ECB(12, 121),
498 new ECBlocks(28, new ECB(12, 47),
500 new ECBlocks(30, new ECB(39, 24),
502 new ECBlocks(30, new ECB(22, 15),
504 VERSIONS.push_back(Ref<Version>(new Version(36, intArray(7, 6, 24, 50, 76,
506 new ECBlocks(30, new ECB(6, 121),
508 new ECBlocks(28, new ECB(6, 47),
510 new ECBlocks(30, new ECB(46, 24),
512 new ECBlocks(30, new ECB(2, 15),
514 VERSIONS.push_back(Ref<Version>(new Version(37, intArray(7, 6, 28, 54, 80,
516 new ECBlocks(30, new ECB(17, 122),
518 new ECBlocks(28, new ECB(29, 46),
520 new ECBlocks(30, new ECB(49, 24),
522 new ECBlocks(30, new ECB(24, 15),
524 VERSIONS.push_back(Ref<Version>(new Version(38, intArray(7, 6, 32, 58, 84,
526 new ECBlocks(30, new ECB(4, 122),
528 new ECBlocks(28, new ECB(13, 46),
530 new ECBlocks(30, new ECB(48, 24),
532 new ECBlocks(30, new ECB(42, 15),
534 VERSIONS.push_back(Ref<Version>(new Version(39, intArray(7, 6, 26, 54, 82,
536 new ECBlocks(30, new ECB(20, 117),
538 new ECBlocks(28, new ECB(40, 47),
540 new ECBlocks(30, new ECB(43, 24),
542 new ECBlocks(30, new ECB(10, 15),
544 VERSIONS.push_back(Ref<Version>(new Version(40, intArray(7, 6, 30, 58, 86,
546 new ECBlocks(30, new ECB(19, 118),
548 new ECBlocks(28, new ECB(18, 47),
550 new ECBlocks(30, new ECB(34, 24),
552 new ECBlocks(30, new ECB(20, 15),
554 return VERSIONS.size();