diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-05-21 01:31:06 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2016-05-21 01:31:06 +0000 |
commit | 11b7242986af9199615449b341cbd6e49139cd83 (patch) | |
tree | ca64cfc0abe6e9a32459b3a4c616ab8bae26e212 /generator/pbmtextps.c | |
parent | 1a47490bc519a89cfaa8f5c08f4b8f355d9da5e9 (diff) | |
download | netpbm-mirror-11b7242986af9199615449b341cbd6e49139cd83.tar.gz netpbm-mirror-11b7242986af9199615449b341cbd6e49139cd83.tar.xz netpbm-mirror-11b7242986af9199615449b341cbd6e49139cd83.zip |
cleanup, small functional changes
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@2781 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'generator/pbmtextps.c')
-rw-r--r-- | generator/pbmtextps.c | 346 |
1 files changed, 123 insertions, 223 deletions
diff --git a/generator/pbmtextps.c b/generator/pbmtextps.c index 15d2c0a7..06f7ee3e 100644 --- a/generator/pbmtextps.c +++ b/generator/pbmtextps.c @@ -14,7 +14,14 @@ * * Additions by Bryan Henderson contributed to public domain by author. * + * PostScript(R) Language Reference, Third Edition (a.k.a. "Red Book") + * http://www.adobe.com/products/postscript/pdfs/PLRM.pdf + * ISBN 0-201-37922-8 + * + * Other resources: + * http://partners.adobe.com/public/developer/ps/index_specs.html */ + #define _XOPEN_SOURCE /* Make sure popen() is in stdio.h */ #define _BSD_SOURCE /* Make sure stdrup() is in string.h */ #include <unistd.h> @@ -22,6 +29,7 @@ #include <stdlib.h> #include <string.h> #include <errno.h> +#include <assert.h> #include "pm_c_util.h" #include "mallocvar.h" @@ -30,9 +38,6 @@ #include "pm_system.h" #include "pbm.h" - -#define BUFFER_SIZE 2048 - struct CmdlineInfo { /* All the information the user supplied in the command line, in a form easy for the program to use. @@ -49,35 +54,6 @@ struct CmdlineInfo { static void -writeFileToStdout(const char * const fileName){ - /* simple pbmtopbm */ - - FILE * ifP; - int format; - int cols, rows, row ; - unsigned char * bitrow; - - ifP = pm_openr(fileName); - pbm_readpbminit(ifP, &cols, &rows, &format); - - if (cols==0 || rows==0 || cols>INT_MAX-10 || rows>INT_MAX-10) - pm_error("Abnormal output from gs program. " - "width x height = %u x %u", cols, rows); - - pbm_writepbminit(stdout, cols, rows, 0); - - bitrow = pbm_allocrow_packed(cols); - - for (row = 0; row < rows; ++row) { - pbm_readpbmrow_packed(ifP, bitrow, cols, format); - pbm_writepbmrow_packed(stdout, bitrow, cols, 0); - } - pbm_freerow_packed(bitrow); -} - - - -static void buildTextFromArgs(int const argc, const char ** const argv, const char ** const textP) { @@ -144,103 +120,80 @@ parseCommandLine(int argc, const char ** argv, pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); buildTextFromArgs(argc, argv, &cmdlineP->text); -} - - - -static const char * -construct_postscript(struct CmdlineInfo const cmdline) { - - const char * retval; - const char * template; - - if (cmdline.stroke < 0) - template = - "/%s findfont\n" - "%d scalefont\n" - "setfont\n" - "12 36 moveto\n" - "(%s) show\n" - "showpage\n"; - else - template = - "/%s findfont\n" - "%d scalefont\n" - "setfont\n" - "12 36 moveto\n" - "%f setlinewidth\n" - "0 setgray\n" - "(%s) true charpath\n" - "stroke\n" - "showpage\n"; - - if (cmdline.stroke < 0) - pm_asprintf(&retval, template, cmdline.font, cmdline.fontsize, - cmdline.text); - else - pm_asprintf(&retval, template, cmdline.font, cmdline.fontsize, - cmdline.stroke, cmdline.text); - return retval; + free(option_def); } static const char * -gsExecutableName() { - - const char * const which = "which gs"; - - static char buffer[BUFFER_SIZE]; - - FILE * f; - - memset(buffer, 0, BUFFER_SIZE); - - f = popen(which, "r"); - if (!f) - 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"); - - return buffer; -} +constructPostscript(struct CmdlineInfo const cmdline) { +/*----------------------------------------------------------------------------- + In Postscript, the bottom of the page is row zero. Negative values are + allowed but negative regions are clipped from the output image. We make + adjustments to ensure that nothing is lost. + + Postscript fonts also allow negative values in the bounding box coordinates. + The bottom edge of "L" is row zero. The feet of "g" "p" "y" extend into + negative region. In a similar manner the left edge of the bounding box may + be negative. We add margins on the left and the bottom with "xinit" and + "yinit" to provide for such characters. + + The sequence "textstring false charpath flattenpath pathbbox" determines + the bounding box of the entire text when rendered. We make adjustments + with "xdelta", "ydelta" whenever "xinit", "yinit" is insufficient. + This may sound unlikely, but is likely to happen with right-to-left or + vertical writing, which we haven't tested. +-----------------------------------------------------------------------------*/ + + /* C89 limits the size of a string constant, so we have to build the + Postscript command in pieces. + */ + const char * const psTemplate = + "/%s findfont\n" + "/fontsize %u def\n" + "/stroke %f def\n" + "/textstring (%s) def\n"; + + const char * const psFixed1 = + "fontsize scalefont\n" + "setfont\n" + "/xinit fontsize 2 div def\n" + "/yinit fontsize 1.5 mul def\n" + "xinit yinit moveto\n" + "textstring false charpath flattenpath pathbbox\n" + "/top exch def\n" + "/right exch def\n" + "/bottom exch def\n" + "/left exch def\n" + "/xdelta left 0 lt {left neg} {0} ifelse def\n" + "/ydelta bottom 0 lt {bottom neg} {0} ifelse def\n" + "/width right xdelta add def\n" + "/height top ydelta add def\n"; + + const char * const psFixed2 = + "<</PageSize [width height]>> setpagedevice\n" + "xinit yinit moveto\n" + "xdelta ydelta rmoveto\n" + "stroke 0 lt\n" + " {textstring show}\n" + " {stroke setlinewidth 0 setgray\n" + " textstring true charpath stroke}\n" + " ifelse\n" + "textstring false charpath flattenpath pathbbox\n" + "showpage"; + const char * retval; + const char * psVariable; -static const char * -cropExecutableName(void) { + pm_asprintf(&psVariable, psTemplate, cmdline.font, cmdline.fontsize, + cmdline.stroke, cmdline.text); - const char * const which = "which pnmcrop"; + pm_asprintf(&retval, "%s%s%s", psVariable, psFixed1, psFixed2); - static char buffer[BUFFER_SIZE]; - const char * retval; + pm_strfree(psVariable); - FILE * f; - - memset(buffer, 0, BUFFER_SIZE); - - f = popen(which, "r"); - if (!f) - retval = NULL; - else { - fread(buffer, 1, BUFFER_SIZE, f); - if (buffer[strlen(buffer) - 1] == '\n') - buffer[strlen(buffer) - 1] = 0; - pclose(f); - - if (buffer[0] != '/' && buffer[0] != '.') { - retval = NULL; - pm_message("Can't find pnmcrop"); - } else - retval = buffer; - } return retval; } @@ -252,9 +205,6 @@ gsArgList(const char * const psFname, struct CmdlineInfo const cmdline) { unsigned int const maxArgCt = 50; - double const x = (double) cmdline.res * 11; - double const y = (double) cmdline.res * - ((double) cmdline.fontsize * 2 + 72) / 72; const char ** retval; unsigned int argCt; /* Number of arguments in 'retval' so far */ @@ -264,62 +214,25 @@ gsArgList(const char * const psFname, if (cmdline.fontsize <= 0) pm_error("Font size must be positive."); - - /* The following checks are for guarding against overflows in this - function. Huge x,y values that pass these checks may be - rejected by the 'gs' program. - */ - - if (x > (double) INT_MAX-10) - pm_error("Absurdly fine resolution: %u. Output width too large.", - cmdline.res ); - if (y > (double) INT_MAX-10) - pm_error("Absurdly fine resolution (%u) and/or huge font size (%u). " - "Output height too large.", cmdline.res, cmdline.fontsize); - + MALLOCARRAY_NOFAIL(retval, maxArgCt+2); argCt = 0; /* initial value */ pm_asprintf(&retval[argCt++], "ghostscript"); - pm_asprintf(&retval[argCt++], "-g%dx%d", (int) x, (int) y); pm_asprintf(&retval[argCt++], "-r%d", cmdline.res); - pm_asprintf(&retval[argCt++], "-sDEVICE=pbm"); + pm_asprintf(&retval[argCt++], "-sDEVICE=pbmraw"); pm_asprintf(&retval[argCt++], "-sOutputFile=%s", outputFilename); pm_asprintf(&retval[argCt++], "-q"); pm_asprintf(&retval[argCt++], "-dBATCH"); + pm_asprintf(&retval[argCt++], "-dSAFER"); pm_asprintf(&retval[argCt++], "-dNOPAUSE"); pm_asprintf(&retval[argCt++], "%s", psFname); retval[argCt++] = NULL; - return retval; -} - - - -static const char ** -cropArgList(const char * const inputFileName) { - - unsigned int const maxArgCt = 50; - - const char ** retval; - unsigned int argCt; - - MALLOCARRAY_NOFAIL(retval, maxArgCt+2); - - argCt = 0; /* initial value */ - - pm_asprintf(&retval[argCt++], "pnmcrop"); - - pm_asprintf(&retval[argCt++], "-top"); - pm_asprintf(&retval[argCt++], "-right"); - if (pm_plain_output) - pm_asprintf(&retval[argCt++], "-plain"); - pm_asprintf(&retval[argCt++], "%s", inputFileName); - - retval[argCt++] = NULL; + assert(argCt < maxArgCt); return retval; } @@ -338,7 +251,7 @@ writeProgram(const char * const psFname, pm_error("Can't open temp file '%s'. Errno=%d (%s)", psFname, errno, strerror(errno)); - ps = construct_postscript(cmdline); + ps = constructPostscript(cmdline); if (cmdline.verbose) pm_message("Postscript program = '%s'", ps); @@ -347,7 +260,6 @@ writeProgram(const char * const psFname, pm_error("Can't write postscript to temp file"); fclose(psfile); - pm_strfree(ps); } @@ -387,8 +299,9 @@ executeProgram(const char * const psFname, const char * const outputFname, struct CmdlineInfo const cmdline) { - const char * const executableNm = gsExecutableName(); + const char * const executableNm = "gs"; const char ** const argList = gsArgList(psFname, outputFname, cmdline); + int termStatus; if (cmdline.verbose) @@ -413,54 +326,36 @@ executeProgram(const char * const psFname, static void -reportCrop(const char * const executableNm, - const char ** const argList) { - - unsigned int i; - - pm_message("Running '%s' to crop the output", executableNm); - - pm_message("Program arguments:"); - - for (i = 0; argList[i]; ++i) - pm_message(" '%s'", argList[i]); -} - - - -static void -cropToStdout(const char * const inputFileName, - bool const verbose) { - - const char * executableNm = cropExecutableName(); - - if (executableNm) { - const char ** const argList = cropArgList(inputFileName); - - int termStatus; +writePbmToStdout(const char * const fileName){ +/*---------------------------------------------------------------------------- + Write the PBM image that is in the file named 'fileName" to Standard + Output. I.e. pbmtopbm. + + It's not a byte-for-byte copy because PBM allows the same image to be + represented many ways (all of which we can accept as our input), but we use + libnetpbm to write our output in its specific way. +----------------------------------------------------------------------------*/ + FILE * ifP; + int format; + int cols, rows, row ; + unsigned char * bitrow; + + ifP = pm_openr(fileName); + pbm_readpbminit(ifP, &cols, &rows, &format); - if (verbose) - reportCrop(executableNm, argList); + if (cols == 0 || rows == 0 || cols > INT_MAX - 10 || rows > INT_MAX - 10) + pm_error("Abnormal output from gs program. " + "width x height = %u x %u", cols, rows); + + pbm_writepbminit(stdout, cols, rows, 0); + + bitrow = pbm_allocrow_packed(cols); - pm_system2_vp(executableNm, - argList, - pm_feed_null, NULL, - NULL, NULL, - &termStatus); - - if (termStatus != 0) { - const char * const msg = pm_termStatusDesc(termStatus); - - pm_error("Failed to run pnmcrop process. %s", msg); - - pm_strfree(msg); - } - freeArgList(argList); - } else { - /* No pnmcrop. So don't crop. */ - pm_message("Can't find pnmcrop program, image will be large"); - writeFileToStdout(inputFileName); + for (row = 0; row < rows; ++row) { + pbm_readpbmrow_packed(ifP, bitrow, cols, format); + pbm_writepbmrow_packed(stdout, bitrow, cols, 0); } + pbm_freerow_packed(bitrow); } @@ -468,30 +363,35 @@ cropToStdout(const char * const inputFileName, static void createOutputFile(struct CmdlineInfo const cmdline) { - const char * const template = "./pstextpbm.%d.tmp.%s"; - const char * psFname; - const char * uncroppedPbmFname; + const char * tempPbmFname; + FILE * psFileP; + FILE * pbmFileP; - pm_asprintf(&psFname, template, getpid(), "ps"); - if (psFname == NULL) - pm_error("Unable to allocate memory"); + pm_make_tmpfile(&psFileP, &psFname); + assert(psFileP != NULL && psFname != NULL); + fclose(psFileP); writeProgram(psFname, cmdline); - pm_asprintf(&uncroppedPbmFname, template, getpid(), "pbm"); - if (uncroppedPbmFname == NULL) - pm_error("Unable to allocate memory"); - - executeProgram(psFname, uncroppedPbmFname, cmdline); + pm_make_tmpfile(&pbmFileP, &tempPbmFname); + assert(pbmFileP != NULL && tempPbmFname != NULL); + fclose(pbmFileP); + + executeProgram(psFname, tempPbmFname, cmdline); unlink(psFname); pm_strfree(psFname); - cropToStdout(uncroppedPbmFname, cmdline.verbose); + /* Although Ghostscript created a legal PBM file, it uses a different + implementation of the format from libnetpbm's canonical output format, + so instead of copying the content of 'tempPbmFname' to Standard output + byte for byte, we copy it as a PBM image. + */ + writePbmToStdout(tempPbmFname); - unlink(uncroppedPbmFname); - pm_strfree(uncroppedPbmFname); + unlink(tempPbmFname); + pm_strfree(tempPbmFname); } |