/*
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;
}
/* }}} */