From 1fd361a1ea06e44286c213ca1f814f49306fdc43 Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sat, 19 Aug 2006 03:12:28 +0000 Subject: Create Subversion repository git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- generator/pbmtextps.c | 377 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 377 insertions(+) create mode 100644 generator/pbmtextps.c (limited to 'generator/pbmtextps.c') diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c new file mode 100644 index 00000000..ef8ae008 --- /dev/null +++ b/generator/pbmtextps.c @@ -0,0 +1,377 @@ +/* + * pbmtextps.c - render text into a bitmap using a postscript interpreter + * + * Copyright (C) 2002 by James McCann. + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, provided + * that the above copyright notice appear in all copies and that both that + * copyright notice and this permission notice appear in supporting + * documentation. This software is provided "as is" without express or + * implied warranty. + * + * PostScript is a registered trademark of Adobe Systems International. + * + * Additions by Bryan Henderson contributed to public domain by author. + * + */ +#define _XOPEN_SOURCE /* Make sure popen() is in stdio.h */ +#define _BSD_SOURCE /* Make sure stdrup() is in string.h */ +#include +#include +#include +#include +#include "pbm.h" +#include "nstring.h" +#include "shhopt.h" + + +#define BUFFER_SIZE 2048 + +static const char *gs_exe_path = +#ifdef GHOSTSCRIPT_EXECUTABLE_PATH +GHOSTSCRIPT_EXECUTABLE_PATH; +#else +0; +#endif + +static const char *pnmcrop_exe_path = +#ifdef PNMCROP_EXECUTABLE_PATH +PNMCROP_EXECUTABLE_PATH; +#else +0; +#endif + +struct cmdlineInfo { + /* All the information the user supplied in the command line, + in a form easy for the program to use. + */ + int res; /* resolution, DPI */ + int fontsize; /* Size of font in points */ + const char * font; /* Name of postscript font */ + float stroke; + /* Width of stroke in points (only for outline font) */ + unsigned int verbose; + const char * text; +}; + + + +static void +parseCommandLine(int argc, char ** argv, + struct cmdlineInfo *cmdlineP) { +/*--------------------------------------------------------------------------- + Note that the file spec array we return is stored in the storage that + was passed to us as the argv array. +---------------------------------------------------------------------------*/ + optEntry *option_def = malloc(100*sizeof(optEntry)); + /* Instructions to OptParseOptions2 on how to parse our options. + */ + optStruct3 opt; + + unsigned int option_def_index; + int i; + char * text; + int totaltextsize = 0; + + option_def_index = 0; /* incremented by OPTENTRY */ + OPTENT3(0, "resolution", OPT_INT, &cmdlineP->res, NULL, 0); + OPTENT3(0, "font", OPT_STRING, &cmdlineP->font, NULL, 0); + OPTENT3(0, "fontsize", OPT_INT, &cmdlineP->fontsize, NULL, 0); + OPTENT3(0, "stroke", OPT_FLOAT, &cmdlineP->stroke, NULL, 0); + OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); + + /* Set the defaults */ + cmdlineP->res = 150; + cmdlineP->fontsize = 24; + cmdlineP->font = "Times-Roman"; + cmdlineP->stroke = -1; + + opt.opt_table = option_def; + opt.short_allowed = FALSE; /* We have no short (old-fashioned) options */ + opt.allowNegNum = FALSE; + + optParseOptions3(&argc, argv, opt, sizeof(opt), 0); + + text = NULL; + + for (i = 1; i < argc; i++) { + if (i > 1) { + totaltextsize += 1; + text = realloc(text, totaltextsize); + if (text == NULL) + pm_error("out of memory"); + strcat(text, " "); + } + totaltextsize += strlen(argv[i]); + text = realloc(text, totaltextsize); + if (text == NULL) + pm_error("out of memory"); + strcat(text, argv[i]); + } + cmdlineP->text = text; +} + + + +static const char * +construct_postscript(struct cmdlineInfo const cmdl) { + + const char * retval; + const char * template; + + if (cmdl.stroke <= 0) + template = "/%s findfont\n%d scalefont\nsetfont\n12 36 moveto\n" + "(%s) show\nshowpage\n"; + else + template = "/%s findfont\n%d scalefont\nsetfont\n12 36 moveto\n" + "%f setlinewidth\n0 setgray\n" + "(%s) true charpath\nstroke\nshowpage\n"; + + if (cmdl.stroke < 0) + asprintfN(&retval, template, cmdl.font, cmdl.fontsize, + cmdl.text); + else + asprintfN(&retval, template, cmdl.font, cmdl.fontsize, + cmdl.stroke, cmdl.text); + + return retval; +} + + + +static const char * +gs_executable_name() +{ + static char buffer[BUFFER_SIZE]; + if(! gs_exe_path) { + const char * const which = "which gs"; + FILE *f; + memset(buffer, 0, BUFFER_SIZE); + if(!(f = popen(which, "r"))) + pm_error("Can't find ghostscript"); + fread(buffer, 1, BUFFER_SIZE, f); + if(buffer[strlen(buffer) - 1] == '\n') + buffer[strlen(buffer) - 1] = 0; + pclose(f); + if(buffer[0] != '/' && buffer[0] != '.') + pm_error("Can't find ghostscript"); + } + else + strcpy(buffer, gs_exe_path); + + return buffer; +} + + + +static const char * +crop_executable_name() +{ + static char buffer[BUFFER_SIZE]; + if(! pnmcrop_exe_path) { + const char * const which = "which pnmcrop"; + FILE *f; + memset(buffer, 0, BUFFER_SIZE); + if(!(f = popen(which, "r"))) { + return 0; + } + + fread(buffer, 1, BUFFER_SIZE, f); + if(buffer[strlen(buffer) - 1] == '\n') + buffer[strlen(buffer) - 1] = 0; + pclose(f); + if(buffer[0] != '/' && buffer[0] != '.') { + buffer[0] = 0; + pm_message("Can't find pnmcrop"); + } + } + else + strcpy(buffer, pnmcrop_exe_path); + + return buffer; +} + + + +static const char * +gsCommand(const char * const psFname, + const char * const outputFilename, + struct cmdlineInfo const cmdline) { + + const char * retval; + int const x = cmdline.res * 11; + int const y = cmdline.res * (cmdline.fontsize * 2 + 72) / 72.; + asprintfN(&retval, "%s -g%dx%d -r%d -sDEVICE=pbm " + "-sOutputFile=%s -q -dBATCH -dNOPAUSE %s /dev/null", + gs_executable_name(), x, y, cmdline.res, + outputFilename, psFname); + return retval; +} + + + +static const char * +cropCommand(const char * const inputFileName) { + + const char * retval; + + if (crop_executable_name()) { + asprintfN(&retval, "%s -top -right %s", + crop_executable_name(), inputFileName); + if (retval == NULL) + pm_error("Unable to allocate memory"); + } else + retval = NULL; + + return retval; +} + + + +static void +writeProgram(const char * const psFname, + struct cmdlineInfo const cmdline) { + + const char *ps; + FILE * psfile; + + psfile = fopen(psFname, "w"); + if (psfile == NULL) + pm_error("Can't open temp file '%s'. Errno=%d (%s)", + psFname, errno, strerror(errno)); + + ps = construct_postscript(cmdline); + + if (cmdline.verbose) + pm_message("Postscript program = '%s'", ps); + + if (fwrite(ps, 1, strlen(ps), psfile) != strlen(ps)) + pm_error("Can't write postscript to temp file"); + + fclose(psfile); + + strfree(ps); +} + + + +static void +executeProgram(const char * const psFname, + const char * const outputFname, + struct cmdlineInfo const cmdline) { + + const char * com; + int rc; + + com = gsCommand(psFname, outputFname, cmdline); + if (com == NULL) + pm_error("Can't allocate memory for a 'ghostscript' command"); + + if (cmdline.verbose) + pm_message("Running Postscript interpreter '%s'", com); + + rc = system(com); + if (rc != 0) + pm_error("Failed to run Ghostscript process. rc=%d", rc); + + strfree(com); +} + + + +static void +cropToStdout(const char * const inputFileName, + bool const verbose) { + + const char * com; + + com = cropCommand(inputFileName); + if (com == NULL) { + /* No pnmcrop. So don't crop. */ + pm_message("Can't find pnmcrop command, image will be large"); + asprintfN(&com, "cat %s", inputFileName); + if (com == NULL) + pm_error("Unable to allocate memory."); + } else { + FILE *pnmcrop; + + if (verbose) + pm_message("Running crop command '%s'", com); + + pnmcrop = popen(com, "r"); + if (pnmcrop == NULL) + pm_error("Can't run pnmcrop process"); + else { + char buf[2048]; + bool eof; + + eof = FALSE; + + while (!eof) { + int bytesRead; + + bytesRead = fread(buf, 1, sizeof(buf), pnmcrop); + if (bytesRead > 0) { + int rc; + rc = fwrite(buf, 1, bytesRead, stdout); + if (rc != bytesRead) + pm_error("Can't write to stdout"); + } else if (bytesRead == 0) + eof = TRUE; + else + pm_error("Failed to read output of Pnmcrop process. " + "Errno=%d (%s)", errno, strerror(errno)); + } + fclose(pnmcrop); + } + } + strfree(com); +} + + + +static void +createOutputFile(struct cmdlineInfo const cmdline) { + + const char * const template = "./pstextpbm.%d.tmp.%s"; + + const char * psFname; + const char * uncroppedPbmFname; + + asprintfN(&psFname, template, getpid(), "ps"); + if (psFname == NULL) + pm_error("Unable to allocate memory"); + + writeProgram(psFname, cmdline); + + asprintfN(&uncroppedPbmFname, template, getpid(), "pbm"); + if (uncroppedPbmFname == NULL) + pm_error("Unable to allocate memory"); + + executeProgram(psFname, uncroppedPbmFname, cmdline); + + unlink(psFname); + strfree(psFname); + + cropToStdout(uncroppedPbmFname, cmdline.verbose); + + unlink(uncroppedPbmFname); + strfree(uncroppedPbmFname); +} + + + +int +main(int argc, char *argv[]) { + + struct cmdlineInfo cmdline; + + pbm_init(&argc, argv); + + parseCommandLine(argc, argv, &cmdline); + + createOutputFile(cmdline); + + return 0; +} -- cgit 1.4.1