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