/* text-png.c by Michael J. Fromberger Copyright (C) 2002 The Trustees of Dartmouth College Convert a one-line text message into a small human-readable PNG file suitable for use on a web page. Usage: text-png [options] Options: --output=file Write output to this file (default "textN.png") --fgcolor=color Set foreground (text) colour to this value (df. black) --bgcolor=color Set background colour to this value (df. white) --serif Use a serif font (df. no) --size=sz Use this point size (df. 12pt) $Id: text-png.c,v 1.3 2004/08/16 14:46:37 sting Exp $ */ #include #include #include #include #include #include #include "gd.h" #include #ifdef HAS_GNU_GETOPT #include struct option g_opts[] = { { "output", 1, 0, 'o' }, { "fgcolor", 1, 0, 'f' }, { "bgcolor", 1, 0, 'b' }, { "serif", 0, 0, 's' }, { "size", 1, 0, 'z' }, { NULL, 0, 0, 0 } }; #endif char *g_optstr = "o:f:b:sz:"; /* short option equivalents */ char *g_serif = "/usr/X11R6/lib/X11/fonts/TTF/VeraSe.ttf"; char *g_sans = "/usr/X11R6/lib/X11/fonts/TTF/Vera.ttf"; double g_size = 12.0; /* default is 12.0 points */ char *g_font; FILE *open_file(char *name, char *mode); int parse_color(char *str, int *r, int *g, int *b); int hex_val(char c); int main(int argc, char *argv[]) { gdImagePtr image; int bgcolor, fgcolor; int bounds[8]; /* will tell us how big the image needs be */ int wid, hgt, x, y, opt; int fgR, fgG, fgB, bgR, bgG, bgB; char *res; /* result from FreeType */ FILE *ofp = NULL; g_font = g_sans; /* default font is sans-serif */ /* Set default colours to black and white */ fgR = fgG = fgB = 0; bgR = bgG = bgB = 255; /* Process command-line options, if any */ #ifdef HAS_GNU_GETOPT while((opt = getopt_long_only(argc, argv, g_optstr, g_opts, NULL)) >= 0) { #else while((opt = getopt(argc, argv, g_optstr)) >= 0) { #endif switch(opt) { case 'o': /* send output to specified file */ if((ofp = open_file(optarg, "wb")) == NULL) { fprintf(stderr, "%s: opening '%s': %s\n", argv[0], optarg, strerror(errno)); return 1; } break; case 'f': /* set foreground colour */ if(!parse_color(optarg, &fgR, &fgG, &fgB)) { fprintf(stderr, "%s: invalid foreground color: %s\n", argv[0], optarg); return 1; } break; case 'b': /* set background colour */ if(!parse_color(optarg, &bgR, &bgG, &bgB)) { fprintf(stderr, "%s: invalid background color: %s\n", argv[0], optarg); return 1; } break; case 's': /* use a serif font for output */ g_font = g_serif; break; case 'z': /* set point size */ if((g_size = atof(optarg)) <= 0.0) { fprintf(stderr, "%s: invalid point size specified\n", argv[0]); return 1; } break; default: #ifdef HAS_GNU_GETOPT fprintf(stderr, "Usage: %s [options] \n" "Options:\n" " --output=file : specify output file\n" " --fgcolor=color : specify text colour\n" " --bgcolor=color : specify background colour\n" " --serif : use a serif font\n" " --size=pts : set font size in points\n\n", argv[0]); #else fprintf(stderr, "Usage: %s [options] \n" "Options:\n" " -o file : specify output file\n" " -f color : specify text colour\n" " -b color : specify background colour\n" " -s : use a serif font\n" " -z pts : set font size in points\n\n", argv[0]); #endif return 1; } } /* You have to provide a message */ if(optind >= argc) { fprintf(stderr, "Usage: %s [options] \n", argv[0]); return 1; } /* Compute the image bounds needed to draw the string */ if((res = gdImageStringFT(NULL, bounds, 0, g_font, g_size, 0.0, 0, 0, argv[optind])) != NULL) { fprintf(stderr, "%s: error bounding message: %s\n", argv[0], res); return 1; } wid = bounds[2] - bounds[6] + 6; hgt = bounds[3] - bounds[7] + 6; image = gdImageCreate(wid, hgt); bgcolor = gdImageColorResolve(image, bgR, bgG, bgB); fgcolor = gdImageColorResolve(image, fgR, fgG, fgB); /* Compute starting position for text drawing */ x = 3 - bounds[6]; y = 3 - bounds[7]; /* Draw the actual image this time (should go fast, since GD caches the rendering that was done the first time) */ if((res = gdImageStringFT(image, bounds, fgcolor, g_font, g_size, 0.0, x, y, argv[optind])) != NULL) { fprintf(stderr, "%s: error generating image: %s\n", argv[0], res); return 1; } /* If the user didn't specify an output file, make one up */ if(ofp == NULL) { if((ofp = open_file(NULL, "wb")) == NULL) { fprintf(stderr, "%s: unable to open output file, sorry\n", argv[0]); return 1; } } /* Write out the results as a PNG file */ gdImagePng(image, ofp); fclose(ofp); /* Clean up... */ gdImageDestroy(image); return 0; } /* {{{ open_file(name, mode) */ FILE *open_file(char *name, char *mode) { static char fnbuf[64]; if(name == NULL) { FILE *res; int try; for(try = 1; try < 100; ++try) { sprintf(fnbuf, "text%d.png", try); if((res = fopen(fnbuf, "r")) == NULL) return fopen(fnbuf, mode); fclose(res); } return NULL; /* no name found */ } return fopen(name, mode); } /* }}} */ /* {{{ parse_color(str, r, g, b) */ int parse_color(char *str, int *r, int *g, int *b) { int ix; if(strlen(str) != 6) return 0; for(ix = 0; ix < 6; ++ix) { if(!isxdigit((int)str[ix])) return 0; } *r = hex_val(str[0]) * 16 + hex_val(str[1]); *g = hex_val(str[2]) * 16 + hex_val(str[3]); *b = hex_val(str[4]) * 16 + hex_val(str[5]); return 1; } /* }}} */ /* {{{ hex_val(c) */ int hex_val(char c) { if(isdigit((int)c)) return c - '0'; else return tolower((int)c) - 'a' + 10; } /* }}} */