├── .gitignore
├── LICENSE.txt
├── README.md
├── examples
└── QRCode
│ └── QRCode.ino
├── generate_table.py
├── keywords.txt
├── library.properties
├── src
├── qrcode.c
└── qrcode.h
└── tests
├── BitBuffer.cpp
├── BitBuffer.hpp
├── QrCode.cpp
├── QrCode.hpp
├── QrSegment.cpp
├── QrSegment.hpp
├── README.md
├── run-tests.cpp
└── run.sh
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 |
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | This library is written and maintained by Richard Moore.
4 | Major parts were derived from Project Nayuki's library.
5 |
6 | Copyright (c) 2017 Richard Moore (https://github.com/ricmoo/QRCode)
7 | Copyright (c) 2017 Project Nayuki (https://www.nayuki.io/page/qr-code-generator-library)
8 |
9 | Permission is hereby granted, free of charge, to any person obtaining a copy
10 | of this software and associated documentation files (the "Software"), to deal
11 | in the Software without restriction, including without limitation the rights
12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13 | copies of the Software, and to permit persons to whom the Software is
14 | furnished to do so, subject to the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be included in
17 | all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25 | THE SOFTWARE.
26 |
27 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | QRCode
2 | ======
3 |
4 | A simple library for generating [QR codes](https://en.wikipedia.org/wiki/QR_code) in C,
5 | optimized for processing and memory constrained systems.
6 |
7 | **Features:**
8 |
9 | - Stack-based (no heap necessary; but you can use heap if you want)
10 | - Low-memory foot print (relatively)
11 | - Compile-time stripping of unecessary logic and constants
12 | - MIT License; do with this as you please
13 |
14 |
15 | Installing
16 | ----------
17 |
18 | To install this library, download and save it to your Arduino libraries directory.
19 |
20 | Rename the directory to QRCode (if downloaded from GitHub, the filename may be
21 | qrcode-master; library names may not contain the hyphen, so it must be renamed)
22 |
23 |
24 | API
25 | ---
26 |
27 | **Generate a QR Code**
28 |
29 | ```c
30 | // The structure to manage the QR code
31 | QRCode qrcode;
32 |
33 | // Allocate a chunk of memory to store the QR code
34 | uint8_t qrcodeBytes[qrcode_getBufferSize()];
35 |
36 | qrcode_initText(&qrcode, qrcodeBytes, 3, ECC_LOW, "HELLO WORLD");
37 | ```
38 |
39 | **Draw a QR Code**
40 |
41 | How a QR code is used will vary greatly from project to project. For example:
42 |
43 | - Display on an OLED screen (128x64 nicely supports 2 side-by-side version 3 QR codes)
44 | - Print as a bitmap on a thermal printer
45 | - Store as a BMP (or with a some extra work, possibly a PNG) on an SD card
46 |
47 | The following example prints a QR code to the Serial Monitor (it likely will
48 | not be scannable, but is just for demonstration purposes).
49 |
50 | ```c
51 | for (uint8 y = 0; y < qrcode.size; y++) {
52 | for (uint8 x = 0; x < qrcode.size; x++) {
53 | if (qrcode_getModule(&qrcode, x, y) {
54 | Serial.print("**");
55 | } else {
56 | Serial.print(" ");
57 | }
58 | }
59 | Serial.print("\n");
60 | }
61 | ```
62 |
63 |
64 | What is Version, Error Correction and Mode?
65 | -------------------------------------------
66 |
67 | A QR code is composed of many little squares, called **modules**, which represent
68 | encoded data, with additional error correction (allowing partially damaged QR
69 | codes to still be read).
70 |
71 | The **version** of a QR code is a number between 1 and 40 (inclusive), which indicates
72 | the size of the QR code. The width and height of a QR code are always equal (it is
73 | square) and are equal to `4 * version + 17`.
74 |
75 | The level of **error correction** is a number between 0 and 3 (inclusive), or can be
76 | one of the symbolic names ECC_LOW, ECC_MEDIUM, ECC_QUARTILE and ECC_HIGH. Higher
77 | levels of error correction sacrifice data capacity, but allow a larger portion of
78 | the QR code to be damaged or unreadable.
79 |
80 | The **mode** of a QR code is determined by the data being encoded. Each mode is encoded
81 | internally using a compact representation, so lower modes can contain more data.
82 |
83 | - **NUMERIC:** numbers (`0-9`)
84 | - **ALPHANUMERIC:** uppercase letters (`A-Z`), numbers (`0-9`), the space (` `), dollar sign (`$`), percent sign (`%`), asterisk (`*`), plus (`+`), minus (`-`), decimal point (`.`), slash (`/`) and colon (`:`).
85 | - **BYTE:** any character
86 |
87 |
88 | Data Capacities
89 | ---------------
90 |
91 |
92 |
93 | Version
94 | Size
95 | Error Correction
96 | Mode
97 |
98 |
99 | Numeric
100 | Alphanumeric
101 | Byte
102 |
103 |
104 | 1
105 | 21 x 21
106 | LOW 41 25 17
107 |
108 |
109 | MEDIUM 34 20 14
110 |
111 |
112 | QUARTILE 27 16 11
113 |
114 |
115 | HIGH 17 10 7
116 |
117 |
118 | 2
119 | 25 x 25
120 | LOW 77 47 32
121 |
122 |
123 | MEDIUM 63 38 26
124 |
125 |
126 | QUARTILE 48 29 20
127 |
128 |
129 | HIGH 34 20 14
130 |
131 |
132 | 3
133 | 29 x 29
134 | LOW 127 77 53
135 |
136 |
137 | MEDIUM 101 61 42
138 |
139 |
140 | QUARTILE 77 47 32
141 |
142 |
143 | HIGH 58 35 24
144 |
145 |
146 | 4
147 | 33 x 33
148 | LOW 187 114 78
149 |
150 |
151 | MEDIUM 149 90 62
152 |
153 |
154 | QUARTILE 111 67 46
155 |
156 |
157 | HIGH 82 50 34
158 |
159 |
160 | 5
161 | 37 x 37
162 | LOW 255 154 106
163 |
164 |
165 | MEDIUM 202 122 84
166 |
167 |
168 | QUARTILE 144 87 60
169 |
170 |
171 | HIGH 106 64 44
172 |
173 |
174 | 6
175 | 41 x 41
176 | LOW 322 195 134
177 |
178 |
179 | MEDIUM 255 154 106
180 |
181 |
182 | QUARTILE 178 108 74
183 |
184 |
185 | HIGH 139 84 58
186 |
187 |
188 | 7
189 | 45 x 45
190 | LOW 370 224 154
191 |
192 |
193 | MEDIUM 293 178 122
194 |
195 |
196 | QUARTILE 207 125 86
197 |
198 |
199 | HIGH 154 93 64
200 |
201 |
202 | 8
203 | 49 x 49
204 | LOW 461 279 192
205 |
206 |
207 | MEDIUM 365 221 152
208 |
209 |
210 | QUARTILE 259 157 108
211 |
212 |
213 | HIGH 202 122 84
214 |
215 |
216 | 9
217 | 53 x 53
218 | LOW 552 335 230
219 |
220 |
221 | MEDIUM 432 262 180
222 |
223 |
224 | QUARTILE 312 189 130
225 |
226 |
227 | HIGH 235 143 98
228 |
229 |
230 | 10
231 | 57 x 57
232 | LOW 652 395 271
233 |
234 |
235 | MEDIUM 513 311 213
236 |
237 |
238 | QUARTILE 364 221 151
239 |
240 |
241 | HIGH 288 174 119
242 |
243 |
244 | 11
245 | 61 x 61
246 | LOW 772 468 321
247 |
248 |
249 | MEDIUM 604 366 251
250 |
251 |
252 | QUARTILE 427 259 177
253 |
254 |
255 | HIGH 331 200 137
256 |
257 |
258 | 12
259 | 65 x 65
260 | LOW 883 535 367
261 |
262 |
263 | MEDIUM 691 419 287
264 |
265 |
266 | QUARTILE 489 296 203
267 |
268 |
269 | HIGH 374 227 155
270 |
271 |
272 | 13
273 | 69 x 69
274 | LOW 1022 619 425
275 |
276 |
277 | MEDIUM 796 483 331
278 |
279 |
280 | QUARTILE 580 352 241
281 |
282 |
283 | HIGH 427 259 177
284 |
285 |
286 | 14
287 | 73 x 73
288 | LOW 1101 667 458
289 |
290 |
291 | MEDIUM 871 528 362
292 |
293 |
294 | QUARTILE 621 376 258
295 |
296 |
297 | HIGH 468 283 194
298 |
299 |
300 | 15
301 | 77 x 77
302 | LOW 1250 758 520
303 |
304 |
305 | MEDIUM 991 600 412
306 |
307 |
308 | QUARTILE 703 426 292
309 |
310 |
311 | HIGH 530 321 220
312 |
313 |
314 | 16
315 | 81 x 81
316 | LOW 1408 854 586
317 |
318 |
319 | MEDIUM 1082 656 450
320 |
321 |
322 | QUARTILE 775 470 322
323 |
324 |
325 | HIGH 602 365 250
326 |
327 |
328 | 17
329 | 85 x 85
330 | LOW 1548 938 644
331 |
332 |
333 | MEDIUM 1212 734 504
334 |
335 |
336 | QUARTILE 876 531 364
337 |
338 |
339 | HIGH 674 408 280
340 |
341 |
342 | 18
343 | 89 x 89
344 | LOW 1725 1046 718
345 |
346 |
347 | MEDIUM 1346 816 560
348 |
349 |
350 | QUARTILE 948 574 394
351 |
352 |
353 | HIGH 746 452 310
354 |
355 |
356 | 19
357 | 93 x 93
358 | LOW 1903 1153 792
359 |
360 |
361 | MEDIUM 1500 909 624
362 |
363 |
364 | QUARTILE 1063 644 442
365 |
366 |
367 | HIGH 813 493 338
368 |
369 |
370 | 20
371 | 97 x 97
372 | LOW 2061 1249 858
373 |
374 |
375 | MEDIUM 1600 970 666
376 |
377 |
378 | QUARTILE 1159 702 482
379 |
380 |
381 | HIGH 919 557 382
382 |
383 |
384 | 21
385 | 101 x 101
386 | LOW 2232 1352 929
387 |
388 |
389 | MEDIUM 1708 1035 711
390 |
391 |
392 | QUARTILE 1224 742 509
393 |
394 |
395 | HIGH 969 587 403
396 |
397 |
398 | 22
399 | 105 x 105
400 | LOW 2409 1460 1003
401 |
402 |
403 | MEDIUM 1872 1134 779
404 |
405 |
406 | QUARTILE 1358 823 565
407 |
408 |
409 | HIGH 1056 640 439
410 |
411 |
412 | 23
413 | 109 x 109
414 | LOW 2620 1588 1091
415 |
416 |
417 | MEDIUM 2059 1248 857
418 |
419 |
420 | QUARTILE 1468 890 611
421 |
422 |
423 | HIGH 1108 672 461
424 |
425 |
426 | 24
427 | 113 x 113
428 | LOW 2812 1704 1171
429 |
430 |
431 | MEDIUM 2188 1326 911
432 |
433 |
434 | QUARTILE 1588 963 661
435 |
436 |
437 | HIGH 1228 744 511
438 |
439 |
440 | 25
441 | 117 x 117
442 | LOW 3057 1853 1273
443 |
444 |
445 | MEDIUM 2395 1451 997
446 |
447 |
448 | QUARTILE 1718 1041 715
449 |
450 |
451 | HIGH 1286 779 535
452 |
453 |
454 | 26
455 | 121 x 121
456 | LOW 3283 1990 1367
457 |
458 |
459 | MEDIUM 2544 1542 1059
460 |
461 |
462 | QUARTILE 1804 1094 751
463 |
464 |
465 | HIGH 1425 864 593
466 |
467 |
468 | 27
469 | 125 x 125
470 | LOW 3517 2132 1465
471 |
472 |
473 | MEDIUM 2701 1637 1125
474 |
475 |
476 | QUARTILE 1933 1172 805
477 |
478 |
479 | HIGH 1501 910 625
480 |
481 |
482 | 28
483 | 129 x 129
484 | LOW 3669 2223 1528
485 |
486 |
487 | MEDIUM 2857 1732 1190
488 |
489 |
490 | QUARTILE 2085 1263 868
491 |
492 |
493 | HIGH 1581 958 658
494 |
495 |
496 | 29
497 | 133 x 133
498 | LOW 3909 2369 1628
499 |
500 |
501 | MEDIUM 3035 1839 1264
502 |
503 |
504 | QUARTILE 2181 1322 908
505 |
506 |
507 | HIGH 1677 1016 698
508 |
509 |
510 | 30
511 | 137 x 137
512 | LOW 4158 2520 1732
513 |
514 |
515 | MEDIUM 3289 1994 1370
516 |
517 |
518 | QUARTILE 2358 1429 982
519 |
520 |
521 | HIGH 1782 1080 742
522 |
523 |
524 | 31
525 | 141 x 141
526 | LOW 4417 2677 1840
527 |
528 |
529 | MEDIUM 3486 2113 1452
530 |
531 |
532 | QUARTILE 2473 1499 1030
533 |
534 |
535 | HIGH 1897 1150 790
536 |
537 |
538 | 32
539 | 145 x 145
540 | LOW 4686 2840 1952
541 |
542 |
543 | MEDIUM 3693 2238 1538
544 |
545 |
546 | QUARTILE 2670 1618 1112
547 |
548 |
549 | HIGH 2022 1226 842
550 |
551 |
552 | 33
553 | 149 x 149
554 | LOW 4965 3009 2068
555 |
556 |
557 | MEDIUM 3909 2369 1628
558 |
559 |
560 | QUARTILE 2805 1700 1168
561 |
562 |
563 | HIGH 2157 1307 898
564 |
565 |
566 | 34
567 | 153 x 153
568 | LOW 5253 3183 2188
569 |
570 |
571 | MEDIUM 4134 2506 1722
572 |
573 |
574 | QUARTILE 2949 1787 1228
575 |
576 |
577 | HIGH 2301 1394 958
578 |
579 |
580 | 35
581 | 157 x 157
582 | LOW 5529 3351 2303
583 |
584 |
585 | MEDIUM 4343 2632 1809
586 |
587 |
588 | QUARTILE 3081 1867 1283
589 |
590 |
591 | HIGH 2361 1431 983
592 |
593 |
594 | 36
595 | 161 x 161
596 | LOW 5836 3537 2431
597 |
598 |
599 | MEDIUM 4588 2780 1911
600 |
601 |
602 | QUARTILE 3244 1966 1351
603 |
604 |
605 | HIGH 2524 1530 1051
606 |
607 |
608 | 37
609 | 165 x 165
610 | LOW 6153 3729 2563
611 |
612 |
613 | MEDIUM 4775 2894 1989
614 |
615 |
616 | QUARTILE 3417 2071 1423
617 |
618 |
619 | HIGH 2625 1591 1093
620 |
621 |
622 | 38
623 | 169 x 169
624 | LOW 6479 3927 2699
625 |
626 |
627 | MEDIUM 5039 3054 2099
628 |
629 |
630 | QUARTILE 3599 2181 1499
631 |
632 |
633 | HIGH 2735 1658 1139
634 |
635 |
636 | 39
637 | 173 x 173
638 | LOW 6743 4087 2809
639 |
640 |
641 | MEDIUM 5313 3220 2213
642 |
643 |
644 | QUARTILE 3791 2298 1579
645 |
646 |
647 | HIGH 2927 1774 1219
648 |
649 |
650 | 40
651 | 177 x 177
652 | LOW 7089 4296 2953
653 |
654 |
655 | MEDIUM 5596 3391 2331
656 |
657 |
658 | QUARTILE 3993 2420 1663
659 |
660 |
661 | HIGH 3057 1852 1273
662 |
663 |
664 |
665 |
666 | Special Thanks
667 | --------------
668 |
669 | A HUGE thank you to [Project Nayuki](https://www.nayuki.io/) for the
670 | [QR code C++ library](https://github.com/nayuki/QR-Code-generator/tree/master/cpp)
671 | which was critical in development of this library.
672 |
673 |
674 | License
675 | -------
676 |
677 | MIT License.
678 |
--------------------------------------------------------------------------------
/examples/QRCode/QRCode.ino:
--------------------------------------------------------------------------------
1 | /**
2 | * QRCode
3 | *
4 | * A quick example of generating a QR code.
5 | *
6 | * This prints the QR code to the serial monitor as solid blocks. Each module
7 | * is two characters wide, since the monospace font used in the serial monitor
8 | * is approximately twice as tall as wide.
9 | *
10 | */
11 |
12 | #include "qrcode.h"
13 |
14 | void setup() {
15 | Serial.begin(115200);
16 |
17 | // Start time
18 | uint32_t dt = millis();
19 |
20 | // Create the QR code
21 | QRCode qrcode;
22 | uint8_t qrcodeData[qrcode_getBufferSize(3)];
23 | qrcode_initText(&qrcode, qrcodeData, 3, 0, "HELLO WORLD");
24 |
25 | // Delta time
26 | dt = millis() - dt;
27 | Serial.print("QR Code Generation Time: ");
28 | Serial.print(dt);
29 | Serial.print("\n");
30 |
31 | // Top quiet zone
32 | Serial.print("\n\n\n\n");
33 |
34 | for (uint8_t y = 0; y < qrcode.size; y++) {
35 |
36 | // Left quiet zone
37 | Serial.print(" ");
38 |
39 | // Each horizontal module
40 | for (uint8_t x = 0; x < qrcode.size; x++) {
41 |
42 | // Print each module (UTF-8 \u2588 is a solid block)
43 | Serial.print(qrcode_getModule(&qrcode, x, y) ? "\u2588\u2588": " ");
44 |
45 | }
46 |
47 | Serial.print("\n");
48 | }
49 |
50 | // Bottom quiet zone
51 | Serial.print("\n\n\n\n");
52 | }
53 |
54 | void loop() {
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/generate_table.py:
--------------------------------------------------------------------------------
1 | Data = [
2 | ["1", "41", "25", "17", "34", "20", "14","27", "16", "11","17", "10", "7"],
3 | ["2", "77", "47", "32", "63", "38", "26", "48", "29", "20", "34", "20", "14"],
4 | ["3", "127", "77", "53", "101", "61", "42", "77", "47", "32", "58", "35", "24"],
5 | ["4", "187", "114", "78", "149", "90", "62", "111", "67", "46", "82", "50", "34"],
6 | ["5", "255", "154", "106", "202", "122", "84", "144", "87", "60", "106", "64", "44"],
7 | ["6", "322", "195", "134", "255", "154", "106", "178", "108", "74", "139", "84", "58"],
8 | ["7", "370", "224", "154", "293", "178", "122", "207", "125", "86", "154", "93", "64"],
9 | ["8", "461", "279", "192", "365", "221", "152", "259", "157", "108", "202", "122", "84"],
10 | ["9", "552", "335", "230", "432", "262", "180", "312", "189", "130", "235", "143", "98"],
11 | ["10", "652", "395", "271", "513", "311", "213", "364", "221", "151", "288", "174", "119"],
12 | ["11", "772", "468", "321", "604", "366", "251", "427", "259", "177", "331", "200", "137"],
13 | ["12", "883", "535", "367", "691", "419", "287", "489", "296", "203", "374", "227", "155"],
14 | ["13", "1022", "619", "425", "796", "483", "331", "580", "352", "241", "427", "259", "177"],
15 | ["14", "1101", "667", "458", "871", "528", "362", "621", "376", "258", "468", "283", "194"],
16 | ["15", "1250", "758", "520", "991", "600", "412", "703", "426", "292", "530", "321", "220"],
17 | ["16", "1408", "854", "586", "1082", "656", "450", "775", "470", "322", "602", "365", "250"],
18 | ["17", "1548", "938", "644", "1212", "734", "504", "876", "531", "364", "674", "408", "280"],
19 | ["18", "1725", "1046", "718", "1346", "816", "560", "948", "574", "394", "746", "452", "310"],
20 | ["19", "1903", "1153", "792", "1500", "909", "624", "1063", "644", "442", "813", "493", "338"],
21 | ["20", "2061", "1249", "858", "1600", "970", "666", "1159", "702", "482", "919", "557", "382"],
22 | ["21", "2232", "1352", "929", "1708", "1035", "711", "1224", "742", "509", "969", "587", "403"],
23 | ["22", "2409", "1460", "1003", "1872", "1134", "779", "1358", "823", "565", "1056", "640", "439"],
24 | ["23", "2620", "1588", "1091", "2059", "1248", "857", "1468", "890", "611", "1108", "672", "461"],
25 | ["24", "2812", "1704", "1171", "2188", "1326", "911", "1588", "963", "661", "1228", "744", "511"],
26 | ["25", "3057", "1853", "1273", "2395", "1451", "997", "1718", "1041", "715", "1286", "779", "535"],
27 | ["26", "3283", "1990", "1367", "2544", "1542", "1059", "1804", "1094", "751", "1425", "864", "593"],
28 | ["27", "3517", "2132", "1465", "2701", "1637", "1125", "1933", "1172", "805", "1501", "910", "625"],
29 | ["28", "3669", "2223", "1528", "2857", "1732", "1190", "2085", "1263", "868", "1581", "958", "658"],
30 | ["29", "3909", "2369", "1628", "3035", "1839", "1264", "2181", "1322", "908", "1677", "1016", "698"],
31 | ["30", "4158", "2520", "1732", "3289", "1994", "1370", "2358", "1429", "982", "1782", "1080", "742"],
32 | ["31", "4417", "2677", "1840", "3486", "2113", "1452", "2473", "1499", "1030", "1897", "1150", "790"],
33 | ["32", "4686", "2840", "1952", "3693", "2238", "1538", "2670", "1618", "1112", "2022", "1226", "842"],
34 | ["33", "4965", "3009", "2068", "3909", "2369", "1628", "2805", "1700", "1168", "2157", "1307", "898"],
35 | ["34", "5253", "3183", "2188", "4134", "2506", "1722", "2949", "1787", "1228", "2301", "1394", "958"],
36 | ["35", "5529", "3351", "2303", "4343", "2632", "1809", "3081", "1867", "1283", "2361", "1431", "983"],
37 | ["36", "5836", "3537", "2431", "4588", "2780", "1911", "3244", "1966", "1351", "2524", "1530", "1051"],
38 | ["37", "6153", "3729", "2563", "4775", "2894", "1989", "3417", "2071", "1423", "2625", "1591", "1093"],
39 | ["38", "6479", "3927", "2699", "5039", "3054", "2099", "3599", "2181", "1499", "2735", "1658", "1139"],
40 | ["39", "6743", "4087", "2809", "5313", "3220", "2213", "3791", "2298", "1579", "2927", "1774", "1219"],
41 | ["40", "7089", "4296", "2953", "5596", "3391", "2331", "3993", "2420", "1663", "3057", "1852", "1273"],
42 | ]
43 | Template = '''
44 | %s
45 | %s
46 | LOW %s %s %s
47 |
48 |
49 | MEDIUM %s %s %s
50 |
51 |
52 | QUARTILE %s %s %s
53 |
54 |
55 | HIGH %s %s %s
56 | '''
57 |
58 | for data in Data:
59 | data = data[:]
60 | size = 4 * int(data[0]) + 17
61 | data.insert(1, "%d x %d" % (size, size))
62 | print Template % tuple(data)
63 |
--------------------------------------------------------------------------------
/keywords.txt:
--------------------------------------------------------------------------------
1 |
2 | # Datatypes (KEYWORD1)
3 |
4 | bool KEYWORD1
5 | uint8_t KEYWORD1
6 | QRCode KEYWORD1
7 |
8 |
9 | # Methods and Functions (KEYWORD2)
10 |
11 | qrcode_getBufferSize KEYWORD2
12 | qrcode_initText KEYWORD2
13 | qrcode_initBytes KEYWORD2
14 | qrcode_getModule KEYWORD2
15 |
16 |
17 | # Instances (KEYWORD2)
18 |
19 |
20 | # Constants (LITERAL1)
21 |
22 | false LITERAL1
23 | true LITERAL1
24 |
25 | ECC_LOW LITERAL1
26 | ECC_MEDIUM LITERAL1
27 | ECC_QUARTILE LITERAL1
28 | ECC_HIGH LITERAL1
29 | MODE_NUMERIC LITERAL1
30 | MODE_ALPHANUMERIC LITERAL1
31 | MODE_BYTE LITERAL1
32 |
--------------------------------------------------------------------------------
/library.properties:
--------------------------------------------------------------------------------
1 | name=QRCode
2 | version=0.0.1
3 | author=Richard Moore
4 | maintainer=Richard Moore
5 | sentence=A simple QR code generation library.
6 | paragraph=A simple QR code generation library.
7 | category=Other
8 | url=https://github.com/ricmoo/qrcode/
9 | architectures=*
10 | includes=qrcode.h
11 |
--------------------------------------------------------------------------------
/src/qrcode.c:
--------------------------------------------------------------------------------
1 | /**
2 | * The MIT License (MIT)
3 | *
4 | * This library is written and maintained by Richard Moore.
5 | * Major parts were derived from Project Nayuki's library.
6 | *
7 | * Copyright (c) 2017 Richard Moore (https://github.com/ricmoo/QRCode)
8 | * Copyright (c) 2017 Project Nayuki (https://www.nayuki.io/page/qr-code-generator-library)
9 | *
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy
11 | * of this software and associated documentation files (the "Software"), to deal
12 | * in the Software without restriction, including without limitation the rights
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | * copies of the Software, and to permit persons to whom the Software is
15 | * furnished to do so, subject to the following conditions:
16 | *
17 | * The above copyright notice and this permission notice shall be included in
18 | * all copies or substantial portions of the Software.
19 | *
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | * THE SOFTWARE.
27 | */
28 |
29 | /**
30 | * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was
31 | * heavily inspired and compared against.
32 | *
33 | * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp
34 | */
35 |
36 | #include "qrcode.h"
37 |
38 | #include
39 | #include
40 |
41 | #pragma mark - Error Correction Lookup tables
42 |
43 | #if LOCK_VERSION == 0
44 |
45 | static const uint16_t NUM_ERROR_CORRECTION_CODEWORDS[4][40] = {
46 | // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
47 | { 10, 16, 26, 36, 48, 64, 72, 88, 110, 130, 150, 176, 198, 216, 240, 280, 308, 338, 364, 416, 442, 476, 504, 560, 588, 644, 700, 728, 784, 812, 868, 924, 980, 1036, 1064, 1120, 1204, 1260, 1316, 1372}, // Medium
48 | { 7, 10, 15, 20, 26, 36, 40, 48, 60, 72, 80, 96, 104, 120, 132, 144, 168, 180, 196, 224, 224, 252, 270, 300, 312, 336, 360, 390, 420, 450, 480, 510, 540, 570, 570, 600, 630, 660, 720, 750}, // Low
49 | { 17, 28, 44, 64, 88, 112, 130, 156, 192, 224, 264, 308, 352, 384, 432, 480, 532, 588, 650, 700, 750, 816, 900, 960, 1050, 1110, 1200, 1260, 1350, 1440, 1530, 1620, 1710, 1800, 1890, 1980, 2100, 2220, 2310, 2430}, // High
50 | { 13, 22, 36, 52, 72, 96, 108, 132, 160, 192, 224, 260, 288, 320, 360, 408, 448, 504, 546, 600, 644, 690, 750, 810, 870, 952, 1020, 1050, 1140, 1200, 1290, 1350, 1440, 1530, 1590, 1680, 1770, 1860, 1950, 2040}, // Quartile
51 | };
52 |
53 | static const uint8_t NUM_ERROR_CORRECTION_BLOCKS[4][40] = {
54 | // Version: (note that index 0 is for padding, and is set to an illegal value)
55 | // 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
56 | { 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
57 | { 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
58 | { 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
59 | { 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
60 | };
61 |
62 | static const uint16_t NUM_RAW_DATA_MODULES[40] = {
63 | // 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17,
64 | 208, 359, 567, 807, 1079, 1383, 1568, 1936, 2336, 2768, 3232, 3728, 4256, 4651, 5243, 5867, 6523,
65 | // 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
66 | 7211, 7931, 8683, 9252, 10068, 10916, 11796, 12708, 13652, 14628, 15371, 16411, 17483, 18587,
67 | // 32, 33, 34, 35, 36, 37, 38, 39, 40
68 | 19723, 20891, 22091, 23008, 24272, 25568, 26896, 28256, 29648
69 | };
70 |
71 | // @TODO: Put other LOCK_VERSIONS here
72 | #elif LOCK_VERSION == 3
73 |
74 | static const int16_t NUM_ERROR_CORRECTION_CODEWORDS[4] = {
75 | 26, 15, 44, 36
76 | };
77 |
78 | static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4] = {
79 | 1, 1, 2, 2
80 | };
81 |
82 | static const uint16_t NUM_RAW_DATA_MODULES = 567;
83 |
84 | #else
85 |
86 | #error Unsupported LOCK_VERSION (add it...)
87 |
88 | #endif
89 |
90 |
91 | static int max(int a, int b) {
92 | if (a > b) { return a; }
93 | return b;
94 | }
95 |
96 | /*
97 | static int abs(int value) {
98 | if (value < 0) { return -value; }
99 | return value;
100 | }
101 | */
102 |
103 |
104 | #pragma mark - Mode testing and conversion
105 |
106 | static int8_t getAlphanumeric(char c) {
107 |
108 | if (c >= '0' && c <= '9') { return (c - '0'); }
109 | if (c >= 'A' && c <= 'Z') { return (c - 'A' + 10); }
110 |
111 | switch (c) {
112 | case ' ': return 36;
113 | case '$': return 37;
114 | case '%': return 38;
115 | case '*': return 39;
116 | case '+': return 40;
117 | case '-': return 41;
118 | case '.': return 42;
119 | case '/': return 43;
120 | case ':': return 44;
121 | }
122 |
123 | return -1;
124 | }
125 |
126 | static bool isAlphanumeric(const char *text, uint16_t length) {
127 | while (length != 0) {
128 | if (getAlphanumeric(text[--length]) == -1) { return false; }
129 | }
130 | return true;
131 | }
132 |
133 |
134 | static bool isNumeric(const char *text, uint16_t length) {
135 | while (length != 0) {
136 | char c = text[--length];
137 | if (c < '0' || c > '9') { return false; }
138 | }
139 | return true;
140 | }
141 |
142 |
143 | #pragma mark - Counting
144 |
145 | // We store the following tightly packed (less 8) in modeInfo
146 | // <=9 <=26 <= 40
147 | // NUMERIC ( 10, 12, 14);
148 | // ALPHANUMERIC ( 9, 11, 13);
149 | // BYTE ( 8, 16, 16);
150 | static char getModeBits(uint8_t version, uint8_t mode) {
151 | // Note: We use 15 instead of 16; since 15 doesn't exist and we cannot store 16 (8 + 8) in 3 bits
152 | // hex(int("".join(reversed([('00' + bin(x - 8)[2:])[-3:] for x in [10, 9, 8, 12, 11, 15, 14, 13, 15]])), 2))
153 | unsigned int modeInfo = 0x7bbb80a;
154 |
155 | #if LOCK_VERSION == 0 || LOCK_VERSION > 9
156 | if (version > 9) { modeInfo >>= 9; }
157 | #endif
158 |
159 | #if LOCK_VERSION == 0 || LOCK_VERSION > 26
160 | if (version > 26) { modeInfo >>= 9; }
161 | #endif
162 |
163 | char result = 8 + ((modeInfo >> (3 * mode)) & 0x07);
164 | if (result == 15) { result = 16; }
165 |
166 | return result;
167 | }
168 |
169 |
170 | #pragma mark - BitBucket
171 |
172 | typedef struct BitBucket {
173 | uint32_t bitOffsetOrWidth;
174 | uint16_t capacityBytes;
175 | uint8_t *data;
176 | } BitBucket;
177 |
178 | /*
179 | void bb_dump(BitBucket *bitBuffer) {
180 | printf("Buffer: ");
181 | for (uint32_t i = 0; i < bitBuffer->capacityBytes; i++) {
182 | printf("%02x", bitBuffer->data[i]);
183 | if ((i % 4) == 3) { printf(" "); }
184 | }
185 | printf("\n");
186 | }
187 | */
188 |
189 | static uint16_t bb_getGridSizeBytes(uint8_t size) {
190 | return (((size * size) + 7) / 8);
191 | }
192 |
193 | static uint16_t bb_getBufferSizeBytes(uint32_t bits) {
194 | return ((bits + 7) / 8);
195 | }
196 |
197 | static void bb_initBuffer(BitBucket *bitBuffer, uint8_t *data, int32_t capacityBytes) {
198 | bitBuffer->bitOffsetOrWidth = 0;
199 | bitBuffer->capacityBytes = capacityBytes;
200 | bitBuffer->data = data;
201 |
202 | memset(data, 0, bitBuffer->capacityBytes);
203 | }
204 |
205 | static void bb_initGrid(BitBucket *bitGrid, uint8_t *data, uint8_t size) {
206 | bitGrid->bitOffsetOrWidth = size;
207 | bitGrid->capacityBytes = bb_getGridSizeBytes(size);
208 | bitGrid->data = data;
209 |
210 | memset(data, 0, bitGrid->capacityBytes);
211 | }
212 |
213 | static void bb_appendBits(BitBucket *bitBuffer, uint32_t val, uint8_t length) {
214 | uint32_t offset = bitBuffer->bitOffsetOrWidth;
215 | for (int8_t i = length - 1; i >= 0; i--, offset++) {
216 | bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7));
217 | }
218 | bitBuffer->bitOffsetOrWidth = offset;
219 | }
220 | /*
221 | void bb_setBits(BitBucket *bitBuffer, uint32_t val, int offset, uint8_t length) {
222 | for (int8_t i = length - 1; i >= 0; i--, offset++) {
223 | bitBuffer->data[offset >> 3] |= ((val >> i) & 1) << (7 - (offset & 7));
224 | }
225 | }
226 | */
227 | static void bb_setBit(BitBucket *bitGrid, uint8_t x, uint8_t y, bool on) {
228 | uint32_t offset = y * bitGrid->bitOffsetOrWidth + x;
229 | uint8_t mask = 1 << (7 - (offset & 0x07));
230 | if (on) {
231 | bitGrid->data[offset >> 3] |= mask;
232 | } else {
233 | bitGrid->data[offset >> 3] &= ~mask;
234 | }
235 | }
236 |
237 | static void bb_invertBit(BitBucket *bitGrid, uint8_t x, uint8_t y, bool invert) {
238 | uint32_t offset = y * bitGrid->bitOffsetOrWidth + x;
239 | uint8_t mask = 1 << (7 - (offset & 0x07));
240 | bool on = ((bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0);
241 | if (on ^ invert) {
242 | bitGrid->data[offset >> 3] |= mask;
243 | } else {
244 | bitGrid->data[offset >> 3] &= ~mask;
245 | }
246 | }
247 |
248 | static bool bb_getBit(BitBucket *bitGrid, uint8_t x, uint8_t y) {
249 | uint32_t offset = y * bitGrid->bitOffsetOrWidth + x;
250 | return (bitGrid->data[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0;
251 | }
252 |
253 |
254 | #pragma mark - Drawing Patterns
255 |
256 | // XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
257 | // properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
258 | // This means it is possible to apply a mask, undo it, and try another mask. Note that a final
259 | // well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
260 | static void applyMask(BitBucket *modules, BitBucket *isFunction, uint8_t mask) {
261 | uint8_t size = modules->bitOffsetOrWidth;
262 |
263 | for (uint8_t y = 0; y < size; y++) {
264 | for (uint8_t x = 0; x < size; x++) {
265 | if (bb_getBit(isFunction, x, y)) { continue; }
266 |
267 | bool invert = 0;
268 | switch (mask) {
269 | case 0: invert = (x + y) % 2 == 0; break;
270 | case 1: invert = y % 2 == 0; break;
271 | case 2: invert = x % 3 == 0; break;
272 | case 3: invert = (x + y) % 3 == 0; break;
273 | case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
274 | case 5: invert = x * y % 2 + x * y % 3 == 0; break;
275 | case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
276 | case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
277 | }
278 | bb_invertBit(modules, x, y, invert);
279 | }
280 | }
281 | }
282 |
283 | static void setFunctionModule(BitBucket *modules, BitBucket *isFunction, uint8_t x, uint8_t y, bool on) {
284 | bb_setBit(modules, x, y, on);
285 | bb_setBit(isFunction, x, y, true);
286 | }
287 |
288 | // Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
289 | static void drawFinderPattern(BitBucket *modules, BitBucket *isFunction, uint8_t x, uint8_t y) {
290 | uint8_t size = modules->bitOffsetOrWidth;
291 |
292 | for (int8_t i = -4; i <= 4; i++) {
293 | for (int8_t j = -4; j <= 4; j++) {
294 | uint8_t dist = max(abs(i), abs(j)); // Chebyshev/infinity norm
295 | int16_t xx = x + j, yy = y + i;
296 | if (0 <= xx && xx < size && 0 <= yy && yy < size) {
297 | setFunctionModule(modules, isFunction, xx, yy, dist != 2 && dist != 4);
298 | }
299 | }
300 | }
301 | }
302 |
303 | // Draws a 5*5 alignment pattern, with the center module at (x, y).
304 | static void drawAlignmentPattern(BitBucket *modules, BitBucket *isFunction, uint8_t x, uint8_t y) {
305 | for (int8_t i = -2; i <= 2; i++) {
306 | for (int8_t j = -2; j <= 2; j++) {
307 | setFunctionModule(modules, isFunction, x + j, y + i, max(abs(i), abs(j)) != 1);
308 | }
309 | }
310 | }
311 |
312 | // Draws two copies of the format bits (with its own error correction code)
313 | // based on the given mask and this object's error correction level field.
314 | static void drawFormatBits(BitBucket *modules, BitBucket *isFunction, uint8_t ecc, uint8_t mask) {
315 |
316 | uint8_t size = modules->bitOffsetOrWidth;
317 |
318 | // Calculate error correction code and pack bits
319 | uint32_t data = ecc << 3 | mask; // errCorrLvl is uint2, mask is uint3
320 | uint32_t rem = data;
321 | for (int i = 0; i < 10; i++) {
322 | rem = (rem << 1) ^ ((rem >> 9) * 0x537);
323 | }
324 |
325 | data = data << 10 | rem;
326 | data ^= 0x5412; // uint15
327 |
328 | // Draw first copy
329 | for (uint8_t i = 0; i <= 5; i++) {
330 | setFunctionModule(modules, isFunction, 8, i, ((data >> i) & 1) != 0);
331 | }
332 |
333 | setFunctionModule(modules, isFunction, 8, 7, ((data >> 6) & 1) != 0);
334 | setFunctionModule(modules, isFunction, 8, 8, ((data >> 7) & 1) != 0);
335 | setFunctionModule(modules, isFunction, 7, 8, ((data >> 8) & 1) != 0);
336 |
337 | for (int8_t i = 9; i < 15; i++) {
338 | setFunctionModule(modules, isFunction, 14 - i, 8, ((data >> i) & 1) != 0);
339 | }
340 |
341 | // Draw second copy
342 | for (int8_t i = 0; i <= 7; i++) {
343 | setFunctionModule(modules, isFunction, size - 1 - i, 8, ((data >> i) & 1) != 0);
344 | }
345 |
346 | for (int8_t i = 8; i < 15; i++) {
347 | setFunctionModule(modules, isFunction, 8, size - 15 + i, ((data >> i) & 1) != 0);
348 | }
349 |
350 | setFunctionModule(modules, isFunction, 8, size - 8, true);
351 | }
352 |
353 |
354 | // Draws two copies of the version bits (with its own error correction code),
355 | // based on this object's version field (which only has an effect for 7 <= version <= 40).
356 | static void drawVersion(BitBucket *modules, BitBucket *isFunction, uint8_t version) {
357 |
358 | int8_t size = modules->bitOffsetOrWidth;
359 |
360 | #if LOCK_VERSION != 0 && LOCK_VERSION < 7
361 | return;
362 |
363 | #else
364 | if (version < 7) { return; }
365 |
366 | // Calculate error correction code and pack bits
367 | uint32_t rem = version; // version is uint6, in the range [7, 40]
368 | for (uint8_t i = 0; i < 12; i++) {
369 | rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
370 | }
371 |
372 | uint32_t data = version << 12 | rem; // uint18
373 |
374 | // Draw two copies
375 | for (uint8_t i = 0; i < 18; i++) {
376 | bool bit = ((data >> i) & 1) != 0;
377 | uint8_t a = size - 11 + i % 3, b = i / 3;
378 | setFunctionModule(modules, isFunction, a, b, bit);
379 | setFunctionModule(modules, isFunction, b, a, bit);
380 | }
381 |
382 | #endif
383 | }
384 |
385 | static void drawFunctionPatterns(BitBucket *modules, BitBucket *isFunction, uint8_t version, uint8_t ecc) {
386 |
387 | uint8_t size = modules->bitOffsetOrWidth;
388 |
389 | // Draw the horizontal and vertical timing patterns
390 | for (uint8_t i = 0; i < size; i++) {
391 | setFunctionModule(modules, isFunction, 6, i, i % 2 == 0);
392 | setFunctionModule(modules, isFunction, i, 6, i % 2 == 0);
393 | }
394 |
395 | // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
396 | drawFinderPattern(modules, isFunction, 3, 3);
397 | drawFinderPattern(modules, isFunction, size - 4, 3);
398 | drawFinderPattern(modules, isFunction, 3, size - 4);
399 |
400 | #if LOCK_VERSION == 0 || LOCK_VERSION > 1
401 |
402 | if (version > 1) {
403 |
404 | // Draw the numerous alignment patterns
405 |
406 | uint8_t alignCount = version / 7 + 2;
407 | uint8_t step;
408 | if (version != 32) {
409 | step = (version * 4 + alignCount * 2 + 1) / (2 * alignCount - 2) * 2; // ceil((size - 13) / (2*numAlign - 2)) * 2
410 | } else { // C-C-C-Combo breaker!
411 | step = 26;
412 | }
413 |
414 | uint8_t alignPositionIndex = alignCount - 1;
415 | uint8_t alignPosition[alignCount];
416 |
417 | alignPosition[0] = 6;
418 |
419 | uint8_t size = version * 4 + 17;
420 | for (uint8_t i = 0, pos = size - 7; i < alignCount - 1; i++, pos -= step) {
421 | alignPosition[alignPositionIndex--] = pos;
422 | }
423 |
424 | for (uint8_t i = 0; i < alignCount; i++) {
425 | for (uint8_t j = 0; j < alignCount; j++) {
426 | if ((i == 0 && j == 0) || (i == 0 && j == alignCount - 1) || (i == alignCount - 1 && j == 0)) {
427 | continue; // Skip the three finder corners
428 | } else {
429 | drawAlignmentPattern(modules, isFunction, alignPosition[i], alignPosition[j]);
430 | }
431 | }
432 | }
433 | }
434 |
435 | #endif
436 |
437 | // Draw configuration data
438 | drawFormatBits(modules, isFunction, ecc, 0); // Dummy mask value; overwritten later in the constructor
439 | drawVersion(modules, isFunction, version);
440 | }
441 |
442 |
443 | // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
444 | // data area of this QR Code symbol. Function modules need to be marked off before this is called.
445 | static void drawCodewords(BitBucket *modules, BitBucket *isFunction, BitBucket *codewords) {
446 |
447 | uint32_t bitLength = codewords->bitOffsetOrWidth;
448 | uint8_t *data = codewords->data;
449 |
450 | uint8_t size = modules->bitOffsetOrWidth;
451 |
452 | // Bit index into the data
453 | uint32_t i = 0;
454 |
455 | // Do the funny zigzag scan
456 | for (int16_t right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
457 | if (right == 6) { right = 5; }
458 |
459 | for (uint8_t vert = 0; vert < size; vert++) { // Vertical counter
460 | for (int j = 0; j < 2; j++) {
461 | uint8_t x = right - j; // Actual x coordinate
462 | bool upwards = ((right & 2) == 0) ^ (x < 6);
463 | uint8_t y = upwards ? size - 1 - vert : vert; // Actual y coordinate
464 | if (!bb_getBit(isFunction, x, y) && i < bitLength) {
465 | bb_setBit(modules, x, y, ((data[i >> 3] >> (7 - (i & 7))) & 1) != 0);
466 | i++;
467 | }
468 | // If there are any remainder bits (0 to 7), they are already
469 | // set to 0/false/white when the grid of modules was initialized
470 | }
471 | }
472 | }
473 | }
474 |
475 |
476 |
477 | #pragma mark - Penalty Calculation
478 |
479 | #define PENALTY_N1 3
480 | #define PENALTY_N2 3
481 | #define PENALTY_N3 40
482 | #define PENALTY_N4 10
483 |
484 | // Calculates and returns the penalty score based on state of this QR Code's current modules.
485 | // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
486 | // @TODO: This can be optimized by working with the bytes instead of bits.
487 | static uint32_t getPenaltyScore(BitBucket *modules) {
488 | uint32_t result = 0;
489 |
490 | uint8_t size = modules->bitOffsetOrWidth;
491 |
492 | // Adjacent modules in row having same color
493 | for (uint8_t y = 0; y < size; y++) {
494 |
495 | bool colorX = bb_getBit(modules, 0, y);
496 | for (uint8_t x = 1, runX = 1; x < size; x++) {
497 | bool cx = bb_getBit(modules, x, y);
498 | if (cx != colorX) {
499 | colorX = cx;
500 | runX = 1;
501 |
502 | } else {
503 | runX++;
504 | if (runX == 5) {
505 | result += PENALTY_N1;
506 | } else if (runX > 5) {
507 | result++;
508 | }
509 | }
510 | }
511 | }
512 |
513 | // Adjacent modules in column having same color
514 | for (uint8_t x = 0; x < size; x++) {
515 | bool colorY = bb_getBit(modules, x, 0);
516 | for (uint8_t y = 1, runY = 1; y < size; y++) {
517 | bool cy = bb_getBit(modules, x, y);
518 | if (cy != colorY) {
519 | colorY = cy;
520 | runY = 1;
521 | } else {
522 | runY++;
523 | if (runY == 5) {
524 | result += PENALTY_N1;
525 | } else if (runY > 5) {
526 | result++;
527 | }
528 | }
529 | }
530 | }
531 |
532 | uint16_t black = 0;
533 | for (uint8_t y = 0; y < size; y++) {
534 | uint16_t bitsRow = 0, bitsCol = 0;
535 | for (uint8_t x = 0; x < size; x++) {
536 | bool color = bb_getBit(modules, x, y);
537 |
538 | // 2*2 blocks of modules having same color
539 | if (x > 0 && y > 0) {
540 | bool colorUL = bb_getBit(modules, x - 1, y - 1);
541 | bool colorUR = bb_getBit(modules, x, y - 1);
542 | bool colorL = bb_getBit(modules, x - 1, y);
543 | if (color == colorUL && color == colorUR && color == colorL) {
544 | result += PENALTY_N2;
545 | }
546 | }
547 |
548 | // Finder-like pattern in rows and columns
549 | bitsRow = ((bitsRow << 1) & 0x7FF) | color;
550 | bitsCol = ((bitsCol << 1) & 0x7FF) | bb_getBit(modules, y, x);
551 |
552 | // Needs 11 bits accumulated
553 | if (x >= 10) {
554 | if (bitsRow == 0x05D || bitsRow == 0x5D0) {
555 | result += PENALTY_N3;
556 | }
557 | if (bitsCol == 0x05D || bitsCol == 0x5D0) {
558 | result += PENALTY_N3;
559 | }
560 | }
561 |
562 | // Balance of black and white modules
563 | if (color) { black++; }
564 | }
565 | }
566 |
567 | // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
568 | uint16_t total = size * size;
569 | for (uint16_t k = 0; black * 20 < (9 - k) * total || black * 20 > (11 + k) * total; k++) {
570 | result += PENALTY_N4;
571 | }
572 |
573 | return result;
574 | }
575 |
576 |
577 | #pragma mark - Reed-Solomon Generator
578 |
579 | static uint8_t rs_multiply(uint8_t x, uint8_t y) {
580 | // Russian peasant multiplication
581 | // See: https://en.wikipedia.org/wiki/Ancient_Egyptian_multiplication
582 | uint16_t z = 0;
583 | for (int8_t i = 7; i >= 0; i--) {
584 | z = (z << 1) ^ ((z >> 7) * 0x11D);
585 | z ^= ((y >> i) & 1) * x;
586 | }
587 | return z;
588 | }
589 |
590 | static void rs_init(uint8_t degree, uint8_t *coeff) {
591 | memset(coeff, 0, degree);
592 | coeff[degree - 1] = 1;
593 |
594 | // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
595 | // drop the highest term, and store the rest of the coefficients in order of descending powers.
596 | // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
597 | uint16_t root = 1;
598 | for (uint8_t i = 0; i < degree; i++) {
599 | // Multiply the current product by (x - r^i)
600 | for (uint8_t j = 0; j < degree; j++) {
601 | coeff[j] = rs_multiply(coeff[j], root);
602 | if (j + 1 < degree) {
603 | coeff[j] ^= coeff[j + 1];
604 | }
605 | }
606 | root = (root << 1) ^ ((root >> 7) * 0x11D); // Multiply by 0x02 mod GF(2^8/0x11D)
607 | }
608 | }
609 |
610 | static void rs_getRemainder(uint8_t degree, uint8_t *coeff, uint8_t *data, uint8_t length, uint8_t *result, uint8_t stride) {
611 | // Compute the remainder by performing polynomial division
612 |
613 | //for (uint8_t i = 0; i < degree; i++) { result[] = 0; }
614 | //memset(result, 0, degree);
615 |
616 | for (uint8_t i = 0; i < length; i++) {
617 | uint8_t factor = data[i] ^ result[0];
618 | for (uint8_t j = 1; j < degree; j++) {
619 | result[(j - 1) * stride] = result[j * stride];
620 | }
621 | result[(degree - 1) * stride] = 0;
622 |
623 | for (uint8_t j = 0; j < degree; j++) {
624 | result[j * stride] ^= rs_multiply(coeff[j], factor);
625 | }
626 | }
627 | }
628 |
629 |
630 |
631 | #pragma mark - QrCode
632 |
633 | static int8_t encodeDataCodewords(BitBucket *dataCodewords, const uint8_t *text, uint16_t length, uint8_t version) {
634 | int8_t mode = MODE_BYTE;
635 |
636 | if (isNumeric((char*)text, length)) {
637 | mode = MODE_NUMERIC;
638 | bb_appendBits(dataCodewords, 1 << MODE_NUMERIC, 4);
639 | bb_appendBits(dataCodewords, length, getModeBits(version, MODE_NUMERIC));
640 |
641 | uint16_t accumData = 0;
642 | uint8_t accumCount = 0;
643 | for (uint16_t i = 0; i < length; i++) {
644 | accumData = accumData * 10 + ((char)(text[i]) - '0');
645 | accumCount++;
646 | if (accumCount == 3) {
647 | bb_appendBits(dataCodewords, accumData, 10);
648 | accumData = 0;
649 | accumCount = 0;
650 | }
651 | }
652 |
653 | // 1 or 2 digits remaining
654 | if (accumCount > 0) {
655 | bb_appendBits(dataCodewords, accumData, accumCount * 3 + 1);
656 | }
657 |
658 | } else if (isAlphanumeric((char*)text, length)) {
659 | mode = MODE_ALPHANUMERIC;
660 | bb_appendBits(dataCodewords, 1 << MODE_ALPHANUMERIC, 4);
661 | bb_appendBits(dataCodewords, length, getModeBits(version, MODE_ALPHANUMERIC));
662 |
663 | uint16_t accumData = 0;
664 | uint8_t accumCount = 0;
665 | for (uint16_t i = 0; i < length; i++) {
666 | accumData = accumData * 45 + getAlphanumeric((char)(text[i]));
667 | accumCount++;
668 | if (accumCount == 2) {
669 | bb_appendBits(dataCodewords, accumData, 11);
670 | accumData = 0;
671 | accumCount = 0;
672 | }
673 | }
674 |
675 | // 1 character remaining
676 | if (accumCount > 0) {
677 | bb_appendBits(dataCodewords, accumData, 6);
678 | }
679 |
680 | } else {
681 | bb_appendBits(dataCodewords, 1 << MODE_BYTE, 4);
682 | bb_appendBits(dataCodewords, length, getModeBits(version, MODE_BYTE));
683 | for (uint16_t i = 0; i < length; i++) {
684 | bb_appendBits(dataCodewords, (char)(text[i]), 8);
685 | }
686 | }
687 |
688 | //bb_setBits(dataCodewords, length, 4, getModeBits(version, mode));
689 |
690 | return mode;
691 | }
692 |
693 | static void performErrorCorrection(uint8_t version, uint8_t ecc, BitBucket *data) {
694 |
695 | // See: http://www.thonky.com/qr-code-tutorial/structure-final-message
696 |
697 | #if LOCK_VERSION == 0
698 | uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc][version - 1];
699 | uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc][version - 1];
700 | uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1];
701 | #else
702 | uint8_t numBlocks = NUM_ERROR_CORRECTION_BLOCKS[ecc];
703 | uint16_t totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[ecc];
704 | uint16_t moduleCount = NUM_RAW_DATA_MODULES;
705 | #endif
706 |
707 | uint8_t blockEccLen = totalEcc / numBlocks;
708 | uint8_t numShortBlocks = numBlocks - moduleCount / 8 % numBlocks;
709 | uint8_t shortBlockLen = moduleCount / 8 / numBlocks;
710 |
711 | uint8_t shortDataBlockLen = shortBlockLen - blockEccLen;
712 |
713 | uint8_t result[data->capacityBytes];
714 | memset(result, 0, sizeof(result));
715 |
716 | uint8_t coeff[blockEccLen];
717 | rs_init(blockEccLen, coeff);
718 |
719 | uint16_t offset = 0;
720 | uint8_t *dataBytes = data->data;
721 |
722 |
723 | // Interleave all short blocks
724 | for (uint8_t i = 0; i < shortDataBlockLen; i++) {
725 | uint16_t index = i;
726 | uint8_t stride = shortDataBlockLen;
727 | for (uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) {
728 | result[offset++] = dataBytes[index];
729 |
730 | #if LOCK_VERSION == 0 || LOCK_VERSION >= 5
731 | if (blockNum == numShortBlocks) { stride++; }
732 | #endif
733 | index += stride;
734 | }
735 | }
736 |
737 | // Version less than 5 only have short blocks
738 | #if LOCK_VERSION == 0 || LOCK_VERSION >= 5
739 | {
740 | // Interleave long blocks
741 | uint16_t index = shortDataBlockLen * (numShortBlocks + 1);
742 | uint8_t stride = shortDataBlockLen;
743 | for (uint8_t blockNum = 0; blockNum < numBlocks - numShortBlocks; blockNum++) {
744 | result[offset++] = dataBytes[index];
745 |
746 | if (blockNum == 0) { stride++; }
747 | index += stride;
748 | }
749 | }
750 | #endif
751 |
752 | // Add all ecc blocks, interleaved
753 | uint8_t blockSize = shortDataBlockLen;
754 | for (uint8_t blockNum = 0; blockNum < numBlocks; blockNum++) {
755 |
756 | #if LOCK_VERSION == 0 || LOCK_VERSION >= 5
757 | if (blockNum == numShortBlocks) { blockSize++; }
758 | #endif
759 | rs_getRemainder(blockEccLen, coeff, dataBytes, blockSize, &result[offset + blockNum], numBlocks);
760 | dataBytes += blockSize;
761 | }
762 |
763 | memcpy(data->data, result, data->capacityBytes);
764 | data->bitOffsetOrWidth = moduleCount;
765 | }
766 |
767 | // We store the Format bits tightly packed into a single byte (each of the 4 modes is 2 bits)
768 | // The format bits can be determined by ECC_FORMAT_BITS >> (2 * ecc)
769 | static const uint8_t ECC_FORMAT_BITS = (0x02 << 6) | (0x03 << 4) | (0x00 << 2) | (0x01 << 0);
770 |
771 |
772 | #pragma mark - Public QRCode functions
773 |
774 | uint16_t qrcode_getBufferSize(uint8_t version) {
775 | return bb_getGridSizeBytes(4 * version + 17);
776 | }
777 |
778 | // @TODO: Return error if data is too big.
779 | int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length) {
780 | uint8_t size = version * 4 + 17;
781 | qrcode->version = version;
782 | qrcode->size = size;
783 | qrcode->ecc = ecc;
784 | qrcode->modules = modules;
785 |
786 | uint8_t eccFormatBits = (ECC_FORMAT_BITS >> (2 * ecc)) & 0x03;
787 |
788 | #if LOCK_VERSION == 0
789 | uint16_t moduleCount = NUM_RAW_DATA_MODULES[version - 1];
790 | uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits][version - 1];
791 | #else
792 | version = LOCK_VERSION;
793 | uint16_t moduleCount = NUM_RAW_DATA_MODULES;
794 | uint16_t dataCapacity = moduleCount / 8 - NUM_ERROR_CORRECTION_CODEWORDS[eccFormatBits];
795 | #endif
796 |
797 | struct BitBucket codewords;
798 | uint8_t codewordBytes[bb_getBufferSizeBytes(moduleCount)];
799 | bb_initBuffer(&codewords, codewordBytes, (int32_t)sizeof(codewordBytes));
800 |
801 | // Place the data code words into the buffer
802 | int8_t mode = encodeDataCodewords(&codewords, data, length, version);
803 |
804 | if (mode < 0) { return -1; }
805 | qrcode->mode = mode;
806 |
807 | // Add terminator and pad up to a byte if applicable
808 | uint32_t padding = (dataCapacity * 8) - codewords.bitOffsetOrWidth;
809 | if (padding > 4) { padding = 4; }
810 | bb_appendBits(&codewords, 0, padding);
811 | bb_appendBits(&codewords, 0, (8 - codewords.bitOffsetOrWidth % 8) % 8);
812 |
813 | // Pad with alternate bytes until data capacity is reached
814 | for (uint8_t padByte = 0xEC; codewords.bitOffsetOrWidth < (dataCapacity * 8); padByte ^= 0xEC ^ 0x11) {
815 | bb_appendBits(&codewords, padByte, 8);
816 | }
817 |
818 | BitBucket modulesGrid;
819 | bb_initGrid(&modulesGrid, modules, size);
820 |
821 | BitBucket isFunctionGrid;
822 | uint8_t isFunctionGridBytes[bb_getGridSizeBytes(size)];
823 | bb_initGrid(&isFunctionGrid, isFunctionGridBytes, size);
824 |
825 | // Draw function patterns, draw all codewords, do masking
826 | drawFunctionPatterns(&modulesGrid, &isFunctionGrid, version, eccFormatBits);
827 | performErrorCorrection(version, eccFormatBits, &codewords);
828 | drawCodewords(&modulesGrid, &isFunctionGrid, &codewords);
829 |
830 | // Find the best (lowest penalty) mask
831 | uint8_t mask = 0;
832 | int32_t minPenalty = INT32_MAX;
833 | for (uint8_t i = 0; i < 8; i++) {
834 | drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, i);
835 | applyMask(&modulesGrid, &isFunctionGrid, i);
836 | int penalty = getPenaltyScore(&modulesGrid);
837 | if (penalty < minPenalty) {
838 | mask = i;
839 | minPenalty = penalty;
840 | }
841 | applyMask(&modulesGrid, &isFunctionGrid, i); // Undoes the mask due to XOR
842 | }
843 |
844 | qrcode->mask = mask;
845 |
846 | // Overwrite old format bits
847 | drawFormatBits(&modulesGrid, &isFunctionGrid, eccFormatBits, mask);
848 |
849 | // Apply the final choice of mask
850 | applyMask(&modulesGrid, &isFunctionGrid, mask);
851 |
852 | return 0;
853 | }
854 |
855 | int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data) {
856 | return qrcode_initBytes(qrcode, modules, version, ecc, (uint8_t*)data, strlen(data));
857 | }
858 |
859 | bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y) {
860 | if (x < 0 || x >= qrcode->size || y < 0 || y >= qrcode->size) {
861 | return false;
862 | }
863 |
864 | uint32_t offset = y * qrcode->size + x;
865 | return (qrcode->modules[offset >> 3] & (1 << (7 - (offset & 0x07)))) != 0;
866 | }
867 |
868 | /*
869 | uint8_t qrcode_getHexLength(QRCode *qrcode) {
870 | return ((qrcode->size * qrcode->size) + 7) / 4;
871 | }
872 |
873 | void qrcode_getHex(QRCode *qrcode, char *result) {
874 |
875 | }
876 | */
877 |
--------------------------------------------------------------------------------
/src/qrcode.h:
--------------------------------------------------------------------------------
1 | /**
2 | * The MIT License (MIT)
3 | *
4 | * This library is written and maintained by Richard Moore.
5 | * Major parts were derived from Project Nayuki's library.
6 | *
7 | * Copyright (c) 2017 Richard Moore (https://github.com/ricmoo/QRCode)
8 | * Copyright (c) 2017 Project Nayuki (https://www.nayuki.io/page/qr-code-generator-library)
9 | *
10 | * Permission is hereby granted, free of charge, to any person obtaining a copy
11 | * of this software and associated documentation files (the "Software"), to deal
12 | * in the Software without restriction, including without limitation the rights
13 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
14 | * copies of the Software, and to permit persons to whom the Software is
15 | * furnished to do so, subject to the following conditions:
16 | *
17 | * The above copyright notice and this permission notice shall be included in
18 | * all copies or substantial portions of the Software.
19 | *
20 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
25 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
26 | * THE SOFTWARE.
27 | */
28 |
29 | /**
30 | * Special thanks to Nayuki (https://www.nayuki.io/) from which this library was
31 | * heavily inspired and compared against.
32 | *
33 | * See: https://github.com/nayuki/QR-Code-generator/tree/master/cpp
34 | */
35 |
36 |
37 | #ifndef __QRCODE_H_
38 | #define __QRCODE_H_
39 |
40 | #ifndef __cplusplus
41 | typedef unsigned char bool;
42 | static const bool false = 0;
43 | static const bool true = 1;
44 | #endif
45 |
46 | #include
47 |
48 |
49 | // QR Code Format Encoding
50 | #define MODE_NUMERIC 0
51 | #define MODE_ALPHANUMERIC 1
52 | #define MODE_BYTE 2
53 |
54 |
55 | // Error Correction Code Levels
56 | #define ECC_LOW 0
57 | #define ECC_MEDIUM 1
58 | #define ECC_QUARTILE 2
59 | #define ECC_HIGH 3
60 |
61 |
62 | // If set to non-zero, this library can ONLY produce QR codes at that version
63 | // This saves a lot of dynamic memory, as the codeword tables are skipped
64 | #ifndef LOCK_VERSION
65 | #define LOCK_VERSION 0
66 | #endif
67 |
68 |
69 | typedef struct QRCode {
70 | uint8_t version;
71 | uint8_t size;
72 | uint8_t ecc;
73 | uint8_t mode;
74 | uint8_t mask;
75 | uint8_t *modules;
76 | } QRCode;
77 |
78 |
79 | #ifdef __cplusplus
80 | extern "C"{
81 | #endif /* __cplusplus */
82 |
83 |
84 |
85 | uint16_t qrcode_getBufferSize(uint8_t version);
86 |
87 | int8_t qrcode_initText(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, const char *data);
88 | int8_t qrcode_initBytes(QRCode *qrcode, uint8_t *modules, uint8_t version, uint8_t ecc, uint8_t *data, uint16_t length);
89 |
90 | bool qrcode_getModule(QRCode *qrcode, uint8_t x, uint8_t y);
91 |
92 |
93 |
94 | #ifdef __cplusplus
95 | }
96 | #endif /* __cplusplus */
97 |
98 |
99 | #endif /* __QRCODE_H_ */
100 |
--------------------------------------------------------------------------------
/tests/BitBuffer.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * QR Code generator library (C++)
3 | *
4 | * Copyright (c) Project Nayuki
5 | * https://www.nayuki.io/page/qr-code-generator-library
6 | *
7 | * (MIT License)
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | * - The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | * - The Software is provided "as is", without warranty of any kind, express or
17 | * implied, including but not limited to the warranties of merchantability,
18 | * fitness for a particular purpose and noninfringement. In no event shall the
19 | * authors or copyright holders be liable for any claim, damages or other
20 | * liability, whether in an action of contract, tort or otherwise, arising from,
21 | * out of or in connection with the Software or the use or other dealings in the
22 | * Software.
23 | */
24 |
25 | #include
26 | #include "BitBuffer.hpp"
27 |
28 |
29 | qrcodegen::BitBuffer::BitBuffer() :
30 | data(),
31 | bitLength(0) {}
32 |
33 |
34 | int qrcodegen::BitBuffer::getBitLength() const {
35 | return bitLength;
36 | }
37 |
38 |
39 | std::vector qrcodegen::BitBuffer::getBytes() const {
40 | return data;
41 | }
42 |
43 |
44 | void qrcodegen::BitBuffer::appendBits(uint32_t val, int len) {
45 | if (len < 0 || len > 32 || (len < 32 && (val >> len) != 0))
46 | throw "Value out of range";
47 | size_t newBitLen = bitLength + len;
48 | while (data.size() * 8 < newBitLen)
49 | data.push_back(0);
50 | for (int i = len - 1; i >= 0; i--, bitLength++) // Append bit by bit
51 | data.at(bitLength >> 3) |= ((val >> i) & 1) << (7 - (bitLength & 7));
52 | }
53 |
54 |
55 | void qrcodegen::BitBuffer::appendData(const QrSegment &seg) {
56 | size_t newBitLen = bitLength + seg.bitLength;
57 | while (data.size() * 8 < newBitLen)
58 | data.push_back(0);
59 | for (int i = 0; i < seg.bitLength; i++, bitLength++) { // Append bit by bit
60 | int bit = (seg.data.at(i >> 3) >> (7 - (i & 7))) & 1;
61 | data.at(bitLength >> 3) |= bit << (7 - (bitLength & 7));
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/tests/BitBuffer.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * QR Code generator library (C++)
3 | *
4 | * Copyright (c) Project Nayuki
5 | * https://www.nayuki.io/page/qr-code-generator-library
6 | *
7 | * (MIT License)
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | * - The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | * - The Software is provided "as is", without warranty of any kind, express or
17 | * implied, including but not limited to the warranties of merchantability,
18 | * fitness for a particular purpose and noninfringement. In no event shall the
19 | * authors or copyright holders be liable for any claim, damages or other
20 | * liability, whether in an action of contract, tort or otherwise, arising from,
21 | * out of or in connection with the Software or the use or other dealings in the
22 | * Software.
23 | */
24 |
25 | #pragma once
26 |
27 | #include
28 | #include
29 | #include "QrSegment.hpp"
30 |
31 |
32 | namespace qrcodegen {
33 |
34 | /*
35 | * An appendable sequence of bits. Bits are packed in big endian within a byte.
36 | */
37 | class BitBuffer {
38 |
39 | /*---- Fields ----*/
40 | private:
41 |
42 | std::vector data;
43 | int bitLength;
44 |
45 |
46 |
47 | /*---- Constructor ----*/
48 | public:
49 |
50 | // Creates an empty bit buffer (length 0).
51 | BitBuffer();
52 |
53 |
54 |
55 | /*---- Methods ----*/
56 | public:
57 |
58 | // Returns the number of bits in the buffer, which is a non-negative value.
59 | int getBitLength() const;
60 |
61 |
62 | // Returns a copy of all bytes, padding up to the nearest byte.
63 | std::vector getBytes() const;
64 |
65 |
66 | // Appends the given number of bits of the given value to this sequence.
67 | // If 0 <= len <= 31, then this requires 0 <= val < 2^len.
68 | void appendBits(uint32_t val, int len);
69 |
70 |
71 | // Appends the data of the given segment to this bit buffer.
72 | void appendData(const QrSegment &seg);
73 |
74 | };
75 |
76 | }
77 |
--------------------------------------------------------------------------------
/tests/QrCode.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * QR Code generator library (C++)
3 | *
4 | * Copyright (c) Project Nayuki
5 | * https://www.nayuki.io/page/qr-code-generator-library
6 | *
7 | * (MIT License)
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | * - The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | * - The Software is provided "as is", without warranty of any kind, express or
17 | * implied, including but not limited to the warranties of merchantability,
18 | * fitness for a particular purpose and noninfringement. In no event shall the
19 | * authors or copyright holders be liable for any claim, damages or other
20 | * liability, whether in an action of contract, tort or otherwise, arising from,
21 | * out of or in connection with the Software or the use or other dealings in the
22 | * Software.
23 | */
24 |
25 | #include
26 | #include
27 | #include
28 | #include
29 | #include
30 | #include "BitBuffer.hpp"
31 | #include "QrCode.hpp"
32 |
33 |
34 | qrcodegen::QrCode::Ecc::Ecc(int ord, int fb) :
35 | ordinal(ord),
36 | formatBits(fb) {}
37 |
38 |
39 | const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::LOW (0, 1);
40 | const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::MEDIUM (1, 0);
41 | const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::QUARTILE(2, 3);
42 | const qrcodegen::QrCode::Ecc qrcodegen::QrCode::Ecc::HIGH (3, 2);
43 |
44 |
45 | qrcodegen::QrCode qrcodegen::QrCode::encodeText(const char *text, int version, const Ecc &ecl) {
46 | std::vector segs(QrSegment::makeSegments(text));
47 | return encodeSegments(segs, ecl, version, version, -1, false);
48 | }
49 |
50 |
51 | qrcodegen::QrCode qrcodegen::QrCode::encodeBinary(const std::vector &data, const Ecc &ecl) {
52 | std::vector segs;
53 | segs.push_back(QrSegment::makeBytes(data));
54 | return encodeSegments(segs, ecl);
55 | }
56 |
57 |
58 | qrcodegen::QrCode qrcodegen::QrCode::encodeSegments(const std::vector &segs, const Ecc &ecl,
59 | int minVersion, int maxVersion, int mask, bool boostEcl) {
60 | if (!(1 <= minVersion && minVersion <= maxVersion && maxVersion <= 40) || mask < -1 || mask > 7)
61 | throw "Invalid value";
62 |
63 | // Find the minimal version number to use
64 | int version, dataUsedBits;
65 | for (version = minVersion; ; version++) {
66 | int dataCapacityBits = getNumDataCodewords(version, ecl) * 8; // Number of data bits available
67 | dataUsedBits = QrSegment::getTotalBits(segs, version);
68 | if (dataUsedBits != -1 && dataUsedBits <= dataCapacityBits)
69 | break; // This version number is found to be suitable
70 | if (version >= maxVersion) // All versions in the range could not fit the given data
71 | throw "Data too long";
72 | }
73 | if (dataUsedBits == -1)
74 | throw "Assertion error";
75 |
76 | // Increase the error correction level while the data still fits in the current version number
77 | const Ecc *newEcl = &ecl;
78 | if (boostEcl) {
79 | if (dataUsedBits <= getNumDataCodewords(version, Ecc::MEDIUM ) * 8) newEcl = &Ecc::MEDIUM ;
80 | if (dataUsedBits <= getNumDataCodewords(version, Ecc::QUARTILE) * 8) newEcl = &Ecc::QUARTILE;
81 | if (dataUsedBits <= getNumDataCodewords(version, Ecc::HIGH ) * 8) newEcl = &Ecc::HIGH ;
82 | }
83 |
84 | // Create the data bit string by concatenating all segments
85 | int dataCapacityBits = getNumDataCodewords(version, *newEcl) * 8;
86 | BitBuffer bb;
87 | for (size_t i = 0; i < segs.size(); i++) {
88 | const QrSegment &seg(segs.at(i));
89 | bb.appendBits(seg.mode.modeBits, 4);
90 | bb.appendBits(seg.numChars, seg.mode.numCharCountBits(version));
91 | bb.appendData(seg);
92 | }
93 |
94 | // Add terminator and pad up to a byte if applicable
95 | bb.appendBits(0, std::min(4, dataCapacityBits - bb.getBitLength()));
96 | bb.appendBits(0, (8 - bb.getBitLength() % 8) % 8);
97 |
98 | // Pad with alternate bytes until data capacity is reached
99 | for (uint8_t padByte = 0xEC; bb.getBitLength() < dataCapacityBits; padByte ^= 0xEC ^ 0x11)
100 | bb.appendBits(padByte, 8);
101 | if (bb.getBitLength() % 8 != 0)
102 | throw "Assertion error";
103 |
104 | // Create the QR Code symbol
105 | return QrCode(version, *newEcl, bb.getBytes(), mask);
106 | }
107 |
108 |
109 | qrcodegen::QrCode::QrCode(int ver, const Ecc &ecl, const std::vector &dataCodewords, int mask) :
110 | // Initialize scalar fields
111 | version(ver),
112 | size(1 <= ver && ver <= 40 ? ver * 4 + 17 : -1), // Avoid signed overflow undefined behavior
113 | errorCorrectionLevel(ecl) {
114 |
115 | // Check arguments
116 | if (ver < 1 || ver > 40 || mask < -1 || mask > 7)
117 | throw "Value out of range";
118 |
119 | std::vector row(size);
120 | for (int i = 0; i < size; i++) {
121 | modules.push_back(row);
122 | isFunction.push_back(row);
123 | }
124 |
125 | // Draw function patterns, draw all codewords, do masking
126 | drawFunctionPatterns();
127 | const std::vector allCodewords(appendErrorCorrection(dataCodewords));
128 | drawCodewords(allCodewords);
129 | this->mask = handleConstructorMasking(mask);
130 | }
131 |
132 |
133 | qrcodegen::QrCode::QrCode(const QrCode &qr, int mask) :
134 | // Copy scalar fields
135 | version(qr.version),
136 | size(qr.size),
137 | errorCorrectionLevel(qr.errorCorrectionLevel) {
138 |
139 | // Check arguments
140 | if (mask < -1 || mask > 7)
141 | throw "Mask value out of range";
142 |
143 | // Handle grid fields
144 | modules = qr.modules;
145 | isFunction = qr.isFunction;
146 |
147 | // Handle masking
148 | applyMask(qr.mask); // Undo old mask
149 | this->mask = handleConstructorMasking(mask);
150 | }
151 |
152 |
153 | int qrcodegen::QrCode::getMask() const {
154 | return mask;
155 | }
156 |
157 |
158 | int qrcodegen::QrCode::getModule(int x, int y) const {
159 | if (0 <= x && x < size && 0 <= y && y < size)
160 | return modules.at(y).at(x) ? 1 : 0;
161 | else
162 | return 0; // Infinite white border
163 | }
164 |
165 |
166 | std::string qrcodegen::QrCode::toSvgString(int border) const {
167 | if (border < 0)
168 | throw "Border must be non-negative";
169 | std::ostringstream sb;
170 | sb << "\n";
171 | sb << "\n";
172 | sb << "\n";
174 | sb << "\t\n";
175 | sb << "\t\n";
189 | sb << " \n";
190 | return sb.str();
191 | }
192 |
193 |
194 | void qrcodegen::QrCode::drawFunctionPatterns() {
195 | // Draw the horizontal and vertical timing patterns
196 | for (int i = 0; i < size; i++) {
197 | setFunctionModule(6, i, i % 2 == 0);
198 | setFunctionModule(i, 6, i % 2 == 0);
199 | }
200 |
201 | // Draw 3 finder patterns (all corners except bottom right; overwrites some timing modules)
202 | drawFinderPattern(3, 3);
203 | drawFinderPattern(size - 4, 3);
204 | drawFinderPattern(3, size - 4);
205 |
206 | // Draw the numerous alignment patterns
207 | const std::vector alignPatPos(getAlignmentPatternPositions(version));
208 | int numAlign = alignPatPos.size();
209 | for (int i = 0; i < numAlign; i++) {
210 | for (int j = 0; j < numAlign; j++) {
211 | if ((i == 0 && j == 0) || (i == 0 && j == numAlign - 1) || (i == numAlign - 1 && j == 0))
212 | continue; // Skip the three finder corners
213 | else
214 | drawAlignmentPattern(alignPatPos.at(i), alignPatPos.at(j));
215 | }
216 | }
217 |
218 | // Draw configuration data
219 | drawFormatBits(0); // Dummy mask value; overwritten later in the constructor
220 | drawVersion();
221 | }
222 |
223 |
224 | void qrcodegen::QrCode::drawFormatBits(int mask) {
225 | // Calculate error correction code and pack bits
226 | int data = errorCorrectionLevel.formatBits << 3 | mask; // errCorrLvl is uint2, mask is uint3
227 | int rem = data;
228 | for (int i = 0; i < 10; i++)
229 | rem = (rem << 1) ^ ((rem >> 9) * 0x537);
230 | data = data << 10 | rem;
231 | data ^= 0x5412; // uint15
232 | if (data >> 15 != 0)
233 | throw "Assertion error";
234 |
235 | // Draw first copy
236 | for (int i = 0; i <= 5; i++)
237 | setFunctionModule(8, i, ((data >> i) & 1) != 0);
238 | setFunctionModule(8, 7, ((data >> 6) & 1) != 0);
239 | setFunctionModule(8, 8, ((data >> 7) & 1) != 0);
240 | setFunctionModule(7, 8, ((data >> 8) & 1) != 0);
241 | for (int i = 9; i < 15; i++)
242 | setFunctionModule(14 - i, 8, ((data >> i) & 1) != 0);
243 |
244 | // Draw second copy
245 | for (int i = 0; i <= 7; i++)
246 | setFunctionModule(size - 1 - i, 8, ((data >> i) & 1) != 0);
247 | for (int i = 8; i < 15; i++)
248 | setFunctionModule(8, size - 15 + i, ((data >> i) & 1) != 0);
249 | setFunctionModule(8, size - 8, true);
250 | }
251 |
252 |
253 | void qrcodegen::QrCode::drawVersion() {
254 | if (version < 7)
255 | return;
256 |
257 | // Calculate error correction code and pack bits
258 | int rem = version; // version is uint6, in the range [7, 40]
259 | for (int i = 0; i < 12; i++)
260 | rem = (rem << 1) ^ ((rem >> 11) * 0x1F25);
261 | int data = version << 12 | rem; // uint18
262 | if (data >> 18 != 0)
263 | throw "Assertion error";
264 |
265 | // Draw two copies
266 | for (int i = 0; i < 18; i++) {
267 | bool bit = ((data >> i) & 1) != 0;
268 | int a = size - 11 + i % 3, b = i / 3;
269 | setFunctionModule(a, b, bit);
270 | setFunctionModule(b, a, bit);
271 | }
272 | }
273 |
274 |
275 | void qrcodegen::QrCode::drawFinderPattern(int x, int y) {
276 | for (int i = -4; i <= 4; i++) {
277 | for (int j = -4; j <= 4; j++) {
278 | int dist = std::max(std::abs(i), std::abs(j)); // Chebyshev/infinity norm
279 | int xx = x + j, yy = y + i;
280 | if (0 <= xx && xx < size && 0 <= yy && yy < size)
281 | setFunctionModule(xx, yy, dist != 2 && dist != 4);
282 | }
283 | }
284 | }
285 |
286 |
287 | void qrcodegen::QrCode::drawAlignmentPattern(int x, int y) {
288 | for (int i = -2; i <= 2; i++) {
289 | for (int j = -2; j <= 2; j++)
290 | setFunctionModule(x + j, y + i, std::max(std::abs(i), std::abs(j)) != 1);
291 | }
292 | }
293 |
294 |
295 | void qrcodegen::QrCode::setFunctionModule(int x, int y, bool isBlack) {
296 | modules.at(y).at(x) = isBlack;
297 | isFunction.at(y).at(x) = true;
298 | }
299 |
300 |
301 | std::vector qrcodegen::QrCode::appendErrorCorrection(const std::vector &data) const {
302 | if (data.size() != static_cast(getNumDataCodewords(version, errorCorrectionLevel)))
303 | throw "Invalid argument";
304 |
305 | // Calculate parameter numbers
306 | int numBlocks = NUM_ERROR_CORRECTION_BLOCKS[errorCorrectionLevel.ordinal][version];
307 | int totalEcc = NUM_ERROR_CORRECTION_CODEWORDS[errorCorrectionLevel.ordinal][version];
308 | if (totalEcc % numBlocks != 0)
309 | throw "Assertion error";
310 | int blockEccLen = totalEcc / numBlocks;
311 | int numShortBlocks = numBlocks - getNumRawDataModules(version) / 8 % numBlocks;
312 | int shortBlockLen = getNumRawDataModules(version) / 8 / numBlocks;
313 |
314 | // Split data into blocks and append ECC to each block
315 | std::vector > blocks;
316 | const ReedSolomonGenerator rs(blockEccLen);
317 | for (int i = 0, k = 0; i < numBlocks; i++) {
318 | std::vector dat;
319 | dat.insert(dat.begin(), data.begin() + k, data.begin() + (k + shortBlockLen - blockEccLen + (i < numShortBlocks ? 0 : 1)));
320 | k += dat.size();
321 | const std::vector ecc(rs.getRemainder(dat));
322 | if (i < numShortBlocks)
323 | dat.push_back(0);
324 | dat.insert(dat.end(), ecc.begin(), ecc.end());
325 | blocks.push_back(dat);
326 | }
327 |
328 | // Interleave (not concatenate) the bytes from every block into a single sequence
329 | std::vector result;
330 | for (int i = 0; static_cast(i) < blocks.at(0).size(); i++) {
331 | for (int j = 0; static_cast(j) < blocks.size(); j++) {
332 | // Skip the padding byte in short blocks
333 | if (i != shortBlockLen - blockEccLen || j >= numShortBlocks)
334 | result.push_back(blocks.at(j).at(i));
335 | }
336 | }
337 | if (result.size() != static_cast(getNumRawDataModules(version) / 8))
338 | throw "Assertion error";
339 | return result;
340 | }
341 |
342 |
343 | void qrcodegen::QrCode::drawCodewords(const std::vector &data) {
344 | if (data.size() != static_cast(getNumRawDataModules(version) / 8))
345 | throw "Invalid argument";
346 |
347 | size_t i = 0; // Bit index into the data
348 | // Do the funny zigzag scan
349 | for (int right = size - 1; right >= 1; right -= 2) { // Index of right column in each column pair
350 | if (right == 6)
351 | right = 5;
352 | for (int vert = 0; vert < size; vert++) { // Vertical counter
353 | for (int j = 0; j < 2; j++) {
354 | int x = right - j; // Actual x coordinate
355 | bool upwards = ((right & 2) == 0) ^ (x < 6);
356 | int y = upwards ? size - 1 - vert : vert; // Actual y coordinate
357 | if (!isFunction.at(y).at(x) && i < data.size() * 8) {
358 | modules.at(y).at(x) = ((data.at(i >> 3) >> (7 - (i & 7))) & 1) != 0;
359 | i++;
360 | }
361 | // If there are any remainder bits (0 to 7), they are already
362 | // set to 0/false/white when the grid of modules was initialized
363 | }
364 | }
365 | }
366 | if (static_cast(i) != data.size() * 8)
367 | throw "Assertion error";
368 | }
369 |
370 |
371 | void qrcodegen::QrCode::applyMask(int mask) {
372 | if (mask < 0 || mask > 7)
373 | throw "Mask value out of range";
374 | for (int y = 0; y < size; y++) {
375 | for (int x = 0; x < size; x++) {
376 | bool invert;
377 | switch (mask) {
378 | case 0: invert = (x + y) % 2 == 0; break;
379 | case 1: invert = y % 2 == 0; break;
380 | case 2: invert = x % 3 == 0; break;
381 | case 3: invert = (x + y) % 3 == 0; break;
382 | case 4: invert = (x / 3 + y / 2) % 2 == 0; break;
383 | case 5: invert = x * y % 2 + x * y % 3 == 0; break;
384 | case 6: invert = (x * y % 2 + x * y % 3) % 2 == 0; break;
385 | case 7: invert = ((x + y) % 2 + x * y % 3) % 2 == 0; break;
386 | default: throw "Assertion error";
387 | }
388 | modules.at(y).at(x) = modules.at(y).at(x) ^ (invert & !isFunction.at(y).at(x));
389 | }
390 | }
391 | }
392 |
393 |
394 | int qrcodegen::QrCode::handleConstructorMasking(int mask) {
395 | if (mask == -1) { // Automatically choose best mask
396 | int32_t minPenalty = INT32_MAX;
397 | for (int i = 0; i < 8; i++) {
398 | drawFormatBits(i);
399 | applyMask(i);
400 | int penalty = getPenaltyScore();
401 | if (penalty < minPenalty) {
402 | mask = i;
403 | minPenalty = penalty;
404 | }
405 | applyMask(i); // Undoes the mask due to XOR
406 | }
407 | }
408 | if (mask < 0 || mask > 7)
409 | throw "Assertion error";
410 | drawFormatBits(mask); // Overwrite old format bits
411 | applyMask(mask); // Apply the final choice of mask
412 | return mask; // The caller shall assign this value to the final-declared field
413 | }
414 |
415 |
416 | int qrcodegen::QrCode::getPenaltyScore() const {
417 | int result = 0;
418 |
419 | // Adjacent modules in row having same color
420 | for (int y = 0; y < size; y++) {
421 | bool colorX = modules.at(y).at(0);
422 | for (int x = 1, runX = 1; x < size; x++) {
423 | if (modules.at(y).at(x) != colorX) {
424 | colorX = modules.at(y).at(x);
425 | runX = 1;
426 | } else {
427 | runX++;
428 | if (runX == 5)
429 | result += PENALTY_N1;
430 | else if (runX > 5)
431 | result++;
432 | }
433 | }
434 | }
435 | // Adjacent modules in column having same color
436 | for (int x = 0; x < size; x++) {
437 | bool colorY = modules.at(0).at(x);
438 | for (int y = 1, runY = 1; y < size; y++) {
439 | if (modules.at(y).at(x) != colorY) {
440 | colorY = modules.at(y).at(x);
441 | runY = 1;
442 | } else {
443 | runY++;
444 | if (runY == 5)
445 | result += PENALTY_N1;
446 | else if (runY > 5)
447 | result++;
448 | }
449 | }
450 | }
451 |
452 | // 2*2 blocks of modules having same color
453 | for (int y = 0; y < size - 1; y++) {
454 | for (int x = 0; x < size - 1; x++) {
455 | bool color = modules.at(y).at(x);
456 | if ( color == modules.at(y).at(x + 1) &&
457 | color == modules.at(y + 1).at(x) &&
458 | color == modules.at(y + 1).at(x + 1))
459 | result += PENALTY_N2;
460 | }
461 | }
462 |
463 | // Finder-like pattern in rows
464 | for (int y = 0; y < size; y++) {
465 | for (int x = 0, bits = 0; x < size; x++) {
466 | bits = ((bits << 1) & 0x7FF) | (modules.at(y).at(x) ? 1 : 0);
467 | if (x >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
468 | result += PENALTY_N3;
469 | }
470 | }
471 | // Finder-like pattern in columns
472 | for (int x = 0; x < size; x++) {
473 | for (int y = 0, bits = 0; y < size; y++) {
474 | bits = ((bits << 1) & 0x7FF) | (modules.at(y).at(x) ? 1 : 0);
475 | if (y >= 10 && (bits == 0x05D || bits == 0x5D0)) // Needs 11 bits accumulated
476 | result += PENALTY_N3;
477 | }
478 | }
479 |
480 | // Balance of black and white modules
481 | int black = 0;
482 | for (int y = 0; y < size; y++) {
483 | for (int x = 0; x < size; x++) {
484 | if (modules.at(y).at(x))
485 | black++;
486 | }
487 | }
488 | int total = size * size;
489 | // Find smallest k such that (45-5k)% <= dark/total <= (55+5k)%
490 | for (int k = 0; black*20 < (9-k)*total || black*20 > (11+k)*total; k++)
491 | result += PENALTY_N4;
492 | return result;
493 | }
494 |
495 |
496 | std::vector qrcodegen::QrCode::getAlignmentPatternPositions(int ver) {
497 | if (ver < 1 || ver > 40)
498 | throw "Version number out of range";
499 | else if (ver == 1)
500 | return std::vector();
501 | else {
502 | int numAlign = ver / 7 + 2;
503 | int step;
504 | if (ver != 32)
505 | step = (ver * 4 + numAlign * 2 + 1) / (2 * numAlign - 2) * 2; // ceil((size - 13) / (2*numAlign - 2)) * 2
506 | else // C-C-C-Combo breaker!
507 | step = 26;
508 |
509 | std::vector result;
510 | int size = ver * 4 + 17;
511 | for (int i = 0, pos = size - 7; i < numAlign - 1; i++, pos -= step)
512 | result.insert(result.begin(), pos);
513 | result.insert(result.begin(), 6);
514 | return result;
515 | }
516 | }
517 |
518 |
519 | int qrcodegen::QrCode::getNumRawDataModules(int ver) {
520 | if (ver < 1 || ver > 40)
521 | throw "Version number out of range";
522 | int result = (16 * ver + 128) * ver + 64;
523 | if (ver >= 2) {
524 | int numAlign = ver / 7 + 2;
525 | result -= (25 * numAlign - 10) * numAlign - 55;
526 | if (ver >= 7)
527 | result -= 18 * 2; // Subtract version information
528 | }
529 | return result;
530 | }
531 |
532 |
533 | int qrcodegen::QrCode::getNumDataCodewords(int ver, const Ecc &ecl) {
534 | if (ver < 1 || ver > 40)
535 | throw "Version number out of range";
536 | return getNumRawDataModules(ver) / 8 - NUM_ERROR_CORRECTION_CODEWORDS[ecl.ordinal][ver];
537 | }
538 |
539 |
540 | /*---- Tables of constants ----*/
541 |
542 | const int qrcodegen::QrCode::PENALTY_N1 = 3;
543 | const int qrcodegen::QrCode::PENALTY_N2 = 3;
544 | const int qrcodegen::QrCode::PENALTY_N3 = 40;
545 | const int qrcodegen::QrCode::PENALTY_N4 = 10;
546 |
547 |
548 | const int16_t qrcodegen::QrCode::NUM_ERROR_CORRECTION_CODEWORDS[4][41] = {
549 | // Version: (note that index 0 is for padding, and is set to an illegal value)
550 | //0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
551 | {-1, 7, 10, 15, 20, 26, 36, 40, 48, 60, 72, 80, 96, 104, 120, 132, 144, 168, 180, 196, 224, 224, 252, 270, 300, 312, 336, 360, 390, 420, 450, 480, 510, 540, 570, 570, 600, 630, 660, 720, 750}, // Low
552 | {-1, 10, 16, 26, 36, 48, 64, 72, 88, 110, 130, 150, 176, 198, 216, 240, 280, 308, 338, 364, 416, 442, 476, 504, 560, 588, 644, 700, 728, 784, 812, 868, 924, 980, 1036, 1064, 1120, 1204, 1260, 1316, 1372}, // Medium
553 | {-1, 13, 22, 36, 52, 72, 96, 108, 132, 160, 192, 224, 260, 288, 320, 360, 408, 448, 504, 546, 600, 644, 690, 750, 810, 870, 952, 1020, 1050, 1140, 1200, 1290, 1350, 1440, 1530, 1590, 1680, 1770, 1860, 1950, 2040}, // Quartile
554 | {-1, 17, 28, 44, 64, 88, 112, 130, 156, 192, 224, 264, 308, 352, 384, 432, 480, 532, 588, 650, 700, 750, 816, 900, 960, 1050, 1110, 1200, 1260, 1350, 1440, 1530, 1620, 1710, 1800, 1890, 1980, 2100, 2220, 2310, 2430}, // High
555 | };
556 |
557 | const int8_t qrcodegen::QrCode::NUM_ERROR_CORRECTION_BLOCKS[4][41] = {
558 | // Version: (note that index 0 is for padding, and is set to an illegal value)
559 | //0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40 Error correction level
560 | {-1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 4, 4, 4, 4, 4, 6, 6, 6, 6, 7, 8, 8, 9, 9, 10, 12, 12, 12, 13, 14, 15, 16, 17, 18, 19, 19, 20, 21, 22, 24, 25}, // Low
561 | {-1, 1, 1, 1, 2, 2, 4, 4, 4, 5, 5, 5, 8, 9, 9, 10, 10, 11, 13, 14, 16, 17, 17, 18, 20, 21, 23, 25, 26, 28, 29, 31, 33, 35, 37, 38, 40, 43, 45, 47, 49}, // Medium
562 | {-1, 1, 1, 2, 2, 4, 4, 6, 6, 8, 8, 8, 10, 12, 16, 12, 17, 16, 18, 21, 20, 23, 23, 25, 27, 29, 34, 34, 35, 38, 40, 43, 45, 48, 51, 53, 56, 59, 62, 65, 68}, // Quartile
563 | {-1, 1, 1, 2, 4, 4, 4, 5, 6, 8, 8, 11, 11, 16, 16, 18, 16, 19, 21, 25, 25, 25, 34, 30, 32, 35, 37, 40, 42, 45, 48, 51, 54, 57, 60, 63, 66, 70, 74, 77, 81}, // High
564 | };
565 |
566 |
567 | qrcodegen::QrCode::ReedSolomonGenerator::ReedSolomonGenerator(int degree) :
568 | coefficients() {
569 | if (degree < 1 || degree > 255)
570 | throw "Degree out of range";
571 |
572 | // Start with the monomial x^0
573 | coefficients.resize(degree);
574 | coefficients.at(degree - 1) = 1;
575 |
576 | // Compute the product polynomial (x - r^0) * (x - r^1) * (x - r^2) * ... * (x - r^{degree-1}),
577 | // drop the highest term, and store the rest of the coefficients in order of descending powers.
578 | // Note that r = 0x02, which is a generator element of this field GF(2^8/0x11D).
579 | int root = 1;
580 | for (int i = 0; i < degree; i++) {
581 | // Multiply the current product by (x - r^i)
582 | for (size_t j = 0; j < coefficients.size(); j++) {
583 | coefficients.at(j) = multiply(coefficients.at(j), static_cast(root));
584 | if (j + 1 < coefficients.size())
585 | coefficients.at(j) ^= coefficients.at(j + 1);
586 | }
587 | root = (root << 1) ^ ((root >> 7) * 0x11D); // Multiply by 0x02 mod GF(2^8/0x11D)
588 | }
589 | }
590 |
591 |
592 | std::vector qrcodegen::QrCode::ReedSolomonGenerator::getRemainder(const std::vector &data) const {
593 | // Compute the remainder by performing polynomial division
594 | std::vector result(coefficients.size());
595 | for (size_t i = 0; i < data.size(); i++) {
596 | uint8_t factor = data.at(i) ^ result.at(0);
597 | result.erase(result.begin());
598 | result.push_back(0);
599 | for (size_t j = 0; j < result.size(); j++)
600 | result.at(j) ^= multiply(coefficients.at(j), factor);
601 | }
602 | return result;
603 | }
604 |
605 |
606 | uint8_t qrcodegen::QrCode::ReedSolomonGenerator::multiply(uint8_t x, uint8_t y) {
607 | // Russian peasant multiplication
608 | int z = 0;
609 | for (int i = 7; i >= 0; i--) {
610 | z = (z << 1) ^ ((z >> 7) * 0x11D);
611 | z ^= ((y >> i) & 1) * x;
612 | }
613 | if (z >> 8 != 0)
614 | throw "Assertion error";
615 | return static_cast(z);
616 | }
617 |
--------------------------------------------------------------------------------
/tests/QrCode.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * QR Code generator library (C++)
3 | *
4 | * Copyright (c) Project Nayuki
5 | * https://www.nayuki.io/page/qr-code-generator-library
6 | *
7 | * (MIT License)
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | * - The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | * - The Software is provided "as is", without warranty of any kind, express or
17 | * implied, including but not limited to the warranties of merchantability,
18 | * fitness for a particular purpose and noninfringement. In no event shall the
19 | * authors or copyright holders be liable for any claim, damages or other
20 | * liability, whether in an action of contract, tort or otherwise, arising from,
21 | * out of or in connection with the Software or the use or other dealings in the
22 | * Software.
23 | */
24 |
25 | #pragma once
26 |
27 | #include
28 | #include
29 | #include
30 | #include "QrSegment.hpp"
31 |
32 |
33 | namespace qrcodegen {
34 |
35 | /*
36 | * Represents an immutable square grid of black and white cells for a QR Code symbol, and
37 | * provides static functions to create a QR Code from user-supplied textual or binary data.
38 | * This class covers the QR Code model 2 specification, supporting all versions (sizes)
39 | * from 1 to 40, all 4 error correction levels, and only 3 character encoding modes.
40 | */
41 | class QrCode {
42 |
43 | /*---- Public helper enumeration ----*/
44 | public:
45 |
46 | /*
47 | * Represents the error correction level used in a QR Code symbol.
48 | */
49 | class Ecc {
50 | // Constants declared in ascending order of error protection.
51 | public:
52 | const static Ecc LOW, MEDIUM, QUARTILE, HIGH;
53 |
54 | // Fields.
55 | public:
56 | const int ordinal; // (Public) In the range 0 to 3 (unsigned 2-bit integer).
57 | const int formatBits; // (Package-private) In the range 0 to 3 (unsigned 2-bit integer).
58 |
59 | // Constructor.
60 | private:
61 | Ecc(int ord, int fb);
62 | };
63 |
64 |
65 |
66 | /*---- Public static factory functions ----*/
67 | public:
68 |
69 | /*
70 | * Returns a QR Code symbol representing the given Unicode text string at the given error correction level.
71 | * As a conservative upper bound, this function is guaranteed to succeed for strings that have 738 or fewer Unicode
72 | * code points (not UTF-16 code units). The smallest possible QR Code version is automatically chosen for the output.
73 | * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
74 | */
75 | static QrCode encodeText(const char *text, int version, const Ecc &ecl);
76 |
77 |
78 | /*
79 | * Returns a QR Code symbol representing the given binary data string at the given error correction level.
80 | * This function always encodes using the binary segment mode, not any text mode. The maximum number of
81 | * bytes allowed is 2953. The smallest possible QR Code version is automatically chosen for the output.
82 | * The ECC level of the result may be higher than the ecl argument if it can be done without increasing the version.
83 | */
84 | static QrCode encodeBinary(const std::vector &data, const Ecc &ecl);
85 |
86 |
87 | /*
88 | * Returns a QR Code symbol representing the given data segments with the given encoding parameters.
89 | * The smallest possible QR Code version within the given range is automatically chosen for the output.
90 | * This function allows the user to create a custom sequence of segments that switches
91 | * between modes (such as alphanumeric and binary) to encode text more efficiently.
92 | * This function is considered to be lower level than simply encoding text or binary data.
93 | */
94 | static QrCode encodeSegments(const std::vector &segs, const Ecc &ecl,
95 | int minVersion=1, int maxVersion=40, int mask=-1, bool boostEcl=true); // All optional parameters
96 |
97 |
98 |
99 | /*---- Instance fields ----*/
100 |
101 | // Public immutable scalar parameters
102 | public:
103 |
104 | /* This QR Code symbol's version number, which is always between 1 and 40 (inclusive). */
105 | const int version;
106 |
107 | /* The width and height of this QR Code symbol, measured in modules.
108 | * Always equal to version × 4 + 17, in the range 21 to 177. */
109 | const int size;
110 |
111 | /* The error correction level used in this QR Code symbol. */
112 | const Ecc &errorCorrectionLevel;
113 |
114 | /* The mask pattern used in this QR Code symbol, in the range 0 to 7 (i.e. unsigned 3-bit integer).
115 | * Note that even if a constructor was called with automatic masking requested
116 | * (mask = -1), the resulting object will still have a mask value between 0 and 7. */
117 | private:
118 | int mask;
119 |
120 | // Private grids of modules/pixels (conceptually immutable)
121 | private:
122 | std::vector > modules; // The modules of this QR Code symbol (false = white, true = black)
123 | std::vector > isFunction; // Indicates function modules that are not subjected to masking
124 |
125 |
126 |
127 | /*---- Constructors ----*/
128 | public:
129 |
130 | /*
131 | * Creates a new QR Code symbol with the given version number, error correction level, binary data array,
132 | * and mask number. This is a cumbersome low-level constructor that should not be invoked directly by the user.
133 | * To go one level up, see the encodeSegments() function.
134 | */
135 | QrCode(int ver, const Ecc &ecl, const std::vector &dataCodewords, int mask);
136 |
137 |
138 | /*
139 | * Creates a new QR Code symbol based on the given existing object, but with a potentially
140 | * different mask pattern. The version, error correction level, codewords, etc. of the newly
141 | * created object are all identical to the argument object; only the mask may differ.
142 | */
143 | QrCode(const QrCode &qr, int mask);
144 |
145 |
146 |
147 | /*---- Public instance methods ----*/
148 | public:
149 |
150 | int getMask() const;
151 |
152 |
153 | /*
154 | * Returns the color of the module (pixel) at the given coordinates, which is either 0 for white or 1 for black. The top
155 | * left corner has the coordinates (x=0, y=0). If the given coordinates are out of bounds, then 0 (white) is returned.
156 | */
157 | int getModule(int x, int y) const;
158 |
159 |
160 | /*
161 | * Based on the given number of border modules to add as padding, this returns a
162 | * string whose contents represents an SVG XML file that depicts this QR Code symbol.
163 | * Note that Unix newlines (\n) are always used, regardless of the platform.
164 | */
165 | std::string toSvgString(int border) const;
166 |
167 |
168 |
169 | /*---- Private helper methods for constructor: Drawing function modules ----*/
170 | private:
171 |
172 | void drawFunctionPatterns();
173 |
174 |
175 | // Draws two copies of the format bits (with its own error correction code)
176 | // based on the given mask and this object's error correction level field.
177 | void drawFormatBits(int mask);
178 |
179 |
180 | // Draws two copies of the version bits (with its own error correction code),
181 | // based on this object's version field (which only has an effect for 7 <= version <= 40).
182 | void drawVersion();
183 |
184 |
185 | // Draws a 9*9 finder pattern including the border separator, with the center module at (x, y).
186 | void drawFinderPattern(int x, int y);
187 |
188 |
189 | // Draws a 5*5 alignment pattern, with the center module at (x, y).
190 | void drawAlignmentPattern(int x, int y);
191 |
192 |
193 | // Sets the color of a module and marks it as a function module.
194 | // Only used by the constructor. Coordinates must be in range.
195 | void setFunctionModule(int x, int y, bool isBlack);
196 |
197 |
198 | /*---- Private helper methods for constructor: Codewords and masking ----*/
199 | private:
200 |
201 | // Returns a new byte string representing the given data with the appropriate error correction
202 | // codewords appended to it, based on this object's version and error correction level.
203 | std::vector appendErrorCorrection(const std::vector &data) const;
204 |
205 |
206 | // Draws the given sequence of 8-bit codewords (data and error correction) onto the entire
207 | // data area of this QR Code symbol. Function modules need to be marked off before this is called.
208 | void drawCodewords(const std::vector &data);
209 |
210 |
211 | // XORs the data modules in this QR Code with the given mask pattern. Due to XOR's mathematical
212 | // properties, calling applyMask(m) twice with the same value is equivalent to no change at all.
213 | // This means it is possible to apply a mask, undo it, and try another mask. Note that a final
214 | // well-formed QR Code symbol needs exactly one mask applied (not zero, not two, etc.).
215 | void applyMask(int mask);
216 |
217 |
218 | // A messy helper function for the constructors. This QR Code must be in an unmasked state when this
219 | // method is called. The given argument is the requested mask, which is -1 for auto or 0 to 7 for fixed.
220 | // This method applies and returns the actual mask chosen, from 0 to 7.
221 | int handleConstructorMasking(int mask);
222 |
223 |
224 | // Calculates and returns the penalty score based on state of this QR Code's current modules.
225 | // This is used by the automatic mask choice algorithm to find the mask pattern that yields the lowest score.
226 | int getPenaltyScore() const;
227 |
228 |
229 |
230 | /*---- Private static helper functions ----*/
231 | private:
232 |
233 | // Returns a set of positions of the alignment patterns in ascending order. These positions are
234 | // used on both the x and y axes. Each value in the resulting array is in the range [0, 177).
235 | // This stateless pure function could be implemented as table of 40 variable-length lists of unsigned bytes.
236 | static std::vector getAlignmentPatternPositions(int ver);
237 |
238 |
239 | // Returns the number of raw data modules (bits) available at the given version number.
240 | // These data modules are used for both user data codewords and error correction codewords.
241 | // This stateless pure function could be implemented as a 40-entry lookup table.
242 | static int getNumRawDataModules(int ver);
243 |
244 |
245 | // Returns the number of 8-bit data (i.e. not error correction) codewords contained in any
246 | // QR Code of the given version number and error correction level, with remainder bits discarded.
247 | // This stateless pure function could be implemented as a (40*4)-cell lookup table.
248 | static int getNumDataCodewords(int ver, const Ecc &ecl);
249 |
250 |
251 | /*---- Private tables of constants ----*/
252 | private:
253 |
254 | // For use in getPenaltyScore(), when evaluating which mask is best.
255 | static const int PENALTY_N1;
256 | static const int PENALTY_N2;
257 | static const int PENALTY_N3;
258 | static const int PENALTY_N4;
259 |
260 | static const int16_t NUM_ERROR_CORRECTION_CODEWORDS[4][41];
261 | static const int8_t NUM_ERROR_CORRECTION_BLOCKS[4][41];
262 |
263 |
264 |
265 | /*---- Private helper class ----*/
266 | private:
267 |
268 | /*
269 | * Computes the Reed-Solomon error correction codewords for a sequence of data codewords
270 | * at a given degree. Objects are immutable, and the state only depends on the degree.
271 | * This class exists because the divisor polynomial does not need to be recalculated for every input.
272 | */
273 | class ReedSolomonGenerator {
274 |
275 | /*-- Immutable field --*/
276 | private:
277 |
278 | // Coefficients of the divisor polynomial, stored from highest to lowest power, excluding the leading term which
279 | // is always 1. For example the polynomial x^3 + 255x^2 + 8x + 93 is stored as the uint8 array {255, 8, 93}.
280 | std::vector coefficients;
281 |
282 |
283 | /*-- Constructor --*/
284 | public:
285 |
286 | /*
287 | * Creates a Reed-Solomon ECC generator for the given degree. This could be implemented
288 | * as a lookup table over all possible parameter values, instead of as an algorithm.
289 | */
290 | ReedSolomonGenerator(int degree);
291 |
292 |
293 | /*-- Method --*/
294 | public:
295 |
296 | /*
297 | * Computes and returns the Reed-Solomon error correction codewords for the given sequence of data codewords.
298 | * The returned object is always a new byte array. This method does not alter this object's state (because it is immutable).
299 | */
300 | std::vector getRemainder(const std::vector &data) const;
301 |
302 |
303 | /*-- Static function --*/
304 | private:
305 |
306 | // Returns the product of the two given field elements modulo GF(2^8/0x11D). The arguments and result
307 | // are unsigned 8-bit integers. This could be implemented as a lookup table of 256*256 entries of uint8.
308 | static uint8_t multiply(uint8_t x, uint8_t y);
309 |
310 | };
311 |
312 | };
313 |
314 | }
315 |
--------------------------------------------------------------------------------
/tests/QrSegment.cpp:
--------------------------------------------------------------------------------
1 | /*
2 | * QR Code generator library (C++)
3 | *
4 | * Copyright (c) Project Nayuki
5 | * https://www.nayuki.io/page/qr-code-generator-library
6 | *
7 | * (MIT License)
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | * - The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | * - The Software is provided "as is", without warranty of any kind, express or
17 | * implied, including but not limited to the warranties of merchantability,
18 | * fitness for a particular purpose and noninfringement. In no event shall the
19 | * authors or copyright holders be liable for any claim, damages or other
20 | * liability, whether in an action of contract, tort or otherwise, arising from,
21 | * out of or in connection with the Software or the use or other dealings in the
22 | * Software.
23 | */
24 |
25 | #include
26 | #include "BitBuffer.hpp"
27 | #include "QrSegment.hpp"
28 |
29 |
30 | qrcodegen::QrSegment::Mode::Mode(int mode, int cc0, int cc1, int cc2) :
31 | modeBits(mode) {
32 | numBitsCharCount[0] = cc0;
33 | numBitsCharCount[1] = cc1;
34 | numBitsCharCount[2] = cc2;
35 | }
36 |
37 |
38 | int qrcodegen::QrSegment::Mode::numCharCountBits(int ver) const {
39 | if ( 1 <= ver && ver <= 9) return numBitsCharCount[0];
40 | else if (10 <= ver && ver <= 26) return numBitsCharCount[1];
41 | else if (27 <= ver && ver <= 40) return numBitsCharCount[2];
42 | else throw "Version number out of range";
43 | }
44 |
45 |
46 | const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::NUMERIC (0x1, 10, 12, 14);
47 | const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::ALPHANUMERIC(0x2, 9, 11, 13);
48 | const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::BYTE (0x4, 8, 16, 16);
49 | const qrcodegen::QrSegment::Mode qrcodegen::QrSegment::Mode::KANJI (0x8, 8, 10, 12);
50 |
51 |
52 |
53 | qrcodegen::QrSegment qrcodegen::QrSegment::makeBytes(const std::vector &data) {
54 | return QrSegment(Mode::BYTE, data.size(), data, data.size() * 8);
55 | }
56 |
57 |
58 | qrcodegen::QrSegment qrcodegen::QrSegment::makeNumeric(const char *digits) {
59 | BitBuffer bb;
60 | int accumData = 0;
61 | int accumCount = 0;
62 | int charCount = 0;
63 | for (; *digits != '\0'; digits++, charCount++) {
64 | char c = *digits;
65 | if (c < '0' || c > '9')
66 | throw "String contains non-numeric characters";
67 | accumData = accumData * 10 + (c - '0');
68 | accumCount++;
69 | if (accumCount == 3) {
70 | bb.appendBits(accumData, 10);
71 | accumData = 0;
72 | accumCount = 0;
73 | }
74 | }
75 | if (accumCount > 0) // 1 or 2 digits remaining
76 | bb.appendBits(accumData, accumCount * 3 + 1);
77 | return QrSegment(Mode::NUMERIC, charCount, bb.getBytes(), bb.getBitLength());
78 | }
79 |
80 |
81 | qrcodegen::QrSegment qrcodegen::QrSegment::makeAlphanumeric(const char *text) {
82 | BitBuffer bb;
83 | int accumData = 0;
84 | int accumCount = 0;
85 | int charCount = 0;
86 | for (; *text != '\0'; text++, charCount++) {
87 | char c = *text;
88 | if (c < ' ' || c > 'Z')
89 | throw "String contains unencodable characters in alphanumeric mode";
90 | accumData = accumData * 45 + ALPHANUMERIC_ENCODING_TABLE[c - ' '];
91 | accumCount++;
92 | if (accumCount == 2) {
93 | bb.appendBits(accumData, 11);
94 | accumData = 0;
95 | accumCount = 0;
96 | }
97 | }
98 | if (accumCount > 0) // 1 character remaining
99 | bb.appendBits(accumData, 6);
100 | return QrSegment(Mode::ALPHANUMERIC, charCount, bb.getBytes(), bb.getBitLength());
101 | }
102 |
103 |
104 | std::vector qrcodegen::QrSegment::makeSegments(const char *text) {
105 | // Select the most efficient segment encoding automatically
106 | std::vector result;
107 | if (*text == '\0'); // Leave the vector empty
108 | else if (QrSegment::isNumeric(text))
109 | result.push_back(QrSegment::makeNumeric(text));
110 | else if (QrSegment::isAlphanumeric(text))
111 | result.push_back(QrSegment::makeAlphanumeric(text));
112 | else {
113 | std::vector bytes;
114 | for (; *text != '\0'; text++)
115 | bytes.push_back(static_cast(*text));
116 | result.push_back(QrSegment::makeBytes(bytes));
117 | }
118 | return result;
119 | }
120 |
121 |
122 | qrcodegen::QrSegment::QrSegment(const Mode &md, int numCh, const std::vector &b, int bitLen) :
123 | mode(md),
124 | numChars(numCh),
125 | data(b),
126 | bitLength(bitLen) {
127 | if (numCh < 0 || bitLen < 0 || b.size() != static_cast((bitLen + 7) / 8))
128 | throw "Invalid value";
129 | }
130 |
131 |
132 | int qrcodegen::QrSegment::getTotalBits(const std::vector &segs, int version) {
133 | if (version < 1 || version > 40)
134 | throw "Version number out of range";
135 | int result = 0;
136 | for (size_t i = 0; i < segs.size(); i++) {
137 | const QrSegment &seg(segs.at(i));
138 | int ccbits = seg.mode.numCharCountBits(version);
139 | // Fail if segment length value doesn't fit in the length field's bit-width
140 | if (seg.numChars >= (1 << ccbits))
141 | return -1;
142 | result += 4 + ccbits + seg.bitLength;
143 | }
144 | return result;
145 | }
146 |
147 |
148 | bool qrcodegen::QrSegment::isAlphanumeric(const char *text) {
149 | for (; *text != '\0'; text++) {
150 | char c = *text;
151 | if (c < ' ' || c > 'Z' || ALPHANUMERIC_ENCODING_TABLE[c - ' '] == -1)
152 | return false;
153 | }
154 | return true;
155 | }
156 |
157 |
158 | bool qrcodegen::QrSegment::isNumeric(const char *text) {
159 | for (; *text != '\0'; text++) {
160 | char c = *text;
161 | if (c < '0' || c > '9')
162 | return false;
163 | }
164 | return true;
165 | }
166 |
167 |
168 | const int8_t qrcodegen::QrSegment::ALPHANUMERIC_ENCODING_TABLE[59] = {
169 | // SP, !, ", #, $, %, &, ', (, ), *, +, ,, -, ., /, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, :, ;, <, =, >, ?, @, // ASCII codes 32 to 64
170 | 36, -1, -1, -1, 37, 38, -1, -1, -1, -1, 39, 40, -1, 41, 42, 43, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 44, -1, -1, -1, -1, -1, -1, // Array indices 0 to 32
171 | 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, // Array indices 33 to 58
172 | // A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U, V, W, X, Y, Z, // ASCII codes 65 to 90
173 | };
174 |
--------------------------------------------------------------------------------
/tests/QrSegment.hpp:
--------------------------------------------------------------------------------
1 | /*
2 | * QR Code generator library (C++)
3 | *
4 | * Copyright (c) Project Nayuki
5 | * https://www.nayuki.io/page/qr-code-generator-library
6 | *
7 | * (MIT License)
8 | * Permission is hereby granted, free of charge, to any person obtaining a copy of
9 | * this software and associated documentation files (the "Software"), to deal in
10 | * the Software without restriction, including without limitation the rights to
11 | * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
12 | * the Software, and to permit persons to whom the Software is furnished to do so,
13 | * subject to the following conditions:
14 | * - The above copyright notice and this permission notice shall be included in
15 | * all copies or substantial portions of the Software.
16 | * - The Software is provided "as is", without warranty of any kind, express or
17 | * implied, including but not limited to the warranties of merchantability,
18 | * fitness for a particular purpose and noninfringement. In no event shall the
19 | * authors or copyright holders be liable for any claim, damages or other
20 | * liability, whether in an action of contract, tort or otherwise, arising from,
21 | * out of or in connection with the Software or the use or other dealings in the
22 | * Software.
23 | */
24 |
25 | #pragma once
26 |
27 | #include
28 | #include
29 |
30 |
31 | namespace qrcodegen {
32 |
33 | /*
34 | * Represents a character string to be encoded in a QR Code symbol. Each segment has
35 | * a mode, and a sequence of characters that is already encoded as a sequence of bits.
36 | * Instances of this class are immutable.
37 | * This segment class imposes no length restrictions, but QR Codes have restrictions.
38 | * Even in the most favorable conditions, a QR Code can only hold 7089 characters of data.
39 | * Any segment longer than this is meaningless for the purpose of generating QR Codes.
40 | */
41 | class QrSegment {
42 |
43 | /*---- Public helper enumeration ----*/
44 |
45 | /*
46 | * The mode field of a segment. Immutable. Provides methods to retrieve closely related values.
47 | */
48 | public:
49 | class Mode {
50 |
51 | /*-- Constants --*/
52 | public:
53 |
54 | static const Mode NUMERIC;
55 | static const Mode ALPHANUMERIC;
56 | static const Mode BYTE;
57 | static const Mode KANJI;
58 |
59 |
60 | /*-- Fields --*/
61 |
62 | /* (Package-private) An unsigned 4-bit integer value (range 0 to 15) representing the mode indicator bits for this mode object. */
63 | public:
64 | const int modeBits;
65 |
66 | private:
67 | int numBitsCharCount[3];
68 |
69 |
70 | /*-- Constructor --*/
71 |
72 | private:
73 | Mode(int mode, int cc0, int cc1, int cc2);
74 |
75 |
76 | /*-- Method --*/
77 |
78 | /*
79 | * (Package-private) Returns the bit width of the segment character count field for this mode object at the given version number.
80 | */
81 | public:
82 | int numCharCountBits(int ver) const;
83 |
84 | };
85 |
86 |
87 |
88 | /*---- Public static factory functions ----*/
89 | public:
90 |
91 | /*
92 | * Returns a segment representing the given binary data encoded in byte mode.
93 | */
94 | static QrSegment makeBytes(const std::vector &data);
95 |
96 |
97 | /*
98 | * Returns a segment representing the given string of decimal digits encoded in numeric mode.
99 | */
100 | static QrSegment makeNumeric(const char *digits);
101 |
102 |
103 | /*
104 | * Returns a segment representing the given text string encoded in alphanumeric mode. The characters allowed are:
105 | * 0 to 9, A to Z (uppercase only), space, dollar, percent, asterisk, plus, hyphen, period, slash, colon.
106 | */
107 | static QrSegment makeAlphanumeric(const char *text);
108 |
109 |
110 | /*
111 | * Returns a list of zero or more segments to represent the given text string.
112 | * The result may use various segment modes and switch modes to optimize the length of the bit stream.
113 | */
114 | static std::vector makeSegments(const char *text);
115 |
116 |
117 | /*---- Public static helper functions ----*/
118 | public:
119 |
120 | /*
121 | * Tests whether the given string can be encoded as a segment in alphanumeric mode.
122 | */
123 | static bool isAlphanumeric(const char *text);
124 |
125 |
126 | /*
127 | * Tests whether the given string can be encoded as a segment in numeric mode.
128 | */
129 | static bool isNumeric(const char *text);
130 |
131 |
132 |
133 | /*---- Instance fields ----*/
134 | public:
135 |
136 | /* The mode indicator for this segment. */
137 | const Mode mode;
138 |
139 | /* The length of this segment's unencoded data, measured in characters. Always zero or positive. */
140 | const int numChars;
141 |
142 | /* The bits of this segment packed into a byte array in big endian. */
143 | const std::vector data;
144 |
145 | /* The length of this segment's encoded data, measured in bits. Satisfies ceil(bitLength / 8) = data.size(). */
146 | const int bitLength;
147 |
148 |
149 | /*---- Constructor ----*/
150 | public:
151 |
152 | /*
153 | * Creates a new QR Code data segment with the given parameters and data.
154 | */
155 | QrSegment(const Mode &md, int numCh, const std::vector &b, int bitLen);
156 |
157 |
158 | // Package-private helper function.
159 | static int getTotalBits(const std::vector &segs, int version);
160 |
161 |
162 | /*---- Private constant ----*/
163 | private:
164 |
165 | /* Maps shifted ASCII codes to alphanumeric mode character codes. */
166 | static const int8_t ALPHANUMERIC_ENCODING_TABLE[59];
167 |
168 | };
169 |
170 | }
171 |
--------------------------------------------------------------------------------
/tests/README.md:
--------------------------------------------------------------------------------
1 | Testing
2 | =======
3 |
4 | The testcases work by using the Nayuki QR code generating library, generating a QR code
5 | in both libraries and comparing them.
6 |
7 | Running
8 | -------
9 |
10 | ```
11 | ./run.sh
12 | ```
13 |
--------------------------------------------------------------------------------
/tests/run-tests.cpp:
--------------------------------------------------------------------------------
1 | #include
2 | #include
3 |
4 | #include "../src/qrcode.h"
5 | #include "QrCode.hpp"
6 |
7 | static uint32_t check(const qrcodegen::QrCode &nayuki, QRCode *ricmoo) {
8 | uint32_t wrong = 0;
9 |
10 | if (nayuki.size != ricmoo->size) { wrong += (1 << 20); }
11 |
12 | int border = 4;
13 | for (int y = -border; y < nayuki.size + border; y++) {
14 | for (int x = -border; x < nayuki.size + border; x++) {
15 | if (!!nayuki.getModule(x, y) != qrcode_getModule(ricmoo, x, y)) {
16 | wrong++;
17 | }
18 | }
19 | }
20 |
21 | return wrong;
22 | }
23 |
24 | int main() {
25 | std::clock_t t0, totalNayuki, totalRicMoo;
26 |
27 | int total = 0, passed = 0;
28 | for (char version = 1; version <= 40; version++) {
29 | if (LOCK_VERSION != 0 && LOCK_VERSION != version) { continue; }
30 |
31 | for (char ecc = 0; ecc < 4; ecc++) {
32 | const qrcodegen::QrCode::Ecc *errCorLvl;
33 | switch (ecc) {
34 | case 0:
35 | errCorLvl = &qrcodegen::QrCode::Ecc::LOW;
36 | break;
37 | case 1:
38 | errCorLvl = &qrcodegen::QrCode::Ecc::MEDIUM;
39 | break;
40 | case 2:
41 | errCorLvl = &qrcodegen::QrCode::Ecc::QUARTILE;
42 | break;
43 | case 3:
44 | errCorLvl = &qrcodegen::QrCode::Ecc::HIGH;
45 | break;
46 | }
47 |
48 | for (char tc = 0; tc < 3; tc++) {
49 | char *data;
50 | switch(tc) {
51 | case 0:
52 | data = (char*)"HELLO";
53 | break;
54 | case 1:
55 | data = (char*)"Hello";
56 | break;
57 | case 2:
58 | data = (char*)"1234";
59 | break;
60 | }
61 | t0 = std::clock();
62 | const qrcodegen::QrCode nayuki = qrcodegen::QrCode::encodeText(data, version, *errCorLvl);
63 | totalNayuki += std::clock() - t0;
64 |
65 | t0 = std::clock();
66 | QRCode ricmoo;
67 | uint8_t ricmooBytes[qrcode_getBufferSize(version)];
68 | qrcode_initText(&ricmoo, ricmooBytes, version, ecc, data);
69 | totalRicMoo += std::clock() - t0;
70 |
71 | uint32_t badModules = check(nayuki, &ricmoo);
72 | if (badModules) {
73 | printf("Failed test case: version=%d, ecc=%d, data=\"%s\", faliured=%d\n", version, ecc, data, badModules);
74 | } else {
75 | passed++;
76 | }
77 |
78 | total++;
79 | }
80 | }
81 | }
82 |
83 | printf("Tests complete: %d passed (out of %d)\n", passed, total);
84 | printf("Timing: Nayuki=%lu, RicMoo=%lu\n", totalNayuki, totalRicMoo);
85 | }
86 |
--------------------------------------------------------------------------------
/tests/run.sh:
--------------------------------------------------------------------------------
1 | #!/bin/bash
2 |
3 | clang++ run-tests.cpp QrCode.cpp QrSegment.cpp BitBuffer.cpp ../src/qrcode.c -o test && ./test
4 | clang++ run-tests.cpp QrCode.cpp QrSegment.cpp BitBuffer.cpp ../src/qrcode.c -o test -D LOCK_VERSION=3 && ./test
5 |
6 |
--------------------------------------------------------------------------------