From 9a8509a688eb9fe25e1d6ab9c186d627eb307e9a Mon Sep 17 00:00:00 2001 From: giraffedata Date: Sat, 30 Jul 2011 21:15:34 +0000 Subject: cleanup git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1521 9d0c8265-081b-0410-96cb-a4ca84ce46f8 --- converter/other/pnmtops.c | 2294 +++++++++++++++++++++++---------------------- 1 file changed, 1188 insertions(+), 1106 deletions(-) (limited to 'converter') diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c index e9f17215..c238e765 100644 --- a/converter/other/pnmtops.c +++ b/converter/other/pnmtops.c @@ -57,7 +57,7 @@ struct cmdlineInfo { in a form easy for the program to use. */ const char * inputFileName; /* Filespecs of input file */ - float scale; + float scale; unsigned int dpiX; /* horiz component of DPI option */ unsigned int dpiY; /* vert component of DPI option */ unsigned int width; /* in 1/72 inch */ @@ -85,42 +85,44 @@ struct cmdlineInfo { static bool verbose; + + static void parseDpi(const char * const dpiOpt, - unsigned int * const dpiXP, - unsigned int * const dpiYP) { + unsigned int * const dpiXP, + unsigned int * const dpiYP) { char *dpistr2; unsigned long int dpiX, dpiY; dpiX = strtol(dpiOpt, &dpistr2, 10); if (dpistr2 == dpiOpt) - pm_error("Invalid value for -dpi: '%s'. Must be either number " - "or NxN ", dpiOpt); + pm_error("Invalid value for -dpi: '%s'. Must be either number " + "or NxN ", dpiOpt); else if (dpiX > INT_MAX) - pm_error("Invalid value for -dpi: '%s'. " - "Value too large for computation", dpiOpt); - else { - if (*dpistr2 == '\0') { - *dpiXP = dpiX; - *dpiYP = dpiX; - } else if (*dpistr2 == 'x') { - char * dpistr3; - - dpistr2++; /* Move past 'x' */ - dpiY = strtol(dpistr2, &dpistr3, 10); - if (dpiY > INT_MAX) pm_error("Invalid value for -dpi: '%s'. " - "Value too large for computation", dpiOpt); - else if (dpistr3 != dpistr2 && *dpistr3 == '\0') { - *dpiXP = dpiX; - *dpiYP = dpiY; - } else { - pm_error("Invalid value for -dpi: '%s'. Must be either " - "number or NxN", dpiOpt); + "Value too large for computation", dpiOpt); + else { + if (*dpistr2 == '\0') { + *dpiXP = dpiX; + *dpiYP = dpiX; + } else if (*dpistr2 == 'x') { + char * dpistr3; + + dpistr2++; /* Move past 'x' */ + dpiY = strtol(dpistr2, &dpistr3, 10); + if (dpiY > INT_MAX) + pm_error("Invalid value for -dpi: '%s'. " + "Value too large for computation", dpiOpt); + else if (dpistr3 != dpistr2 && *dpistr3 == '\0') { + *dpiXP = dpiX; + *dpiYP = dpiY; + } else { + pm_error("Invalid value for -dpi: '%s'. Must be either " + "number or NxN", dpiOpt); + } } } - } } @@ -134,34 +136,35 @@ validateBps_1_2_4_8_12(unsigned int const bitsPerSample) { case 4: case 8: case 12: - break; + break; default: - pm_error("Invalid -bitspersample value: %u. Must be " - "1, 2, 4, 8, or 12", bitsPerSample); + pm_error("Invalid -bitspersample value: %u. Must be " + "1, 2, 4, 8, or 12", bitsPerSample); } } + static void validateCompDimension(unsigned int const value, - unsigned int const scaleFactor, - const char * const vname) { + unsigned int const scaleFactor, + const char * const vname) { /*---------------------------------------------------------------------------- - Validate that the image dimension (width or height) 'value' isn't so big - that in this program's calculations, involving scale factor 'scaleFactor', - it would cause a register overflow. If it is, abort the program and refer - to the offending dimension as 'vname' in the error message. - - Note that this early validation approach (calling this function) means - the actual computations don't have to be complicated with arithmetic - overflow checks, so they're easier to read. + Validate that the image dimension (width or height) 'value' isn't so big + that in this program's calculations, involving scale factor 'scaleFactor', + it would cause a register overflow. If it is, abort the program and refer + to the offending dimension as 'vname' in the error message. + + Note that this early validation approach (calling this function) means + the actual computations don't have to be complicated with arithmetic + overflow checks, so they're easier to read. -----------------------------------------------------------------------------*/ if (value > 0) { - unsigned int const maxWidthHeight = INT_MAX - 2; - unsigned int const maxScaleFactor = maxWidthHeight / value; + unsigned int const maxWidthHeight = INT_MAX - 2; + unsigned int const maxScaleFactor = maxWidthHeight / value; - if (scaleFactor > maxScaleFactor) - pm_error("%s is too large for compuations: %u", vname, value); + if (scaleFactor > maxScaleFactor) + pm_error("%s is too large for compuations: %u", vname, value); } } @@ -169,7 +172,7 @@ validateCompDimension(unsigned int const value, static void parseCommandLine(int argc, const char ** argv, - struct cmdlineInfo * const cmdlineP) { + struct cmdlineInfo * const cmdlineP) { unsigned int imagewidthSpec, imageheightSpec; float imagewidth, imageheight; @@ -203,7 +206,7 @@ parseCommandLine(int argc, const char ** argv, OPTENT3(0, "imagewidth", OPT_FLOAT, &imagewidth, &imagewidthSpec, 0); OPTENT3(0, "imageheight", OPT_FLOAT, &imageheight, &imageheightSpec, 0); OPTENT3(0, "bitspersample", OPT_UINT, &cmdlineP->bitspersample, - &cmdlineP->bitspersampleSpec, 0); + &cmdlineP->bitspersampleSpec, 0); OPTENT3(0, "nosetpage", OPT_FLAG, NULL, &nosetpage, 0); OPTENT3(0, "setpage", OPT_FLAG, NULL, &cmdlineP->setpage, 0); OPTENT3(0, "noshowpage", OPT_FLAG, NULL, &noshowpage, 0); @@ -213,7 +216,7 @@ parseCommandLine(int argc, const char ** argv, OPTENT3(0, "showpage", OPT_FLAG, NULL, &showpage, 0); OPTENT3(0, "verbose", OPT_FLAG, NULL, &cmdlineP->verbose, 0); OPTENT3(0, "level", OPT_UINT, &cmdlineP->level, - &cmdlineP->levelSpec, 0); + &cmdlineP->levelSpec, 0); opt.opt_table = option_def; opt.short_allowed = FALSE; @@ -222,28 +225,28 @@ parseCommandLine(int argc, const char ** argv, pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0); if (cmdlineP->mustturn && noturn) - pm_error("You cannot specify both -turn and -noturn"); + pm_error("You cannot specify both -turn and -noturn"); if (center && nocenter) - pm_error("You cannot specify both -center and -nocenter"); + pm_error("You cannot specify both -center and -nocenter"); if (showpage && noshowpage) - pm_error("You cannot specify both -showpage and -noshowpage"); + pm_error("You cannot specify both -showpage and -noshowpage"); if (cmdlineP->setpage && nosetpage) - pm_error("You cannot specify both -setpage and -nosetpage"); + pm_error("You cannot specify both -setpage and -nosetpage"); if (!scaleSpec) - cmdlineP->scale = 1.0; + cmdlineP->scale = 1.0; if (!widthSpec) - width = 8.5; + width = 8.5; if (!heightSpec) - height = 11.0; + height = 11.0; if (dpiSpec) - parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); + parseDpi(dpiOpt, &cmdlineP->dpiX, &cmdlineP->dpiY); else { - cmdlineP->dpiX = 300; - cmdlineP->dpiY = 300; + cmdlineP->dpiX = 300; + cmdlineP->dpiY = 300; } cmdlineP->center = !nocenter; @@ -257,714 +260,785 @@ parseCommandLine(int argc, const char ** argv, cmdlineP->height = height * 72; if (imagewidthSpec) { - validateCompDimension(imagewidth, 72, "-imagewidth value"); - cmdlineP->imagewidth = imagewidth * 72; + validateCompDimension(imagewidth, 72, "-imagewidth value"); + cmdlineP->imagewidth = imagewidth * 72; } else - cmdlineP->imagewidth = 0; + cmdlineP->imagewidth = 0; if (imageheightSpec) { - validateCompDimension(imagewidth, 72, "-imageheight value"); - cmdlineP->imageheight = imageheight * 72; + validateCompDimension(imagewidth, 72, "-imageheight value"); + cmdlineP->imageheight = imageheight * 72; } else - cmdlineP->imageheight = 0; - -#ifdef NOFLATE - if (cmdlineP->flate) - pm_error("This program cannot handle flate compression. " - "Flate support suppressed at compile time."); -#endif + cmdlineP->imageheight = 0; if (!cmdlineP->psfilter && - (cmdlineP->flate || cmdlineP->ascii85)) - pm_error("You must specify -psfilter in order to specify " - "-flate or -ascii85"); + (cmdlineP->flate || cmdlineP->ascii85)) + pm_error("You must specify -psfilter in order to specify " + "-flate or -ascii85"); if (cmdlineP->bitspersampleSpec) - validateBps_1_2_4_8_12(cmdlineP->bitspersample); + validateBps_1_2_4_8_12(cmdlineP->bitspersample); if (argc-1 == 0) - cmdlineP->inputFileName = "-"; + cmdlineP->inputFileName = "-"; else if (argc-1 != 1) - pm_error("Program takes zero or one argument (filename). You " - "specified %d", argc-1); + pm_error("Program takes zero or one argument (filename). You " + "specified %d", argc-1); else - cmdlineP->inputFileName = argv[1]; + cmdlineP->inputFileName = argv[1]; free(option_def); } + +static bool +progIsFlateCapable(void) { + + return +#ifdef NOFLATE + false +#else + true +#endif + ; +} + + + +static const char * +basebasename(const char * const filespec) { +/*---------------------------------------------------------------------------- + Return filename up to first period +-----------------------------------------------------------------------------*/ + char const dirsep = '/'; + const char * const lastSlashPos = strrchr(filespec, dirsep); + + char * name; + const char * filename; + + if (lastSlashPos) + filename = lastSlashPos + 1; + else + filename = filespec; + + name = strdup(filename); + if (name != NULL) { + char * const dotPosition = strchr(name, '.'); + + if (dotPosition) + *dotPosition = '\0'; + } + return name; +} + + + +#define MAX_FILTER_CT 10 + /* The maximum number of filters this code is capable of applying */ + + + +static void +initPidList(pid_t * const pidList) { + + pidList[0] = (pid_t)0; /* end of list marker */ +} + + + +static void +addToPidList(pid_t * const pidList, + pid_t const newPid) { + + unsigned int i; + + for (i = 0; i < MAX_FILTER_CT && pidList[i]; ++i); + + assert(i < MAX_FILTER_CT); + + pidList[i] = newPid; + pidList[i+1] = (pid_t)0; /* end of list marker */ +} + + + /*=========================================================================== The output encoder -===========================================================================*/ + ===========================================================================*/ -enum output {AsciiHex, Ascii85}; -enum compress {none, Runlength, Flate, RunlengthFlate}; +enum OutputType {AsciiHex, Ascii85}; typedef struct { - enum output output; - enum compress compress; - unsigned int runlengthRefresh; - int pid[3]; /* child process ID, transmitted to parent */ + enum OutputType outputType; + bool compressRle; + bool compressFlate; + unsigned int runlengthRefresh; } OutputEncoder; + static void initOutputEncoder(OutputEncoder * const oeP, - unsigned int const icols, - unsigned int const bitsPerSample, - bool const rle, - bool const flate, - bool const ascii85, - bool const psFilter) { + unsigned int const icols, + unsigned int const bitsPerSample, + bool const rle, + bool const flate, + bool const ascii85, + bool const psFilter) { unsigned int const bytesPerRow = icols / (8/bitsPerSample) + - (icols % (8/bitsPerSample) > 0 ? 1 : 0); - /* Size of row buffer, padded up to byte boundary. + (icols % (8/bitsPerSample) > 0 ? 1 : 0); + /* Size of row buffer, padded up to byte boundary. + + A more straightforward calculation would be + (icols * bitsPerSample + 7) / 8 , + but this overflows when icols is large. + */ + + oeP->outputType = ascii85 ? Ascii85 : AsciiHex; - A more straightforward calculation would be - (icols * bitsPerSample + 7) / 8 , - but this overflows when icols is large. + if (rle) { + oeP->compressRle = true; + oeP->runlengthRefresh = psFilter ? INT_MAX : bytesPerRow; + } else + oeP->compressRle = false; + + if (flate) { + assert(psFilter); + oeP->compressFlate = true; + } else + oeP->compressFlate = false; + + if (ascii85) { + assert(psFilter); + oeP->outputType = Ascii85; + } else + oeP->outputType = AsciiHex; +} + + + +typedef void FilterFn(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP); + /* This is a function that can be run in a separate process to do + arbitrary modifications of the raster data stream. */ + - oeP->output = ascii85 ? Ascii85 : AsciiHex; - if (rle && flate) { - assert(psFilter); - oeP->compress = RunlengthFlate; - oeP->runlengthRefresh = INT_MAX; - } - else if (rle) { - oeP->compress = Runlength; - oeP->runlengthRefresh = psFilter ? INT_MAX : bytesPerRow; - } - else if (flate) { - assert(psFilter); - oeP->compress = Flate; - } - else /* neither rle nor flate */ - oeP->compress = none; +#ifndef NOFLATE +static void +initZlib(z_stream * const strmP) { - if(ascii85) { - assert(psFilter); - oeP->output = Ascii85; - } - else - oeP->output = AsciiHex; + int const level = 9; /* maximum compression. see zlib.h */ + + int ret; + /* allocate deflate state */ + strmP->zalloc = Z_NULL; + strmP->zfree = Z_NULL; + strmP->opaque = Z_NULL; + + ret = deflateInit(strmP, level); + if (ret != Z_OK) + pm_error("Failed to initialize zlib."); } +#endif -/* -The following function flateFilter() is based on def() in zpipe.c. -zpipe is an example program which comes with the zlib source package. -zpipe.c is public domain and is available from the Zlib website: -http://www.zlib.net/ -See zlib.h for details on zlib parameters Z_NULL, Z_OK, etc. -*/ + +static FilterFn flateFilter; static void -flateFilter(int const fdsource, int const fddest, OutputEncoder * const oeP) +flateFilter(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { + #ifndef NOFLATE -{ -#define CHUNK 128*1024 /* recommended in zpipe.c */ - /* 4096 is not efficient but works */ + /* This code is based on def() in zpipe.c. zpipe is an example program + which comes with the zlib source package. zpipe.c is public domain and + is available from the Zlib website: http://www.zlib.net/ - int ret, flush; - unsigned have; + See zlib.h for details on zlib parameters Z_NULL, Z_OK, etc. + */ + unsigned int const chunkSz = 128*1024; + /* 128K recommended in zpipe.c. 4096 is not efficient but works. */ + + int flush; z_stream strm; - unsigned char * const in = pm_allocrow(CHUNK, 1); - unsigned char * const out = pm_allocrow(CHUNK, 1); - const int level = 9; /* maximum compression. see zlib.h */ + unsigned char * in; + unsigned char * out; - FILE * source; - FILE * dest; - - /* allocate deflate state */ - strm.zalloc = Z_NULL; - strm.zfree = Z_NULL; - strm.opaque = Z_NULL; - ret = deflateInit(&strm, level); - if (ret != Z_OK) - pm_error("Failed to initialize zlib."); + in = pm_allocrow(chunkSz, 1); + out = pm_allocrow(chunkSz, 1); - /* open files */ - source = fdopen(fdsource, "r"); - dest = fdopen(fddest, "w"); - if (source ==NULL || dest==NULL) - pm_error("Failed to open internal pipe(s) for flate compression."); + initZlib(&strm); /* compress until end of file */ do { - strm.avail_in = fread(in, 1, CHUNK, source); - if (ferror(source)) { - (void)deflateEnd(&strm); - pm_error("Error reading from internal pipe during " - "flate compression."); - } - flush = feof(source) ? Z_FINISH : Z_NO_FLUSH; - strm.next_in = in; - - /* run deflate() on input until output buffer not full, finish - compression if all of source has been read in */ - do { - strm.avail_out = CHUNK; - strm.next_out = out; - ret = deflate(&strm, flush); /* no bad return value */ - assert(ret != Z_STREAM_ERROR); /* state not clobbered */ - have = CHUNK - strm.avail_out; - if (fwrite(out, 1, have, dest) != have || ferror(dest)) { - (void)deflateEnd(&strm); - pm_error("Error writing to internal pipe during " - "flate compression."); + strm.avail_in = fread(in, 1, chunkSz, ifP); + if (ferror(ifP)) { + deflateEnd(&strm); + pm_error("Error reading from internal pipe during " + "flate compression."); } - } while (strm.avail_out == 0); - assert(strm.avail_in == 0); /* all input will be used */ + flush = feof(ifP) ? Z_FINISH : Z_NO_FLUSH; + strm.next_in = in; - /* done when last data in file processed */ + /* run deflate() on input until output buffer not full, finish + compression if we have reached end of input. + */ + do { + unsigned int have; + size_t bytesWritten; + + strm.avail_out = chunkSz; + strm.next_out = out; + deflate(&strm, flush); + have = chunkSz - strm.avail_out; + bytesWritten = fwrite(out, 1, have, ofP); + if (ferror(ofP) || bytesWritten != have) { + deflateEnd(&strm); + pm_error("Error writing to internal pipe during " + "flate compression."); + } + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); /* all input is used */ + + /* done when last data in file processed */ } while (flush != Z_FINISH); - assert(ret == Z_STREAM_END); /* stream will be complete */ - /* clean up and return */ free(in); free(out); - (void)deflateEnd(&strm); - fclose(source); - fclose(dest); -} + deflateEnd(&strm); + fclose(ifP); + fclose(ofP); #else -{ - assert(0==1); /* should never be executed */ -} + assert(false); /* filter is never used */ #endif +} + /* Run length encoding -In this simple run-length encoding scheme, compressed and uncompressed -strings follow a single index byte N. N 0-127 means the next N+1 -bytes are uncompressed; 129-255 means the next byte is to be repeated -257-N times. + In this simple run-length encoding scheme, compressed and uncompressed + strings follow a single index byte N. N 0-127 means the next N+1 + bytes are uncompressed; 129-255 means the next byte is to be repeated + 257-N times. -In native (non-psfilter) mode, the run length filter must flush at -the end of every row. But the entire raster is sent to the run length -filter as one continuous stream. The run length filter learns the -refresh interval from oeP->runlengthRefresh. + In native (non-psfilter) mode, the run length filter must flush at + the end of every row. But the entire raster is sent to the run length + filter as one continuous stream. The run length filter learns the + refresh interval from oeP->runlengthRefresh. */ static void -rlePutBuffer (unsigned int const repeat, - unsigned int const count, - unsigned int const repeatitem, - unsigned char * const itembuf, - FILE * const fp) { - - if (repeat) { - fputc ( 257-count, fp); - fputc ( repeatitem, fp); - } - else { - fputc ( count-1, fp); - fwrite( itembuf, 1, count, fp); - } +rlePutBuffer (unsigned int const repeat, + unsigned int const count, + unsigned int const repeatitem, + unsigned char * const itembuf, + FILE * const fP) { + + if (repeat) { + fputc(257 - count, fP); + fputc(repeatitem, fP); + } else { + fputc(count - 1, fP); + fwrite(itembuf, 1, count, fP); + } } +static FilterFn rleFilter; + static void -rleFilter (int const in, int const out, OutputEncoder * const oeP) -{ +rleFilter (FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { - unsigned int repeat = 1, count = 0, incount=0, repeatcount; - unsigned int const refresh = oeP->runlengthRefresh; - unsigned char repeatitem; - int rleitem; - unsigned char itembuf[128]; - int i; - FILE *fin; - FILE *fout; + unsigned int const refresh = oeP->runlengthRefresh; + bool eof; + bool repeat; + unsigned int count; + unsigned int incount; + unsigned int repeatcount; + unsigned char repeatitem; + unsigned char itembuf[128]; - fin = fdopen (in, "r"); - fout = fdopen (out, "w"); - if (fin == NULL || fout == NULL) - pm_error("Failed to open internal pipe(s) for run-length compression."); + repeat = true; /* initial value */ + count = 0; /* initial value */ - while ((rleitem = fgetc (fin)) != EOF) { - incount++; + for (eof = false, incount = 0; !eof; ) { + int rleitem; - if (repeat && count == 0) { /* Still initializing a repeat buf. */ - itembuf[count++] = repeatitem = rleitem; - } - else if (repeat) { /* Repeating - watch for end of run. */ - if (rleitem == repeatitem) { /* Run continues. */ - itembuf[count++] = rleitem; - } - else { /* Run ended - is it long enough to dump? */ - if (count > 2) { - /* Yes, dump a repeat-mode buffer and start a new one. */ - rlePutBuffer (repeat, count, repeatitem, itembuf, fout); - repeat = 1; - count = 0; - itembuf[count++] = repeatitem = rleitem; - } - else { - /* Not long enough - convert to non-repeat mode. */ - repeat = 0; - itembuf[count++] = repeatitem = rleitem; - repeatcount = 1; - } - } - } - else { - /* Not repeating - watch for a run worth repeating. */ - if (rleitem == repeatitem) { /* Possible run continues. */ - ++repeatcount; - if (repeatcount > 3) { - /* Long enough - dump non-repeat part and start repeat. */ - count = count - (repeatcount - 1); - rlePutBuffer (repeat, count, repeatitem, itembuf, fout); - repeat = 1; - count = repeatcount; - for (i = 0; i < count; ++i) - itembuf[i] = rleitem; - } - else { - /* Not long enough yet - continue as non-repeat buf. */ - itembuf[count++] = rleitem; + rleitem = fgetc(ifP); + if (rleitem == EOF) + eof = true; + else { + ++incount; + + if (repeat && count == 0) { + /* Still initializing a repeat buf. */ + itembuf[count++] = repeatitem = rleitem; + } + else if (repeat) { + /* Repeating - watch for end of run. */ + if (rleitem == repeatitem) { + /* Run continues. */ + itembuf[count++] = rleitem; + } else { + /* Run ended */ + if (count > 2) { + /* Long enough to dump, so dump a repeat-mode buffer + and start a new one. + */ + rlePutBuffer(repeat, count, repeatitem, itembuf, ofP); + repeat = true; + count = 0; + itembuf[count++] = repeatitem = rleitem; + } else { + /* Not long enough - convert to non-repeat mode. */ + repeat = false; + itembuf[count++] = repeatitem = rleitem; + repeatcount = 1; + } + } + } else { + /* Not repeating - watch for a run worth repeating. */ + if (rleitem == repeatitem) { + /* Possible run continues. */ + ++repeatcount; + if (repeatcount > 3) { + /* Long enough - dump non-repeat part and start + repeat. + */ + unsigned int i; + count = count - (repeatcount - 1); + rlePutBuffer(repeat, count, repeatitem, itembuf, ofP); + repeat = true; + count = repeatcount; + for (i = 0; i < count; ++i) + itembuf[i] = rleitem; + } else { + /* Not long enough yet - continue as non-repeat buf. */ + itembuf[count++] = rleitem; + } + } else { /* Broken run. */ + itembuf[count++] = repeatitem = rleitem; + repeatcount = 1; + } + } + + if (incount == refresh) { + rlePutBuffer(repeat, count, repeatitem, itembuf, ofP); + repeat = true; + count = incount = 0; + } + + if (count == 128) { + rlePutBuffer(repeat, count, repeatitem, itembuf, ofP); + repeat = true; + count = 0; + } + } } - } - else { /* Broken run. */ - itembuf[count++] = repeatitem = rleitem; - repeatcount = 1; - } - } + if (count > 0) + rlePutBuffer(repeat, count, repeatitem, itembuf, ofP); + + fclose(ifP); + fclose(ofP); +} + + + +static FilterFn asciiHexFilter; + +static void +asciiHexFilter(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { + + char const hexits[16] = "0123456789abcdef"; + + bool eof; + unsigned char inbuff[40], outbuff[81]; - if (incount == refresh) { - rlePutBuffer (repeat, count, repeatitem, itembuf, fout); - repeat = 1; - count = incount = 0; + for (eof = false; !eof; ) { + size_t bytesRead; + + bytesRead = fread(inbuff, 1, 40, ifP); + + if (bytesRead == 0) + eof = true; + else { + unsigned int i; + + for (i = 0; i < bytesRead; ++i) { + int const item = inbuff[i]; + outbuff[i*2] = hexits[item >> 4]; + outbuff[i*2+1] = hexits[item & 15]; + } + } + outbuff[bytesRead * 2] = '\n'; + fwrite(outbuff, 1, bytesRead*2 + 1, ofP); } - if (count == 128) { - rlePutBuffer (repeat, count, repeatitem, itembuf, fout); - repeat = 1; - count = 0; + fclose(ifP); + fclose(ofP); +} + + + +static FilterFn ascii85Filter; + +static void +ascii85Filter(FILE * const ifP, + FILE * const ofP, + OutputEncoder * const oeP) { + + bool eof; + char outbuff[5]; + unsigned long int value; /* requires 32 bits */ + int count; + int outcount; + + value = 0; /* initial value */ + count = 0; /* initial value */ + outcount = 0; /* initial value */ + + for (eof = false; !eof; ) { + int c; + + c = fgetc(ifP); + + if (c == EOF) + eof = true; + else { + value = value*256 + c; + ++count; + + if (value == 0 && count == 4) { + putchar('z'); /* Ascii85 encoding z exception */ + ++outcount; + count = 0; + } else if (count == 4) { + outbuff[4] = value % 85 + 33; value/=85; + outbuff[3] = value % 85 + 33; value/=85; + outbuff[2] = value % 85 + 33; value/=85; + outbuff[1] = value % 85 + 33; + outbuff[0] = value / 85 + 33; + + fwrite(outbuff, 1, count + 1, ofP); + count = value = 0; + outcount += 5; + } + + if (outcount > 75) { + putchar('\n'); + outcount = 0; + } + } } - } + if (count > 0) { /* EOF, flush */ + assert (count < 4); - if (count > 0) - rlePutBuffer (repeat, count, repeatitem, itembuf, fout); + value <<= (4 - count) * 8; value/=85; + outbuff[3] = value % 85 + 33; value/=85; + outbuff[2] = value % 85 + 33; value/=85; + outbuff[1] = value % 85 + 33; + outbuff[0] = value / 85 + 33; + outbuff[count + 1] = '\n'; - fclose (fin); - fclose (fout); + fwrite(outbuff, 1, count + 2, ofP); + } + + fclose(ifP); + fclose(ofP); } static void -asciiHexFilter (int const fd) -{ - FILE *fp; - int c; - unsigned char inbuff[40], outbuff[81]; - const char hexits[16] = "0123456789abcdef"; - - fp = fdopen (fd, "r"); - if (fp == NULL) - pm_error ("Ascii Hex filter input pipe open failed"); - - while ((c = fread (inbuff, 1, 40, fp)) > 0) { - int i; - for (i = 0; i < c; ++i) { - int const item = inbuff[i]; - outbuff[i*2] =hexits[item >> 4]; - outbuff[i*2+1] =hexits[item & 15]; - } - - outbuff[c*2] = '\n'; - fwrite(outbuff, 1, c*2+1, stdout); - } - - fclose (fp); - fclose (stdout); +makePipe(int * const pipeFdArray) { + + int rc; + rc = pipe(pipeFdArray); + if (rc == -1) + pm_error("pipe() failed, errno = %d (%s)", errno, strerror(errno)); } static void -ascii85Filter (int const fd) { - FILE *fp; - int c; - char outbuff[5]; - unsigned long int value=0; /* requires 32 bits */ - int count=0; - int outcount=0; - - fp = fdopen (fd, "r"); - if (fp == NULL) - pm_error ("Ascii 85 filter input pipe open failed"); - - while ((c = fgetc (fp)) !=EOF) { - value = value*256 + c; - count++; - - if (value == 0 && count == 4) { - putchar('z'); /* Ascii85 encoding z exception */ - outcount++; - count=0; - } - else if (count == 4) { +closeAllBut(int const saveFd0, + int const saveFd1, + int const saveFd2) { +/*---------------------------------------------------------------------------- + Close every file descriptor in this process except 'saveFd0', + 'saveFd1', and 'saveFd2'. - outbuff[4] = value % 85 + 33; value/=85; - outbuff[3] = value % 85 + 33; value/=85; - outbuff[2] = value % 85 + 33; value/=85; - outbuff[1] = value % 85 + 33; - outbuff[0] = value / 85 + 33; + This is helpful because even if this process doesn't touch other file + desriptors, its very existence will keep the files open. +-----------------------------------------------------------------------------*/ + + /* Unix provides no good way to do this; we just assume file descriptors + above 9 are not used in this program; Caller must ensure that is true. + */ + int fd; - fwrite(outbuff, 1, count+1, stdout); - count = value = 0; - outcount+=5; + for (fd = 0; fd < 10; ++fd) { + if (fd != saveFd0 && fd != saveFd1 && fd != saveFd2) + close(fd); } +} - if (outcount > 75) { - putchar('\n'); - outcount=0; - } - } - if (count >0) { /* EOF, flush */ - assert (count < 4 ); - value <<= ( 4 - count ) * 8; value/=85; - outbuff[3] = value % 85 + 33; value/=85; - outbuff[2] = value % 85 + 33; value/=85; - outbuff[1] = value % 85 + 33; - outbuff[0] = value / 85 + 33; - outbuff[count+1] = '\n'; +static void +spawnFilter(FILE * const ofP, + FilterFn * const filterFn, + OutputEncoder * const oeP, + FILE ** const feedFilePP, + pid_t * const pidP) { +/*---------------------------------------------------------------------------- + Fork a child process to run filter function 'filterFn' and send its + output to *ofP. - fwrite(outbuff, 1, count+2, stdout); - } + Create a pipe for feeding the filter and return as *feedFilePP the + stream to which Caller can write to push stuff into the filter. - fclose (fp); - fclose (stdout); -} + *oeP is the parameter to 'filterFn'. +-----------------------------------------------------------------------------*/ + int pipeFd[2]; + pid_t rc; + makePipe(pipeFd); + + rc = fork(); -/* -Open pipes and spawn child processes + if (rc == (pid_t)-1) + pm_error("fork() of filter process failed. errno=%d (%s)", + errno, strerror(errno)); + else if (rc == 0) { + /* This is the child process */ + + FILE * ifP; -Each filter is a separate child process. The parent process feeds -raster data into the pipeline. + ifP = fdopen(pipeFd[0], "r"); - convertRow | asciiHexFilter - convertRow | ascii85Filter - convertRow | rleFilter | asciiHexFilter - convertRow | flateFilter | asciiHexFilter - convertRow | flateFilter | rleFilter | asciiHexFilter + if (!ifP) + pm_error("filter process failed to make " + "file stream (\"FILE\") " + "out of the file descriptor which is input to the " + "filter. errno=%d (%s)", + errno, strerror(errno)); -When adding functionality, it should be done by writing new filters, -amending existing filters and/or the convertRow functions. The -following activate*Filter functions and the bit accumulator functions -should be kept as simple as possible. + closeAllBut(fileno(ifP), fileno(ofP), STDERR_FILENO); -*/ + filterFn(ifP, ofP, oeP); + exit(EXIT_SUCCESS); + } else { + /* This is the parent process */ -static void -activateOneFilter (int * const feedP, OutputEncoder * const oeP) -{ - int p1[2]; - /* open pipe */ - - if (pipe (p1) == -1) { - pm_error ("pipe() failed"); - exit (1); - } - - switch (oeP->pid[0] = fork ()) { - case -1: /* error */ - pm_error("fork() of filter process failed. errno=%d (%s)", - errno, strerror(errno)); - exit (EXIT_FAILURE); - break; - - case 0: /* child */ - close (p1[1]); - if(oeP->output==Ascii85) - ascii85Filter (p1[0]); - else - asciiHexFilter (p1[0]); + pid_t const childPid = rc; + + close(pipeFd[0]); - exit (EXIT_SUCCESS); - break; - } + *feedFilePP = fdopen(pipeFd[1], "w"); - /* parent (Neither child comes here) */ - close (p1[0]); - *feedP = p1[1]; - oeP->pid[1] = oeP->pid[2] = 0; + *pidP = childPid; + } } static void -activateTwoFilters (int * const feedP, OutputEncoder * const oeP) -{ - int p1[2], p2[2]; - /* open pipes */ - - if (pipe (p1) == -1) { - pm_error ("pipe() failed"); - exit (1); - } - - if (pipe (p2) == -1) { - pm_error ("pipe() failed"); - exit (1); - } - - switch (oeP->pid[0] = fork ()) { - case -1: /* error */ - pm_error("fork() of filter process failed. errno=%d (%s)", - errno, strerror(errno)); - exit (EXIT_FAILURE); - break; - - case 0: /* child */ - close (p1[1]); - close (p2[0]); - - switch(oeP->compress) { - case(Runlength): - rleFilter (p1[0], p2[1], oeP); - break; - case(Flate): - flateFilter (p1[0], p2[1], oeP); - break; - default: - /* error */ - break; - } +addFilter(const char * const description, + FilterFn * const filter, + OutputEncoder * const oeP, + FILE ** const feedFilePP, + pid_t * const pidList) { - exit (EXIT_SUCCESS); - break; - } + pid_t pid; - switch (oeP->pid[1] = fork ()) { - case -1: /* error */ - pm_error("fork() of filter process failed. errno=%d (%s)", - errno, strerror(errno)); - exit (EXIT_FAILURE); - break; + FILE * const oldFeedFileP = *feedFilePP; - case 0: /* child */ - close (p1[0]); close (p1[1]); close (p2[1]); + FILE * newFeedFileP; + + spawnFilter(oldFeedFileP, filter, oeP, &newFeedFileP, &pid); + + if (verbose) + pm_message("%s filter spawned: pid %u", + description, (unsigned)pid); + + fclose(oldFeedFileP); /* Child keeps this open now */ + + addToPidList(pidList, pid); - if(oeP->output==Ascii85) - ascii85Filter (p2[0]); - else - asciiHexFilter (p2[0]); - - exit (EXIT_SUCCESS); - break; - } - /* parent (Neither child comes here) */ - close (p1[0]); close (p2[0]); close (p2[1]); - *feedP = p1[1]; - oeP->pid[2] = 0; + *feedFilePP = newFeedFileP; } static void -activateThreeFilters (int * const feedP, OutputEncoder * const oeP) -{ - int p1[2], p2[2], p3[2]; - /* open pipes */ - - if (pipe (p1) == -1) { - pm_error ("pipe() failed"); - exit (1); - } - - if (pipe (p2) == -1) { - pm_error ("pipe() failed"); - exit (1); - } - - if (pipe (p3) == -1) { - pm_error ("pipe() failed"); - exit (1); - } - - switch (oeP->pid[0] = fork ()) { - case -1: /* error */ - pm_error("fork() of filter process failed. errno=%d (%s)", - errno, strerror(errno)); - exit (EXIT_FAILURE); - break; - - case 0: /* child */ - close (p1[1]); close (p2[0]); close (p3[0]); close (p3[1]); - rleFilter (p1[0], p2[1], oeP); - exit (EXIT_SUCCESS); - break; - } - - switch (oeP->pid[1] = fork ()) { - case -1: /* error */ - pm_error("fork() of filter process failed. errno=%d (%s)", - errno, strerror(errno)); - exit (EXIT_FAILURE); - break; - - case 0: /* child */ - close (p1[0]); close (p1[1]); close (p2[1]); close (p3[0]); - flateFilter(p2[0], p3[1], oeP); - exit (EXIT_SUCCESS); - break; - } - - switch (oeP->pid[2] = fork ()) { - case -1: /* error */ - pm_error("fork() of filter process failed. errno=%d (%s)", - errno, strerror(errno)); - exit (EXIT_FAILURE); - break; - - case 0: /* child */ - close (p1[0]); close (p1[1]); close (p2[0]); close (p2[1]); - close (p3[1]); - - if(oeP->output==Ascii85) - ascii85Filter (p3[0]); - else - asciiHexFilter (p3[0]); +spawnFilters(FILE * const ofP, + OutputEncoder * const oeP, + FILE ** const feedFilePP, + pid_t * const pidList) { +/*---------------------------------------------------------------------------- + Get all the child processes for the filters running and connected. + Return at *feedFileP the file stream to which to write the raw data, + with the filtered data going to *ofP. - exit (EXIT_SUCCESS); - break; - } + Filter according to *oeP. +-----------------------------------------------------------------------------*/ - /* parent (Neither child comes here) */ - close (p1[0]); close (p2[0]); close (p2[1]); - close (p3[0]); close (p3[1]); - *feedP = p1[1]; -} + /* Build up the pipeline from the final to the initial stage. The + result is one of: + FEED | convertRow | asciiHexFilter | *ofP + FEED | convertRow | ascii85Filter | *ofP + FEED | convertRow | rleFilter | asciiHexFilter | *ofP + FEED | convertRow | flateFilter | asciiHexFilter | *ofP + FEED | convertRow | flateFilter | rleFilter | asciiHexFilter | *ofP + */ -static void -activateFilters (int * const feedP, OutputEncoder * const oeP){ - - switch(oeP->compress) { - case none: - activateOneFilter(feedP, oeP); - break; - case RunlengthFlate: - activateThreeFilters(feedP, oeP); - break; - default: - activateTwoFilters(feedP, oeP); - } + FILE * feedFileP; + /* The current head of the filter chain; changes as we add filters */ + + initPidList(pidList); + + feedFileP = ofP; /* Initial state: no filter at all */ + + addFilter( + "output", + oeP->outputType == Ascii85 ? &ascii85Filter : asciiHexFilter, + oeP, + &feedFileP, + pidList); + + if (oeP->compressFlate) + addFilter("flate", flateFilter, oeP, &feedFileP, pidList); + + if (oeP->compressRle) + addFilter("rle", rleFilter, oeP, &feedFileP, pidList); + + *feedFilePP = feedFileP; } + + static void -waitForChildren(int * const pid) { - - int i; - int status; - - for (i = 0; i < 3; ++i) { - if (pid[i] != 0) { - if (waitpid (pid[i], &status, 0) == -1) { - pm_error ("waitpid() failed"); - exit (EXIT_FAILURE); - } - else if (status != EXIT_SUCCESS) { - pm_error ("Child process terminated abnoramally"); - exit (EXIT_FAILURE); - } +waitForChildren(const pid_t * const pidList) { +/*---------------------------------------------------------------------------- + Wait for all child processes with PIDs in pidList[] to exit. + In pidList[], end-of-list is marked with a special zero value. +-----------------------------------------------------------------------------*/ + unsigned int i; + + for (i = 0; pidList[i]; ++i) { + pid_t rc; + int status; + + if (verbose) + pm_message("Waiting for PID %u to exit", (unsigned)pidList[i]); + + rc = waitpid(pidList[i], &status, 0); + if (rc == -1) + pm_error ("waitpid() for child %u failed", i); + else if (status != EXIT_SUCCESS) + pm_error ("Child process %u terminated abnormally", i); } - } + if (verbose) + pm_message("All children have exited"); } + + + /*============================================================================ - END OF OUTPUT ENCODERS + END OF OUTPUT ENCODERS ============================================================================*/ static void validateComputableBoundingBox(float const scols, - float const srows, - float const llx, - float const lly) { - - float const bbWidth = llx + scols + 0.5; - float const bbHeight = lly + srows + 0.5; - - if (bbHeight < INT_MIN || bbHeight > INT_MAX || - bbWidth < INT_MIN || bbWidth > INT_MAX) - pm_error("Bounding box dimensions %.1f x %.1f are too large " - "for computations. " - "This probably means input image width, height, " - "or scale factor is too large", bbWidth, bbHeight); + float const srows, + float const llx, + float const lly) { + + float const bbWidth = llx + scols + 0.5; + float const bbHeight = lly + srows + 0.5; + + if (bbHeight < INT_MIN || bbHeight > INT_MAX || + bbWidth < INT_MIN || bbWidth > INT_MAX) + pm_error("Bounding box dimensions %.1f x %.1f are too large " + "for computations. " + "This probably means input image width, height, " + "or scale factor is too large", bbWidth, bbHeight); } static void computeImagePosition(int const dpiX, - int const dpiY, - int const icols, - int const irows, - bool const mustturn, - bool const canturn, - bool const center, - int const pagewid, - int const pagehgt, - float const requestedScale, - float const imagewidth, - float const imageheight, - bool const equalpixels, - float * const scolsP, - float * const srowsP, - float * const llxP, - float * const llyP, - bool * const turnedP ) { + int const dpiY, + int const icols, + int const irows, + bool const mustturn, + bool const canturn, + bool const center, + int const pagewid, + int const pagehgt, + float const requestedScale, + float const imagewidth, + float const imageheight, + bool const equalpixels, + float * const scolsP, + float * const srowsP, + float * const llxP, + float * const llyP, + bool * const turnedP ) { /*---------------------------------------------------------------------------- - Determine where on the page the image is to go. This means position, - dimensions, and orientation. + Determine where on the page the image is to go. This means position, + dimensions, and orientation. - icols/irows are the dimensions of the PNM input in xels. + icols/irows are the dimensions of the PNM input in xels. - 'mustturn' means we are required to rotate the image. + 'mustturn' means we are required to rotate the image. - 'canturn' means we may rotate the image if it fits better, but don't - have to. + 'canturn' means we may rotate the image if it fits better, but don't + have to. - *scolsP, *srowsP are the dimensions of the image in 1/72 inch. + *scolsP, *srowsP are the dimensions of the image in 1/72 inch. - *llxP, *llyP are the coordinates, in 1/72 inch, of the lower left - corner of the image on the page. + *llxP, *llyP are the coordinates, in 1/72 inch, of the lower left + corner of the image on the page. - *turnedP is true iff the image is to be rotated 90 degrees on the page. + *turnedP is true iff the image is to be rotated 90 degrees on the page. - imagewidth/imageheight are the requested dimensions of the image on - the page, in 1/72 inch. Image will be as large as possible within - those dimensions. Zero means unspecified, so 'scale', 'pagewid', - 'pagehgt', 'irows', and 'icols' determine image size. + imagewidth/imageheight are the requested dimensions of the image on + the page, in 1/72 inch. Image will be as large as possible within + those dimensions. Zero means unspecified, so 'scale', 'pagewid', + 'pagehgt', 'irows', and 'icols' determine image size. - 'equalpixels' means the user wants one printed pixel per input pixel. - It is inconsistent with imagewidth or imageheight != 0 + 'equalpixels' means the user wants one printed pixel per input pixel. + It is inconsistent with imagewidth or imageheight != 0 - 'requestedScale' is meaningful only when imageheight/imagewidth == 0 - and equalpixels == FALSE. It tells how many inches the user wants - 72 pixels of input to occupy, if it fits on the page. + 'requestedScale' is meaningful only when imageheight/imagewidth == 0 + and equalpixels == FALSE. It tells how many inches the user wants + 72 pixels of input to occupy, if it fits on the page. -----------------------------------------------------------------------------*/ int cols, rows; /* Number of columns, rows of input xels in the output, as @@ -973,65 +1047,65 @@ computeImagePosition(int const dpiX, bool shouldturn; /* The image fits the page better if we turn it */ if (icols > irows && pagehgt > pagewid) - shouldturn = TRUE; + shouldturn = TRUE; else if (irows > icols && pagewid > pagehgt) - shouldturn = TRUE; + shouldturn = TRUE; else - shouldturn = FALSE; + shouldturn = FALSE; if (mustturn || (canturn && shouldturn)) { - *turnedP = TRUE; - cols = irows; - rows = icols; + *turnedP = TRUE; + cols = irows; + rows = icols; } else { - *turnedP = FALSE; - cols = icols; - rows = irows; + *turnedP = FALSE; + cols = icols; + rows = irows; } if (equalpixels) { - *scolsP = (72.0/dpiX)*cols; - *srowsP = (72.0/dpiY)*rows; + *scolsP = (72.0/dpiX)*cols; + *srowsP = (72.0/dpiY)*rows; } else if (imagewidth > 0 || imageheight > 0) { - float scale; + float scale; - if (imagewidth == 0) - scale = (float) imageheight/rows; - else if (imageheight == 0) - scale = (float) imagewidth/cols; - else - scale = MIN((float)imagewidth/cols, (float)imageheight/rows); + if (imagewidth == 0) + scale = (float) imageheight/rows; + else if (imageheight == 0) + scale = (float) imagewidth/cols; + else + scale = MIN((float)imagewidth/cols, (float)imageheight/rows); - *scolsP = cols*scale; - *srowsP = rows*scale; + *scolsP = cols*scale; + *srowsP = rows*scale; } else { - /* He didn't give us a bounding box for the image so figure - out output image size from other inputs. - */ - const int devpixX = dpiX / 72.0 + 0.5; - const int devpixY = dpiY / 72.0 + 0.5; + /* He didn't give us a bounding box for the image so figure + out output image size from other inputs. + */ + const int devpixX = dpiX / 72.0 + 0.5; + const int devpixY = dpiY / 72.0 + 0.5; /* How many device pixels make up 1/72 inch, rounded to nearest integer */ - const float pixfacX = 72.0 / dpiX * devpixX; /* 1, approx. */ - const float pixfacY = 72.0 / dpiY * devpixY; /* 1, approx. */ - float scale; + const float pixfacX = 72.0 / dpiX * devpixX; /* 1, approx. */ + const float pixfacY = 72.0 / dpiY * devpixY; /* 1, approx. */ + float scale; - scale = MIN(requestedScale, - MIN((float)pagewid/cols, (float)pagehgt/rows)); + scale = MIN(requestedScale, + MIN((float)pagewid/cols, (float)pagehgt/rows)); - *scolsP = scale * cols * pixfacX; - *srowsP = scale * rows * pixfacY; + *scolsP = scale * cols * pixfacX; + *srowsP = scale * rows * pixfacY; - if (scale != requestedScale) - pm_message("warning, image too large for page, rescaling to %g", - scale ); - - /* Before May 2001, Pnmtops enforced a 5% margin around the page. - If the image would be too big to leave a 5% margin, Pnmtops would - scale it down. But people have images that are exactly the size - of a page, e.g. because they created them with Sane's 'scanimage' - program from a full page of input. So we removed the gratuitous - 5% margin. -Bryan. - */ + if (scale != requestedScale) + pm_message("warning, image too large for page, rescaling to %g", + scale ); + + /* Before May 2001, Pnmtops enforced a 5% margin around the page. + If the image would be too big to leave a 5% margin, Pnmtops would + scale it down. But people have images that are exactly the size + of a page, e.g. because they created them with Sane's 'scanimage' + program from a full page of input. So we removed the gratuitous + 5% margin. -Bryan. + */ } *llxP = (center) ? ( pagewid - *scolsP ) / 2 : 0; *llyP = (center) ? ( pagehgt - *srowsP ) / 2 : 0; @@ -1039,30 +1113,30 @@ computeImagePosition(int const dpiX, validateComputableBoundingBox( *scolsP, *srowsP, *llxP, *llyP); if (verbose) - pm_message("Image will be %3.2f points wide by %3.2f points high, " - "left edge %3.2f points from left edge of page, " - "bottom edge %3.2f points from top of page; " - "%sturned to landscape orientation", - *scolsP, *srowsP, *llxP, *llyP, *turnedP ? "" : "NOT "); + pm_message("Image will be %3.2f points wide by %3.2f points high, " + "left edge %3.2f points from left edge of page, " + "bottom edge %3.2f points from top of page; " + "%sturned to landscape orientation", + *scolsP, *srowsP, *llxP, *llyP, *turnedP ? "" : "NOT "); } static void determineDictionaryRequirement(bool const userWantsDict, - bool const psFilter, - unsigned int * const dictSizeP) { + bool const psFilter, + unsigned int * const dictSizeP) { if (userWantsDict) { - if (psFilter) { - /* The Postscript this program generates to use built-in - Postscript filters does not define any variables. - */ - *dictSizeP = 0; - } else - *dictSizeP = 8; + if (psFilter) { + /* The Postscript this program generates to use built-in + Postscript filters does not define any variables. + */ + *dictSizeP = 0; + } else + *dictSizeP = 8; } else - *dictSizeP = 0; + *dictSizeP = 0; } @@ -1070,45 +1144,45 @@ determineDictionaryRequirement(bool const userWantsDict, static void defineReadstring(bool const rle) { /*---------------------------------------------------------------------------- - Write to Standard Output Postscript statements to define /readstring. + Write to Standard Output Postscript statements to define /readstring. -----------------------------------------------------------------------------*/ if (rle) { - printf("/rlestr1 1 string def\n"); - printf("/readrlestring {\n"); /* s -- nr */ - printf(" /rlestr exch def\n"); /* - */ - printf(" currentfile rlestr1 readhexstring pop\n"); /* s1 */ - printf(" 0 get\n"); /* c */ - printf(" dup 127 le {\n"); /* c */ - printf(" currentfile rlestr 0\n"); /* c f s 0 */ - printf(" 4 3 roll\n"); /* f s 0 c */ - printf(" 1 add getinterval\n"); /* f s */ - printf(" readhexstring pop\n"); /* s */ - printf(" length\n"); /* nr */ - printf(" } {\n"); /* c */ - printf(" 257 exch sub dup\n"); /* n n */ - printf(" currentfile rlestr1 readhexstring pop\n");/* n n s1 */ - printf(" 0 get\n"); /* n n c */ - printf(" exch 0 exch 1 exch 1 sub {\n"); /* n c 0 1 n-1*/ - printf(" rlestr exch 2 index put\n"); - printf(" } for\n"); /* n c */ - printf(" pop\n"); /* nr */ - printf(" } ifelse\n"); /* nr */ - printf("} bind def\n"); - printf("/readstring {\n"); /* s -- s */ - printf(" dup length 0 {\n"); /* s l 0 */ - printf(" 3 copy exch\n"); /* s l n s n l*/ - printf(" 1 index sub\n"); /* s l n s n r*/ - printf(" getinterval\n"); /* s l n ss */ - printf(" readrlestring\n"); /* s l n nr */ - printf(" add\n"); /* s l n */ - printf(" 2 copy le { exit } if\n"); /* s l n */ - printf(" } loop\n"); /* s l l */ - printf(" pop pop\n"); /* s */ - printf("} bind def\n"); + printf("/rlestr1 1 string def\n"); + printf("/readrlestring {\n"); /* s -- nr */ + printf(" /rlestr exch def\n"); /* - */ + printf(" currentfile rlestr1 readhexstring pop\n"); /* s1 */ + printf(" 0 get\n"); /* c */ + printf(" dup 127 le {\n"); /* c */ + printf(" currentfile rlestr 0\n"); /* c f s 0 */ + printf(" 4 3 roll\n"); /* f s 0 c */ + printf(" 1 add getinterval\n"); /* f s */ + printf(" readhexstring pop\n"); /* s */ + printf(" length\n"); /* nr */ + printf(" } {\n"); /* c */ + printf(" 257 exch sub dup\n"); /* n n */ + printf(" currentfile rlestr1 readhexstring pop\n");/* n n s1 */ + printf(" 0 get\n"); /* n n c */ + printf(" exch 0 exch 1 exch 1 sub {\n"); /* n c 0 1 n-1*/ + printf(" rlestr exch 2 index put\n"); + printf(" } for\n"); /* n c */ + printf(" pop\n"); /* nr */ + printf(" } ifelse\n"); /* nr */ + printf("} bind def\n"); + printf("/readstring {\n"); /* s -- s */ + printf(" dup length 0 {\n"); /* s l 0 */ + printf(" 3 copy exch\n"); /* s l n s n l*/ + printf(" 1 index sub\n"); /* s l n s n r*/ + printf(" getinterval\n"); /* s l n ss */ + printf(" readrlestring\n"); /* s l n nr */ + printf(" add\n"); /* s l n */ + printf(" 2 copy le { exit } if\n"); /* s l n */ + printf(" } loop\n"); /* s l l */ + printf(" pop pop\n"); /* s */ + printf("} bind def\n"); } else { - printf("/readstring {\n"); /* s -- s */ - printf(" currentfile exch readhexstring pop\n"); - printf("} bind def\n"); + printf("/readstring {\n"); /* s -- s */ + printf(" currentfile exch readhexstring pop\n"); + printf("} bind def\n"); } } @@ -1116,47 +1190,50 @@ defineReadstring(bool const rle) { static void setupReadstringNative(bool const rle, - bool const color, - unsigned int const icols, - unsigned int const bitsPerSample) { + bool const color, + unsigned int const icols, + unsigned int const bitsPerSample) { /*---------------------------------------------------------------------------- - Write to Standard Output statements to define /readstring and also - arguments for it (/picstr or /rpicstr, /gpicstr, and /bpicstr). + Write to Standard Output statements to define /readstring and also + arguments for it (/picstr or /rpicstr, /gpicstr, and /bpicstr). -----------------------------------------------------------------------------*/ unsigned int const bytesPerRow = icols / (8/bitsPerSample) + - (icols % (8/bitsPerSample) > 0 ? 1 : 0); - /* Size of row buffer, padded up to byte boundary. */ + (icols % (8/bitsPerSample) > 0 ? 1 : 0); + /* Size of row buffer, padded up to byte boundary. */ defineReadstring(rle); if (color) { - printf("/rpicstr %d string def\n", bytesPerRow); - printf("/gpicstr %d string def\n", bytesPerRow); - printf("/bpicstr %d string def\n", bytesPerRow); + printf("/rpicstr %d string def\n", bytesPerRow); + printf("/gpicstr %d string def\n", bytesPerRow); + printf("/bpicstr %d string def\n", bytesPerRow); } else - printf("/picstr %d string def\n", bytesPerRow); + printf("/picstr %d string def\n", bytesPerRow); } static void putFilters(unsigned int const postscriptLevel, - bool const rle, - bool const flate, - bool const ascii85, - bool const color) { + bool const rle, + bool const flate, + bool const ascii85, + bool const color) { assert(postscriptLevel > 1); + /* We say to decode flate, then rle, so Caller must ensure it encodes + rel, then flate. + */ + if (ascii85) - printf("/ASCII85Decode filter "); + printf("/ASCII85Decode filter "); else - printf("/ASCIIHexDecode filter "); + printf("/ASCIIHexDecode filter "); if (flate) - printf("/FlateDecode filter "); - if (rle) /* activateThreeFilters() encodes rle before flate, - so decode must be flate then rle */ - printf("/RunLengthDecode filter "); + printf("/FlateDecode filter "); + if (rle) + printf("/RunLengthDecode filter "); } @@ -1165,33 +1242,33 @@ static void putReadstringNative(bool const color) { if (color) { - printf("{ rpicstr readstring }\n"); - printf("{ gpicstr readstring }\n"); - printf("{ bpicstr readstring }\n"); + printf("{ rpicstr readstring }\n"); + printf("{ gpicstr readstring }\n"); + printf("{ bpicstr readstring }\n"); } else - printf("{ picstr readstring }\n"); + printf("{ picstr readstring }\n"); } static void putSetup(unsigned int const dictSize, - bool const psFilter, - bool const rle, - bool const color, - unsigned int const icols, - unsigned int const bitsPerSample) { + bool const psFilter, + bool const rle, + bool const color, + unsigned int const icols, + unsigned int const bitsPerSample) { /*---------------------------------------------------------------------------- - Put the setup section in the Postscript program on Standard Output. + Put the setup section in the Postscript program on Standard Output. -----------------------------------------------------------------------------*/ printf("%%%%BeginSetup\n"); if (dictSize > 0) - /* inputf {r,g,b,}pictsr readstring readrlestring rlestring */ - printf("%u dict begin\n", dictSize); + /* inputf {r,g,b,}pictsr readstring readrlestring rlestring */ + printf("%u dict begin\n", dictSize); if (!psFilter) - setupReadstringNative(rle, color, icols, bitsPerSample); + setupReadstringNative(rle, color, icols, bitsPerSample); printf("%%%%EndSetup\n"); } @@ -1200,29 +1277,29 @@ putSetup(unsigned int const dictSize, static void putImage(bool const psFilter, - bool const color) { + bool const color) { /*---------------------------------------------------------------------------- - Put the image/colorimage statement in the Postscript program on - Standard Output. + Put the image/colorimage statement in the Postscript program on + Standard Output. -----------------------------------------------------------------------------*/ if (color) { - if (psFilter) - printf("false 3\n"); - else - printf("true 3\n"); - printf("colorimage"); + if (psFilter) + printf("false 3\n"); + else + printf("true 3\n"); + printf("colorimage"); } else - printf("image"); + printf("image"); } static void putInitPsFilter(unsigned int const postscriptLevel, - bool const rle, - bool const flate, - bool const ascii85, - bool const color) { + bool const rle, + bool const flate, + bool const ascii85, + bool const color) { bool const filterTrue = TRUE; @@ -1251,27 +1328,27 @@ putInitReadstringNative(bool const color) { static void putInit(unsigned int const postscriptLevel, - char const name[], - int const icols, - int const irows, - float const scols, - float const srows, - float const llx, - float const lly, - int const bitsPerSample, - int const pagewid, - int const pagehgt, - bool const color, - bool const turned, - bool const rle, - bool const flate, - bool const ascii85, - bool const setpage, - bool const psFilter, - unsigned int const dictSize) { + char const name[], + int const icols, + int const irows, + float const scols, + float const srows, + float const llx, + float const lly, + int const bitsPerSample, + int const pagewid, + int const pagehgt, + bool const color, + bool const turned, + bool const rle, + bool const flate, + bool const ascii85, + bool const setpage, + bool const psFilter, + unsigned int const dictSize) { /*---------------------------------------------------------------------------- - Write out to Standard Output the headers stuff for the Postscript - program (everything up to the raster). + Write out to Standard Output the headers stuff for the Postscript + program (everything up to the raster). -----------------------------------------------------------------------------*/ /* The numbers in the %! line often confuse people. They are NOT the PostScript language level. The first is the level of the DSC comment @@ -1285,29 +1362,29 @@ putInit(unsigned int const postscriptLevel, printf("%%%%Title: %s.ps\n", name); printf("%%%%Pages: 1\n"); printf( - "%%%%BoundingBox: %d %d %d %d\n", - (int) llx, (int) lly, - (int) (llx + scols + 0.5), (int) (lly + srows + 0.5)); + "%%%%BoundingBox: %d %d %d %d\n", + (int) llx, (int) lly, + (int) (llx + scols + 0.5), (int) (lly + srows + 0.5)); printf("%%%%EndComments\n"); putSetup(dictSize, psFilter, rle, color, icols, bitsPerSample); printf("%%%%Page: 1 1\n"); if (setpage) - printf("<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n", - pagewid, pagehgt); + printf("<< /PageSize [ %d %d ] /ImagingBBox null >> setpagedevice\n", + pagewid, pagehgt); printf("gsave\n"); printf("%g %g translate\n", llx, lly); printf("%g %g scale\n", scols, srows); if (turned) - printf("0.5 0.5 translate 90 rotate -0.5 -0.5 translate\n"); + printf("0.5 0.5 translate 90 rotate -0.5 -0.5 translate\n"); printf("%d %d %d\n", icols, irows, bitsPerSample); printf("[ %d 0 0 -%d 0 %d ]\n", icols, irows, irows); if (psFilter) - putInitPsFilter(postscriptLevel, rle, flate, ascii85, color); + putInitPsFilter(postscriptLevel, rle, flate, ascii85, color); else - putInitReadstringNative(color); + putInitReadstringNative(color); printf("\n"); fflush(stdout); @@ -1323,28 +1400,28 @@ putEnd(bool const showpage, bool const vmreclaim) { if (psFilter) { - if (ascii85) - printf("%s\n", "~>"); - else - printf("%s\n", ">"); + if (ascii85) + printf("%s\n", "~>"); + else + printf("%s\n", ">"); } else { - printf("currentdict /inputf undef\n"); - printf("currentdict /picstr undef\n"); - printf("currentdict /rpicstr undef\n"); - printf("currentdict /gpicstr undef\n"); - printf("currentdict /bpicstr undef\n"); + printf("currentdict /inputf undef\n"); + printf("currentdict /picstr undef\n"); + printf("currentdict /rpicstr undef\n"); + printf("currentdict /gpicstr undef\n"); + printf("currentdict /bpicstr undef\n"); } if (dictSize > 0) - printf("end\n"); + printf("end\n"); if (vmreclaim) - printf("1 vmreclaim\n"); + printf("1 vmreclaim\n"); printf("grestore\n"); if (showpage) - printf("showpage\n"); + printf("showpage\n"); printf("%%%%Trailer\n"); } @@ -1352,46 +1429,46 @@ putEnd(bool const showpage, static void validateBpsRequest(unsigned int const bitsPerSampleReq, - unsigned int const postscriptLevel, - bool const psFilter) { + unsigned int const postscriptLevel, + bool const psFilter) { if (postscriptLevel < 2 && bitsPerSampleReq > 8) - pm_error("You requested %u bits per sample, but in Postscript " - "level 1, 8 is the maximum. You can get 12 with " - "-level 2 and -psfilter", bitsPerSampleReq); + pm_error("You requested %u bits per sample, but in Postscript " + "level 1, 8 is the maximum. You can get 12 with " + "-level 2 and -psfilter", bitsPerSampleReq); else if (!psFilter && bitsPerSampleReq > 8) - pm_error("You requested %u bits per sample, but without " - "-psfilter, the maximum is 8", bitsPerSampleReq); + pm_error("You requested %u bits per sample, but without " + "-psfilter, the maximum is 8", bitsPerSampleReq); } static unsigned int bpsFromInput(unsigned int const bitsRequiredByMaxval, - unsigned int const postscriptLevel, - bool const psFilter) { + unsigned int const postscriptLevel, + bool const psFilter) { unsigned int retval; if (bitsRequiredByMaxval <= 1) - retval = 1; + retval = 1; else if (bitsRequiredByMaxval <= 2) - retval = 2; + retval = 2; else if (bitsRequiredByMaxval <= 4) - retval = 4; + retval = 4; else if (bitsRequiredByMaxval <= 8) - retval = 8; - else { - /* Post script level 2 defines a format with 12 bits per sample, - but I don't know the details of that format (both RLE and - non-RLE variations) and existing native raster generation code - simply can't handle bps > 8. But the built-in filters know - how to do 12 bps. - */ - if (postscriptLevel >= 2 && psFilter) - retval = 12; - else retval = 8; + else { + /* Post script level 2 defines a format with 12 bits per sample, + but I don't know the details of that format (both RLE and + non-RLE variations) and existing native raster generation code + simply can't handle bps > 8. But the built-in filters know + how to do 12 bps. + */ + if (postscriptLevel >= 2 && psFilter) + retval = 12; + else + retval = 8; } return retval; } @@ -1400,188 +1477,198 @@ bpsFromInput(unsigned int const bitsRequiredByMaxval, static void warnUserAboutReducedDepth(unsigned int const bitsGot, - unsigned int const bitsWanted, - bool const userRequested, - unsigned int const postscriptLevel, - bool const psFilter) { + unsigned int const bitsWanted, + bool const userRequested, + unsigned int const postscriptLevel, + bool const psFilter) { if (bitsGot < bitsWanted) { - pm_message("Postscript will have %u bits of color resolution, " - "though the input has %u bits.", - bitsGot, bitsWanted); - - if (!userRequested) { - if (postscriptLevel < 2) - pm_message("Postscript level %u has a maximum depth of " - "8 bits. " - "You could get up to 12 with -level=2 " - "and -psfilter.", - postscriptLevel); - else { - if (!psFilter) - pm_message("You can get up to 12 bits with -psfilter"); - else - pm_message("The Postscript maximum is 12."); + pm_message("Postscript will have %u bits of color resolution, " + "though the input has %u bits.", + bitsGot, bitsWanted); + + if (!userRequested) { + if (postscriptLevel < 2) + pm_message("Postscript level %u has a maximum depth of " + "8 bits. " + "You could get up to 12 with -level=2 " + "and -psfilter.", + postscriptLevel); + else { + if (!psFilter) + pm_message("You can get up to 12 bits with -psfilter"); + else + pm_message("The Postscript maximum is 12."); + } } } - } } static void computeDepth(xelval const inputMaxval, - unsigned int const postscriptLevel, - bool const psFilter, - unsigned int const bitsPerSampleReq, - unsigned int * const bitsPerSampleP) { + unsigned int const postscriptLevel, + bool const psFilter, + unsigned int const bitsPerSampleReq, + unsigned int * const bitsPerSampleP) { /*---------------------------------------------------------------------------- - Figure out how many bits will represent each sample in the Postscript - program, and the maxval of the Postscript program samples. The maxval - is just the maximum value allowable in the number of bits. + Figure out how many bits will represent each sample in the Postscript + program, and the maxval of the Postscript program samples. The maxval + is just the maximum value allowable in the number of bits. - 'bitsPerSampleReq' is the bits per sample that the user requests, or - zero if he made no request. + 'bitsPerSampleReq' is the bits per sample that the user requests, or + zero if he made no request. -----------------------------------------------------------------------------*/ unsigned int const bitsRequiredByMaxval = pm_maxvaltobits(inputMaxval); if (bitsPerSampleReq != 0) { - validateBpsRequest(bitsPerSampleReq, postscriptLevel, psFilter); - *bitsPerSampleP = bitsPerSampleReq; + validateBpsRequest(bitsPerSampleReq, postscriptLevel, psFilter); + *bitsPerSampleP = bitsPerSampleReq; } else { - *bitsPerSampleP = bpsFromInput(bitsRequiredByMaxval, - postscriptLevel, psFilter); + *bitsPerSampleP = bpsFromInput(bitsRequiredByMaxval, + postscriptLevel, psFilter); } warnUserAboutReducedDepth(*bitsPerSampleP, bitsRequiredByMaxval, - bitsPerSampleReq != 0, - postscriptLevel, psFilter); + bitsPerSampleReq != 0, + postscriptLevel, psFilter); if (verbose) { - unsigned int const psMaxval = pm_bitstomaxval(*bitsPerSampleP); - pm_message("Input maxval is %u. Postscript raster will have " - "%u bits per sample, so maxval = %u", - inputMaxval, *bitsPerSampleP, psMaxval); + unsigned int const psMaxval = pm_bitstomaxval(*bitsPerSampleP); + pm_message("Input maxval is %u. Postscript raster will have " + "%u bits per sample, so maxval = %u", + inputMaxval, *bitsPerSampleP, psMaxval); } } + + /*=========================================================================== The bit accumulator ===========================================================================*/ typedef struct { - unsigned int value; - int consumed; + unsigned int value; + unsigned int consumed; } BitAccumulator; + +static void +ba_init(BitAccumulator * const baP) { + + baP->value = 0; + baP->consumed = 0; +} + + + static void -bits12_add(BitAccumulator * const baP, - unsigned int const new12, - FILE * const fp) { +ba_add12(BitAccumulator * const baP, + unsigned int const new12, + FILE * const fP) { /*---------------------------------------------------------------------------- - Read a 12-bit string into the bit accumulator baP->value. - On every other call, combine two 12-bit strings and write out three bytes. + Read a 12-bit string into the bit accumulator baP->value. + On every other call, combine two 12-bit strings and write out three bytes. -----------------------------------------------------------------------------*/ - - assert (baP->consumed ==12 || baP->consumed ==0); - - if ( baP->consumed == 12){ - char const oldHi8 = (baP->value) >> 4; - char const oldLo4 = (baP->value) & 0x0f; - char const newHi4 = new12 >> 8; - char const newLo8 = new12 & 0xff; - - fputc(oldHi8, fp); - fputc( (oldLo4 << 4) | newHi4 , fp); - fputc(newLo8, fp); - baP->value = 0; baP->consumed = 0; - } - else { - baP->value = new12; baP->consumed = 12; - } + assert (baP->consumed == 12 || baP->consumed == 0); + + if (baP->consumed == 12){ + char const oldHi8 = (baP->value) >> 4; + char const oldLo4 = (baP->value) & 0x0f; + char const newHi4 = new12 >> 8; + char const newLo8 = new12 & 0xff; + + fputc(oldHi8, fP); + fputc((oldLo4 << 4) | newHi4 , fP); + fputc(newLo8, fP); + baP->value = 0; baP->consumed = 0; + } else { + baP->value = new12; baP->consumed = 12; + } } static void -bits_add(BitAccumulator * const baP, - unsigned int const b, - int const bitsPerSample, - FILE * const fp) { +ba_add(BitAccumulator * const baP, + unsigned int const b, + unsigned int const bitsPerSample, + FILE * const fP) { /*---------------------------------------------------------------------------- - Combine bit sequences that do not fit into a byte. + Combine bit sequences that do not fit into a byte. - Used when bitsPerSample =1, 2, 4. - Logic also works for bitsPerSample = 8, 16. + Used when bitsPerSample =1, 2, 4. + Logic also works for bitsPerSample = 8, 16. - The accumulator, baP->value is unsigned int (usually 32 bits), but - only 8 bits are used. + The accumulator, baP->value is unsigned int (usually 32 bits), but + only 8 bits are used. -----------------------------------------------------------------------------*/ - int const bufSize = 8; + unsigned int const bufSize = 8; - assert (bitsPerSample ==1 || bitsPerSample ==2 || - bitsPerSample ==4 ); + assert (bitsPerSample == 1 || bitsPerSample == 2 || bitsPerSample == 4); - baP->value = (baP->value << bitsPerSample) | b ; - baP->consumed += bitsPerSample; - if ( baP->consumed == bufSize ) { /* flush */ - fputc( baP->value, fp); - baP->value = 0; - baP->consumed = 0; - } + baP->value = (baP->value << bitsPerSample) | b ; + baP->consumed += bitsPerSample; + if (baP->consumed == bufSize) { + /* flush */ + fputc( baP->value, fP); + baP->value = 0; + baP->consumed = 0; + } } static void -bits_flush(BitAccumulator * const baP, FILE * const fp) { +ba_flush(BitAccumulator * const baP, + FILE * const fP) { /*---------------------------------------------------------------------------- - Flush partial bits in baP->consumed. + Flush partial bits in baP->consumed. -----------------------------------------------------------------------------*/ - if (baP->consumed == 12) { - char const oldHi8 = (baP->value) >> 4; - char const oldLo4 = (baP->value) & 0x0f; - fputc(oldHi8, fp); - fputc(oldLo4 << 4, fp); - } - - else if (baP->consumed == 8) - fputc( baP->value , fp); - + char const oldHi8 = (baP->value) >> 4; + char const oldLo4 = (baP->value) & 0x0f; + fputc(oldHi8, fP); + fputc(oldLo4 << 4, fP); + } else if (baP->consumed == 8) + fputc(baP->value , fP); else if (baP->consumed > 0) { - int const leftShift = 8 - baP->consumed; - baP->value <<= leftShift; - fputc( baP->value , fp); + unsigned int const leftShift = 8 - baP->consumed; + assert(baP->consumed <= 8); /* why? */ + baP->value <<= leftShift; + fputc(baP->value , fP); } - baP->value = 0; baP->consumed = 0; } -static __inline__ void -outputSample(BitAccumulator * const baP, - unsigned int const sampleValue, - unsigned int const bitsPerSample, - FILE * const fp) { + +static void +outputSample(BitAccumulator * const baP, + unsigned int const sampleValue, + unsigned int const bitsPerSample, + FILE * const fP) { if (bitsPerSample == 8) - fputc( sampleValue, fp); + fputc(sampleValue, fP); else if (bitsPerSample == 12) - bits12_add(baP, sampleValue, fp); - else { - bits_add(baP, sampleValue, bitsPerSample, fp); - } + ba_add12(baP, sampleValue, fP); + else + ba_add(baP, sampleValue, bitsPerSample, fP); } static void -flushOutput(BitAccumulator * const baP, FILE * const fp) { - bits_flush(baP, fp); +flushOutput(BitAccumulator * const baP, + FILE * const fP) { + ba_flush(baP, fP); } + + /*---------------------------------------------------------------------- Row converters @@ -1594,11 +1681,11 @@ flushOutput(BitAccumulator * const baP, FILE * const fp) { convertRowNative and convertRowPsFilter are the general converters. They are quite similar, the differences being: (1) Native output separates the color planes: - (RRR...RRR GGG...GGG BBB...BBB), - whereas psFilter does not: - (RGB RGB RGB RGB ......... RGB). + (RRR...RRR GGG...GGG BBB...BBB), + whereas psFilter does not: + (RGB RGB RGB RGB ......... RGB). (2) Native flushes the run-length encoder at the end of each row if - grayscale, at the end of each plane if color. + grayscale, at the end of each plane if color. Both convertRowNative and convertRowPsFilter can handle PBM, though we don't use them. @@ -1606,13 +1693,13 @@ flushOutput(BitAccumulator * const baP, FILE * const fp) { If studying the code, read convertRowPbm first. convertRowNative and convertRowPsFilter are constructs that pack raster data into a form similar to a binary PBM bitrow. -----------------------------------------------------------------------*/ + ----------------------------------------------------------------------*/ static void convertRowPbm(struct pam * const pamP, - unsigned char * const bitrow, - bool const psFilter, - FILE * fp) { + unsigned char * const bitrow, + bool const psFilter, + FILE * const fP) { /*--------------------------------------------------------------------- Feed PBM raster data directly to the output encoder. Invert bits: 0 is "white" in PBM, 0 is "black" in postscript. @@ -1624,64 +1711,67 @@ convertRowPbm(struct pam * const pamP, pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, pamP->format); for (colChar = 0; colChar < colChars; ++colChar) - bitrow[colChar] = ~ bitrow[colChar]; + bitrow[colChar] = ~ bitrow[colChar]; - if(padRight > 0) { - bitrow[colChars-1] >>= padRight; /* Zero clear padding beyond */ - bitrow[colChars-1] <<= padRight; /* right edge */ + if (padRight > 0) { + bitrow[colChars-1] >>= padRight; /* Zero clear padding beyond */ + bitrow[colChars-1] <<= padRight; /* right edge */ } - fwrite(bitrow, 1, colChars, fp); + fwrite(bitrow, 1, colChars, fP); } static void convertRowNative(struct pam * const pamP, - tuple * tuplerow, - unsigned int const bitsPerSample, - FILE * const fp) { + tuple * tuplerow, + unsigned int const bitsPerSample, + FILE * const fP) { - unsigned int plane; unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample); + + unsigned int plane; BitAccumulator ba; - ba.value = ba.consumed =0; + + ba_init(&ba); pnm_readpamrow(pamP, tuplerow); pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval); for (plane = 0; plane < pamP->depth; ++plane) { - unsigned int col; - for (col= 0; col < pamP->width; ++col) { - outputSample(&ba, tuplerow[col][plane], bitsPerSample, fp); - } + unsigned int col; + for (col= 0; col < pamP->width; ++col) + outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP); - flushOutput(&ba, fp); + flushOutput(&ba, fP); } - } static void convertRowPsFilter(struct pam * const pamP, - tuple * tuplerow, - unsigned int const bitsPerSample, - FILE * const fp) { - unsigned int col; + tuple * tuplerow, + unsigned int const bitsPerSample, + FILE * const fP) { + unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample); + + unsigned int col; BitAccumulator ba; - ba.value = ba.consumed =0; + + ba_init(&ba); pnm_readpamrow(pamP, tuplerow); pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval); for (col = 0; col < pamP->width; ++col) { - unsigned int plane; - for (plane = 0; plane < pamP->depth; ++plane) - outputSample(&ba, tuplerow[col][plane], bitsPerSample, fp); + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) + outputSample(&ba, tuplerow[col][plane], bitsPerSample, fP); } - flushOutput(&ba, fp); + flushOutput(&ba, fP); } @@ -1689,16 +1779,16 @@ convertRowPsFilter(struct pam * const pamP, static void selectPostscriptLevel(bool const levelIsGiven, - unsigned int const levelGiven, - bool const color, - bool const dict, - bool const flate, - bool const ascii85, - bool const psFilter, - unsigned int * const postscriptLevelP) { + unsigned int const levelGiven, + bool const color, + bool const dict, + bool const flate, + bool const ascii85, + bool const psFilter, + unsigned int * const postscriptLevelP) { unsigned int const maxPermittedLevel = - levelIsGiven ? levelGiven : UINT_MAX; + levelIsGiven ? levelGiven : UINT_MAX; unsigned int minPossibleLevel; /* Until we know, later in this function, that we needs certain @@ -1710,178 +1800,165 @@ selectPostscriptLevel(bool const levelIsGiven, various features are required: */ if (color) { - minPossibleLevel = MAX(minPossibleLevel, 2); - if (2 > maxPermittedLevel) - pm_error("Color requires at least Postscript level 2"); + minPossibleLevel = MAX(minPossibleLevel, 2); + if (2 > maxPermittedLevel) + pm_error("Color requires at least Postscript level 2"); } if (flate) { - minPossibleLevel = MAX(minPossibleLevel, 3); - if (2 > maxPermittedLevel) - pm_error("flate compression requires at least Postscript level 3"); + minPossibleLevel = MAX(minPossibleLevel, 3); + if (2 > maxPermittedLevel) + pm_error("flate compression requires at least Postscript level 3"); } if (ascii85) { - minPossibleLevel = MAX(minPossibleLevel, 2); - if (2 > maxPermittedLevel) - pm_error("ascii85 encoding requires at least Postscript level 2"); + minPossibleLevel = MAX(minPossibleLevel, 2); + if (2 > maxPermittedLevel) + pm_error("ascii85 encoding requires at least Postscript level 2"); } if (psFilter) { - minPossibleLevel = MAX(minPossibleLevel, 2); - if (2 > maxPermittedLevel) - pm_error("-psfilter requires at least Postscript level 2"); + minPossibleLevel = MAX(minPossibleLevel, 2); + if (2 > maxPermittedLevel) + pm_error("-psfilter requires at least Postscript level 2"); } if (levelIsGiven) - *postscriptLevelP = levelGiven; + *postscriptLevelP = levelGiven; else - *postscriptLevelP = minPossibleLevel; + *postscriptLevelP = minPossibleLevel; +} + + + +static void +convertRaster(struct pam * const inpamP, + unsigned int const bitsPerSample, + bool const psFilter, + FILE * const fP) { + + if (PAM_FORMAT_TYPE(inpamP->format) == PBM_TYPE && bitsPerSample == 1) { + unsigned char * bitrow; + unsigned int row; + + bitrow = pbm_allocrow_packed(inpamP->width); + + for (row = 0; row < inpamP->height; ++row) + convertRowPbm(inpamP, bitrow, psFilter, fP); + + pbm_freerow(bitrow); + } else { + tuple *tuplerow; + unsigned int row; + + tuplerow = pnm_allocpamrow(inpamP); + + for (row = 0; row < inpamP->height; ++row) { + if (psFilter) + convertRowPsFilter(inpamP, tuplerow, bitsPerSample, fP); + else + convertRowNative(inpamP, tuplerow, bitsPerSample, fP); + } + pnm_freepamrow(tuplerow); + } } static void convertPage(FILE * const ifP, - int const turnflag, - int const turnokflag, - bool const psFilter, - bool const rle, - bool const flate, - bool const ascii85, - bool const setpage, - bool const showpage, - bool const center, - float const scale, - int const dpiX, - int const dpiY, - int const pagewid, - int const pagehgt, - int const imagewidth, - int const imageheight, - bool const equalpixels, - unsigned int const bitsPerSampleReq, - char const name[], - bool const dict, - bool const vmreclaim, - bool const levelIsGiven, - bool const levelGiven) { + int const turnflag, + int const turnokflag, + bool const psFilter, + bool const rle, + bool const flate, + bool const ascii85, + bool const setpage, + bool const showpage, + bool const center, + float const scale, + int const dpiX, + int const dpiY, + int const pagewid, + int const pagehgt, + int const imagewidth, + int const imageheight, + bool const equalpixels, + unsigned int const bitsPerSampleReq, + char const name[], + bool const dict, + bool const vmreclaim, + bool const levelIsGiven, + bool const levelGiven) { struct pam inpam; - int row; float scols, srows; float llx, lly; bool turned; bool color; unsigned int postscriptLevel; unsigned int bitsPerSample; - unsigned int dictSize; - /* Size of Postscript dictionary we should define */ - OutputEncoder * oeP; - - int feed; - FILE * fp; + unsigned int dictSize; + /* Size of Postscript dictionary we should define */ + OutputEncoder oe; + pid_t filterPidList[MAX_FILTER_CT + 1]; + + FILE * feedFileP; + /* The file stream which is the head of the filter chain; we write to + this and filtered stuff comes out the other end. + */ pnm_readpaminit(ifP, &inpam, PAM_STRUCT_SIZE(tuple_type)); validateCompDimension(inpam.width, 16, "Input image width"); if (!STRSEQ(inpam.tuple_type, PAM_PBM_TUPLETYPE) && - !STRSEQ(inpam.tuple_type, PAM_PGM_TUPLETYPE) && - !STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE)) - pm_error("Unrecognized tuple type %s. This program accepts only " - "PBM, PGM, PPM, and equivalent PAM input images", - inpam.tuple_type); + !STRSEQ(inpam.tuple_type, PAM_PGM_TUPLETYPE) && + !STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE)) + pm_error("Unrecognized tuple type %s. This program accepts only " + "PBM, PGM, PPM, and equivalent PAM input images", + inpam.tuple_type); color = STRSEQ(inpam.tuple_type, PAM_PPM_TUPLETYPE); selectPostscriptLevel(levelIsGiven, levelGiven, color, - dict, flate, ascii85, psFilter, &postscriptLevel); + dict, flate, ascii85, psFilter, &postscriptLevel); if (color) - pm_message("generating color Postscript program."); + pm_message("generating color Postscript program."); computeDepth(inpam.maxval, postscriptLevel, psFilter, bitsPerSampleReq, - &bitsPerSample); + &bitsPerSample); /* In positioning/scaling the image, we treat the input image as if it has a density of 72 pixels per inch. */ computeImagePosition(dpiX, dpiY, inpam.width, inpam.height, - turnflag, turnokflag, center, - pagewid, pagehgt, scale, imagewidth, imageheight, - equalpixels, - &scols, &srows, &llx, &lly, &turned); + turnflag, turnokflag, center, + pagewid, pagehgt, scale, imagewidth, imageheight, + equalpixels, + &scols, &srows, &llx, &lly, &turned); determineDictionaryRequirement(dict, psFilter, &dictSize); putInit(postscriptLevel, name, inpam.width, inpam.height, - scols, srows, llx, lly, bitsPerSample, - pagewid, pagehgt, color, - turned, rle, flate, ascii85, setpage, psFilter, dictSize); + scols, srows, llx, lly, bitsPerSample, + pagewid, pagehgt, color, + turned, rle, flate, ascii85, setpage, psFilter, dictSize); - MALLOCVAR_NOFAIL(oeP); + initOutputEncoder(&oe, inpam.width, bitsPerSample, + rle, flate, ascii85, psFilter); - initOutputEncoder (oeP, inpam.width, bitsPerSample, rle, - flate, ascii85, psFilter); - activateFilters(&feed, oeP); + spawnFilters(stdout, &oe, &feedFileP, filterPidList); - fp=fdopen (feed, "w"); + convertRaster(&inpam, bitsPerSample, psFilter, feedFileP); - if( PAM_FORMAT_TYPE(inpam.format) == PBM_TYPE && bitsPerSample==1 ) { - unsigned char * const bitrow = pbm_allocrow_packed(inpam.width); + fflush(feedFileP); + fclose(feedFileP); - for (row = 0; row < inpam.height; ++row) - convertRowPbm(&inpam, bitrow, psFilter, fp); - pbm_freerow(bitrow); - } - else { - tuple * const tuplerow = pnm_allocpamrow(&inpam); - - for (row = 0; row < inpam.height; ++row) { - if (psFilter) - convertRowPsFilter(&inpam, tuplerow, bitsPerSample, fp); - else - convertRowNative(&inpam, tuplerow, bitsPerSample, fp); - } - - pnm_freepamrow(tuplerow); - } - - fclose (fp); - - waitForChildren(oeP->pid); - free(oeP); + waitForChildren(filterPidList); putEnd(showpage, psFilter, ascii85, dictSize, vmreclaim); } -static const char * -basebasename(const char * const filespec) { -/*---------------------------------------------------------------------------- - Return filename up to first period ------------------------------------------------------------------------------*/ - char const dirsep = '/'; - const char * const lastSlashPos = strrchr(filespec, dirsep); - - char * name; - const char * filename; - - if (lastSlashPos) - filename = lastSlashPos + 1; - else - filename = filespec; - - name = strdup(filename); - if (name != NULL) { - char * const dotPosition = strchr(name, '.'); - - if (dotPosition) - *dotPosition = '\0'; - } - return name; -} - - - int main(int argc, const char * argv[]) { @@ -1895,44 +1972,49 @@ main(int argc, const char * argv[]) { verbose = cmdline.verbose; + if (cmdline.flate && !progIsFlateCapable()) + pm_error("This program cannot do flate compression. " + "(There are other versions of the program that do, " + "though -- it's a build-time option"); + ifP = pm_openr(cmdline.inputFileName); if (streq(cmdline.inputFileName, "-")) - name = strdup("noname"); + name = strdup("noname"); else - name = basebasename(cmdline.inputFileName); + name = basebasename(cmdline.inputFileName); { - int eof; /* There are no more images in the input file */ - unsigned int imageSeq; - - /* I don't know if this works at all for multi-image PNM input. - Before July 2000, it ignored everything after the first image, - so this probably is at least as good -- it should be identical - for a single-image file, which is the only kind which was legal - before July 2000. - - Maybe there needs to be some per-file header and trailers stuff - in the Postscript program, with some per-page header and trailer - stuff inside. I don't know Postscript. - Bryan 2000.06.19. - */ + int eof; /* There are no more images in the input file */ + unsigned int imageSeq; + + /* I don't know if this works at all for multi-image PNM input. + Before July 2000, it ignored everything after the first image, + so this probably is at least as good -- it should be identical + for a single-image file, which is the only kind which was legal + before July 2000. + + Maybe there needs to be some per-file header and trailers stuff + in the Postscript program, with some per-page header and trailer + stuff inside. I don't know Postscript. - Bryan 2000.06.19. + */ - eof = FALSE; /* There is always at least one image */ - for (imageSeq = 0; !eof; ++imageSeq) { - convertPage(ifP, cmdline.mustturn, cmdline.canturn, - cmdline.psfilter, - cmdline.rle, cmdline.flate, cmdline.ascii85, - cmdline.setpage, cmdline.showpage, - cmdline.center, cmdline.scale, - cmdline.dpiX, cmdline.dpiY, - cmdline.width, cmdline.height, - cmdline.imagewidth, cmdline.imageheight, - cmdline.equalpixels, - cmdline.bitspersampleSpec ? cmdline.bitspersample : 0, - name, - cmdline.dict, cmdline.vmreclaim, - cmdline.levelSpec, cmdline.level); - pnm_nextimage(ifP, &eof); - } + eof = FALSE; /* There is always at least one image */ + for (imageSeq = 0; !eof; ++imageSeq) { + convertPage(ifP, cmdline.mustturn, cmdline.canturn, + cmdline.psfilter, + cmdline.rle, cmdline.flate, cmdline.ascii85, + cmdline.setpage, cmdline.showpage, + cmdline.center, cmdline.scale, + cmdline.dpiX, cmdline.dpiY, + cmdline.width, cmdline.height, + cmdline.imagewidth, cmdline.imageheight, + cmdline.equalpixels, + cmdline.bitspersampleSpec ? cmdline.bitspersample : 0, + name, + cmdline.dict, cmdline.vmreclaim, + cmdline.levelSpec, cmdline.level); + pnm_nextimage(ifP, &eof); + } } pm_strfree(name); -- cgit 1.4.1