source: trunk/zoo-project/zoo-services/qrencode/qrenc-service.c @ 726

Last change on this file since 726 was 385, checked in by djay, 12 years ago

Add QREncode service. Fix memory leaks. Avoid printing anything from the conf_read function to be able to detect and return valid headers.

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

Search

Context Navigation

ZOO Sponsors

http://www.zoo-project.org/trac/chrome/site/img/geolabs-logo.pnghttp://www.zoo-project.org/trac/chrome/site/img/neogeo-logo.png http://www.zoo-project.org/trac/chrome/site/img/apptech-logo.png http://www.zoo-project.org/trac/chrome/site/img/3liz-logo.png http://www.zoo-project.org/trac/chrome/site/img/gateway-logo.png

Become a sponsor !

Knowledge partners

http://www.zoo-project.org/trac/chrome/site/img/ocu-logo.png http://www.zoo-project.org/trac/chrome/site/img/gucas-logo.png http://www.zoo-project.org/trac/chrome/site/img/polimi-logo.png http://www.zoo-project.org/trac/chrome/site/img/fem-logo.png http://www.zoo-project.org/trac/chrome/site/img/supsi-logo.png http://www.zoo-project.org/trac/chrome/site/img/cumtb-logo.png

Become a knowledge partner

Related links

http://zoo-project.org/img/ogclogo.png http://zoo-project.org/img/osgeologo.png