]> git.sur5r.net Git - glabels/blob - glabels2/qrencode-3.1.0/qrenc.c
c68aec317849104843d66f45a6f8b7451f5b3aaa
[glabels] / glabels2 / qrencode-3.1.0 / qrenc.c
1 /**
2  * qrencode - QR Code encoder
3  *
4  * QR Code encoding tool
5  * Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi <fukuchi@megaui.net>
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 #include <stdio.h>
23 #include <stdlib.h>
24 #include <png.h>
25 #include <getopt.h>
26
27 #include "config.h"
28 #include "qrencode.h"
29
30 static int casesensitive = 1;
31 static int eightbit = 0;
32 static int version = 0;
33 static int size = 3;
34 static int margin = 4;
35 static int structured = 0;
36 static QRecLevel level = QR_ECLEVEL_L;
37 static QRencodeMode hint = QR_MODE_8;
38
39 static const struct option options[] = {
40         {"help"         , no_argument      , NULL, 'h'},
41         {"output"       , required_argument, NULL, 'o'},
42         {"level"        , required_argument, NULL, 'l'},
43         {"size"         , required_argument, NULL, 's'},
44         {"symversion"   , required_argument, NULL, 'v'},
45         {"margin"       , required_argument, NULL, 'm'},
46         {"structured"   , no_argument      , NULL, 'S'},
47         {"kanji"        , no_argument      , NULL, 'k'},
48         {"casesensitive", no_argument      , NULL, 'c'},
49         {"ignorecase"   , no_argument      , NULL, 'i'},
50         {"8bit"         , no_argument      , NULL, '8'},
51         {"version"      , no_argument      , NULL, 'V'},
52         {NULL, 0, NULL, 0}
53 };
54
55 static char *optstring = "ho:l:s:v:m:Skci8V";
56
57 static void usage(int help, int longopt)
58 {
59         fprintf(stderr,
60 "qrencode version %s\n"
61 "Copyright (C) 2006, 2007, 2008, 2009 Kentaro Fukuchi\n", VERSION);
62         if(help) {
63                 if(longopt) {
64                         fprintf(stderr,
65 "Usage: qrencode [OPTION]... [STRING]\n"
66 "Encode input data in a QR Code and save as a PNG image.\n\n"
67 "  -h, --help   display the help message. -h displays only the help of short\n"
68 "               options.\n\n"
69 "  -o FILENAME, --output=FILENAME\n"
70 "               write PNG image to FILENAME. If '-' is specified, the result\n"
71 "               will be output to standard output. If -S is given, structured\n"
72 "               symbols are written to FILENAME-01.png, FILENAME-02.png, ...;\n"
73 "               if specified, remove a trailing '.png' from FILENAME.\n\n"
74 "  -s NUMBER, --size=NUMBER\n"
75 "               specify the size of dot (pixel). (default=3)\n\n"
76 "  -l {LMQH}, --level={LMQH}\n"
77 "               specify error collectin level from L (lowest) to H (highest).\n"
78 "               (default=L)\n\n"
79 "  -v NUMBER, --symversion=NUMBER\n"
80 "               specify the version of the symbol. (default=auto)\n\n"
81 "  -m NUMBER, --margin=NUMBER\n"
82 "               specify the width of margin. (default=4)\n\n"
83 "  -S, --structured\n"
84 "               make structured symbols. Version must be specified.\n\n"
85 "  -k, --kanji  assume that the input text contains kanji (shift-jis).\n\n"
86 "  -c, --casesensitive\n"
87 "               encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
88 "  -i, --ignorecase\n"
89 "               ignore case distinctions and use only upper-case characters.\n\n"
90 "  -8, -8bit    encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
91 "  -V, --version\n"
92 "               display the version number and copyrights of the qrencode.\n\n"
93 "  [STRING]     input data. If it is not specified, data will be taken from\n"
94 "               standard input.\n"
95                         );
96                 } else {
97                         fprintf(stderr,
98 "Usage: qrencode [OPTION]... [STRING]\n"
99 "Encode input data in a QR Code and save as a PNG image.\n\n"
100 "  -h           display this message.\n"
101 "  --help       display the usage of long options.\n"
102 "  -o FILENAME  write PNG image to FILENAME. If '-' is specified, the result\n"
103 "               will be output to standard output. If -S is given, structured\n"
104 "               symbols are written to FILENAME-01.png, FILENAME-02.png, ...;\n"
105 "               if specified, remove a trailing '.png' from FILENAME.\n"
106 "  -s NUMBER    specify the size of dot (pixel). (default=3)\n"
107 "  -l {LMQH}    specify error collectin level from L (lowest) to H (highest).\n"
108 "               (default=L)\n"
109 "  -v NUMBER    specify the version of the symbol. (default=auto)\n"
110 "  -m NUMBER    specify the width of margin. (default=4)\n"
111 "  -S           make structured symbols. Version must be specified.\n"
112 "  -k           assume that the input text contains kanji (shift-jis).\n"
113 "  -c           encode lower-case alphabet characters in 8-bit mode. (default)\n"
114 "  -i           ignore case distinctions and use only upper-case characters.\n"
115 "  -8           encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
116 "  -V           display the version number and copyrights of the qrencode.\n"
117 "  [STRING]     input data. If it is not specified, data will be taken from\n"
118 "               standard input.\n"
119                         );
120                 }
121         }
122 }
123
124 #define MAX_DATA_SIZE (7090 * 16) /* from the specification */
125 static char *readStdin(void)
126 {
127         char *buffer;
128         int ret;
129
130         buffer = (char *)malloc(MAX_DATA_SIZE);
131         if(buffer == NULL) {
132                 fprintf(stderr, "Memory allocation failed.\n");
133                 exit(EXIT_FAILURE);
134         }
135         ret = fread(buffer, 1, MAX_DATA_SIZE, stdin);
136         if(ret == 0) {
137                 fprintf(stderr, "No input data.\n");
138                 exit(EXIT_FAILURE);
139         }
140         if(feof(stdin) == 0) {
141                 fprintf(stderr, "Input data is too large.\n");
142                 exit(EXIT_FAILURE);
143         }
144
145         buffer[ret] = '\0';
146
147         return buffer;
148 }
149
150 static int writePNG(QRcode *qrcode, const char *outfile)
151 {
152         static FILE *fp; // avoid clobbering by setjmp.
153         png_structp png_ptr;
154         png_infop info_ptr;
155         unsigned char *row, *p, *q;
156         int x, y, xx, yy, bit;
157         int realwidth;
158
159         realwidth = (qrcode->width + margin * 2) * size;
160         row = (unsigned char *)malloc((realwidth + 7) / 8);
161         if(row == NULL) {
162                 fprintf(stderr, "Failed to allocate memory.\n");
163                 exit(EXIT_FAILURE);
164         }
165
166         if(outfile[0] == '-' && outfile[1] == '\0') {
167                 fp = stdout;
168         } else {
169                 fp = fopen(outfile, "wb");
170                 if(fp == NULL) {
171                         fprintf(stderr, "Failed to create file: %s\n", outfile);
172                         perror(NULL);
173                         exit(EXIT_FAILURE);
174                 }
175         }
176
177         png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
178         if(png_ptr == NULL) {
179                 fprintf(stderr, "Failed to initialize PNG writer.\n");
180                 exit(EXIT_FAILURE);
181         }
182
183         info_ptr = png_create_info_struct(png_ptr);
184         if(info_ptr == NULL) {
185                 fprintf(stderr, "Failed to initialize PNG write.\n");
186                 exit(EXIT_FAILURE);
187         }
188
189         if(setjmp(png_jmpbuf(png_ptr))) {
190                 png_destroy_write_struct(&png_ptr, &info_ptr);
191                 fprintf(stderr, "Failed to write PNG image.\n");
192                 exit(EXIT_FAILURE);
193         }
194
195         png_init_io(png_ptr, fp);
196         png_set_IHDR(png_ptr, info_ptr,
197                         realwidth, realwidth,
198                         1,
199                         PNG_COLOR_TYPE_GRAY,
200                         PNG_INTERLACE_NONE,
201                         PNG_COMPRESSION_TYPE_DEFAULT,
202                         PNG_FILTER_TYPE_DEFAULT);
203         png_write_info(png_ptr, info_ptr);
204
205         /* top margin */
206         memset(row, 0xff, (realwidth + 7) / 8);
207         for(y=0; y<margin * size; y++) {
208                 png_write_row(png_ptr, row);
209         }
210
211         /* data */
212         p = qrcode->data;
213         for(y=0; y<qrcode->width; y++) {
214                 bit = 7;
215                 memset(row, 0xff, (realwidth + 7) / 8);
216                 q = row;
217                 q += margin * size / 8;
218                 bit = 7 - (margin * size % 8);
219                 for(x=0; x<qrcode->width; x++) {
220                         for(xx=0; xx<size; xx++) {
221                                 *q ^= (*p & 1) << bit;
222                                 bit--;
223                                 if(bit < 0) {
224                                         q++;
225                                         bit = 7;
226                                 }
227                         }
228                         p++;
229                 }
230                 for(yy=0; yy<size; yy++) {
231                         png_write_row(png_ptr, row);
232                 }
233         }
234         /* bottom margin */
235         memset(row, 0xff, (realwidth + 7) / 8);
236         for(y=0; y<margin * size; y++) {
237                 png_write_row(png_ptr, row);
238         }
239
240         png_write_end(png_ptr, info_ptr);
241         png_destroy_write_struct(&png_ptr, &info_ptr);
242
243         fclose(fp);
244         free(row);
245
246         return 0;
247 }
248
249 static QRcode *encode(const char *intext)
250 {
251         QRcode *code;
252
253         if(eightbit) {
254                 code = QRcode_encodeString8bit(intext, version, level);
255         } else {
256                 code = QRcode_encodeString(intext, version, level, hint, casesensitive);
257         }
258
259         return code;
260 }
261
262 static void qrencode(const char *intext, const char *outfile)
263 {
264         QRcode *qrcode;
265         
266         qrcode = encode(intext);
267         if(qrcode == NULL) {
268                 perror("Failed to encode the input data:");
269                 exit(EXIT_FAILURE);
270         }
271         writePNG(qrcode, outfile);
272         QRcode_free(qrcode);
273 }
274
275 static QRcode_List *encodeStructured(const char *intext)
276 {
277         QRcode_List *list;
278
279         if(eightbit) {
280                 list = QRcode_encodeString8bitStructured(intext, version, level);
281         } else {
282                 list = QRcode_encodeStringStructured(intext, version, level, hint, casesensitive);
283         }
284
285         return list;
286 }
287
288 static void qrencodeStructured(const char *intext, const char *outfile)
289 {
290         QRcode_List *qrlist, *p;
291         char filename[FILENAME_MAX];
292         char *base, *q, *suffix = NULL;
293         int i = 1;
294
295         base = strdup(outfile);
296         if(base == NULL) {
297                 fprintf(stderr, "Failed to allocate memory.\n");
298                 exit(EXIT_FAILURE);
299         }
300         if(strlen(base) > 4) {
301                 q = base + strlen(base) - 4;
302                 if(strcasecmp(".png", q) == 0) {
303                         suffix = strdup(q);
304                         *q = '\0';
305                 }
306         }
307         
308         qrlist = encodeStructured(intext);
309         if(qrlist == NULL) {
310                 perror("Failed to encode the input data:");
311                 exit(EXIT_FAILURE);
312         }
313
314         for(p = qrlist; p != NULL; p = p->next) {
315                 if(p->code == NULL) {
316                         fprintf(stderr, "Failed to encode the input data.\n");
317                         exit(EXIT_FAILURE);
318                 }
319                 if(suffix) {
320                         snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix);
321                 } else {
322                         snprintf(filename, FILENAME_MAX, "%s-%02d", base, i);
323                 }
324                 writePNG(p->code, filename);
325                 i++;
326         }
327
328         free(base);
329         if(suffix) {
330                 free(suffix);
331         }
332
333         QRcode_List_free(qrlist);
334 }
335
336 int main(int argc, char **argv)
337 {
338         int opt, lindex = -1;
339         char *outfile = NULL;
340         char *intext = NULL;
341
342         while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
343                 switch(opt) {
344                         case 'h':
345                                 if(lindex == 0) {
346                                         usage(1, 1);
347                                 } else {
348                                         usage(1, 0);
349                                 }
350                                 exit(0);
351                                 break;
352                         case 'o':
353                                 outfile = optarg;
354                                 break;
355                         case 's':
356                                 size = atoi(optarg);
357                                 if(size <= 0) {
358                                         fprintf(stderr, "Invalid size: %d\n", size);
359                                         exit(EXIT_FAILURE);
360                                 }
361                                 break;
362                         case 'v':
363                                 version = atoi(optarg);
364                                 if(version < 0) {
365                                         fprintf(stderr, "Invalid version: %d\n", version);
366                                         exit(EXIT_FAILURE);
367                                 }
368                                 break;
369                         case 'l':
370                                 switch(*optarg) {
371                                         case 'l':
372                                         case 'L':
373                                                 level = QR_ECLEVEL_L;
374                                                 break;
375                                         case 'm':
376                                         case 'M':
377                                                 level = QR_ECLEVEL_M;
378                                                 break;
379                                         case 'q':
380                                         case 'Q':
381                                                 level = QR_ECLEVEL_Q;
382                                                 break;
383                                         case 'h':
384                                         case 'H':
385                                                 level = QR_ECLEVEL_H;
386                                                 break;
387                                         default:
388                                                 fprintf(stderr, "Invalid level: %s\n", optarg);
389                                                 exit(EXIT_FAILURE);
390                                                 break;
391                                 }
392                                 break;
393                         case 'm':
394                                 margin = atoi(optarg);
395                                 if(margin < 0) {
396                                         fprintf(stderr, "Invalid margin: %d\n", margin);
397                                         exit(EXIT_FAILURE);
398                                 }
399                                 break;
400                         case 'S':
401                                 structured = 1;
402                         case 'k':
403                                 hint = QR_MODE_KANJI;
404                                 break;
405                         case 'c':
406                                 casesensitive = 1;
407                                 break;
408                         case 'i':
409                                 casesensitive = 0;
410                                 break;
411                         case '8':
412                                 eightbit = 1;
413                                 break;
414                         case 'V':
415                                 usage(0, 0);
416                                 exit(0);
417                                 break;
418                         default:
419                                 fprintf(stderr, "Try `qrencode --help' for more information.\n");
420                                 exit(EXIT_FAILURE);
421                                 break;
422                 }
423         }
424
425         if(argc == 1) {
426                 usage(1, 0);
427                 exit(0);
428         }
429
430         if(outfile == NULL) {
431                 fprintf(stderr, "No output filename is given.\n");
432                 exit(EXIT_FAILURE);
433         }
434
435         if(optind < argc) {
436                 intext = argv[optind];
437         }
438         if(intext == NULL) {
439                 intext = readStdin();
440         }
441
442         if(structured) {
443                 if(version == 0) {
444                         fprintf(stderr, "Version must be specified to encode structured symbols.\n");
445                         exit(EXIT_FAILURE);
446                 }
447                 qrencodeStructured(intext, outfile);
448         } else {
449                 qrencode(intext, outfile);
450         }
451
452         return 0;
453 }