diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2011-07-29 21:49:43 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2011-07-29 21:49:43 +0000 |
commit | d853d8e71fa702bdd4b02a034975b3ac0aa61470 (patch) | |
tree | 28b1d3daf6c75905f79e39046209f9bdc48fd13b | |
parent | b30cd0bb620b0b3255b5d9f9357fc99305125f82 (diff) | |
download | netpbm-mirror-d853d8e71fa702bdd4b02a034975b3ac0aa61470.tar.gz netpbm-mirror-d853d8e71fa702bdd4b02a034975b3ac0aa61470.tar.xz netpbm-mirror-d853d8e71fa702bdd4b02a034975b3ac0aa61470.zip |
Pnmtops rewrite from Prophet of the Way
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1520 9d0c8265-081b-0410-96cb-a4ca84ce46f8
-rw-r--r-- | converter/other/Makefile | 6 | ||||
-rw-r--r-- | converter/other/bmepsoe.c | 560 | ||||
-rw-r--r-- | converter/other/bmepsoe.h | 79 | ||||
-rw-r--r-- | converter/other/pnmtops.c | 1948 |
4 files changed, 1197 insertions, 1396 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile index 96196b8a..d94ca281 100644 --- a/converter/other/Makefile +++ b/converter/other/Makefile @@ -117,7 +117,7 @@ endif MERGEBINARIES = $(BINARIES) -EXTRA_OBJECTS = exif.o rast.o bmepsoe.o ipdb.o srf.o +EXTRA_OBJECTS = exif.o rast.o ipdb.o srf.o ifeq ($(HAVE_PNGLIB),Y) EXTRA_OBJECTS += pngtxt.o EXTRA_OBJECTS += pngx.o @@ -205,8 +205,8 @@ rletopnm pnmtorle: %: %.o $(NETPBMLIB) $(URTLIBDEP) $(LIBOPT) $(shell $(LIBOPT) $(URTLIB) $(NETPBMLIB)) \ $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) -pnmtops: %: %.o bmepsoe.o $(NETPBMLIB) $(LIBOPT) - $(LD) -o $@ $@.o bmepsoe.o \ +pnmtops: %: %.o $(NETPBMLIB) $(LIBOPT) + $(LD) -o $@ $@.o \ $(shell $(LIBOPT) $(NETPBMLIB) $(ZLIB)) \ $(MATHLIB) $(LDFLAGS) $(LDLIBS) $(RPATH) $(LADD) diff --git a/converter/other/bmepsoe.c b/converter/other/bmepsoe.c deleted file mode 100644 index 02bf39aa..00000000 --- a/converter/other/bmepsoe.c +++ /dev/null @@ -1,560 +0,0 @@ -/* - * This was adapted for Netpbm from bmpesoe.c in Dirk Krause's Bmeps package - * by Bryan Henderson on 2005.01.05. - * - * Differences: - * - doesn't require Bmeps configuration stuff (bmepsco.h) - * - doesn't include pngeps.h - * - doesn't have test scaffold code - * - a few compiler warnings fixed - * - * Copyright (C) 2000 - Dirk Krause - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * In this package the copy of the GNU Library General Public License - * is placed in file COPYING. - */ - -#include "bmepsoe.h" - -#define RL_RUNLENGTH(i) (257 - (i)) -#define RL_STRINGLENGTH(i) ((i) - 1) -#define RL_MAXLENGTH (127) - -#define FINALOUTPUT(c) fputc((c),o->out) - -void oe_init(Output_Encoder *o, FILE *out, int mode, int rate, int *buf, - Bytef *flib, size_t flis, Bytef *flob, size_t flos -) -{ - - o->out = out; - o->mode = mode; - o->textpos = 0; - o->a85_value = 0UL; o->a85_consumed = 0; - o->a85_0 = 1UL; - o->a85_1 = 85UL; - o->a85_2 = 85UL * 85UL; - o->a85_3 = 85UL * o->a85_2; - o->a85_4 = 85UL * o->a85_3; - o->rl_lastbyte = 0; - o->rl_buffer = buf; - o->rl_bufused = 0; - o->rl_state = 0; - o->bit_value = 0; - o->bit_consumed = 0; - o->flate_rate = rate; - if(o->flate_rate < 0) { - o->mode &= (~OE_FLATE); - } - if(o->flate_rate > 9) { - o->flate_rate = 9; - } - if((o->mode & OE_FLATE) && flib && flis && flob && flos) { - (o->flate_stream).zfree = (free_func)0; - (o->flate_stream).zalloc = (alloc_func)0; - (o->flate_stream).opaque = (voidpf)0; - if(deflateInit((&(o->flate_stream)),o->flate_rate) != Z_OK) { - o->mode &= (~OE_FLATE); - } - } - o->fl_i_buffer = flib; - o->fl_o_buffer = flob; - o->fl_i_size = flis; - o->fl_o_size = flos; - o->fl_i_used = 0; - -} - -static char hexdigits[] = { - "0123456789ABCDEF" -}; - -static void asciihex_add(Output_Encoder *o, int b) -{ - - FINALOUTPUT(hexdigits[(b/16)]) ; - FINALOUTPUT(hexdigits[(b%16)]) ; - o->textpos = o->textpos + 2; - if(o->textpos >= 64) { - FINALOUTPUT('\n') ; - o->textpos = 0; - } - -} - -static void asciihex_flush(Output_Encoder *o) -{ - - if(o->textpos > 0) { - FINALOUTPUT('\n') ; - o->textpos = 0; - } - -} - -static char ascii85_char(unsigned long x) -{ - unsigned u; - int i; - char back; - back = (char)0; - u = (unsigned)x; - i = (int)u; - i += 33; - back = (char)i; - return back; -} - - - -static void -ascii85_output(Output_Encoder * const o) { - unsigned long value; - - value = o->a85_value; /* initial value */ - - if (value == 0 && o->a85_consumed == 4) { - FINALOUTPUT('z'); - ++o->textpos; - } else { - unsigned int i; - unsigned int j; - char buffer[6]; - - buffer[0] = ascii85_char(value / (o->a85_4)); - value = value % (o->a85_4); - buffer[1] = ascii85_char(value / (o->a85_3)); - value = value % (o->a85_3); - buffer[2] = ascii85_char(value / (o->a85_2)); - value = value % (o->a85_2); - buffer[3] = ascii85_char(value / (o->a85_1)); - value = value % (o->a85_1); - buffer[4] = ascii85_char(value); - buffer[5] = '\0'; - - i = o->a85_consumed + 1; - o->textpos += i; - - for (j = 0; j < i; ++j) - FINALOUTPUT(buffer[j]); - } - if (o->textpos >= 64) { - FINALOUTPUT('\n'); - o->textpos = 0; - } -} - - - -static void ascii85_add(Output_Encoder *o, int b) -{ - unsigned u; - unsigned long ul; - - u = (unsigned)b; - ul = (unsigned long)u; - o->a85_value = 256UL * (o->a85_value) + ul; - o->a85_consumed = o->a85_consumed + 1; - if(o->a85_consumed >= 4) { - ascii85_output(o); - o->a85_value = 0UL; - o->a85_consumed = 0; - } - -} - -static void ascii85_flush(Output_Encoder *o) -{ - int i; - - if(o->a85_consumed > 0) { - i = o->a85_consumed; - while(i < 4) { - o->a85_value = 256UL * o->a85_value; - i++; - } - ascii85_output(o); - o->a85_value = 0UL; - o->a85_consumed = 0; - } - if(o->textpos > 0) { - FINALOUTPUT('\n') ; - o->textpos = 0; - } - -} - -static void after_flate_add(Output_Encoder *o, int b) -{ - - if(o->mode & OE_ASC85) { - ascii85_add(o,b); - } else { - asciihex_add(o,b); - } - -} - - - -static void -do_flate_flush(Output_Encoder * const oP, - int const final) { - - Bytef *iptr, *optr, *xptr; - unsigned long is; - unsigned long os; - unsigned long xs; - int err; - int mustContinue; - - iptr = oP->fl_i_buffer; optr = oP->fl_o_buffer; - is = oP->fl_i_size; os = oP->fl_o_size; - - if (iptr && optr && is && os) { - is = oP->fl_i_used; - if (is || final) { - oP->flate_stream.next_in = iptr; - oP->flate_stream.avail_in = is; - if (final) { - mustContinue = 1; - while (mustContinue) { - oP->flate_stream.next_out = optr; - oP->flate_stream.avail_out = os; - mustContinue = 0; - err = deflate(&oP->flate_stream, Z_FINISH); - switch (err) { - case Z_STREAM_END: { - xptr = optr; - - xs = os - (oP->flate_stream.avail_out); - while (xs--) { - after_flate_add(oP, *(xptr++)); - } - } break; - case Z_OK : { - mustContinue = 1; - xptr = optr; - - xs = os - (oP->flate_stream.avail_out); - while (xs--) { - after_flate_add(oP, *(xptr++)); - } - } break; - default : { - } break; - } - } - } else { - mustContinue = 1; - while (mustContinue) { - mustContinue = 0; - oP->flate_stream.avail_out = os; - oP->flate_stream.next_out = optr; - err = deflate(&oP->flate_stream, 0); - switch (err) { - case Z_OK: { - if (oP->flate_stream.avail_in) { - mustContinue = 1; - } - - xptr = optr; xs = os - (oP->flate_stream.avail_out); - while (xs--) { - after_flate_add(oP, *(xptr++)); - } - } break; - default : { - } break; - } - } - } - } - } -} - - - -static void flate_add(Output_Encoder *o, int b) -{ - Byte bt; - Bytef *btptr; - - btptr = o->fl_i_buffer; - if(btptr) { - bt = (Byte)b; - btptr[(o->fl_i_used)] = bt; - o->fl_i_used += 1UL; - if(o->fl_i_used >= o->fl_i_size) { - do_flate_flush(o, 0); - o->fl_i_used = 0UL; - } - } - -} - -static void after_flate_flush(Output_Encoder *o) -{ - - if(o->mode & OE_ASC85) { - ascii85_flush(o); - } else { - asciihex_flush(o); - } - -} - -static void flate_flush(Output_Encoder *o) -{ - do_flate_flush(o,1); - deflateEnd(&(o->flate_stream)); - after_flate_flush(o); -} - - -static void after_rl_add(Output_Encoder *o, int b) -{ - - if(o->mode & OE_FLATE) { - flate_add(o,b); - } else { - after_flate_add(o,b); - } - -} - -static void rl_add(Output_Encoder *o, int b) -{ - int lgt, i; - int *buffer; - /* ##### */ - - buffer = o->rl_buffer; - lgt = o->rl_bufused; - if(buffer) { - - if(lgt > 0) { - if(o->rl_lastbyte == b) { - switch(o->rl_state) { - case 2: { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_state = 2; - o->rl_lastbyte = b; - if(lgt >= RL_MAXLENGTH) { - after_rl_add(o, RL_RUNLENGTH(lgt)); - after_rl_add(o, b); - o->rl_bufused = 0; - o->rl_state = 0; - o->rl_lastbyte = b; - } - } break; - case 1: { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_state = 2; - o->rl_lastbyte = b; - lgt = lgt - 3; - if(lgt > 0) { - after_rl_add(o, RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o, buffer[i]); - } - buffer[0] = buffer[1] = buffer[2] = b; - o->rl_bufused = 3; - o->rl_state = 2; - o->rl_lastbyte = b; - } - } break; - default: { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_state = 1; - o->rl_lastbyte = b; - if(lgt >= RL_MAXLENGTH) { - lgt = lgt - 2; - after_rl_add(o, RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o, buffer[i]); - } - buffer[0] = buffer[1] = b; - o->rl_bufused = 2; - o->rl_state = 1; - o->rl_lastbyte = b; - } - } break; - } - } else { - if(o->rl_state == 2) { - after_rl_add(o, RL_RUNLENGTH(lgt)); - after_rl_add(o, (o->rl_lastbyte)); - buffer[0] = b; o->rl_bufused = 1; o->rl_lastbyte = b; - o->rl_state = 0; - } else { - buffer[lgt++] = b; - o->rl_bufused = lgt; - o->rl_lastbyte = b; - if(lgt >= RL_MAXLENGTH) { - after_rl_add(o, RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o, buffer[i]); - } - o->rl_bufused = 0; - } - o->rl_state = 0; - } - } - } else { - buffer[0] = b; - o->rl_bufused = 1; - o->rl_lastbyte = b; - } - o->rl_lastbyte = b; - - } else { - after_rl_add(o,0); - after_rl_add(o,b); - } - -} - -static void after_rl_flush(Output_Encoder *o) -{ - - if(o->mode & OE_FLATE) { - flate_flush(o); - } else { - after_flate_flush(o); - } - -} - -static void rl_flush(Output_Encoder *o) -{ - int lgt; - int *buffer; - int i; - - buffer = o->rl_buffer; - lgt = o->rl_bufused; - if(lgt > 0) { - if(o->rl_state == 2) { - i = o->rl_lastbyte; - after_rl_add(o,RL_RUNLENGTH(lgt)); - after_rl_add(o,i); - } else { - after_rl_add(o,RL_STRINGLENGTH(lgt)); - for(i = 0; i < lgt; i++) { - after_rl_add(o,buffer[i]); - } - } - } - after_rl_flush(o); - -} - - - -static void -internal_byte_add(Output_Encoder * const oP, - int const b) { - - if (oP->mode & OE_RL) - rl_add(oP, b); - else - after_rl_add(oP, b); -} - - - -static void internal_byte_flush(Output_Encoder *o) -{ - - if((o->mode) & OE_RL) { - rl_flush(o); - } else { - after_rl_flush(o); - } - -} - - - -void -oe_bit_add(Output_Encoder * const oP, - int const b) { - - oP->bit_value = 2 * oP->bit_value + (b ? 1 : 0); - oP->bit_consumed = oP->bit_consumed + 1; - if (oP->bit_consumed >= 8) { - oP->bit_consumed = 0; - internal_byte_add(oP, oP->bit_value); - oP->bit_value = 0; - } -} - - - -void oe_bit_flush(Output_Encoder *o) -{ - - if(o->bit_consumed) { - int v, i; - v = o->bit_value; - i = o->bit_consumed; - while(i < 8) { - i++; - v = v * 2; - } - internal_byte_add(o,v); - o->bit_value = 0; - o->bit_consumed = 0; - } - internal_byte_flush(o); - -} - - - -void -oe_byte_add(Output_Encoder * const oP, - int const b) { - - if (oP->bit_consumed) { - int testval; - int i; - testval = 128; - for (i = 0; i < 8; ++i) { - if (b & testval) { - oe_bit_add(oP, 1); - } else { - oe_bit_add(oP, 0); - } - testval = testval / 2; - } - } else { - internal_byte_add(oP, b); - } -} - - - -void oe_byte_flush(Output_Encoder *o) -{ - - oe_bit_flush(o); - -} diff --git a/converter/other/bmepsoe.h b/converter/other/bmepsoe.h deleted file mode 100644 index 99c59f77..00000000 --- a/converter/other/bmepsoe.h +++ /dev/null @@ -1,79 +0,0 @@ -/* - * libbmeps - Bitmap to EPS conversion library - * Copyright (C) 2000 - Dirk Krause - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - * In this package the copy of the GNU Library General Public License - * is placed in file COPYING. - */ - -#ifndef BMPESOE_H_INCLUDED -#define BMPESOE_H_INCLUDED - -#include <stdio.h> - -#include <zlib.h> - -typedef struct { - int mode; - FILE *out; - int textpos; - unsigned long a85_value; - int a85_consumed; - unsigned long a85_4; - unsigned long a85_3; - unsigned long a85_2; - unsigned long a85_1; - unsigned long a85_0; - int rl_lastbyte; - int *rl_buffer; - int rl_bufused; - int rl_state; - int bit_value; - int bit_consumed; - z_stream flate_stream; - Bytef *fl_i_buffer; - Bytef *fl_o_buffer; - uLong fl_i_size; - uLong fl_o_size; - uLong fl_i_used; - int flate_rate; -} Output_Encoder; - -#ifdef __cplusplus -extern "C" { -#endif - -void oe_init(Output_Encoder *o, FILE *out, int mode, int rate, int *buf, - Bytef *flib, size_t flis, Bytef *flob, size_t flos -); -void oe_byte_add(Output_Encoder *o, int b); -void oe_byte_flush(Output_Encoder *o); -void oe_bit_add(Output_Encoder *o, int b); -void oe_bit_flush(Output_Encoder *o); - -#ifdef __cplusplus -} -#endif - - - -#define OE_ASC85 1 -#define OE_FLATE 2 -#define OE_RL 4 - -#endif - diff --git a/converter/other/pnmtops.c b/converter/other/pnmtops.c index 88c1813a..e9f17215 100644 --- a/converter/other/pnmtops.c +++ b/converter/other/pnmtops.c @@ -5,17 +5,21 @@ We produce two main kinds of Postscript program: 1) Use built in Postscript filters /ASCII85Decode, /ASCIIHexDecode, - /RunLengthDecode, and /FlateDecode; + /RunLengthDecode, and /FlateDecode; - We use methods we learned from Dirk Krause's program Bmeps and - raster encoding code copied almost directly from Bmeps. + We use methods we learned from Dirk Krause's program Bmeps. + Previous versions used raster encoding code based on Bmeps + code. This program does not used any code from Bmeps. 2) Use our own filters and redefine /readstring . This is aboriginal - Netpbm code, from when Postscript was young. + Netpbm code, from when Postscript was young. The filters are + nearly identical to /ASCIIHexDecode and /RunLengthDecode. We + use the same raster encoding code with slight modifications. - (2) is the default, because it's been working for ages and we have - more confidence in it. But (1) gives more options. The user - selects (1) with the -psfilter option. + (2) is the default. (1) gives more options, but relies on features + introduced in Postscript Level 2, which appeared in 1991. Postcript + devices made before 1991 can't handle them. The user selects (1) + with the -psfilter option. We also do a few other bold new things only when the user specifies -psfilter, because we're not sure they work for everyone. @@ -31,16 +35,22 @@ #define _BSD_SOURCE /* Make sure string.h contains strdup() */ #define _XOPEN_SOURCE 500 /* Make sure strdup() is in string.h */ - -#include <string.h> +#include <stdlib.h> +#include <stdio.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> #include <assert.h> +#include <string.h> +#ifndef NOFLATE +#include <zlib.h> +#endif #include "pm_c_util.h" #include "pam.h" #include "mallocvar.h" #include "shhopt.h" #include "nstring.h" -#include "bmepsoe.h" struct cmdlineInfo { /* All the information the user supplied in the command line, @@ -73,46 +83,44 @@ struct cmdlineInfo { unsigned int verbose; }; - 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); + 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); - } + 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); } } + } } @@ -126,19 +134,18 @@ 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', @@ -150,11 +157,11 @@ validateCompDimension(unsigned int const value, 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 computations: %u", vname, value); + if (scaleFactor > maxScaleFactor) + pm_error("%s is too large for compuations: %u", vname, value); } } @@ -162,7 +169,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; @@ -196,7 +203,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); @@ -206,7 +213,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; @@ -215,379 +222,676 @@ 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; cmdlineP->canturn = !noturn; cmdlineP->showpage = !noshowpage; - validateCompDimension(width, 72, "-width value"); + validateCompDimension(width, 72, "-width value"); validateCompDimension(height, 72, "-height value"); cmdlineP->width = width * 72; cmdlineP->height = height * 72; if (imagewidthSpec) { - validateCompDimension(imagewidth, 72, "-imagewidth value"); - cmdlineP->imagewidth = imagewidth * 72; - } else - cmdlineP->imagewidth = 0; + validateCompDimension(imagewidth, 72, "-imagewidth value"); + cmdlineP->imagewidth = imagewidth * 72; + } + else + 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; + cmdlineP->imageheight = 0; + +#ifdef NOFLATE + if (cmdlineP->flate) + pm_error("This program cannot handle flate compression. " + "Flate support suppressed at compile time."); +#endif 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); } /*=========================================================================== - The native output encoder. This is archaic and uses global variables. - It is probably obsoleted by the bmeps output encoder; we just haven't - had a chance to verify that yet. + The output encoder ===========================================================================*/ + +enum output {AsciiHex, Ascii85}; +enum compress {none, Runlength, Flate, RunlengthFlate}; -/*---------------------------------------------------------------------------- - The following global variables are the native output encoder state. ------------------------------------------------------------------------------*/ -static unsigned int itemsinline; - /* The number of items in the line we are currently building */ -static unsigned int bitsinitem; - /* The number of bits filled so far in the item we are currently - building - */ -static unsigned int rlebitsinitem; - /* The number of bits filled so far in the item we are currently - building - */ -static unsigned int bitsPerSample; -static unsigned int item, bitshift, items; -static unsigned int rleitem, rlebitshift; -static unsigned int repeat, itembuf[128], count, repeatitem, repeatcount; - +typedef struct { + enum output output; + enum compress compress; + unsigned int runlengthRefresh; + int pid[3]; /* child process ID, transmitted to parent */ +} OutputEncoder; static void -initNativeOutputEncoder(bool const rle, - unsigned int const bitsPerSample) { -/*---------------------------------------------------------------------------- - Initialize the native output encoder. Call this once per - Postscript image that you will write with putitem(), before for the - first putitem(). +initOutputEncoder(OutputEncoder * const oeP, + unsigned int const icols, + unsigned int const bitsPerSample, + bool const rle, + bool const flate, + bool const ascii85, + bool const psFilter) { - We initialize the item putter state variables, which are the - global variable defined above. ------------------------------------------------------------------------------*/ - itemsinline = 0; - items = 0; - - if (rle) { - rleitem = 0; - rlebitsinitem = 0; - rlebitshift = 8 - bitsPerSample; - repeat = 1; - count = 0; - } else { - item = 0; - bitsinitem = 0; - bitshift = 8 - bitsPerSample; - } -} + unsigned int const bytesPerRow = icols / (8/bitsPerSample) + + (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->output = ascii85 ? Ascii85 : AsciiHex; -static void -putitem(void) { - const char* const hexits = "0123456789abcdef"; + 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; - if (itemsinline == 30) { - putchar('\n'); - itemsinline = 0; + if(ascii85) { + assert(psFilter); + oeP->output = Ascii85; } - assert(item >> 8 == 0); - putchar(hexits[item >> 4]); - putchar(hexits[item & 15]); - ++itemsinline; - ++items; - item = 0; - bitsinitem = 0; - bitshift = 8 - bitsPerSample; + else + oeP->output = AsciiHex; + } +/* +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 void -flushitem() { - if (bitsinitem > 0) - putitem(); +static void +flateFilter(int const fdsource, int const fddest, OutputEncoder * const oeP) +#ifndef NOFLATE +{ + +#define CHUNK 128*1024 /* recommended in zpipe.c */ + /* 4096 is not efficient but works */ + + int ret, flush; + unsigned have; + 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 */ + + 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."); + + /* 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."); + + /* 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."); + } + } while (strm.avail_out == 0); + assert(strm.avail_in == 0); /* all input will be 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); +} +#else +{ + assert(0==1); /* should never be executed */ } +#endif +/* Run length encoding -static void -putxelval(xelval const xv) { - if (bitsinitem == 8) - putitem(); - item += xv << bitshift; - bitsinitem += bitsPerSample; - bitshift -= bitsPerSample; -} +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. +*/ static void -rleputbuffer() { - if (repeat) { - item = 256 - count; - putitem(); - item = repeatitem; - putitem(); - } else { - unsigned int i; - - item = count - 1; - putitem(); - for (i = 0; i < count; ++i) { - item = itembuf[i]; - putitem(); - } - } - repeat = 1; - count = 0; +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 void -rleputitem() { - int i; +rleFilter (int const in, int const out, 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; + - if ( count == 128 ) - rleputbuffer(); + 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."); - if ( repeat && count == 0 ) - { /* Still initializing a repeat buf. */ - itembuf[count] = repeatitem = rleitem; - ++count; + while ((rleitem = fgetc (fin)) != EOF) { + 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; - ++count; - } - else - { /* Run ended - is it long enough to dump? */ - if ( count > 2 ) - { /* Yes, dump a repeat-mode buffer and start a new one. */ - rleputbuffer(); - itembuf[count] = repeatitem = rleitem; - ++count; - } - else - { /* Not long enough - convert to non-repeat mode. */ - repeat = 0; - itembuf[count] = repeatitem = rleitem; - ++count; - repeatcount = 1; - } - } + 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 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(); - count = repeatcount; - for ( i = 0; i < count; ++i ) - itembuf[i] = rleitem; - } - else - { /* Not long enough yet - continue as non-repeat buf. */ - itembuf[count] = rleitem; - ++count; - } - } - else - { /* Broken run. */ - itembuf[count] = repeatitem = rleitem; - ++count; - repeatcount = 1; - } + 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; + } + } + else { /* Broken run. */ + itembuf[count++] = repeatitem = rleitem; + repeatcount = 1; - rleitem = 0; - rlebitsinitem = 0; - rlebitshift = 8 - bitsPerSample; -} + } + } + if (incount == refresh) { + rlePutBuffer (repeat, count, repeatitem, itembuf, fout); + repeat = 1; + count = incount = 0; + } + if (count == 128) { + rlePutBuffer (repeat, count, repeatitem, itembuf, fout); + repeat = 1; + count = 0; + } -static void -rleputxelval(xelval const xv) { - if (rlebitsinitem == 8) - rleputitem(); - rleitem += xv << rlebitshift; - rlebitsinitem += bitsPerSample; - rlebitshift -= bitsPerSample; + } + + if (count > 0) + rlePutBuffer (repeat, count, repeatitem, itembuf, fout); + + fclose (fin); + fclose (fout); } static void -rleflush() { - if (rlebitsinitem > 0) - rleputitem(); - if (count > 0) - rleputbuffer(); +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); } + static void -flushNativeOutput(bool const rle) { - if (rle) - rleflush(); - else - flushitem(); - printf("\n"); -} - -/*=========================================================================== - The BMEPS output encoder. -===========================================================================*/ +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) { -/* This code is just a wrapper around the output encoder that is part of - Bmeps, to give it better modularity. -*/ + 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; -struct bmepsoe { - Output_Encoder * oeP; - int * rleBuffer; - Byte * flateInBuffer; - Byte * flateOutBuffer; -}; + fwrite(outbuff, 1, count+1, stdout); + count = value = 0; + outcount+=5; + } + if (outcount > 75) { + putchar('\n'); + outcount=0; + } + } + if (count >0) { /* EOF, flush */ + assert (count < 4 ); -static void -createBmepsOutputEncoder(struct bmepsoe ** const bmepsoePP, - FILE * const ofP, - bool const rle, - bool const flate, - bool const ascii85) { - - unsigned int const FLATE_IN_SIZE = 16384; - unsigned int const FLATE_OUT_SIZE = 17408; - - struct bmepsoe * bmepsoeP; - int mode; - - MALLOCVAR_NOFAIL(bmepsoeP); - MALLOCVAR_NOFAIL(bmepsoeP->oeP); - MALLOCARRAY_NOFAIL(bmepsoeP->rleBuffer, 129); - MALLOCARRAY_NOFAIL(bmepsoeP->flateInBuffer, FLATE_IN_SIZE); - MALLOCARRAY_NOFAIL(bmepsoeP->flateOutBuffer, FLATE_OUT_SIZE); - - mode = 0; - if (rle) - mode |= OE_RL; - if (flate) - mode |= OE_FLATE; - if (ascii85) - mode |= OE_ASC85; + 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'; - oe_init(bmepsoeP->oeP, ofP, mode, 9, - bmepsoeP->rleBuffer, - bmepsoeP->flateInBuffer, FLATE_IN_SIZE, - bmepsoeP->flateOutBuffer, FLATE_OUT_SIZE); + fwrite(outbuff, 1, count+2, stdout); + } - *bmepsoePP = bmepsoeP; + fclose (fp); + fclose (stdout); } +/* +Open pipes and spawn child processes + +Each filter is a separate child process. The parent process feeds +raster data into the pipeline. + + convertRow | asciiHexFilter + convertRow | ascii85Filter + convertRow | rleFilter | asciiHexFilter + convertRow | flateFilter | asciiHexFilter + convertRow | flateFilter | rleFilter | asciiHexFilter + +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. + +*/ + static void -destroyBmepsOutputEncoder(struct bmepsoe * const bmepsoeP) { - - free(bmepsoeP->rleBuffer); - free(bmepsoeP->flateInBuffer); - free(bmepsoeP->flateOutBuffer); - free(bmepsoeP->oeP); - - free(bmepsoeP); +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]); + + exit (EXIT_SUCCESS); + break; + } + + /* parent (Neither child comes here) */ + close (p1[0]); + *feedP = p1[1]; + oeP->pid[1] = oeP->pid[2] = 0; } static void -outputBmepsSample(struct bmepsoe * const bmepsoeP, - unsigned int const sampleValue, - unsigned int const bitsPerSample) { +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; + } - if (bitsPerSample == 8) - oe_byte_add(bmepsoeP->oeP, sampleValue); - else { - unsigned int m; + exit (EXIT_SUCCESS); + break; + } - for (m = 1 << (bitsPerSample-1); m != 0; m >>= 1) - /* depends on oe_bit_add accepting any value !=0 as 1 */ - oe_bit_add(bmepsoeP->oeP, sampleValue & m); - } + 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]); + + 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; } static void -flushBmepsOutput(struct bmepsoe * const bmepsoeP) { - oe_byte_flush(bmepsoeP->oeP); +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]); + + exit (EXIT_SUCCESS); + break; + } + + /* parent (Neither child comes here) */ + close (p1[0]); close (p2[0]); close (p2[1]); + close (p3[0]); close (p3[1]); + *feedP = p1[1]; } +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); + } +} + +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); + } + } + } +} /*============================================================================ END OF OUTPUT ENCODERS ============================================================================*/ @@ -596,9 +900,9 @@ flushBmepsOutput(struct bmepsoe * const bmepsoeP) { static void validateComputableBoundingBox(float const scols, - float const srows, - float const llx, - float const lly) { + float const srows, + float const llx, + float const lly) { float const bbWidth = llx + scols + 0.5; float const bbHeight = lly + srows + 0.5; @@ -606,32 +910,32 @@ validateComputableBoundingBox(float const scols, 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); + "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. @@ -663,71 +967,71 @@ computeImagePosition(int const dpiX, 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 - rotated if applicable - */ + /* Number of columns, rows of input xels in the output, as + rotated if applicable + */ 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); - - *scolsP = cols*scale; - *srowsP = rows*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); + + *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; - /* 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; - - scale = MIN(requestedScale, - MIN((float)pagewid/cols, (float)pagehgt/rows)); - - *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. - */ + /* 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; + + scale = MIN(requestedScale, + MIN((float)pagewid/cols, (float)pagehgt/rows)); + + *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. + */ } *llxP = (center) ? ( pagewid - *scolsP ) / 2 : 0; *llyP = (center) ? ( pagehgt - *srowsP ) / 2 : 0; @@ -735,30 +1039,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; - } else + 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; } @@ -769,42 +1073,42 @@ defineReadstring(bool const rle) { 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(" 256 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"); } } @@ -812,51 +1116,47 @@ 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). -----------------------------------------------------------------------------*/ unsigned int const bytesPerRow = icols / (8/bitsPerSample) + - (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. - */ + (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); if (ascii85) - printf("/ASCII85Decode filter "); + printf("/ASCII85Decode filter "); else - printf("/ASCIIHexDecode filter "); + printf("/ASCIIHexDecode filter "); if (flate) - printf("/FlateDecode filter "); - if (rle) /* bmeps encodes rle before flate, so must decode after! */ - printf("/RunLengthDecode filter "); + printf("/FlateDecode filter "); + if (rle) /* activateThreeFilters() encodes rle before flate, + so decode must be flate then rle */ + printf("/RunLengthDecode filter "); } @@ -865,33 +1165,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. -----------------------------------------------------------------------------*/ 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"); } @@ -900,29 +1200,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. -----------------------------------------------------------------------------*/ 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; @@ -951,24 +1251,24 @@ 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). @@ -985,31 +1285,32 @@ 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); } @@ -1022,28 +1323,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"); } @@ -1051,46 +1352,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; + 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; + /* 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; } @@ -1099,41 +1400,41 @@ 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 @@ -1145,139 +1446,259 @@ computeDepth(xelval const inputMaxval, 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; +} BitAccumulator; + + +static void +bits12_add(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. +-----------------------------------------------------------------------------*/ + + 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 -padRightNative(unsigned int const bitsPerSample, - unsigned int const width, - bool const rle) { +bits_add(BitAccumulator * const baP, + unsigned int const b, + int const bitsPerSample, + FILE * const fp) { /*---------------------------------------------------------------------------- - Write extra columns to row end to bring output up to byte boundary, - given that the row is 'width' columns wide with 'bitsPerSample' - bits per column. + Combine bit sequences that do not fit into a byte. - 'rle' means to write the padding in RLE row format. + 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. -----------------------------------------------------------------------------*/ - /* - 'stragglers' is the number of bits at the right edge that don't - fill out a whole byte and 'padcols' is the number of columns we - have to add to fill out that last byte. - - E.g. at 2 bits per sample with 10 columns, stragglers is 4; padcols - is 2. - */ - unsigned int const stragglers = - (bitsPerSample * (width % 8)) % 8; - unsigned int const padcols = - stragglers > 0 ? (8-stragglers) / bitsPerSample : 0; + int const bufSize = 8; + + 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; + } +} - unsigned int col; - for (col = 0; col < padcols; ++col) { - if (rle) - rleputxelval(0); - else - putxelval(0); + +static void +bits_flush(BitAccumulator * const baP, FILE * const fp) { +/*---------------------------------------------------------------------------- + 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); + + else if (baP->consumed > 0) { + int const leftShift = 8 - baP->consumed; + 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) { + + if (bitsPerSample == 8) + fputc( sampleValue, fp); + else if (bitsPerSample == 12) + bits12_add(baP, sampleValue, fp); + else { + bits_add(baP, sampleValue, bitsPerSample, fp); + } +} + + + +static void +flushOutput(BitAccumulator * const baP, FILE * const fp) { + bits_flush(baP, fp); +} + +/*---------------------------------------------------------------------- + Row converters + + convertRowPbm is a fast routine for PBM images. + It is used only when the input is PBM and the user does not specify + a -bitspersample value greater than 1. It is not used when the input + image is PGM or PPM and the output resolution is brought down to one + bit per pixel by -bitpersample=1 . + + 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). + (2) Native flushes the run-length encoder at the end of each row if + grayscale, at the end of each plane if color. + + Both convertRowNative and convertRowPsFilter can handle PBM, though we + don't use them. + + 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) { +/*--------------------------------------------------------------------- + Feed PBM raster data directly to the output encoder. + Invert bits: 0 is "white" in PBM, 0 is "black" in postscript. +----------------------------------------------------------------------*/ + unsigned int colChar; + unsigned int const colChars = pbm_packed_bytes(pamP->width); + unsigned int const padRight = (8 - pamP->width %8) %8; + + pbm_readpbmrow_packed(pamP->file, bitrow, pamP->width, pamP->format); + + for (colChar = 0; colChar < colChars; ++colChar) + bitrow[colChar] = ~ bitrow[colChar]; + + if(padRight > 0) { + bitrow[colChars-1] >>= padRight; /* Zero clear padding beyond */ + bitrow[colChars-1] <<= padRight; /* right edge */ } + + fwrite(bitrow, 1, colChars, fp); } static void -convertRowNative(struct pam * const pamP, - tuple * const tuplerow, - unsigned int const bitsPerSample, - bool const rle) { +convertRowNative(struct pam * const pamP, + tuple * tuplerow, + unsigned int const bitsPerSample, + FILE * const fp) { unsigned int plane; unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample); + BitAccumulator ba; + ba.value = ba.consumed =0; - for (plane = 0; plane < pamP->depth; ++plane) { - unsigned int col; - for (col= 0; col < pamP->width; ++col) { - sample const scaledSample = - pnm_scalesample(tuplerow[col][plane], pamP->maxval, psMaxval); - - if (rle) - rleputxelval(scaledSample); - else - putxelval(scaledSample); - } + pnm_readpamrow(pamP, tuplerow); + pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval); - padRightNative(bitsPerSample, pamP->width, rle); + for (plane = 0; plane < pamP->depth; ++plane) { + unsigned int col; + for (col= 0; col < pamP->width; ++col) { + outputSample(&ba, tuplerow[col][plane], bitsPerSample, fp); + } - if (rle) - rleflush(); + flushOutput(&ba, fp); } + } static void convertRowPsFilter(struct pam * const pamP, - tuple * const tuplerow, - struct bmepsoe * const bmepsoeP, - unsigned int const bitsPerSample) { - - unsigned int const stragglers = - (((bitsPerSample * pamP->depth) % 8) * (pamP->width%8)) % 8; - /* Number of bits at the right edge that don't fill out a whole - byte - */ + tuple * tuplerow, + unsigned int const bitsPerSample, + FILE * const fp) { + unsigned int col; unsigned int const psMaxval = pm_bitstomaxval(bitsPerSample); + BitAccumulator ba; + ba.value = ba.consumed =0; - unsigned int col; - tuple scaledTuple; - - scaledTuple = pnm_allocpamtuple(pamP); + pnm_readpamrow(pamP, tuplerow); + pnm_scaletuplerow(pamP, tuplerow, tuplerow, psMaxval); for (col = 0; col < pamP->width; ++col) { - unsigned int plane; - pnm_scaletuple(pamP, scaledTuple, tuplerow[col], psMaxval); - - for (plane = 0; plane < pamP->depth; ++plane) - outputBmepsSample(bmepsoeP, scaledTuple[plane], bitsPerSample); - } - if (stragglers > 0) { - unsigned int i; - for (i = stragglers; i < 8; ++i) - oe_bit_add(bmepsoeP->oeP, 0); + unsigned int plane; + for (plane = 0; plane < pamP->depth; ++plane) + outputSample(&ba, tuplerow[col][plane], bitsPerSample, fp); } - pnm_freepamtuple(scaledTuple); + flushOutput(&ba, fp); + } 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 @@ -1289,130 +1710,144 @@ 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 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; - tuple* tuplerow; int row; float scols, srows; float llx, lly; bool turned; bool color; unsigned int postscriptLevel; - struct bmepsoe * bmepsoeP; + unsigned int bitsPerSample; unsigned int dictSize; - /* Size of Postscript dictionary we should define */ + /* Size of Postscript dictionary we should define */ + OutputEncoder * oeP; + + int feed; + FILE * fp; 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 (oeP, inpam.width, bitsPerSample, rle, + flate, ascii85, psFilter); + activateFilters(&feed, oeP); + + fp=fdopen (feed, "w"); - createBmepsOutputEncoder(&bmepsoeP, stdout, rle, flate, ascii85); - initNativeOutputEncoder(rle, bitsPerSample); + if( PAM_FORMAT_TYPE(inpam.format) == PBM_TYPE && bitsPerSample==1 ) { + unsigned char * const bitrow = pbm_allocrow_packed(inpam.width); - tuplerow = pnm_allocpamrow(&inpam); + 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) { - pnm_readpamrow(&inpam, tuplerow); if (psFilter) - convertRowPsFilter(&inpam, tuplerow, bmepsoeP, bitsPerSample); + convertRowPsFilter(&inpam, tuplerow, bitsPerSample, fp); else - convertRowNative(&inpam, tuplerow, bitsPerSample, rle); - } + convertRowNative(&inpam, tuplerow, bitsPerSample, fp); + } pnm_freepamrow(tuplerow); + } - if (psFilter) - flushBmepsOutput(bmepsoeP); - else - flushNativeOutput(rle); + fclose (fp); - destroyBmepsOutputEncoder(bmepsoeP); + waitForChildren(oeP->pid); + free(oeP); putEnd(showpage, psFilter, ascii85, dictSize, vmreclaim); } @@ -1431,16 +1866,16 @@ basebasename(const char * const filespec) { const char * filename; if (lastSlashPos) - filename = lastSlashPos + 1; + filename = lastSlashPos + 1; else - filename = filespec; + filename = filespec; name = strdup(filename); if (name != NULL) { - char * const dotPosition = strchr(name, '.'); + char * const dotPosition = strchr(name, '.'); - if (dotPosition) - *dotPosition = '\0'; + if (dotPosition) + *dotPosition = '\0'; } return name; } @@ -1463,41 +1898,41 @@ main(int argc, const char * argv[]) { 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); @@ -1522,4 +1957,9 @@ main(int argc, const char * argv[]) { ** -nocenter option added November 1993 by Wolfgang Stuerzlinger, ** wrzl@gup.uni-linz.ac.at. ** +** July 2011 afu +** row convertors rewritten, fast PBM-only row convertor added, +** rle compression slightly modified, flate compression added +** ascii85 output end added. +** */ |