blob: ba6446ca5834f79998a71e054b39d56a7dc64387 [file] [log] [blame]
Nicolas Jager95c526b2016-10-20 09:47:03 -04001/**
2 * qrencode - QR Code encoder
3 *
4 * QR Code encoding tool
5 * Copyright (C) 2006-2013 Kentaro Fukuchi <kentaro@fukuchi.org>
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22#if HAVE_CONFIG_H
23# include "config.h"
24#endif
25#include <stdio.h>
26#include <stdlib.h>
27#include <string.h>
28#include <png.h>
29#include <getopt.h>
30#include <fcntl.h>
31#include <io.h>
32
33#include "qrencode.h"
34
35#define INCHES_PER_METER (100.0/2.54)
36
37static int casesensitive = 1;
38static int eightbit = 0;
39static int version = 0;
40static int size = 3;
41static int margin = -1;
42static int dpi = 72;
43static int structured = 0;
44static int rle = 0;
45static int micro = 0;
46static QRecLevel level = QR_ECLEVEL_L;
47static QRencodeMode hint = QR_MODE_8;
48static unsigned int fg_color[4] = {0, 0, 0, 255};
49static unsigned int bg_color[4] = {255, 255, 255, 255};
50
51static int verbose = 0;
52
53enum imageType {
54 PNG_TYPE,
55 EPS_TYPE,
56 SVG_TYPE,
57 ANSI_TYPE,
58 ANSI256_TYPE,
59 ASCII_TYPE,
60 ASCIIi_TYPE,
61 UTF8_TYPE,
62 ANSIUTF8_TYPE
63};
64
65static enum imageType image_type = PNG_TYPE;
66
67static const struct option options[] = {
68 {"help" , no_argument , NULL, 'h'},
69 {"output" , required_argument, NULL, 'o'},
70 {"level" , required_argument, NULL, 'l'},
71 {"size" , required_argument, NULL, 's'},
72 {"symversion" , required_argument, NULL, 'v'},
73 {"margin" , required_argument, NULL, 'm'},
74 {"dpi" , required_argument, NULL, 'd'},
75 {"type" , required_argument, NULL, 't'},
76 {"structured" , no_argument , NULL, 'S'},
77 {"kanji" , no_argument , NULL, 'k'},
78 {"casesensitive", no_argument , NULL, 'c'},
79 {"ignorecase" , no_argument , NULL, 'i'},
80 {"8bit" , no_argument , NULL, '8'},
81 {"rle" , no_argument , &rle, 1},
82 {"micro" , no_argument , NULL, 'M'},
83 {"foreground" , required_argument, NULL, 'f'},
84 {"background" , required_argument, NULL, 'b'},
85 {"version" , no_argument , NULL, 'V'},
86 {"verbose" , no_argument , &verbose, 1},
87 {NULL, 0, NULL, 0}
88};
89
90static char *optstring = "ho:l:s:v:m:d:t:Skci8MV";
91
92static void usage(int help, int longopt)
93{
94 fprintf(stderr,
95"qrencode version %s\n"
96"Copyright (C) 2006-2012 Kentaro Fukuchi\n", QRcode_APIVersionString());
97 if(help) {
98 if(longopt) {
99 fprintf(stderr,
100"Usage: qrencode [OPTION]... [STRING]\n"
101"Encode input data in a QR Code and save as a PNG or EPS image.\n\n"
102" -h, --help display the help message. -h displays only the help of short\n"
103" options.\n\n"
104" -o FILENAME, --output=FILENAME\n"
105" write image to FILENAME. If '-' is specified, the result\n"
106" will be output to standard output. If -S is given, structured\n"
107" symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n"
108" (suffix is removed from FILENAME, if specified)\n"
109" -s NUMBER, --size=NUMBER\n"
110" specify module size in dots (pixels). (default=3)\n\n"
111" -l {LMQH}, --level={LMQH}\n"
112" specify error correction level from L (lowest) to H (highest).\n"
113" (default=L)\n\n"
114" -v NUMBER, --symversion=NUMBER\n"
115" specify the version of the symbol. See SYMBOL VERSIONS for more\n"
116" information. (default=auto)\n\n"
117" -m NUMBER, --margin=NUMBER\n"
118" specify the width of the margins. (default=4 (2 for Micro QR)))\n\n"
119" -d NUMBER, --dpi=NUMBER\n"
120" specify the DPI of the generated PNG. (default=72)\n\n"
121" -t {PNG,EPS,SVG,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8}, --type={PNG,EPS,\n"
122" SVG,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8}\n"
123" specify the type of the generated image. (default=PNG)\n\n"
124" -S, --structured\n"
125" make structured symbols. Version must be specified.\n\n"
126" -k, --kanji assume that the input text contains kanji (shift-jis).\n\n"
127" -c, --casesensitive\n"
128" encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
129" -i, --ignorecase\n"
130" ignore case distinctions and use only upper-case characters.\n\n"
131" -8, --8bit encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
132" --rle enable run-length encoding for SVG.\n\n"
133" -M, --micro encode in a Micro QR Code. (experimental)\n\n"
134" --foreground=RRGGBB[AA]\n"
135" --background=RRGGBB[AA]\n"
136" specify foreground/background color in hexadecimal notation.\n"
137" 6-digit (RGB) or 8-digit (RGBA) form are supported.\n"
138" Color output support available only in PNG and SVG.\n"
139" -V, --version\n"
140" display the version number and copyrights of the qrencode.\n\n"
141" --verbose\n"
142" display verbose information to stderr.\n\n"
143" [STRING] input data. If it is not specified, data will be taken from\n"
144" standard input.\n\n"
145"*SYMBOL VERSIONS\n"
146" The symbol versions of QR Code range from Version 1 to Version\n"
147" 40. Each version has a different module configuration or number\n"
148" of modules, ranging from Version 1 (21 x 21 modules) up to\n"
149" Version 40 (177 x 177 modules). Each higher version number\n"
150" comprises 4 additional modules per side by default. See\n"
151" http://www.qrcode.com/en/about/version.html for a detailed\n"
152" version list.\n"
153
154 );
155 } else {
156 fprintf(stderr,
157"Usage: qrencode [OPTION]... [STRING]\n"
158"Encode input data in a QR Code and save as a PNG or EPS image.\n\n"
159" -h display this message.\n"
160" --help display the usage of long options.\n"
161" -o FILENAME write image to FILENAME. If '-' is specified, the result\n"
162" will be output to standard output. If -S is given, structured\n"
163" symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n"
164" (suffix is removed from FILENAME, if specified)\n"
165" -s NUMBER specify module size in dots (pixels). (default=3)\n"
166" -l {LMQH} specify error correction level from L (lowest) to H (highest).\n"
167" (default=L)\n"
168" -v NUMBER specify the version of the symbol. (default=auto)\n"
169" -m NUMBER specify the width of the margins. (default=4 (2 for Micro))\n"
170" -d NUMBER specify the DPI of the generated PNG. (default=72)\n"
171" -t {PNG,EPS,SVG,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8}\n"
172" specify the type of the generated image. (default=PNG)\n"
173" -S make structured symbols. Version must be specified.\n"
174" -k assume that the input text contains kanji (shift-jis).\n"
175" -c encode lower-case alphabet characters in 8-bit mode. (default)\n"
176" -i ignore case distinctions and use only upper-case characters.\n"
177" -8 encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
178" -M encode in a Micro QR Code.\n"
179" --foreground=RRGGBB[AA]\n"
180" --background=RRGGBB[AA]\n"
181" specify foreground/background color in hexadecimal notation.\n"
182" 6-digit (RGB) or 8-digit (RGBA) form are supported.\n"
183" Color output support available only in PNG and SVG.\n"
184" -V display the version number and copyrights of the qrencode.\n"
185" [STRING] input data. If it is not specified, data will be taken from\n"
186" standard input.\n"
187 );
188 }
189 }
190}
191
192static int color_set(unsigned int color[4], const char *value)
193{
194 int len = strlen(value);
195 int count;
196 if(len == 6) {
197 count = sscanf(value, "%02x%02x%02x%n", &color[0], &color[1], &color[2], &len);
198 if(count < 3 || len != 6) {
199 return -1;
200 }
201 color[3] = 255;
202 } else if(len == 8) {
203 count = sscanf(value, "%02x%02x%02x%02x%n", &color[0], &color[1], &color[2], &color[3], &len);
204 if(count < 4 || len != 8) {
205 return -1;
206 }
207 } else {
208 return -1;
209 }
210 return 0;
211}
212
213#define MAX_DATA_SIZE (7090 * 16) /* from the specification */
214static unsigned char *readStdin(int *length)
215{
216 unsigned char *buffer;
217 int ret;
218
219 buffer = (unsigned char *)malloc(MAX_DATA_SIZE + 1);
220 if(buffer == NULL) {
221 fprintf(stderr, "Memory allocation failed.\n");
222 exit(EXIT_FAILURE);
223 }
224 ret = fread(buffer, 1, MAX_DATA_SIZE, stdin);
225 if(ret == 0) {
226 fprintf(stderr, "No input data.\n");
227 exit(EXIT_FAILURE);
228 }
229 if(feof(stdin) == 0) {
230 fprintf(stderr, "Input data is too large.\n");
231 exit(EXIT_FAILURE);
232 }
233
234 buffer[ret] = '\0';
235 *length = ret;
236
237 return buffer;
238}
239
240static FILE *openFile(const char *outfile)
241{
242 FILE *fp;
243
244 if(outfile == NULL || (outfile[0] == '-' && outfile[1] == '\0')) {
245 fp = stdout;
246 _setmode(_fileno(stdout), O_BINARY);
247 } else {
248 fp = fopen(outfile, "wb");
249 if(fp == NULL) {
250 fprintf(stderr, "Failed to create file: %s\n", outfile);
251 perror(NULL);
252 exit(EXIT_FAILURE);
253 }
254 }
255
256 return fp;
257}
258
259static int writePNG(QRcode *qrcode, const char *outfile)
260{
261 static FILE *fp; // avoid clobbering by setjmp.
262 png_structp png_ptr;
263 png_infop info_ptr;
264 png_colorp palette;
265 png_byte alpha_values[2];
266 unsigned char *row, *p, *q;
267 int x, y, xx, yy, bit;
268 int realwidth;
269
270 realwidth = (qrcode->width + margin * 2) * size;
271 row = (unsigned char *)malloc((realwidth + 7) / 8);
272 if(row == NULL) {
273 fprintf(stderr, "Failed to allocate memory.\n");
274 exit(EXIT_FAILURE);
275 }
276
277 if(outfile[0] == '-' && outfile[1] == '\0') {
278 fp = stdout;
279 _setmode(_fileno(stdout), O_BINARY);
280 } else {
281 fp = fopen(outfile, "wb");
282 if(fp == NULL) {
283 fprintf(stderr, "Failed to create file: %s\n", outfile);
284 perror(NULL);
285 exit(EXIT_FAILURE);
286 }
287 }
288
289 png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
290 if(png_ptr == NULL) {
291 fprintf(stderr, "Failed to initialize PNG writer.\n");
292 exit(EXIT_FAILURE);
293 }
294
295 info_ptr = png_create_info_struct(png_ptr);
296 if(info_ptr == NULL) {
297 fprintf(stderr, "Failed to initialize PNG write.\n");
298 exit(EXIT_FAILURE);
299 }
300
301 if(setjmp(png_jmpbuf(png_ptr))) {
302 png_destroy_write_struct(&png_ptr, &info_ptr);
303 fprintf(stderr, "Failed to write PNG image.\n");
304 exit(EXIT_FAILURE);
305 }
306
307 palette = (png_colorp) malloc(sizeof(png_color) * 2);
308 if(palette == NULL) {
309 fprintf(stderr, "Failed to allocate memory.\n");
310 exit(EXIT_FAILURE);
311 }
312 palette[0].red = fg_color[0];
313 palette[0].green = fg_color[1];
314 palette[0].blue = fg_color[2];
315 palette[1].red = bg_color[0];
316 palette[1].green = bg_color[1];
317 palette[1].blue = bg_color[2];
318 alpha_values[0] = fg_color[3];
319 alpha_values[1] = bg_color[3];
320 png_set_PLTE(png_ptr, info_ptr, palette, 2);
321 png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL);
322
323 png_init_io(png_ptr, fp);
324 png_set_IHDR(png_ptr, info_ptr,
325 realwidth, realwidth,
326 1,
327 PNG_COLOR_TYPE_PALETTE,
328 PNG_INTERLACE_NONE,
329 PNG_COMPRESSION_TYPE_DEFAULT,
330 PNG_FILTER_TYPE_DEFAULT);
331 png_set_pHYs(png_ptr, info_ptr,
332 dpi * INCHES_PER_METER,
333 dpi * INCHES_PER_METER,
334 PNG_RESOLUTION_METER);
335 png_write_info(png_ptr, info_ptr);
336
337 /* top margin */
338 memset(row, 0xff, (realwidth + 7) / 8);
339 for(y=0; y<margin * size; y++) {
340 png_write_row(png_ptr, row);
341 }
342
343 /* data */
344 p = qrcode->data;
345 for(y=0; y<qrcode->width; y++) {
346 bit = 7;
347 memset(row, 0xff, (realwidth + 7) / 8);
348 q = row;
349 q += margin * size / 8;
350 bit = 7 - (margin * size % 8);
351 for(x=0; x<qrcode->width; x++) {
352 for(xx=0; xx<size; xx++) {
353 *q ^= (*p & 1) << bit;
354 bit--;
355 if(bit < 0) {
356 q++;
357 bit = 7;
358 }
359 }
360 p++;
361 }
362 for(yy=0; yy<size; yy++) {
363 png_write_row(png_ptr, row);
364 }
365 }
366 /* bottom margin */
367 memset(row, 0xff, (realwidth + 7) / 8);
368 for(y=0; y<margin * size; y++) {
369 png_write_row(png_ptr, row);
370 }
371
372 png_write_end(png_ptr, info_ptr);
373 png_destroy_write_struct(&png_ptr, &info_ptr);
374
375 fclose(fp);
376 free(row);
377 free(palette);
378
379 return 0;
380}
381
382static int writeEPS(QRcode *qrcode, const char *outfile)
383{
384 FILE *fp;
385 unsigned char *row, *p;
386 int x, y, yy;
387 int realwidth;
388
389 fp = openFile(outfile);
390
391 realwidth = (qrcode->width + margin * 2) * size;
392 /* EPS file header */
393 fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n"
394 "%%%%BoundingBox: 0 0 %d %d\n"
395 "%%%%Pages: 1 1\n"
396 "%%%%EndComments\n", realwidth, realwidth);
397 /* draw point */
398 fprintf(fp, "/p { "
399 "moveto "
400 "0 1 rlineto "
401 "1 0 rlineto "
402 "0 -1 rlineto "
403 "fill "
404 "} bind def "
405 "%d %d scale ", size, size);
406
407 /* data */
408 p = qrcode->data;
409 for(y=0; y<qrcode->width; y++) {
410 row = (p+(y*qrcode->width));
411 yy = (margin + qrcode->width - y - 1);
412
413 for(x=0; x<qrcode->width; x++) {
414 if(*(row+x)&0x1) {
415 fprintf(fp, "%d %d p ", margin + x, yy);
416 }
417 }
418 }
419
420 fprintf(fp, "\n%%%%EOF\n");
421 fclose(fp);
422
423 return 0;
424}
425
426static void writeSVG_writeRect(FILE *fp, int x, int y, int width, char* col, float opacity)
427{
428 if(fg_color[3] != 255) {
429 fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\
430 "fill=\"#%s\" fill-opacity=\"%f\" />\n",
431 x, y, width, col, opacity );
432 } else {
433 fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\
434 "fill=\"#%s\" />\n",
435 x, y, width, col );
436 }
437}
438
439static int writeSVG( QRcode *qrcode, const char *outfile )
440{
441 FILE *fp;
442 unsigned char *row, *p;
443 int x, y, x0, pen;
444 int symwidth, realwidth;
445 float scale;
446 char fg[7], bg[7];
447 float fg_opacity;
448 float bg_opacity;
449
450 fp = openFile(outfile);
451
452 scale = dpi * INCHES_PER_METER / 100.0;
453
454 symwidth = qrcode->width + margin * 2;
455 realwidth = symwidth * size;
456
457 snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1], fg_color[2]);
458 snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1], bg_color[2]);
459 fg_opacity = (float)fg_color[3] / 255;
460 bg_opacity = (float)bg_color[3] / 255;
461
462 /* XML declaration */
463 fputs( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", fp );
464
465 /* DTD
466 No document type specified because "while a DTD is provided in [the SVG]
467 specification, the use of DTDs for validating XML documents is known to be
468 problematic. In particular, DTDs do not handle namespaces gracefully. It
469 is *not* recommended that a DOCTYPE declaration be included in SVG
470 documents."
471 http://www.w3.org/TR/2003/REC-SVG11-20030114/intro.html#Namespace
472 */
473
474 /* Vanity remark */
475 fprintf( fp, "<!-- Created with qrencode %s (http://fukuchi.org/works/qrencode/index.html.en) -->\n",
476 QRcode_APIVersionString() );
477
478 /* SVG code start */
479 fprintf( fp, "<svg width=\"%0.2fcm\" height=\"%0.2fcm\" viewBox=\"0 0 %d %d\""\
480 " preserveAspectRatio=\"none\" version=\"1.1\""\
481 " xmlns=\"http://www.w3.org/2000/svg\">\n",
482 realwidth / scale, realwidth / scale, symwidth, symwidth
483 );
484
485 /* Make named group */
486 fputs( "\t<g id=\"QRcode\">\n", fp );
487
488 /* Make solid background */
489 if(bg_color[3] != 255) {
490 fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\" fill-opacity=\"%f\" />\n", symwidth, symwidth, bg, bg_opacity);
491 } else {
492 fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\" />\n", symwidth, symwidth, bg);
493 }
494
495 /* Create new viewbox for QR data */
496 fputs( "\t\t<g id=\"Pattern\">\n", fp);
497
498 /* Write data */
499 p = qrcode->data;
500 for(y=0; y<qrcode->width; y++) {
501 row = (p+(y*qrcode->width));
502
503 if( !rle ) {
504 /* no RLE */
505 for(x=0; x<qrcode->width; x++) {
506 if(*(row+x)&0x1) {
507 writeSVG_writeRect(fp, margin + x,
508 margin + y, 1,
509 fg, fg_opacity);
510 }
511 }
512 } else {
513 /* simple RLE */
514 pen = 0;
515 x0 = 0;
516 for(x=0; x<qrcode->width; x++) {
517 if( !pen ) {
518 pen = *(row+x)&0x1;
519 x0 = x;
520 } else {
521 if(!(*(row+x)&0x1)) {
522 writeSVG_writeRect(fp, x0 + margin, y + margin, x-x0, fg, fg_opacity);
523 pen = 0;
524 }
525 }
526 }
527 if( pen ) {
528 writeSVG_writeRect(fp, x0 + margin, y + margin, qrcode->width - x0, fg, fg_opacity);
529 }
530 }
531 }
532 /* Close QR data viewbox */
533 fputs( "\t\t</g>\n", fp );
534
535 /* Close group */
536 fputs( "\t</g>\n", fp );
537
538 /* Close SVG code */
539 fputs( "</svg>\n", fp );
540 fclose( fp );
541
542 return 0;
543}
544
545static void writeANSI_margin(FILE* fp, int realwidth,
546 char* buffer, int buffer_s,
547 char* white, int white_s )
548{
549 int y;
550
551 strncpy(buffer, white, white_s);
552 memset(buffer + white_s, ' ', realwidth * 2);
553 strcpy(buffer + white_s + realwidth * 2, "\033[0m\n"); // reset to default colors
554 for(y=0; y<margin; y++ ){
555 fputs(buffer, fp);
556 }
557}
558
559static int writeANSI(QRcode *qrcode, const char *outfile)
560{
561 FILE *fp;
562 unsigned char *row, *p;
563 int x, y;
564 int realwidth;
565 int last;
566
567 char *white, *black, *buffer;
568 int white_s, black_s, buffer_s;
569
570 if( image_type == ANSI256_TYPE ){
571 /* codes for 256 color compatible terminals */
572 white = "\033[48;5;231m";
573 white_s = 11;
574 black = "\033[48;5;16m";
575 black_s = 10;
576 } else {
577 white = "\033[47m";
578 white_s = 5;
579 black = "\033[40m";
580 black_s = 5;
581 }
582
583 size = 1;
584
585 fp = openFile(outfile);
586
587 realwidth = (qrcode->width + margin * 2) * size;
588 buffer_s = ( realwidth * white_s ) * 2;
589 buffer = (char *)malloc( buffer_s );
590 if(buffer == NULL) {
591 fprintf(stderr, "Failed to allocate memory.\n");
592 exit(EXIT_FAILURE);
593 }
594
595 /* top margin */
596 writeANSI_margin(fp, realwidth, buffer, buffer_s, white, white_s);
597
598 /* data */
599 p = qrcode->data;
600 for(y=0; y<qrcode->width; y++) {
601 row = (p+(y*qrcode->width));
602
603 memset( buffer, 0, buffer_s );
604 strncpy( buffer, white, white_s );
605 for(x=0; x<margin; x++ ){
606 strncat( buffer, " ", 2 );
607 }
608 last = 0;
609
610 for(x=0; x<qrcode->width; x++) {
611 if(*(row+x)&0x1) {
612 if( last != 1 ){
613 strncat( buffer, black, black_s );
614 last = 1;
615 }
616 } else {
617 if( last != 0 ){
618 strncat( buffer, white, white_s );
619 last = 0;
620 }
621 }
622 strncat( buffer, " ", 2 );
623 }
624
625 if( last != 0 ){
626 strncat( buffer, white, white_s );
627 }
628 for(x=0; x<margin; x++ ){
629 strncat( buffer, " ", 2 );
630 }
631 strncat( buffer, "\033[0m\n", 5 );
632 fputs( buffer, fp );
633 }
634
635 /* bottom margin */
636 writeANSI_margin(fp, realwidth, buffer, buffer_s, white, white_s);
637
638 fclose(fp);
639 free(buffer);
640
641 return 0;
642}
643
644static void writeUTF8_margin(FILE* fp, int realwidth,
645 const char* white, const char *reset,
646 int use_ansi)
647{
648 int x, y;
649
650 for (y = 0; y < margin/2; y++) {
651 fputs(white, fp);
652 for (x = 0; x < realwidth; x++)
653 fputs("\342\226\210", fp);
654 fputs(reset, fp);
655 fputc('\n', fp);
656 }
657}
658
659static int writeUTF8(QRcode *qrcode, const char *outfile, int use_ansi)
660{
661 FILE *fp;
662 int x, y;
663 int realwidth;
664 const char *white, *reset;
665
666 if (use_ansi){
667 white = "\033[40;37;1m";
668 reset = "\033[0m";
669 } else {
670 white = "";
671 reset = "";
672 }
673
674 fp = openFile(outfile);
675
676 realwidth = (qrcode->width + margin * 2);
677
678 /* top margin */
679 writeUTF8_margin(fp, realwidth, white, reset, use_ansi);
680
681 /* data */
682 for(y = 0; y < qrcode->width; y += 2) {
683 unsigned char *row1, *row2;
684 row1 = qrcode->data + y*qrcode->width;
685 row2 = row1 + qrcode->width;
686
687 fputs(white, fp);
688
689 for (x = 0; x < margin; x++)
690 fputs("\342\226\210", fp);
691
692 for (x = 0; x < qrcode->width; x++) {
693 if(row1[x] & 1) {
694 if(y < qrcode->width - 1 && row2[x] & 1) {
695 fputc(' ', fp);
696 } else {
697 fputs("\342\226\204", fp);
698 }
699 } else {
700 if(y < qrcode->width - 1 && row2[x] & 1) {
701 fputs("\342\226\200", fp);
702 } else {
703 fputs("\342\226\210", fp);
704 }
705 }
706 }
707
708 for (x = 0; x < margin; x++)
709 fputs("\342\226\210", fp);
710
711 fputs(reset, fp);
712 fputc('\n', fp);
713 }
714
715 /* bottom margin */
716 writeUTF8_margin(fp, realwidth, white, reset, use_ansi);
717
718 fclose(fp);
719
720 return 0;
721}
722
723static void writeASCII_margin(FILE* fp, int realwidth, char* buffer, int buffer_s, int invert)
724{
725 int y, h;
726
727 h = margin;
728
729 memset(buffer, (invert?'#':' '), realwidth);
730 buffer[realwidth] = '\n';
731 buffer[realwidth + 1] = '\0';
732 for(y=0; y<h; y++ ){
733 fputs(buffer, fp);
734 }
735}
736
737static int writeASCII(QRcode *qrcode, const char *outfile, int invert)
738{
739 FILE *fp;
740 unsigned char *row;
741 int x, y;
742 int realwidth;
743 char *buffer, *p;
744 int buffer_s;
745 char black = '#';
746 char white = ' ';
747
748 if(invert) {
749 black = ' ';
750 white = '#';
751 }
752
753 size = 1;
754
755 fp = openFile(outfile);
756
757 realwidth = (qrcode->width + margin * 2) * 2;
758 buffer_s = realwidth + 2;
759 buffer = (char *)malloc( buffer_s );
760 if(buffer == NULL) {
761 fprintf(stderr, "Failed to allocate memory.\n");
762 exit(EXIT_FAILURE);
763 }
764
765 /* top margin */
766 writeASCII_margin(fp, realwidth, buffer, buffer_s, invert);
767
768 /* data */
769 for(y=0; y<qrcode->width; y++) {
770 row = qrcode->data+(y*qrcode->width);
771 p = buffer;
772
773 memset(p, white, margin * 2);
774 p += margin * 2;
775
776 for(x=0; x<qrcode->width; x++) {
777 if(row[x]&0x1) {
778 *p++ = black;
779 *p++ = black;
780 } else {
781 *p++ = white;
782 *p++ = white;
783 }
784 }
785
786 memset(p, white, margin * 2);
787 p += margin * 2;
788 *p++ = '\n';
789 *p++ = '\0';
790 fputs( buffer, fp );
791 }
792
793 /* bottom margin */
794 writeASCII_margin(fp, realwidth, buffer, buffer_s, invert);
795
796 fclose(fp);
797 free(buffer);
798
799 return 0;
800}
801
802static QRcode *encode(const unsigned char *intext, int length)
803{
804 QRcode *code;
805
806 if(micro) {
807 if(eightbit) {
808 code = QRcode_encodeDataMQR(length, intext, version, level);
809 } else {
810 code = QRcode_encodeStringMQR((char *)intext, version, level, hint, casesensitive);
811 }
812 } else {
813 if(eightbit) {
814 code = QRcode_encodeData(length, intext, version, level);
815 } else {
816 code = QRcode_encodeString((char *)intext, version, level, hint, casesensitive);
817 }
818 }
819
820 return code;
821}
822
823static void qrencode(const unsigned char *intext, int length, const char *outfile)
824{
825 QRcode *qrcode;
826
827 qrcode = encode(intext, length);
828 if(qrcode == NULL) {
829 perror("Failed to encode the input data");
830 exit(EXIT_FAILURE);
831 }
832
833 if(verbose) {
834 fprintf(stderr, "File: %s, Version: %d\n", (outfile!=NULL)?outfile:"(stdout)", qrcode->version);
835 }
836
837 switch(image_type) {
838 case PNG_TYPE:
839 writePNG(qrcode, outfile);
840 break;
841 case EPS_TYPE:
842 writeEPS(qrcode, outfile);
843 break;
844 case SVG_TYPE:
845 writeSVG(qrcode, outfile);
846 break;
847 case ANSI_TYPE:
848 case ANSI256_TYPE:
849 writeANSI(qrcode, outfile);
850 break;
851 case ASCIIi_TYPE:
852 writeASCII(qrcode, outfile, 1);
853 break;
854 case ASCII_TYPE:
855 writeASCII(qrcode, outfile, 0);
856 break;
857 case UTF8_TYPE:
858 writeUTF8(qrcode, outfile, 0);
859 break;
860 case ANSIUTF8_TYPE:
861 writeUTF8(qrcode, outfile, 1);
862 break;
863 default:
864 fprintf(stderr, "Unknown image type.\n");
865 exit(EXIT_FAILURE);
866 }
867
868 QRcode_free(qrcode);
869}
870
871static QRcode_List *encodeStructured(const unsigned char *intext, int length)
872{
873 QRcode_List *list;
874
875 if(eightbit) {
876 list = QRcode_encodeDataStructured(length, intext, version, level);
877 } else {
878 list = QRcode_encodeStringStructured((char *)intext, version, level, hint, casesensitive);
879 }
880
881 return list;
882}
883
884static void qrencodeStructured(const unsigned char *intext, int length, const char *outfile)
885{
886 QRcode_List *qrlist, *p;
887 char filename[FILENAME_MAX];
888 char *base, *q, *suffix = NULL;
889 const char *type_suffix;
890 int i = 1;
891 size_t suffix_size;
892
893 switch(image_type) {
894 case PNG_TYPE:
895 type_suffix = ".png";
896 break;
897 case EPS_TYPE:
898 type_suffix = ".eps";
899 break;
900 case SVG_TYPE:
901 type_suffix = ".svg";
902 break;
903 case ANSI_TYPE:
904 case ANSI256_TYPE:
905 case ASCII_TYPE:
906 case UTF8_TYPE:
907 case ANSIUTF8_TYPE:
908 type_suffix = ".txt";
909 break;
910 default:
911 fprintf(stderr, "Unknown image type.\n");
912 exit(EXIT_FAILURE);
913 }
914
915 if(outfile == NULL) {
916 fprintf(stderr, "An output filename must be specified to store the structured images.\n");
917 exit(EXIT_FAILURE);
918 }
919 base = strdup(outfile);
920 if(base == NULL) {
921 fprintf(stderr, "Failed to allocate memory.\n");
922 exit(EXIT_FAILURE);
923 }
924 suffix_size = strlen(type_suffix);
925 if(strlen(base) > suffix_size) {
926 q = base + strlen(base) - suffix_size;
927 if(strcasecmp(type_suffix, q) == 0) {
928 suffix = strdup(q);
929 *q = '\0';
930 }
931 }
932
933 qrlist = encodeStructured(intext, length);
934 if(qrlist == NULL) {
935 perror("Failed to encode the input data");
936 exit(EXIT_FAILURE);
937 }
938
939 for(p = qrlist; p != NULL; p = p->next) {
940 if(p->code == NULL) {
941 fprintf(stderr, "Failed to encode the input data.\n");
942 exit(EXIT_FAILURE);
943 }
944 if(suffix) {
945 snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix);
946 } else {
947 snprintf(filename, FILENAME_MAX, "%s-%02d", base, i);
948 }
949
950 if(verbose) {
951 fprintf(stderr, "File: %s, Version: %d\n", filename, p->code->version);
952 }
953
954 switch(image_type) {
955 case PNG_TYPE:
956 writePNG(p->code, filename);
957 break;
958 case EPS_TYPE:
959 writeEPS(p->code, filename);
960 break;
961 case SVG_TYPE:
962 writeSVG(p->code, filename);
963 break;
964 case ANSI_TYPE:
965 case ANSI256_TYPE:
966 writeANSI(p->code, filename);
967 break;
968 case ASCIIi_TYPE:
969 writeASCII(p->code, filename, 1);
970 break;
971 case ASCII_TYPE:
972 writeASCII(p->code, filename, 0);
973 break;
974 case UTF8_TYPE:
975 writeUTF8(p->code, filename, 0);
976 break;
977 case ANSIUTF8_TYPE:
978 writeUTF8(p->code, filename, 0);
979 break;
980
981 default:
982 fprintf(stderr, "Unknown image type.\n");
983 exit(EXIT_FAILURE);
984 }
985 i++;
986 }
987
988 free(base);
989 if(suffix) {
990 free(suffix);
991 }
992
993 QRcode_List_free(qrlist);
994}
995
996int main(int argc, char **argv)
997{
998 int opt, lindex = -1;
999 char *outfile = NULL;
1000 unsigned char *intext = NULL;
1001 int length = 0;
1002
1003 while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
1004 switch(opt) {
1005 case 'h':
1006 if(lindex == 0) {
1007 usage(1, 1);
1008 } else {
1009 usage(1, 0);
1010 }
1011 exit(EXIT_SUCCESS);
1012 break;
1013 case 'o':
1014 outfile = optarg;
1015 break;
1016 case 's':
1017 size = atoi(optarg);
1018 if(size <= 0) {
1019 fprintf(stderr, "Invalid size: %d\n", size);
1020 exit(EXIT_FAILURE);
1021 }
1022 break;
1023 case 'v':
1024 version = atoi(optarg);
1025 if(version < 0) {
1026 fprintf(stderr, "Invalid version: %d\n", version);
1027 exit(EXIT_FAILURE);
1028 }
1029 break;
1030 case 'l':
1031 switch(*optarg) {
1032 case 'l':
1033 case 'L':
1034 level = QR_ECLEVEL_L;
1035 break;
1036 case 'm':
1037 case 'M':
1038 level = QR_ECLEVEL_M;
1039 break;
1040 case 'q':
1041 case 'Q':
1042 level = QR_ECLEVEL_Q;
1043 break;
1044 case 'h':
1045 case 'H':
1046 level = QR_ECLEVEL_H;
1047 break;
1048 default:
1049 fprintf(stderr, "Invalid level: %s\n", optarg);
1050 exit(EXIT_FAILURE);
1051 break;
1052 }
1053 break;
1054 case 'm':
1055 margin = atoi(optarg);
1056 if(margin < 0) {
1057 fprintf(stderr, "Invalid margin: %d\n", margin);
1058 exit(EXIT_FAILURE);
1059 }
1060 break;
1061 case 'd':
1062 dpi = atoi(optarg);
1063 if( dpi < 0 ) {
1064 fprintf(stderr, "Invalid DPI: %d\n", dpi);
1065 exit(EXIT_FAILURE);
1066 }
1067 break;
1068 case 't':
1069 if(strcasecmp(optarg, "png") == 0) {
1070 image_type = PNG_TYPE;
1071 } else if(strcasecmp(optarg, "eps") == 0) {
1072 image_type = EPS_TYPE;
1073 } else if(strcasecmp(optarg, "svg") == 0) {
1074 image_type = SVG_TYPE;
1075 } else if(strcasecmp(optarg, "ansi") == 0) {
1076 image_type = ANSI_TYPE;
1077 } else if(strcasecmp(optarg, "ansi256") == 0) {
1078 image_type = ANSI256_TYPE;
1079 } else if(strcasecmp(optarg, "asciii") == 0) {
1080 image_type = ASCIIi_TYPE;
1081 } else if(strcasecmp(optarg, "ascii") == 0) {
1082 image_type = ASCII_TYPE;
1083 } else if(strcasecmp(optarg, "utf8") == 0) {
1084 image_type = UTF8_TYPE;
1085 } else if(strcasecmp(optarg, "ansiutf8") == 0) {
1086 image_type = ANSIUTF8_TYPE;
1087 } else {
1088 fprintf(stderr, "Invalid image type: %s\n", optarg);
1089 exit(EXIT_FAILURE);
1090 }
1091 break;
1092 case 'S':
1093 structured = 1;
1094 break;
1095 case 'k':
1096 hint = QR_MODE_KANJI;
1097 break;
1098 case 'c':
1099 casesensitive = 1;
1100 break;
1101 case 'i':
1102 casesensitive = 0;
1103 break;
1104 case '8':
1105 eightbit = 1;
1106 break;
1107 case 'M':
1108 micro = 1;
1109 break;
1110 case 'f':
1111 if(color_set(fg_color, optarg)) {
1112 fprintf(stderr, "Invalid foreground color value.\n");
1113 exit(EXIT_FAILURE);
1114 }
1115 break;
1116 case 'b':
1117 if(color_set(bg_color, optarg)) {
1118 fprintf(stderr, "Invalid background color value.\n");
1119 exit(EXIT_FAILURE);
1120 }
1121 break;
1122 case 'V':
1123 usage(0, 0);
1124 exit(EXIT_SUCCESS);
1125 break;
1126 case 0:
1127 break;
1128 default:
1129 fprintf(stderr, "Try `qrencode --help' for more information.\n");
1130 exit(EXIT_FAILURE);
1131 break;
1132 }
1133 }
1134
1135 if(argc == 1) {
1136 usage(1, 0);
1137 exit(EXIT_SUCCESS);
1138 }
1139
1140 if(outfile == NULL && image_type == PNG_TYPE) {
1141 fprintf(stderr, "No output filename is given.\n");
1142 exit(EXIT_FAILURE);
1143 }
1144
1145 if(optind < argc) {
1146 intext = (unsigned char *)argv[optind];
1147 length = strlen((char *)intext);
1148 }
1149 if(intext == NULL) {
1150 intext = readStdin(&length);
1151 }
1152
1153 if(micro && version > MQRSPEC_VERSION_MAX) {
1154 fprintf(stderr, "Version should be less or equal to %d.\n", MQRSPEC_VERSION_MAX);
1155 exit(EXIT_FAILURE);
1156 } else if(!micro && version > QRSPEC_VERSION_MAX) {
1157 fprintf(stderr, "Version should be less or equal to %d.\n", QRSPEC_VERSION_MAX);
1158 exit(EXIT_FAILURE);
1159 }
1160
1161 if(margin < 0) {
1162 if(micro) {
1163 margin = 2;
1164 } else {
1165 margin = 4;
1166 }
1167 }
1168
1169 if(micro) {
1170 if(version == 0) {
1171 fprintf(stderr, "Version must be specified to encode a Micro QR Code symbol.\n");
1172 exit(EXIT_FAILURE);
1173 }
1174 if(structured) {
1175 fprintf(stderr, "Micro QR Code does not support structured symbols.\n");
1176 exit(EXIT_FAILURE);
1177 }
1178 }
1179
1180 if(structured) {
1181 if(version == 0) {
1182 fprintf(stderr, "Version must be specified to encode structured symbols.\n");
1183 exit(EXIT_FAILURE);
1184 }
1185 qrencodeStructured(intext, length, outfile);
1186 } else {
1187 qrencode(intext, length, outfile);
1188 }
1189
1190 return 0;
1191}