• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * QR Code generator demo (C)
3  *
4  * Run this command-line program with no arguments. The program
5  * computes a demonstration QR Codes and print it to the console.
6  *
7  * Copyright (c) Project Nayuki. (MIT License)
8  * https://www.nayuki.io/page/qr-code-generator-library
9  *
10  * Permission is hereby granted, free of charge, to any person obtaining a copy of
11  * this software and associated documentation files (the "Software"), to deal in
12  * the Software without restriction, including without limitation the rights to
13  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
14  * the Software, and to permit persons to whom the Software is furnished to do so,
15  * subject to the following conditions:
16  * - The above copyright notice and this permission notice shall be included in
17  *   all copies or substantial portions of the Software.
18  * - The Software is provided "as is", without warranty of any kind, express or
19  *   implied, including but not limited to the warranties of merchantability,
20  *   fitness for a particular purpose and noninfringement. In no event shall the
21  *   authors or copyright holders be liable for any claim, damages or other
22  *   liability, whether in an action of contract, tort or otherwise, arising from,
23  *   out of or in connection with the Software or the use or other dealings in the
24  *   Software.
25  */
26 
27 #include <stdbool.h>
28 #include <stddef.h>
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include <string.h>
32 #include "qrcodegen.h"
33 
34 
35 // Function prototypes
36 static void doBasicDemo(void);
37 static void doVarietyDemo(void);
38 static void doSegmentDemo(void);
39 static void doMaskDemo(void);
40 static void printQr(const uint8_t qrcode[]);
41 
42 
43 // The main application program.
main(void)44 int main(void) {
45 	doBasicDemo();
46 	doVarietyDemo();
47 	doSegmentDemo();
48 	doMaskDemo();
49 	return EXIT_SUCCESS;
50 }
51 
52 
53 
54 /*---- Demo suite ----*/
55 
56 // Creates a single QR Code, then prints it to the console.
doBasicDemo(void)57 static void doBasicDemo(void) {
58 	const char *text = "Hello, world!";                // User-supplied text
59 	enum qrcodegen_Ecc errCorLvl = qrcodegen_Ecc_LOW;  // Error correction level
60 
61 	// Make and print the QR Code symbol
62 	uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
63 	uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
64 	bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode, errCorLvl,
65 		qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
66 	if (ok)
67 		printQr(qrcode);
68 }
69 
70 
71 // Creates a variety of QR Codes that exercise different features of the library, and prints each one to the console.
doVarietyDemo(void)72 static void doVarietyDemo(void) {
73 	{  // Numeric mode encoding (3.33 bits per digit)
74 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
75 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
76 		bool ok = qrcodegen_encodeText("314159265358979323846264338327950288419716939937510", tempBuffer, qrcode,
77 			qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
78 		if (ok)
79 			printQr(qrcode);
80 	}
81 
82 	{  // Alphanumeric mode encoding (5.5 bits per character)
83 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
84 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
85 		bool ok = qrcodegen_encodeText("DOLLAR-AMOUNT:$39.87 PERCENTAGE:100.00% OPERATIONS:+-*/", tempBuffer, qrcode,
86 			qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
87 		if (ok)
88 			printQr(qrcode);
89 	}
90 
91 	{  // Unicode text as UTF-8
92 		const char *text = "\xE3\x81\x93\xE3\x82\x93\xE3\x81\xAB\xE3\x81\xA1wa\xE3\x80\x81"
93 			"\xE4\xB8\x96\xE7\x95\x8C\xEF\xBC\x81\x20\xCE\xB1\xCE\xB2\xCE\xB3\xCE\xB4";
94 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
95 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
96 		bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
97 			qrcodegen_Ecc_QUARTILE, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
98 		if (ok)
99 			printQr(qrcode);
100 	}
101 
102 	{  // Moderately large QR Code using longer text (from Lewis Carroll's Alice in Wonderland)
103 		const char *text =
104 			"Alice was beginning to get very tired of sitting by her sister on the bank, "
105 			"and of having nothing to do: once or twice she had peeped into the book her sister was reading, "
106 			"but it had no pictures or conversations in it, 'and what is the use of a book,' thought Alice "
107 			"'without pictures or conversations?' So she was considering in her own mind (as well as she could, "
108 			"for the hot day made her feel very sleepy and stupid), whether the pleasure of making a "
109 			"daisy-chain would be worth the trouble of getting up and picking the daisies, when suddenly "
110 			"a White Rabbit with pink eyes ran close by her.";
111 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
112 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
113 		bool ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
114 			qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
115 		if (ok)
116 			printQr(qrcode);
117 	}
118 }
119 
120 
121 // Creates QR Codes with manually specified segments for better compactness.
doSegmentDemo(void)122 static void doSegmentDemo(void) {
123 	{  // Illustration "silver"
124 		const char *silver0 = "THE SQUARE ROOT OF 2 IS 1.";
125 		const char *silver1 = "41421356237309504880168872420969807856967187537694807317667973799";
126 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
127 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
128 		bool ok;
129 		{
130 			char *concat = calloc(strlen(silver0) + strlen(silver1) + 1, sizeof(char));
131 			if (concat == NULL) {
132 				perror("calloc");
133 				exit(EXIT_FAILURE);
134 			}
135 			strcat(concat, silver0);
136 			strcat(concat, silver1);
137 			ok = qrcodegen_encodeText(concat, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
138 				qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
139 			if (ok)
140 				printQr(qrcode);
141 			free(concat);
142 		}
143 		{
144 			uint8_t *segBuf0 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, strlen(silver0)) * sizeof(uint8_t));
145 			uint8_t *segBuf1 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, strlen(silver1)) * sizeof(uint8_t));
146 			if (segBuf0 == NULL || segBuf1 == NULL) {
147 				perror("malloc");
148 				exit(EXIT_FAILURE);
149 			}
150 			struct qrcodegen_Segment segs[] = {
151 				qrcodegen_makeAlphanumeric(silver0, segBuf0),
152 				qrcodegen_makeNumeric(silver1, segBuf1),
153 			};
154 			ok = qrcodegen_encodeSegments(segs, sizeof(segs) / sizeof(segs[0]), qrcodegen_Ecc_LOW, tempBuffer, qrcode);
155 			free(segBuf0);
156 			free(segBuf1);
157 			if (ok)
158 				printQr(qrcode);
159 		}
160 	}
161 
162 	{  // Illustration "golden"
163 		const char *golden0 = "Golden ratio \xCF\x86 = 1.";
164 		const char *golden1 = "6180339887498948482045868343656381177203091798057628621354486227052604628189024497072072041893911374";
165 		const char *golden2 = "......";
166 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
167 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
168 		bool ok;
169 		{
170 			char *concat = calloc(strlen(golden0) + strlen(golden1) + strlen(golden2) + 1, sizeof(char));
171 			if (concat == NULL) {
172 				perror("calloc");
173 				exit(EXIT_FAILURE);
174 			}
175 			strcat(concat, golden0);
176 			strcat(concat, golden1);
177 			strcat(concat, golden2);
178 			ok = qrcodegen_encodeText(concat, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
179 				qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
180 			if (ok)
181 				printQr(qrcode);
182 			free(concat);
183 		}
184 		{
185 			uint8_t *bytes = malloc(strlen(golden0) * sizeof(uint8_t));
186 			if (bytes == NULL) {
187 				perror("malloc");
188 				exit(EXIT_FAILURE);
189 			}
190 			for (size_t i = 0, len = strlen(golden0); i < len; i++)
191 				bytes[i] = (uint8_t)golden0[i];
192 			uint8_t *segBuf0 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_BYTE, strlen(golden0)) * sizeof(uint8_t));
193 			uint8_t *segBuf1 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_NUMERIC, strlen(golden1)) * sizeof(uint8_t));
194 			uint8_t *segBuf2 = malloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_ALPHANUMERIC, strlen(golden2)) * sizeof(uint8_t));
195 			if (segBuf0 == NULL || segBuf1 == NULL || segBuf2 == NULL) {
196 				perror("malloc");
197 				exit(EXIT_FAILURE);
198 			}
199 			struct qrcodegen_Segment segs[] = {
200 				qrcodegen_makeBytes(bytes, strlen(golden0), segBuf0),
201 				qrcodegen_makeNumeric(golden1, segBuf1),
202 				qrcodegen_makeAlphanumeric(golden2, segBuf2),
203 			};
204 			free(bytes);
205 			ok = qrcodegen_encodeSegments(segs, sizeof(segs) / sizeof(segs[0]), qrcodegen_Ecc_LOW, tempBuffer, qrcode);
206 			free(segBuf0);
207 			free(segBuf1);
208 			free(segBuf2);
209 			if (ok)
210 				printQr(qrcode);
211 		}
212 	}
213 
214 	{  // Illustration "Madoka": kanji, kana, Cyrillic, full-width Latin, Greek characters
215 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
216 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
217 		bool ok;
218 		{
219 			const char *madoka =  // Encoded in UTF-8
220 				"\xE3\x80\x8C\xE9\xAD\x94\xE6\xB3\x95\xE5"
221 				"\xB0\x91\xE5\xA5\xB3\xE3\x81\xBE\xE3\x81"
222 				"\xA9\xE3\x81\x8B\xE2\x98\x86\xE3\x83\x9E"
223 				"\xE3\x82\xAE\xE3\x82\xAB\xE3\x80\x8D\xE3"
224 				"\x81\xA3\xE3\x81\xA6\xE3\x80\x81\xE3\x80"
225 				"\x80\xD0\x98\xD0\x90\xD0\x98\xE3\x80\x80"
226 				"\xEF\xBD\x84\xEF\xBD\x85\xEF\xBD\x93\xEF"
227 				"\xBD\x95\xE3\x80\x80\xCE\xBA\xCE\xB1\xEF"
228 				"\xBC\x9F";
229 			ok = qrcodegen_encodeText(madoka, tempBuffer, qrcode, qrcodegen_Ecc_LOW,
230 				qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
231 			if (ok)
232 				printQr(qrcode);
233 		}
234 		{
235 			const int kanjiChars[] = {  // Kanji mode encoding (13 bits per character)
236 				0x0035, 0x1002, 0x0FC0, 0x0AED, 0x0AD7,
237 				0x015C, 0x0147, 0x0129, 0x0059, 0x01BD,
238 				0x018D, 0x018A, 0x0036, 0x0141, 0x0144,
239 				0x0001, 0x0000, 0x0249, 0x0240, 0x0249,
240 				0x0000, 0x0104, 0x0105, 0x0113, 0x0115,
241 				0x0000, 0x0208, 0x01FF, 0x0008,
242 			};
243 			size_t len = sizeof(kanjiChars) / sizeof(kanjiChars[0]);
244 			uint8_t *segBuf = calloc(qrcodegen_calcSegmentBufferSize(qrcodegen_Mode_KANJI, len), sizeof(uint8_t));
245 			if (segBuf == NULL) {
246 				perror("calloc");
247 				exit(EXIT_FAILURE);
248 			}
249 			struct qrcodegen_Segment seg;
250 			seg.mode = qrcodegen_Mode_KANJI;
251 			seg.numChars = (int)len;
252 			seg.bitLength = 0;
253 			for (size_t i = 0; i < len; i++) {
254 				for (int j = 12; j >= 0; j--, seg.bitLength++)
255 					segBuf[seg.bitLength >> 3] |= ((kanjiChars[i] >> j) & 1) << (7 - (seg.bitLength & 7));
256 			}
257 			seg.data = segBuf;
258 			ok = qrcodegen_encodeSegments(&seg, 1, qrcodegen_Ecc_LOW, tempBuffer, qrcode);
259 			free(segBuf);
260 			if (ok)
261 				printQr(qrcode);
262 		}
263 	}
264 }
265 
266 
267 // Creates QR Codes with the same size and contents but different mask patterns.
doMaskDemo(void)268 static void doMaskDemo(void) {
269 	{  // Project Nayuki URL
270 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
271 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
272 		bool ok;
273 
274 		ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
275 			qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_AUTO, true);
276 		if (ok)
277 			printQr(qrcode);
278 
279 		ok = qrcodegen_encodeText("https://www.nayuki.io/", tempBuffer, qrcode,
280 			qrcodegen_Ecc_HIGH, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_3, true);
281 		if (ok)
282 			printQr(qrcode);
283 	}
284 
285 	{  // Chinese text as UTF-8
286 		const char *text =
287 			"\xE7\xB6\xAD\xE5\x9F\xBA\xE7\x99\xBE\xE7\xA7\x91\xEF\xBC\x88\x57\x69\x6B\x69\x70"
288 			"\x65\x64\x69\x61\xEF\xBC\x8C\xE8\x81\x86\xE8\x81\xBD\x69\x2F\xCB\x8C\x77\xC9\xAA"
289 			"\x6B\xE1\xB5\xBB\xCB\x88\x70\x69\xCB\x90\x64\x69\x2E\xC9\x99\x2F\xEF\xBC\x89\xE6"
290 			"\x98\xAF\xE4\xB8\x80\xE5\x80\x8B\xE8\x87\xAA\xE7\x94\xB1\xE5\x85\xA7\xE5\xAE\xB9"
291 			"\xE3\x80\x81\xE5\x85\xAC\xE9\x96\x8B\xE7\xB7\xA8\xE8\xBC\xAF\xE4\xB8\x94\xE5\xA4"
292 			"\x9A\xE8\xAA\x9E\xE8\xA8\x80\xE7\x9A\x84\xE7\xB6\xB2\xE8\xB7\xAF\xE7\x99\xBE\xE7"
293 			"\xA7\x91\xE5\x85\xA8\xE6\x9B\xB8\xE5\x8D\x94\xE4\xBD\x9C\xE8\xA8\x88\xE7\x95\xAB";
294 		uint8_t qrcode[qrcodegen_BUFFER_LEN_MAX];
295 		uint8_t tempBuffer[qrcodegen_BUFFER_LEN_MAX];
296 		bool ok;
297 
298 		ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
299 			qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_0, true);
300 		if (ok)
301 			printQr(qrcode);
302 
303 		ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
304 			qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_1, true);
305 		if (ok)
306 			printQr(qrcode);
307 
308 		ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
309 			qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_5, true);
310 		if (ok)
311 			printQr(qrcode);
312 
313 		ok = qrcodegen_encodeText(text, tempBuffer, qrcode,
314 			qrcodegen_Ecc_MEDIUM, qrcodegen_VERSION_MIN, qrcodegen_VERSION_MAX, qrcodegen_Mask_7, true);
315 		if (ok)
316 			printQr(qrcode);
317 	}
318 }
319 
320 
321 
322 /*---- Utilities ----*/
323 
324 // Prints the given QR Code to the console.
printQr(const uint8_t qrcode[])325 static void printQr(const uint8_t qrcode[]) {
326 	int size = qrcodegen_getSize(qrcode);
327 	int border = 4;
328 	for (int y = -border; y < size + border; y++) {
329 		for (int x = -border; x < size + border; x++) {
330 			fputs((qrcodegen_getModule(qrcode, x, y) ? "##" : "  "), stdout);
331 		}
332 		fputs("\n", stdout);
333 	}
334 	fputs("\n", stdout);
335 }
336