Edit

kc3-lang/libqrencode/qrenc.c

Branch :

  • Show log

    Commit

  • Author : Kentaro Fukuchi
    Date : 2020-08-28 16:47:35
    Hash : 4fdf22ac
    Message : Documentation updates.

  • qrenc.c
  • /**
     * qrencode - QR Code encoder
     *
     * QR Code encoding tool
     * Copyright (C) 2006-2017 Kentaro Fukuchi <kentaro@fukuchi.org>
     *
     * This library is free software; you can redistribute it and/or
     * modify it under the terms of the GNU Lesser General Public
     * License as published by the Free Software Foundation; either
     * version 2.1 of the License, or any later version.
     *
     * This library is distributed in the hope that it will be useful,
     * but WITHOUT ANY WARRANTY; without even the implied warranty of
     * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
     * Lesser General Public License for more details.
     *
     * You should have received a copy of the GNU Lesser General Public
     * License along with this library; if not, write to the Free Software
     * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
     */
    
    #if HAVE_CONFIG_H
    # include "config.h"
    #endif
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <getopt.h>
    #include <errno.h>
    #if HAVE_PNG
    #include <png.h>
    #endif
    
    #include "qrencode.h"
    
    #define INCHES_PER_METER (100.0/2.54)
    
    static int casesensitive = 1;
    static int eightbit = 0;
    static int version = 0;
    static int size = 3;
    static int margin = -1;
    static int dpi = 72;
    static int structured = 0;
    static int rle = 0;
    static int svg_path = 0;
    static int micro = 0;
    static int inline_svg = 0;
    static int strict_versioning = 0;
    static QRecLevel level = QR_ECLEVEL_L;
    static QRencodeMode hint = QR_MODE_8;
    static unsigned char fg_color[4] = {0, 0, 0, 255};
    static unsigned char bg_color[4] = {255, 255, 255, 255};
    
    static int verbose = 0;
    
    enum imageType {
    	PNG_TYPE,
    	PNG32_TYPE,
    	EPS_TYPE,
    	SVG_TYPE,
    	XPM_TYPE,
    	ANSI_TYPE,
    	ANSI256_TYPE,
    	ASCII_TYPE,
    	ASCIIi_TYPE,
    	UTF8_TYPE,
    	ANSIUTF8_TYPE,
    	ANSI256UTF8_TYPE,
    	UTF8i_TYPE,
    	ANSIUTF8i_TYPE
    };
    
    static enum imageType image_type = PNG_TYPE;
    
    static const struct option options[] = {
    	{"help"          , no_argument      , NULL, 'h'},
    	{"output"        , required_argument, NULL, 'o'},
    	{"read-from"     , required_argument, NULL, 'r'},
    	{"level"         , required_argument, NULL, 'l'},
    	{"size"          , required_argument, NULL, 's'},
    	{"symversion"    , required_argument, NULL, 'v'},
    	{"margin"        , required_argument, NULL, 'm'},
    	{"dpi"           , required_argument, NULL, 'd'},
    	{"type"          , required_argument, NULL, 't'},
    	{"structured"    , no_argument      , NULL, 'S'},
    	{"kanji"         , no_argument      , NULL, 'k'},
    	{"casesensitive" , no_argument      , NULL, 'c'},
    	{"ignorecase"    , no_argument      , NULL, 'i'},
    	{"8bit"          , no_argument      , NULL, '8'},
    	{"micro"         , no_argument      , NULL, 'M'},
    	{"rle"           , no_argument      , &rle,   1},
    	{"svg-path"      , no_argument      , &svg_path, 1},
    	{"inline"        , no_argument      , &inline_svg, 1},
    	{"strict-version", no_argument      , &strict_versioning, 1},
    	{"foreground"    , required_argument, NULL, 'f'},
    	{"background"    , required_argument, NULL, 'b'},
    	{"version"       , no_argument      , NULL, 'V'},
    	{"verbose"       , no_argument      , &verbose, 1},
    	{NULL, 0, NULL, 0}
    };
    
    static char *optstring = "ho:r:l:s:v:m:d:t:Skci8MV";
    
    static void usage(int help, int longopt, int status)
    {
    	FILE *out = status ? stderr : stdout;
    	fprintf(out,
    "qrencode version %s\n"
    "Copyright (C) 2006-2017 Kentaro Fukuchi\n", QRcode_APIVersionString());
    	if(help) {
    		if(longopt) {
    			fprintf(out,
    "Usage: qrencode [-o FILENAME] [OPTION]... [STRING]\n"
    "Encode input data in a QR Code and save as a PNG or EPS image.\n\n"
    "  -h, --help   display the help message. -h displays only the help of short\n"
    "               options.\n\n"
    "  -o FILENAME, --output=FILENAME\n"
    "               write image to FILENAME. If '-' is specified, the result\n"
    "               will be output to standard output. If -S is given, structured\n"
    "               symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n"
    "               (suffix is removed from FILENAME, if specified)\n\n"
    "  -r FILENAME, --read-from=FILENAME\n"
    "               read input data from FILENAME.\n\n"
    "  -s NUMBER, --size=NUMBER\n"
    "               specify module size in dots (pixels). (default=3)\n\n"
    "  -l {LMQH}, --level={LMQH}\n"
    "               specify error correction level from L (lowest) to H (highest).\n"
    "               (default=L)\n\n"
    "  -v NUMBER, --symversion=NUMBER\n"
    "               specify the minimum version of the symbol. See SYMBOL VERSIONS\n"
    "               for more information. (default=auto)\n\n"
    "  -m NUMBER, --margin=NUMBER\n"
    "               specify the width of the margins. (default=4 (2 for Micro QR)))\n\n"
    "  -d NUMBER, --dpi=NUMBER\n"
    "               specify the DPI of the generated PNG. (default=72)\n\n"
    "  -t {PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8,ANSI256UTF8},\n"
    "  --type={PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8,ANSI256UTF8}\n"
    "               specify the type of the generated image. (default=PNG)\n\n"
    "  -S, --structured\n"
    "               make structured symbols. Version must be specified with '-v'.\n\n"
    "  -k, --kanji  assume that the input text contains kanji (shift-jis).\n\n"
    "  -c, --casesensitive\n"
    "               encode lower-case alphabet characters in 8-bit mode. (default)\n\n"
    "  -i, --ignorecase\n"
    "               ignore case distinctions and use only upper-case characters.\n\n"
    "  -8, --8bit   encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n\n"
    "  -M, --micro  encode in a Micro QR Code.\n\n"
    "      --rle    enable run-length encoding for SVG.\n\n"
    "      --svg-path\n"
    "               use single path to draw modules for SVG.\n\n"
    "      --inline only useful for SVG output, generates an SVG without the XML tag.\n\n"
    "      --foreground=RRGGBB[AA]\n"
    "      --background=RRGGBB[AA]\n"
    "               specify foreground/background color in hexadecimal notation.\n"
    "               6-digit (RGB) or 8-digit (RGBA) form are supported.\n"
    "               Color output support available only in PNG, EPS and SVG.\n\n"
    "      --strict-version\n"
    "               disable automatic version number adjustment. If the input data is\n"
    "               too large for the specified version, the program exits with the\n"
    "               code of 1.\n\n"
    "  -V, --version\n"
    "               display the version number and copyrights of the qrencode.\n\n"
    "      --verbose\n"
    "               display verbose information to stderr.\n\n"
    "  [STRING]     input data. If it is not specified, data will be taken from\n"
    "               standard input.\n\n"
    "SYMBOL VERSIONS\n"
    "               The symbol versions of QR Code range from Version 1 to Version\n"
    "               40. Each version has a different module configuration or number\n"
    "               of modules, ranging from Version 1 (21 x 21 modules) up to\n"
    "               Version 40 (177 x 177 modules). Each higher version number\n"
    "               comprises 4 additional modules per side by default. See\n"
    "               http://www.qrcode.com/en/about/version.html for a detailed\n"
    "               version list.\n"
    
    			);
    		} else {
    			fprintf(out,
    "Usage: qrencode [-o FILENAME] [OPTION]... [STRING]\n"
    "Encode input data in a QR Code and save as a PNG or EPS image.\n\n"
    "  -h           display this message.\n"
    "  --help       display the usage of long options.\n"
    "  -o FILENAME  write image to FILENAME. If '-' is specified, the result\n"
    "               will be output to standard output. If -S is given, structured\n"
    "               symbols are written to FILENAME-01.png, FILENAME-02.png, ...\n"
    "               (suffix is removed from FILENAME, if specified)\n"
    "  -r FILENAME  read input data from FILENAME.\n"
    "  -s NUMBER    specify module size in dots (pixels). (default=3)\n"
    "  -l {LMQH}    specify error correction level from L (lowest) to H (highest).\n"
    "               (default=L)\n"
    "  -v NUMBER    specify the minimum version of the symbol. (default=auto)\n"
    "  -m NUMBER    specify the width of the margins. (default=4 (2 for Micro))\n"
    "  -d NUMBER    specify the DPI of the generated PNG. (default=72)\n"
    "  -t {PNG,PNG32,EPS,SVG,XPM,ANSI,ANSI256,ASCII,ASCIIi,UTF8,ANSIUTF8,ANSI256UTF8}\n"
    "               specify the type of the generated image. (default=PNG)\n"
    "  -S           make structured symbols. Version number must be specified with '-v'.\n"
    "  -k           assume that the input text contains kanji (shift-jis).\n"
    "  -c           encode lower-case alphabet characters in 8-bit mode. (default)\n"
    "  -i           ignore case distinctions and use only upper-case characters.\n"
    "  -8           encode entire data in 8-bit mode. -k, -c and -i will be ignored.\n"
    "  -M           encode in a Micro QR Code.\n"
    "  -V           display the version number and copyrights of the qrencode.\n"
    "  [STRING]     input data. If it is not specified, data will be taken from\n"
    "               standard input.\n\n"
    "  Try \"qrencode --help\" for more options.\n"
    			);
    		}
    	}
    }
    
    static int color_set(unsigned char color[4], const char *value)
    {
    	int len = strlen(value);
    	int i, count;
    	unsigned int col[4];
    	if(len == 6) {
    		count = sscanf(value, "%02x%02x%02x%n", &col[0], &col[1], &col[2], &len);
    		if(count < 3 || len != 6) {
    			return -1;
    		}
    		for(i = 0; i < 3; i++) {
    			color[i] = col[i];
    		}
    		color[3] = 255;
    	} else if(len == 8) {
    		count = sscanf(value, "%02x%02x%02x%02x%n", &col[0], &col[1], &col[2], &col[3], &len);
    		if(count < 4 || len != 8) {
    			return -1;
    		}
    		for(i = 0; i < 4; i++) {
    			color[i] = col[i];
    		}
    	} else {
    		return -1;
    	}
    	return 0;
    }
    
    #define MAX_DATA_SIZE (7090 * 2) /* timed by the safty factor 2 */
    static unsigned char data_buffer[MAX_DATA_SIZE];
    static unsigned char *readFile(FILE *fp, int *length)
    {
    	int ret;
    
    	ret = fread(data_buffer, 1, MAX_DATA_SIZE, fp);
    	if(ret == 0) {
    		fprintf(stderr, "No input data.\n");
    		exit(EXIT_FAILURE);
    	}
    	if(feof(fp) == 0) {
    		fprintf(stderr, "Input data is too large.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	data_buffer[ret] = '\0';
    	*length = ret;
    
    	return data_buffer;
    }
    
    static FILE *openFile(const char *outfile)
    {
    	FILE *fp;
    
    	if(outfile == NULL || (outfile[0] == '-' && outfile[1] == '\0')) {
    		fp = stdout;
    	} else {
    		fp = fopen(outfile, "wb");
    		if(fp == NULL) {
    			fprintf(stderr, "Failed to create file: %s\n", outfile);
    			perror(NULL);
    			exit(EXIT_FAILURE);
    		}
    	}
    
    	return fp;
    }
    
    #if HAVE_PNG
    static void fillRow(unsigned char *row, int num, const unsigned char color[])
    {
    	int i;
    
    	for(i = 0; i < num; i++) {
    		memcpy(row, color, 4);
    		row += 4;
    	}
    }
    #endif
    
    static int writePNG(const QRcode *qrcode, const char *outfile, enum imageType type)
    {
    #if HAVE_PNG
    	static FILE *fp; // avoid clobbering by setjmp.
    	png_structp png_ptr;
    	png_infop info_ptr;
    	png_colorp palette = NULL;
    	png_byte alpha_values[2];
    	unsigned char *row, *p, *q;
    	int x, y, xx, yy, bit;
    	int realwidth;
    
    	realwidth = (qrcode->width + margin * 2) * size;
    	if(type == PNG_TYPE) {
    		row = (unsigned char *)malloc((size_t)((realwidth + 7) / 8));
    	} else if(type == PNG32_TYPE) {
    		row = (unsigned char *)malloc((size_t)realwidth * 4);
    	} else {
    		fprintf(stderr, "Internal error.\n");
    		exit(EXIT_FAILURE);
    	}
    	if(row == NULL) {
    		fprintf(stderr, "Failed to allocate memory.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if(outfile[0] == '-' && outfile[1] == '\0') {
    		fp = stdout;
    	} else {
    		fp = fopen(outfile, "wb");
    		if(fp == NULL) {
    			fprintf(stderr, "Failed to create file: %s\n", outfile);
    			perror(NULL);
    			exit(EXIT_FAILURE);
    		}
    	}
    
    	png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
    	if(png_ptr == NULL) {
    		fprintf(stderr, "Failed to initialize PNG writer.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	info_ptr = png_create_info_struct(png_ptr);
    	if(info_ptr == NULL) {
    		fprintf(stderr, "Failed to initialize PNG write.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if(setjmp(png_jmpbuf(png_ptr))) {
    		png_destroy_write_struct(&png_ptr, &info_ptr);
    		fprintf(stderr, "Failed to write PNG image.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if(type == PNG_TYPE) {
    		palette = (png_colorp) malloc(sizeof(png_color) * 2);
    		if(palette == NULL) {
    			fprintf(stderr, "Failed to allocate memory.\n");
    			exit(EXIT_FAILURE);
    		}
    		palette[0].red   = fg_color[0];
    		palette[0].green = fg_color[1];
    		palette[0].blue  = fg_color[2];
    		palette[1].red   = bg_color[0];
    		palette[1].green = bg_color[1];
    		palette[1].blue  = bg_color[2];
    		alpha_values[0] = fg_color[3];
    		alpha_values[1] = bg_color[3];
    		png_set_PLTE(png_ptr, info_ptr, palette, 2);
    		png_set_tRNS(png_ptr, info_ptr, alpha_values, 2, NULL);
    	}
    
    	png_init_io(png_ptr, fp);
    	if(type == PNG_TYPE) {
    		png_set_IHDR(png_ptr, info_ptr,
    				(unsigned int)realwidth, (unsigned int)realwidth,
    				1,
    				PNG_COLOR_TYPE_PALETTE,
    				PNG_INTERLACE_NONE,
    				PNG_COMPRESSION_TYPE_DEFAULT,
    				PNG_FILTER_TYPE_DEFAULT);
    	} else {
    		png_set_IHDR(png_ptr, info_ptr,
    				(unsigned int)realwidth, (unsigned int)realwidth,
    				8,
    				PNG_COLOR_TYPE_RGB_ALPHA,
    				PNG_INTERLACE_NONE,
    				PNG_COMPRESSION_TYPE_DEFAULT,
    				PNG_FILTER_TYPE_DEFAULT);
    	}
    	png_set_pHYs(png_ptr, info_ptr,
    			dpi * INCHES_PER_METER,
    			dpi * INCHES_PER_METER,
    			PNG_RESOLUTION_METER);
    	png_write_info(png_ptr, info_ptr);
    
    	if(type == PNG_TYPE) {
    	/* top margin */
    		memset(row, 0xff, (size_t)((realwidth + 7) / 8));
    		for(y = 0; y < margin * size; y++) {
    			png_write_row(png_ptr, row);
    		}
    
    		/* data */
    		p = qrcode->data;
    		for(y = 0; y < qrcode->width; y++) {
    			memset(row, 0xff, (size_t)((realwidth + 7) / 8));
    			q = row;
    			q += margin * size / 8;
    			bit = 7 - (margin * size % 8);
    			for(x = 0; x < qrcode->width; x++) {
    				for(xx = 0; xx < size; xx++) {
    					*q ^= (*p & 1) << bit;
    					bit--;
    					if(bit < 0) {
    						q++;
    						bit = 7;
    					}
    				}
    				p++;
    			}
    			for(yy = 0; yy < size; yy++) {
    				png_write_row(png_ptr, row);
    			}
    		}
    		/* bottom margin */
    		memset(row, 0xff, (size_t)((realwidth + 7) / 8));
    		for(y = 0; y < margin * size; y++) {
    			png_write_row(png_ptr, row);
    		}
    	} else {
    	/* top margin */
    		fillRow(row, realwidth, bg_color);
    		for(y = 0; y < margin * size; y++) {
    			png_write_row(png_ptr, row);
    		}
    
    		/* data */
    		p = qrcode->data;
    		for(y = 0; y < qrcode->width; y++) {
    			fillRow(row, realwidth, bg_color);
    			for(x = 0; x < qrcode->width; x++) {
    				for(xx = 0; xx < size; xx++) {
    					if(*p & 1) {
    						memcpy(&row[((margin + x) * size + xx) * 4], fg_color, 4);
    					}
    				}
    				p++;
    			}
    			for(yy = 0; yy < size; yy++) {
    				png_write_row(png_ptr, row);
    			}
    		}
    		/* bottom margin */
    		fillRow(row, realwidth, bg_color);
    		for(y = 0; y < margin * size; y++) {
    			png_write_row(png_ptr, row);
    		}
    	}
    
    	png_write_end(png_ptr, info_ptr);
    	png_destroy_write_struct(&png_ptr, &info_ptr);
    
    	fclose(fp);
    	free(row);
    	free(palette);
    
    	return 0;
    #else
    	fputs("PNG output is disabled at compile time. No output generated.\n", stderr);
    	return 0;
    #endif
    }
    
    static int writeEPS(const QRcode *qrcode, const char *outfile)
    {
    	FILE *fp;
    	unsigned char *row, *p;
    	int x, y, yy;
    	int realwidth;
    
    	fp = openFile(outfile);
    
    	realwidth = (qrcode->width + margin * 2) * size;
    	/* EPS file header */
    	fprintf(fp, "%%!PS-Adobe-2.0 EPSF-1.2\n"
    				"%%%%BoundingBox: 0 0 %d %d\n"
    				"%%%%Pages: 1 1\n"
    				"%%%%EndComments\n", realwidth, realwidth);
    	/* draw point */
    	fprintf(fp, "/p { "
    				"moveto "
    				"0 1 rlineto "
    				"1 0 rlineto "
    				"0 -1 rlineto "
    				"fill "
    				"} bind def\n");
    	/* set color */
    	fprintf(fp, "gsave\n");
    	fprintf(fp, "%f %f %f setrgbcolor\n",
    			(float)bg_color[0] / 255,
    			(float)bg_color[1] / 255,
    			(float)bg_color[2] / 255);
    	fprintf(fp, "%d %d scale\n", realwidth, realwidth);
    	fprintf(fp, "0 0 p\ngrestore\n");
    	fprintf(fp, "%f %f %f setrgbcolor\n",
    			(float)fg_color[0] / 255,
    			(float)fg_color[1] / 255,
    			(float)fg_color[2] / 255);
    	fprintf(fp, "%d %d scale\n", size, size);
    
    	/* data */
    	p = qrcode->data;
    	for(y = 0; y < qrcode->width; y++) {
    		row = (p+(y*qrcode->width));
    		yy = (margin + qrcode->width - y - 1);
    
    		for(x = 0; x < qrcode->width; x++) {
    			if(*(row+x)&0x1) {
    				fprintf(fp, "%d %d p ", margin + x,  yy);
    			}
    		}
    	}
    
    	fprintf(fp, "\n%%%%EOF\n");
    	fclose(fp);
    
    	return 0;
    }
    
    static void writeSVG_drawModules(FILE *fp, int x, int y, int width, const char* col, float opacity)
    {
    	if(svg_path) {
    		fprintf(fp, "M%d,%dh%d", x, y, width);
    	} else {
    		if(fg_color[3] != 255) {
    			fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\
    					"fill=\"#%s\" fill-opacity=\"%f\"/>\n",
    					x, y, width, col, opacity );
    		} else {
    			fprintf(fp, "\t\t\t<rect x=\"%d\" y=\"%d\" width=\"%d\" height=\"1\" "\
    					"fill=\"#%s\"/>\n",
    					x, y, width, col );
    		}
    	}
    }
    
    static int writeSVG(const QRcode *qrcode, const char *outfile)
    {
    	FILE *fp;
    	unsigned char *row, *p;
    	int x, y, x0, pen;
    	int symwidth, realwidth;
    	float scale;
    	char fg[7], bg[7];
    	float fg_opacity;
    	float bg_opacity;
    
    	fp = openFile(outfile);
    
    	scale = dpi * INCHES_PER_METER / 100.0;
    
    	symwidth = qrcode->width + margin * 2;
    	realwidth = symwidth * size;
    
    	snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1],  fg_color[2]);
    	snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1],  bg_color[2]);
    	fg_opacity = (float)fg_color[3] / 255;
    	bg_opacity = (float)bg_color[3] / 255;
    
    	/* XML declaration */
    	if (!inline_svg)
    		fputs( "<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?>\n", fp );
    
    	/* DTD
    	   No document type specified because "while a DTD is provided in [the SVG]
    	   specification, the use of DTDs for validating XML documents is known to
    	   be problematic. In particular, DTDs do not handle namespaces gracefully.
    	   It is *not* recommended that a DOCTYPE declaration be included in SVG
    	   documents."
    	   http://www.w3.org/TR/2003/REC-SVG11-20030114/intro.html#Namespace
    	*/
    
    	/* Vanity remark */
    	fprintf(fp, "<!-- Created with qrencode %s (https://fukuchi.org/works/qrencode/index.html) -->\n", QRcode_APIVersionString());
    
    	/* SVG code start */
    	fprintf(fp,
    			"<svg width=\"%.2fcm\" height=\"%.2fcm\" viewBox=\"0 0 %d %d\""\
    			" preserveAspectRatio=\"none\" version=\"1.1\""\
    			" xmlns=\"http://www.w3.org/2000/svg\">\n",
    			realwidth / scale, realwidth / scale, symwidth, symwidth
    		   );
    
    	/* Make named group */
    	fputs("\t<g id=\"QRcode\">\n", fp);
    
    	/* Make solid background */
    	if(bg_color[3] != 255) {
    		fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\" fill-opacity=\"%f\"/>\n", symwidth, symwidth, bg, bg_opacity);
    	} else {
    		fprintf(fp, "\t\t<rect x=\"0\" y=\"0\" width=\"%d\" height=\"%d\" fill=\"#%s\"/>\n", symwidth, symwidth, bg);
    	}
    
    	if(svg_path) {
    		if(fg_color[3] != 255) {
    			fprintf(fp, "\t\t<path style=\"stroke:#%s;stroke-opacity:%f\" transform=\"translate(%d,%d.5)\" d=\"", fg, fg_opacity, margin, margin);
    		} else {
    			fprintf(fp, "\t\t<path style=\"stroke:#%s\" transform=\"translate(%d,%d.5)\" d=\"", fg, margin, margin);
    		}
    	} else {
    		/* Create new viewbox for QR data */
    		fprintf(fp, "\t\t<g id=\"Pattern\" transform=\"translate(%d,%d)\">\n", margin, margin);
    	}
    
    	/* Write data */
    	p = qrcode->data;
    	for(y = 0; y < qrcode->width; y++) {
    		row = (p+(y*qrcode->width));
    
    		if( !rle ) {
    			/* no RLE */
    			for(x = 0; x < qrcode->width; x++) {
    				if(*(row+x)&0x1) {
    					writeSVG_drawModules(fp, x, y, 1, fg, fg_opacity);
    				}
    			}
    		} else {
    			/* simple RLE */
    			pen = 0;
    			x0  = 0;
    			for(x = 0; x < qrcode->width; x++) {
    				if( !pen ) {
    					pen = *(row+x)&0x1;
    					x0 = x;
    				} else if(!(*(row+x)&0x1)) {
    					writeSVG_drawModules(fp, x0, y, x-x0, fg, fg_opacity);
    					pen = 0;
    				}
    			}
    			if( pen ) {
    				writeSVG_drawModules(fp, x0, y, qrcode->width - x0, fg, fg_opacity);
    			}
    		}
    	}
    
    	if(svg_path) {
    		fputs("\"/>\n", fp);
    	} else {
    		/* Close QR data viewbox */
    		fputs("\t\t</g>\n", fp);
    	}
    
    	/* Close group */
    	fputs("\t</g>\n", fp);
    
    	/* Close SVG code */
    	fputs("</svg>\n", fp);
    	fclose(fp);
    
    	return 0;
    }
    
    static int writeXPM(const QRcode *qrcode, const char *outfile)
    {
    	FILE *fp;
    	int x, xx, y, yy, realwidth, realmargin;
    	char *row;
    	char fg[7], bg[7];
    	unsigned char *p;
    
    	fp = openFile(outfile);
    
    	realwidth = (qrcode->width + margin * 2) * size;
    	realmargin = margin * size;
    
    	row = malloc((size_t)realwidth + 1);
    	if (!row ) {
    		fprintf(stderr, "Failed to allocate memory.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	snprintf(fg, 7, "%02x%02x%02x", fg_color[0], fg_color[1],  fg_color[2]);
    	snprintf(bg, 7, "%02x%02x%02x", bg_color[0], bg_color[1],  bg_color[2]);
    
    	fputs("/* XPM */\n", fp);
    	fputs("static const char *const qrcode_xpm[] = {\n", fp);
    	fputs("/* width height ncolors chars_per_pixel */\n", fp);
    	fprintf(fp, "\"%d %d 2 1\",\n", realwidth, realwidth);
    
    	fputs("/* colors */\n", fp);
    	fprintf(fp, "\"F c #%s\",\n", fg);
    	fprintf(fp, "\"B c #%s\",\n", bg);
    
    	fputs("/* pixels */\n", fp);
    	memset(row, 'B', (size_t)realwidth);
    	row[realwidth] = '\0';
    
    	for (y = 0; y < realmargin; y++) {
    		fprintf(fp, "\"%s\",\n", row);
    	}
    
    	p = qrcode->data;
    	for (y = 0; y < qrcode->width; y++) {
    		for (yy = 0; yy < size; yy++) {
    			fputs("\"", fp);
    
    			for (x = 0; x < margin; x++) {
    				for (xx = 0; xx < size; xx++) {
    					fputs("B", fp);
    				}
    			}
    
    			for (x = 0; x < qrcode->width; x++) {
    				for (xx = 0; xx < size; xx++) {
    					if (p[(y * qrcode->width) + x] & 0x1) {
    						fputs("F", fp);
    					} else {
    						fputs("B", fp);
    					}
    				}
    			}
    
    			for (x = 0; x < margin; x++) {
    				for (xx = 0; xx < size; xx++) {
    					fputs("B", fp);
    				}
    			}
    
    			fputs("\",\n", fp);
    		}
    	}
    
    	for (y = 0; y < realmargin; y++) {
    		fprintf(fp, "\"%s\"%s\n", row, y < (size - 1) ? "," : "};");
    	}
    
    	free(row);
    	fclose(fp);
    
    	return 0;
    }
    
    static void writeANSI_margin(FILE* fp, int realwidth,
                                 char* buffer, const char* white, int white_s )
    {
    	int y;
    
    	strncpy(buffer, white, (size_t)white_s);
    	memset(buffer + white_s, ' ', (size_t)realwidth * 2);
    	strcpy(buffer + white_s + realwidth * 2, "\033[0m\n"); // reset to default colors
    	for(y = 0; y < margin; y++ ){
    		fputs(buffer, fp);
    	}
    }
    
    static int writeANSI(const QRcode *qrcode, const char *outfile)
    {
    	FILE *fp;
    	unsigned char *row, *p;
    	int x, y;
    	int realwidth;
    	int last;
    
    	const char *white, *black;
    	char *buffer;
    	int white_s, black_s, buffer_s;
    
    	if(image_type == ANSI256_TYPE){
    		/* codes for 256 color compatible terminals */
    		white = "\033[48;5;231m";
    		white_s = 11;
    		black = "\033[48;5;16m";
    		black_s = 10;
    	} else {
    		white = "\033[47m";
    		white_s = 5;
    		black = "\033[40m";
    		black_s = 5;
    	}
    
    	size = 1;
    
    	fp = openFile(outfile);
    
    	realwidth = (qrcode->width + margin * 2) * size;
    	buffer_s = (realwidth * white_s) * 2;
    	buffer = (char *)malloc((size_t)buffer_s);
    	if(buffer == NULL) {
    		fprintf(stderr, "Failed to allocate memory.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	/* top margin */
    	writeANSI_margin(fp, realwidth, buffer, white, white_s);
    
    	/* data */
    	p = qrcode->data;
    	for(y = 0; y < qrcode->width; y++) {
    		row = (p+(y*qrcode->width));
    
    		memset(buffer, 0, (size_t)buffer_s);
    		strncpy(buffer, white, (size_t)white_s);
    		for(x = 0; x < margin; x++ ){
    			strncat(buffer, "  ", 2);
    		}
    		last = 0;
    
    		for(x = 0; x < qrcode->width; x++) {
    			if(*(row+x)&0x1) {
    				if( last != 1 ){
    					strncat(buffer, black, (size_t)black_s);
    					last = 1;
    				}
    			} else if( last != 0 ){
    				strncat(buffer, white, (size_t)white_s);
    				last = 0;
    			}
    			strncat(buffer, "  ", 2);
    		}
    
    		if( last != 0 ){
    			strncat(buffer, white, (size_t)white_s);
    		}
    		for(x = 0; x < margin; x++ ){
    			strncat(buffer, "  ", 2);
    		}
    		strncat(buffer, "\033[0m\n", 5);
    		fputs(buffer, fp);
    	}
    
    	/* bottom margin */
    	writeANSI_margin(fp, realwidth, buffer, white, white_s);
    
    	fclose(fp);
    	free(buffer);
    
    	return 0;
    }
    
    static void writeUTF8_margin(FILE* fp, int realwidth, const char* white,
                                 const char *reset, const char* full)
    {
    	int x, y;
    
    	for (y = 0; y < margin/2; y++) {
    		fputs(white, fp);
    		for (x = 0; x < realwidth; x++)
    			fputs(full, fp);
    		fputs(reset, fp);
    		fputc('\n', fp);
    	}
    }
    
    static int writeUTF8(const QRcode *qrcode, const char *outfile, int use_ansi, int invert)
    {
    	FILE *fp;
    	int x, y;
    	int realwidth;
    	const char *white, *reset;
    	const char *empty, *lowhalf, *uphalf, *full;
    
    	empty = " ";
    	lowhalf = "\342\226\204";
    	uphalf = "\342\226\200";
    	full = "\342\226\210";
    
    	if (invert) {
    		const char *tmp;
    
    		tmp = empty;
    		empty = full;
    		full = tmp;
    
    		tmp = lowhalf;
    		lowhalf = uphalf;
    		uphalf = tmp;
    	}
    
    	if (use_ansi){
    		if (use_ansi == 2) {
    			white = "\033[38;5;231m\033[48;5;16m";
    		} else {
    			white = "\033[40;37;1m";
    		}
    		reset = "\033[0m";
    	} else {
    		white = "";
    		reset = "";
    	}
    
    	fp = openFile(outfile);
    
    	realwidth = (qrcode->width + margin * 2);
    
    	/* top margin */
    	writeUTF8_margin(fp, realwidth, white, reset, full);
    
    	/* data */
    	for(y = 0; y < qrcode->width; y += 2) {
    		unsigned char *row1, *row2;
    		row1 = qrcode->data + y*qrcode->width;
    		row2 = row1 + qrcode->width;
    
    		fputs(white, fp);
    
    		for (x = 0; x < margin; x++) {
    			fputs(full, fp);
    		}
    
    		for (x = 0; x < qrcode->width; x++) {
    			if(row1[x] & 1) {
    				if(y < qrcode->width - 1 && row2[x] & 1) {
    					fputs(empty, fp);
    				} else {
    					fputs(lowhalf, fp);
    				}
    			} else if(y < qrcode->width - 1 && row2[x] & 1) {
    				fputs(uphalf, fp);
    			} else {
    				fputs(full, fp);
    			}
    		}
    
    		for (x = 0; x < margin; x++)
    			fputs(full, fp);
    
    		fputs(reset, fp);
    		fputc('\n', fp);
    	}
    
    	/* bottom margin */
    	writeUTF8_margin(fp, realwidth, white, reset, full);
    
    	fclose(fp);
    
    	return 0;
    }
    
    static void writeASCII_margin(FILE* fp, int realwidth, char* buffer, int invert)
    {
    	int y, h;
    
    	h = margin;
    
    	memset(buffer, (invert?'#':' '), (size_t)realwidth);
    	buffer[realwidth] = '\n';
    	buffer[realwidth + 1] = '\0';
    	for(y = 0; y < h; y++ ){
    		fputs(buffer, fp);
    	}
    }
    
    static int writeASCII(const QRcode *qrcode, const char *outfile, int invert)
    {
    	FILE *fp;
    	unsigned char *row;
    	int x, y;
    	int realwidth;
    	char *buffer, *p;
    	int buffer_s;
    	char black = '#';
    	char white = ' ';
    
    	if(invert) {
    		black = ' ';
    		white = '#';
    	}
    
    	size = 1;
    
    	fp = openFile(outfile);
    
    	realwidth = (qrcode->width + margin * 2) * 2;
    	buffer_s = realwidth + 2;
    	buffer = (char *)malloc((size_t)buffer_s);
    	if(buffer == NULL) {
    		fprintf(stderr, "Failed to allocate memory.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	/* top margin */
    	writeASCII_margin(fp, realwidth, buffer, invert);
    
    	/* data */
    	for(y = 0; y < qrcode->width; y++) {
    		row = qrcode->data+(y*qrcode->width);
    		p = buffer;
    
    		memset(p, white, (size_t)margin * 2);
    		p += margin * 2;
    
    		for(x = 0; x < qrcode->width; x++) {
    			if(row[x]&0x1) {
    				*p++ = black;
    				*p++ = black;
    			} else {
    				*p++ = white;
    				*p++ = white;
    			}
    		}
    
    		memset(p, white, (size_t)margin * 2);
    		p += margin * 2;
    		*p++ = '\n';
    		*p++ = '\0';
    		fputs( buffer, fp );
    	}
    
    	/* bottom margin */
    	writeASCII_margin(fp, realwidth, buffer, invert);
    
    	fclose(fp);
    	free(buffer);
    
    	return 0;
    }
    
    static QRcode *encode(const unsigned char *intext, int length)
    {
    	QRcode *code;
    
    	if(micro) {
    		if(eightbit) {
    			code = QRcode_encodeDataMQR(length, intext, version, level);
    		} else {
    			code = QRcode_encodeStringMQR((char *)intext, version, level, hint, casesensitive);
    		}
    	} else if(eightbit) {
    		code = QRcode_encodeData(length, intext, version, level);
    	} else {
    		code = QRcode_encodeString((char *)intext, version, level, hint, casesensitive);
    	}
    
    	return code;
    }
    
    static void qrencode(const unsigned char *intext, int length, const char *outfile)
    {
    	QRcode *qrcode;
    
    	qrcode = encode(intext, length);
    	if(qrcode == NULL) {
    		if(errno == ERANGE) {
    			fprintf(stderr, "Failed to encode the input data: Input data too large\n");
    		} else {
    			perror("Failed to encode the input data");
    		}
    		exit(EXIT_FAILURE);
    	}
    	if(strict_versioning && version > 0 && qrcode->version != version) {
    		fprintf(stderr, "Failed to encode the input data: Input data too large\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if(verbose) {
    		fprintf(stderr, "File: %s, Version: %d\n", (outfile!=NULL)?outfile:"(stdout)", qrcode->version);
    	}
    
    	switch(image_type) {
    		case PNG_TYPE:
    		case PNG32_TYPE:
    			writePNG(qrcode, outfile, image_type);
    			break;
    		case EPS_TYPE:
    			writeEPS(qrcode, outfile);
    			break;
    		case SVG_TYPE:
    			writeSVG(qrcode, outfile);
    			break;
    		case XPM_TYPE:
    			writeXPM(qrcode, outfile);
    			break;
    		case ANSI_TYPE:
    		case ANSI256_TYPE:
    			writeANSI(qrcode, outfile);
    			break;
    		case ASCIIi_TYPE:
    			writeASCII(qrcode, outfile,  1);
    			break;
    		case ASCII_TYPE:
    			writeASCII(qrcode, outfile,  0);
    			break;
    		case UTF8_TYPE:
    			writeUTF8(qrcode, outfile, 0, 0);
    			break;
    		case ANSIUTF8_TYPE:
    			writeUTF8(qrcode, outfile, 1, 0);
    			break;
    		case ANSI256UTF8_TYPE:
    			writeUTF8(qrcode, outfile, 2, 0);
    			break;
    		case UTF8i_TYPE:
    			writeUTF8(qrcode, outfile, 0, 1);
    			break;
    		case ANSIUTF8i_TYPE:
    			writeUTF8(qrcode, outfile, 1, 1);
    			break;
    		default:
    			fprintf(stderr, "Unknown image type.\n");
    			exit(EXIT_FAILURE);
    	}
    
    	QRcode_free(qrcode);
    }
    
    static QRcode_List *encodeStructured(const unsigned char *intext, int length)
    {
    	QRcode_List *list;
    
    	if(eightbit) {
    		list = QRcode_encodeDataStructured(length, intext, version, level);
    	} else {
    		list = QRcode_encodeStringStructured((char *)intext, version, level, hint, casesensitive);
    	}
    
    	return list;
    }
    
    static void qrencodeStructured(const unsigned char *intext, int length, const char *outfile)
    {
    	QRcode_List *qrlist, *p;
    	char filename[FILENAME_MAX];
    	char *base, *q, *suffix = NULL;
    	const char *type_suffix;
    	int i = 1;
    	size_t suffix_size;
    
    	switch(image_type) {
    		case PNG_TYPE:
    			type_suffix = ".png";
    			break;
    		case EPS_TYPE:
    			type_suffix = ".eps";
    			break;
    		case SVG_TYPE:
    			type_suffix = ".svg";
    			break;
    		case XPM_TYPE:
    			type_suffix = ".xpm";
    			break;
    		case ANSI_TYPE:
    		case ANSI256_TYPE:
    		case ASCII_TYPE:
    		case UTF8_TYPE:
    		case ANSIUTF8_TYPE:
    		case UTF8i_TYPE:
    		case ANSIUTF8i_TYPE:
    			type_suffix = ".txt";
    			break;
    		default:
    			fprintf(stderr, "Unknown image type.\n");
    			exit(EXIT_FAILURE);
    	}
    
    	if(outfile == NULL) {
    		fprintf(stderr, "An output filename must be specified to store the structured images.\n");
    		exit(EXIT_FAILURE);
    	}
    	base = strdup(outfile);
    	if(base == NULL) {
    		fprintf(stderr, "Failed to allocate memory.\n");
    		exit(EXIT_FAILURE);
    	}
    	suffix_size = strlen(type_suffix);
    	if(strlen(base) > suffix_size) {
    		q = base + strlen(base) - suffix_size;
    		if(strcasecmp(type_suffix, q) == 0) {
    			suffix = strdup(q);
    			*q = '\0';
    		}
    	}
    
    	qrlist = encodeStructured(intext, length);
    	if(qrlist == NULL) {
    		if(errno == ERANGE) {
    			fprintf(stderr, "Failed to encode the input data: Input data too large\n");
    		} else {
    			perror("Failed to encode the input data");
    		}
    		exit(EXIT_FAILURE);
    	}
    
    	for(p = qrlist; p != NULL; p = p->next) {
    		if(p->code == NULL) {
    			fprintf(stderr, "Failed to encode the input data.\n");
    			exit(EXIT_FAILURE);
    		}
    		if(suffix) {
    			snprintf(filename, FILENAME_MAX, "%s-%02d%s", base, i, suffix);
    		} else {
    			snprintf(filename, FILENAME_MAX, "%s-%02d", base, i);
    		}
    
    		if(verbose) {
    			fprintf(stderr, "File: %s, Version: %d\n", filename, p->code->version);
    		}
    
    		switch(image_type) {
    			case PNG_TYPE:
    			case PNG32_TYPE:
    				writePNG(p->code, filename, image_type);
    				break;
    			case EPS_TYPE:
    				writeEPS(p->code, filename);
    				break;
    			case SVG_TYPE:
    				writeSVG(p->code, filename);
    				break;
    			case XPM_TYPE:
    				writeXPM(p->code, filename);
    				break;
    			case ANSI_TYPE:
    			case ANSI256_TYPE:
    				writeANSI(p->code, filename);
    				break;
    			case ASCIIi_TYPE:
    				writeASCII(p->code, filename, 1);
    				break;
    			case ASCII_TYPE:
    				writeASCII(p->code, filename, 0);
    				break;
    			case UTF8_TYPE:
    				writeUTF8(p->code, filename, 0, 0);
    				break;
    			case ANSIUTF8_TYPE:
    				writeUTF8(p->code, filename, 0, 0);
    				break;
    			case ANSI256UTF8_TYPE:
    				writeUTF8(p->code, filename, 0, 0);
    				break;
    			case UTF8i_TYPE:
    				writeUTF8(p->code, filename, 0, 1);
    				break;
    			case ANSIUTF8i_TYPE:
    				writeUTF8(p->code, filename, 0, 1);
    				break;
    
    			default:
    				fprintf(stderr, "Unknown image type.\n");
    				exit(EXIT_FAILURE);
    		}
    		i++;
    	}
    
    	free(base);
    	if(suffix) {
    		free(suffix);
    	}
    
    	QRcode_List_free(qrlist);
    }
    
    int main(int argc, char **argv)
    {
    	int opt, lindex = -1;
    	char *outfile = NULL, *infile = NULL;
    	unsigned char *intext = NULL;
    	int length = 0;
    	FILE *fp;
    
    	while((opt = getopt_long(argc, argv, optstring, options, &lindex)) != -1) {
    		switch(opt) {
    			case 'h':
    				if(lindex == 0) {
    					usage(1, 1, EXIT_SUCCESS);
    				} else {
    					usage(1, 0, EXIT_SUCCESS);
    				}
    				exit(EXIT_SUCCESS);
    			case 'o':
    				outfile = optarg;
    				break;
    			case 'r':
    				infile = optarg;
    				break;
    			case 's':
    				size = atoi(optarg);
    				if(size <= 0) {
    					fprintf(stderr, "Invalid size: %d\n", size);
    					exit(EXIT_FAILURE);
    				}
    				break;
    			case 'v':
    				version = atoi(optarg);
    				if(version < 0) {
    					fprintf(stderr, "Invalid version: %d\n", version);
    					exit(EXIT_FAILURE);
    				}
    				break;
    			case 'l':
    				switch(*optarg) {
    					case 'l':
    					case 'L':
    						level = QR_ECLEVEL_L;
    						break;
    					case 'm':
    					case 'M':
    						level = QR_ECLEVEL_M;
    						break;
    					case 'q':
    					case 'Q':
    						level = QR_ECLEVEL_Q;
    						break;
    					case 'h':
    					case 'H':
    						level = QR_ECLEVEL_H;
    						break;
    					default:
    						fprintf(stderr, "Invalid level: %s\n", optarg);
    						exit(EXIT_FAILURE);
    				}
    				break;
    			case 'm':
    				margin = atoi(optarg);
    				if(margin < 0) {
    					fprintf(stderr, "Invalid margin: %d\n", margin);
    					exit(EXIT_FAILURE);
    				}
    				break;
    			case 'd':
    				dpi = atoi(optarg);
    				if( dpi < 0 ) {
    					fprintf(stderr, "Invalid DPI: %d\n", dpi);
    					exit(EXIT_FAILURE);
    				}
    				break;
    			case 't':
    				if(strcasecmp(optarg, "png32") == 0) {
    					image_type = PNG32_TYPE;
    				} else if(strcasecmp(optarg, "png") == 0) {
    					image_type = PNG_TYPE;
    				} else if(strcasecmp(optarg, "eps") == 0) {
    					image_type = EPS_TYPE;
    				} else if(strcasecmp(optarg, "svg") == 0) {
    					image_type = SVG_TYPE;
    				} else if(strcasecmp(optarg, "xpm") == 0) {
    					image_type = XPM_TYPE;
    				} else if(strcasecmp(optarg, "ansi") == 0) {
    					image_type = ANSI_TYPE;
    				} else if(strcasecmp(optarg, "ansi256") == 0) {
    					image_type = ANSI256_TYPE;
    				} else if(strcasecmp(optarg, "asciii") == 0) {
    					image_type = ASCIIi_TYPE;
    				} else if(strcasecmp(optarg, "ascii") == 0) {
    					image_type = ASCII_TYPE;
    				} else if(strcasecmp(optarg, "utf8") == 0) {
    					image_type = UTF8_TYPE;
    				} else if(strcasecmp(optarg, "ansiutf8") == 0) {
    					image_type = ANSIUTF8_TYPE;
    				} else if(strcasecmp(optarg, "ansi256utf8") == 0) {
    					image_type = ANSI256UTF8_TYPE;
    				} else if(strcasecmp(optarg, "utf8i") == 0) {
    					image_type = UTF8i_TYPE;
    				} else if(strcasecmp(optarg, "ansiutf8i") == 0) {
    					image_type = ANSIUTF8i_TYPE;
    				} else {
    					fprintf(stderr, "Invalid image type: %s\n", optarg);
    					exit(EXIT_FAILURE);
    				}
    				break;
    			case 'S':
    				structured = 1;
    				break;
    			case 'k':
    				hint = QR_MODE_KANJI;
    				break;
    			case 'c':
    				casesensitive = 1;
    				break;
    			case 'i':
    				casesensitive = 0;
    				break;
    			case '8':
    				eightbit = 1;
    				break;
    			case 'M':
    				micro = 1;
    				break;
    			case 'f':
    				if(color_set(fg_color, optarg)) {
    					fprintf(stderr, "Invalid foreground color value.\n");
    					exit(EXIT_FAILURE);
    				}
    				break;
    			case 'b':
    				if(color_set(bg_color, optarg)) {
    					fprintf(stderr, "Invalid background color value.\n");
    					exit(EXIT_FAILURE);
    				}
    				break;
    			case 'V':
    				usage(0, 0, EXIT_SUCCESS);
    				exit(EXIT_SUCCESS);
    			case 0:
    				break;
    			default:
    				fprintf(stderr, "Try \"qrencode --help\" for more information.\n");
    				exit(EXIT_FAILURE);
    		}
    	}
    
    	if(argc == 1) {
    		usage(1, 0, EXIT_FAILURE);
    		exit(EXIT_FAILURE);
    	}
    
    	if(outfile == NULL && image_type == PNG_TYPE) {
    		fprintf(stderr, "No output filename is given.\n");
    		exit(EXIT_FAILURE);
    	}
    
    	if(optind < argc) {
    		intext = (unsigned char *)argv[optind];
    		length = strlen((char *)intext);
    	}
    	if(intext == NULL) {
    		fp = infile == NULL ? stdin : fopen(infile,"r");
    		if(fp == 0) {
    			fprintf(stderr, "Cannot read input file %s.\n", infile);
    			exit(EXIT_FAILURE);
    		}
    		intext = readFile(fp,&length);
    
    	}
    
    	if(micro && version > MQRSPEC_VERSION_MAX) {
    		fprintf(stderr, "Version number should be less or equal to %d.\n", MQRSPEC_VERSION_MAX);
    		exit(EXIT_FAILURE);
    	} else if(!micro && version > QRSPEC_VERSION_MAX) {
    		fprintf(stderr, "Version number should be less or equal to %d.\n", QRSPEC_VERSION_MAX);
    		exit(EXIT_FAILURE);
    	}
    
    	if(margin < 0) {
    		if(micro) {
    			margin = 2;
    		} else {
    			margin = 4;
    		}
    	}
    
    	if(micro) {
    		if(structured) {
    			fprintf(stderr, "Micro QR Code does not support structured symbols.\n");
    			exit(EXIT_FAILURE);
    		}
    	}
    
    	if(structured) {
    		if(version == 0) {
    			fprintf(stderr, "Version number must be specified to encode structured symbols.\n");
    			exit(EXIT_FAILURE);
    		}
    		qrencodeStructured(intext, length, outfile);
    	} else {
    		qrencode(intext, length, outfile);
    	}
    
    	return 0;
    }