about summary refs log tree commit diff
path: root/converter
diff options
context:
space:
mode:
Diffstat (limited to 'converter')
-rw-r--r--converter/other/Makefile27
-rw-r--r--converter/other/pnmtorle.c20
-rw-r--r--converter/other/rletopnm.c78
-rw-r--r--converter/pbm/pbmtolps.c374
4 files changed, 299 insertions, 200 deletions
diff --git a/converter/other/Makefile b/converter/other/Makefile
index 2be88781..5dfc27ec 100644
--- a/converter/other/Makefile
+++ b/converter/other/Makefile
@@ -7,10 +7,26 @@ VPATH=.:$(SRCDIR)/$(SUBDIR)
 
 include $(BUILDDIR)/config.mk
 
-TEST_PKGCONFIG_LIBXML2 = if $(PKG_CONFIG) libxml-2.0; then echo exists; fi
+# The pkg-config test used to be just 'pkg-config libxml-2.0', without the
+# --exists, and on at least one system, it does the same thing as --exists:
+# exit code 0 if the package exists; 1 if it does not, with no Standard
+# Output.  But we have evidence that on one system, it issues the whole
+# package not found try a different path, blah, blah, blah message that
+# looks like a failure in the build.  We're hoping --exists does not do that.
+# But maybe we didn't do --exists in the first place because it doesn't exist
+# on older pkg-config.  19.09.20.
+#
+# Note that --exists is better for another reason - it fails when the named
+# package exists, but it is unusable because its prerequisite packages don't.
+#
+# Also note that in both cases, the shell command fails if pkg-config
+# doesn't even exist.
+
+TEST_PKGCONFIG_LIBXML2 := \
+  if $(PKG_CONFIG) libxml-2.0 --exists; then echo exists; fi
 
 ifneq ($(shell $(TEST_PKGCONFIG_LIBXML2)),)
-  # pkg-config libxml2 works on this system
+  # pkg-config works and says libxml2 exists on this system
   XML2_LIBS = $(shell $(PKG_CONFIG) libxml-2.0 --libs)
   XML2_CFLAGS = $(shell $(PKG_CONFIG) libxml-2.0 --cflags)
 else
@@ -34,10 +50,11 @@ ifneq ($(TIFFLIB),NONE)
   endif
 endif
 
-TEST_PKGCONFIG_LIBPNG = if $(PKG_CONFIG) libpng$(PNGVER); then echo exists; fi
+TEST_PKGCONFIG_LIBPNG := \
+  if $(PKG_CONFIG) libpng$(PNGVER) --exists; then echo exists; fi
 
 ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),)
-  # pkg-config libpng works on this system
+  # pkg-config works and says libpng exists on this system
   HAVE_PNGLIB = Y
   EXTERN_INCLUDES += $(shell $(PKG_CONFIG) libpng$(PNGVER) --cflags)
 else
@@ -193,7 +210,7 @@ tifftopnm pamtotiff pnmtotiffcmyk: \
  $(shell $(LIBOPT)  $(LIBOPTR) $(TIFFLIB) $(TIFFLIB_EXTRALIBS))
 
 ifneq ($(shell $(TEST_PKGCONFIG_LIBPNG)),)
-  # pkg-config libpng works on this system
+  # pkg-config works and says libpng exists on this system
   PNGLIB_LIBOPTS = $(shell $(PKG_CONFIG) libpng$(PNGVER) --libs)
 else
   ifneq ($(shell libpng$(PNGVER)-config --version),)
diff --git a/converter/other/pnmtorle.c b/converter/other/pnmtorle.c
index 8908c356..1882fe5d 100644
--- a/converter/other/pnmtorle.c
+++ b/converter/other/pnmtorle.c
@@ -1,7 +1,7 @@
 /*
  * This is derived from the file of the same name dated June 5, 1995,
  * copied from the Army High Performance Computing Research Center's
- * media-tools.tar.gz package, received from 
+ * media-tools.tar.gz package, received from
  * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13.
  *
  * This software is copyrighted as noted below.  It may be freely copied,
@@ -29,8 +29,8 @@
  *              Minnesota Supercomputer Center, Inc.
  * Date:        March 30, 1994
  * Copyright (c) Minnesota Supercomputer Center, Inc.
- * 
- * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler 
+ *
+ * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler
  *            warnings.
  *
  */
@@ -58,7 +58,7 @@ static gray    maxval;
 /*-----------------------------------------------------------------------------
  *                                        Read the pnm image file header.
  */
-static void 
+static void
 read_pnm_header(void) {
 
     pnm_readpnminit(fp, &width, &height, &maxval, &format);
@@ -90,7 +90,7 @@ read_pnm_header(void) {
 
 
 
-static void 
+static void
 write_rle_header(void) {
 
     hdr.xmin    = 0;
@@ -123,7 +123,7 @@ write_rle_header(void) {
 
 
 
-static void 
+static void
 write_rle_data(void) {
 
     unsigned int scan;
@@ -133,12 +133,14 @@ write_rle_data(void) {
     MALLOCARRAY(xelrow, width);
     MALLOCARRAY(scanlines, height);
 
-    RLE_CHECK_ALLOC(hdr.cmd, scanlines, "scanline pointers");
+    if (!scanlines)
+        pm_error("Failed to allocate memory for %u scanline pointers", height);
 
     for (scan = 0; scan < height; ++scan) {
         int rc;
         rc = rle_row_alloc(&hdr, &scanlines[scan]);
-        RLE_CHECK_ALLOC(hdr.cmd, rc >= 0, "pixel memory");
+        if (rc < 0)
+            pm_error("Failed to allocate memory for a scanline");
     }
     /* Loop through the pnm files image window, read data and flip vertically.
      */
@@ -254,7 +256,7 @@ main(int argc, char **  argv) {
             rle_addhist(argv, NULL, &hdr);
             write_rle_header();
             write_rle_data();
-            
+
             pnm_nextimage(fp, &eof);
         }
     }
diff --git a/converter/other/rletopnm.c b/converter/other/rletopnm.c
index 018456c8..97f271dc 100644
--- a/converter/other/rletopnm.c
+++ b/converter/other/rletopnm.c
@@ -1,7 +1,7 @@
 /*
  * This is derived from the file of the same name dated June 5, 1995,
  * copied from the Army High Performance Computing Research Center's
- * media-tools.tar.gz package, received from 
+ * media-tools.tar.gz package, received from
  * http://www.arc.umn.edu/gvl-software/media-tools.tar.gz on 2000.04.13.
  *
  * This software is copyrighted as noted below.  It may be freely copied,
@@ -29,8 +29,8 @@
  *              Minnesota Supercomputer Center, Inc.
  * Date:        March 30, 1994
  * Copyright (c) Minnesota Supercomputer Center 1994
- * 
- * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler 
+ *
+ * 2000.04.13 adapted for Netpbm by Bryan Henderson.  Quieted compiler
  *            warnings.  Added --alpha option.  Accept input on stdin
  *
  */
@@ -105,11 +105,11 @@ parseCommandLine(int argc, char ** argv,
     MALLOCARRAY(option_def, 100);
 
     option_def_index = 0;   /* incremented by OPTENT3 */
-    OPTENT3('h', "headerdump", OPT_FLAG,   
+    OPTENT3('h', "headerdump", OPT_FLAG,
             NULL,                      &cmdlineP->headerdump,     0);
-    OPTENT3('v', "verbose",    OPT_FLAG,   
+    OPTENT3('v', "verbose",    OPT_FLAG,
             NULL,                      &cmdlineP->verbose,        0);
-    OPTENT3(0,   "alphaout",   OPT_STRING, 
+    OPTENT3(0,   "alphaout",   OPT_STRING,
             &cmdlineP->alphaout, &alphaoutSpec,                   0);
 
     opt.opt_table = option_def;
@@ -127,16 +127,16 @@ parseCommandLine(int argc, char ** argv,
     else if (argc - 1 == 1) {
         if (streq(argv[1], "-"))
             cmdlineP->inputFilename = NULL;  /* he wants stdin */
-        else 
+        else
             cmdlineP->inputFilename = strdup(argv[1]);
-    } else 
+    } else
         pm_error("Too many arguments.  The only argument accepted "
                  "is the input file specification");
 
-    if (cmdlineP->alphaout && 
+    if (cmdlineP->alphaout &&
         streq(cmdlineP->alphaout, "-"))
         cmdlineP->alphaStdout = TRUE;
-    else 
+    else
         cmdlineP->alphaStdout = FALSE;
 }
 
@@ -144,7 +144,7 @@ parseCommandLine(int argc, char ** argv,
 
 static void
 reportRleGetSetupError(int const rleGetSetupRc) {
-    
+
     switch (rleGetSetupRc) {
     case -1:
         pm_error("According to the URT library, the input is not "
@@ -168,7 +168,7 @@ reportRleGetSetupError(int const rleGetSetupRc) {
 
 
 
-static void 
+static void
 readRleHeader(FILE * const ifP,
               bool   const headerDump) {
 
@@ -256,7 +256,7 @@ readRleHeader(FILE * const ifP,
 
 
 
-static void 
+static void
 writePpmRaster(FILE * const imageoutFileP,
                FILE * const alphaFileP) {
 
@@ -264,7 +264,7 @@ writePpmRaster(FILE * const imageoutFileP,
     pixval r, g, b;
     pixel *pixelrow;
     gray *alpharow;
-   
+
     int scan;
     int x;
     /*
@@ -274,11 +274,15 @@ writePpmRaster(FILE * const imageoutFileP,
     alpharow = pgm_allocrow(width);
 
     MALLOCARRAY(scanlines, height);
-    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
+    if (!scanlines)
+        pm_error("Failed to allocate memory for %u scanline pointers", height);
 
-    for ( scan = 0; scan < height; scan++ )
-        RLE_CHECK_ALLOC( hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
-                         "pixel memory" );
+    for (scan = 0; scan < height; ++scan) {
+        int rc;
+        rc = rle_row_alloc(&hdr, &scanlines[scan]);
+        if (rc < 0)
+            pm_error("Failed to allocate memory for a scanline");
+    }
     /*
      * Loop through those scan lines.
      */
@@ -295,7 +299,7 @@ writePpmRaster(FILE * const imageoutFileP,
                 PPM_ASSIGN(pixelrow[x], r, g, b);
                 if (hdr.alpha)
                     alpharow[x] = scanline[-1][x];
-                else 
+                else
                     alpharow[x] = 0;
             }
             break;
@@ -305,7 +309,7 @@ writePpmRaster(FILE * const imageoutFileP,
                 g = colormap[scanline[1][x]+256]>>8;
                 b = colormap[scanline[2][x]+512]>>8;
                 PPM_ASSIGN(pixelrow[x], r, g, b);
-                if (hdr.alpha) 
+                if (hdr.alpha)
                     alpharow[x] = colormap[scanline[-1][x]];
                 else
                     alpharow[x] = 0;
@@ -329,7 +333,7 @@ writePpmRaster(FILE * const imageoutFileP,
                 g = colormap[scanline[0][x]+256]>>8;
                 b = colormap[scanline[0][x]+512]>>8;
                 PPM_ASSIGN(pixelrow[x], r, g, b);
-                if (hdr.alpha) 
+                if (hdr.alpha)
                     alpharow[x] = colormap[scanline[-1][x]];
                 else
                     alpharow[x] = 0;
@@ -341,7 +345,7 @@ writePpmRaster(FILE * const imageoutFileP,
         /*
          * Write the scan line.
          */
-        if (imageoutFileP) 
+        if (imageoutFileP)
             ppm_writeppmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
         if (alphaFileP)
             pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
@@ -358,7 +362,7 @@ writePpmRaster(FILE * const imageoutFileP,
 
 
 
-static void 
+static void
 writePgmRaster(FILE * const imageoutFileP,
                FILE * const alphaFileP) {
 /*----------------------------------------------------------------------------
@@ -375,11 +379,15 @@ writePgmRaster(FILE * const imageoutFileP,
     alpharow = pgm_allocrow(width);
 
     MALLOCARRAY(scanlines, height);
-    RLE_CHECK_ALLOC( hdr.cmd, scanlines, "scanline pointers" );
+    if (!scanlines)
+        pm_error("Failed to allocate memory for %u scanline pointers", height);
 
-    for (scan = 0; scan < height; ++scan)
-        RLE_CHECK_ALLOC(hdr.cmd, (rle_row_alloc(&hdr, &scanlines[scan]) >= 0),
-                        "pixel memory" );
+    for (scan = 0; scan < height; ++scan) {
+        int rc;
+        rc = rle_row_alloc(&hdr, &scanlines[scan]);
+        if (rc < 0)
+            pm_error("Failed to allocate memory for a scanline");
+    }
     /*
      * Loop through those scan lines.
      */
@@ -391,12 +399,12 @@ writePgmRaster(FILE * const imageoutFileP,
         scanline = scanlines[scan];
         for (x = 0; x < width; ++x) {
             pixelrow[x] = scanline[0][x];
-            if (hdr.alpha) 
+            if (hdr.alpha)
                 alpharow[x] = scanline[1][x];
             else
                 alpharow[x] = 0;
         }
-        if (imageoutFileP) 
+        if (imageoutFileP)
             pgm_writepgmrow(imageoutFileP, pixelrow, width, RLE_MAXVAL, 0);
         if (alphaFileP)
             pgm_writepgmrow(alphaFileP, alpharow, width, RLE_MAXVAL, 0);
@@ -428,20 +436,20 @@ main(int argc, char ** argv) {
 
     fname = NULL;  /* initial value */
 
-    if (cmdline.inputFilename != NULL ) 
+    if (cmdline.inputFilename != NULL )
         ifP = pm_openr(cmdline.inputFilename);
     else
         ifP = stdin;
 
     if (cmdline.alphaStdout)
         alphaFileP = stdout;
-    else if (cmdline.alphaout == NULL) 
+    else if (cmdline.alphaout == NULL)
         alphaFileP = NULL;
     else {
         alphaFileP = pm_openw(cmdline.alphaout);
     }
 
-    if (cmdline.alphaStdout) 
+    if (cmdline.alphaStdout)
         imageoutFileP = NULL;
     else
         imageoutFileP = stdout;
@@ -461,7 +469,7 @@ main(int argc, char ** argv) {
     if (cmdline.headerdump)
         exit(0);
 
-    /* 
+    /*
      * Write the alpha file header
      */
     if (alphaFileP)
@@ -486,9 +494,9 @@ main(int argc, char ** argv) {
         writePpmRaster(imageoutFileP, alphaFileP);
         break;
     }
-   
+
     pm_close(ifP);
-    if (imageoutFileP) 
+    if (imageoutFileP)
         pm_close(imageoutFileP);
     if (alphaFileP)
         pm_close(alphaFileP);
diff --git a/converter/pbm/pbmtolps.c b/converter/pbm/pbmtolps.c
index dd0342bc..d974fcb2 100644
--- a/converter/pbm/pbmtolps.c
+++ b/converter/pbm/pbmtolps.c
@@ -1,181 +1,253 @@
-/*
- * pbmtolps -- convert a Portable BitMap into Postscript.  The
- * output Postscript uses lines instead of the image operator to
- * generate a (device dependent) picture which will be imaged
- * much faster.
- *
- * The Postscript path length is constrained to be less that 1000
- * points so that no limits are overrun on the Apple Laserwriter
- * and (presumably) no other printers.
- *
- * To do:
- *      make sure encapsulated format is correct
- *      repitition of black-white strips
- *      make it more device independent (is this possible?)
- *
- * Author:
- *      George Phillips <phillips@cs.ubc.ca>
- *      Department of Computer Science
- *      University of British Columbia
- */
-
-#include <string.h>
-#include <stdio.h>
-
+/*=============================================================================
+                             pbmtolps
+===============================================================================
+
+  Convert a PBM image to Postscript.  The output Postscript uses lines instead
+  of the image operator to generate a (device dependent) picture which will be
+  imaged much faster.
+
+  The Postscript path length is constrained to be at most 1000 vertices so that
+  no limits are overrun on the Apple Laserwriter and (presumably) no other
+  printers.  The typical limit is 1500.  See "4.4 Path Construction" and
+  "Appendix B: Implementation Limits" in: PostScript Language Reference Manual
+  https://www.adobe.com/content/dam/acom/en/devnet/actionscript/
+  articles/psrefman.pdf
+
+  To do:
+       make sure encapsulated format is correct
+       repetition of black-white strips
+       make it more device independent (is this possible?)
+
+  Author:
+       George Phillips <phillips@cs.ubc.ca>
+       Department of Computer Science
+       University of British Columbia
+=============================================================================*/
+#include <stdbool.h>
+
+#include "pm_c_util.h"
+#include "mallocvar.h"
 #include "nstring.h"
+#include "shhopt.h"
 #include "pbm.h"
 
 
-static int prev_white = -1;
-static int prev_black = -1;
-static char cmd = '\0';
-static int pointcount = 2;
+static float        const MAX_DPI           = 5000;
+static float        const MIN_DPI           = 10;
+static unsigned int const MAX_PATH_VERTICES = 1000;
 
-#ifdef RUN
-static int run = 1;
-#endif
 
-static char
-morepoints(char cmd, int howmany_pbmtolps) {
-    pointcount += 2;
-    if (pointcount > 1000) {
-        pointcount = 2;
-        cmd += 'm' - 'a';
-    }
-    return(cmd);
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line, in a form
+       easy for the program to use.
+    */
+    const char * inputFileName;  /* File name of input file */
+    unsigned int inputFileSpec;  /* Input file name specified */
+    float        lineWidth;      /* Line width, if specified */
+    unsigned int lineWidthSpec;  /* Line width specified */
+    float        dpi;            /* Resolution in DPI, if specified */
+    unsigned int dpiSpec;        /* Resolution specified */
+};
+
+
+
+static void
+validateDpi(float const dpi) {
+
+    if (dpi > MAX_DPI || dpi < MIN_DPI)
+        pm_error("Specified DPI value out of range (%f)", dpi);
 }
 
 
 
 static void
-addstrip(int const white,
-         int const black) {
-
-    if (cmd) {
-#ifdef RUN
-        if (white == prev_white && black == prev_black)
-            run++;
-        else {
-            if (run == 1)
-#endif
-                printf("%d %d %c ",
-                       prev_black, prev_white, morepoints(cmd, 2));
-#ifdef RUN
-            else
-                                /* of course, we need to give a new command */
-                printf("%d %d %d %c ",
-                       prev_white, prev_black, run,
-                       morepoints(cmd + 'f' - 'a', 2 * run));
-            run = 1;
-        }
-#endif
+parseCommandLine(int                        argc,
+                 const char **        const argv,
+                 struct CmdlineInfo * const cmdlineP) {
+/*----------------------------------------------------------------------------
+   Parse program command line described in Unix standard form by argc
+   and argv.  Return the information in the options as *cmdlineP.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;  /* malloc'ed */
+        /* Instructions to OptParseOptions3 on how to parse our options.  */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "linewidth", OPT_FLOAT, &cmdlineP->lineWidth,
+                            &cmdlineP->lineWidthSpec,    0);
+    OPTENT3(0, "dpi",       OPT_FLOAT,  &cmdlineP->dpi,
+                            &cmdlineP->dpiSpec,          0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We have no parms that are negative numbers */
+
+    pm_optParseOptions3(&argc, (char **)argv, opt, sizeof(opt), 0);
+        /* Uses and sets argc, argv, and some of *cmdlineP and others. */
+
+    if (cmdlineP->dpiSpec)
+        validateDpi(cmdlineP->dpi);
+    else
+        cmdlineP->dpi = 300;
+
+    if (argc-1 < 1)
+        cmdlineP->inputFileName = "-";
+    else {
+        if (argc-1 > 1)
+            pm_error("Program takes zero or one argument (filename).  You "
+                     "specified %u", argc-1);
+        else
+            cmdlineP->inputFileName = argv[1];
     }
 
-    prev_white = white;
-    prev_black = black;
-    cmd = 'a';
+    if (cmdlineP->inputFileName[0] == '-' &&
+        cmdlineP->inputFileName[1] == '\0')
+        cmdlineP->inputFileSpec = false;
+    else
+        cmdlineP->inputFileSpec = true;
+
+    free(option_def);
 }
 
 
 
 static void
-nextline(void) {
-    /* need to check run, should have an outcommand */
-    if (cmd)
-        printf("%d %d %c\n", prev_black, prev_white, morepoints('c', 3));
-    else
-        printf("%c\n", morepoints('b', 1));
-    cmd = '\0';
+validateLineWidth(float const scCols,
+                  float const scRows,
+                  float const lineWidth) {
+
+    if (lineWidth >= scCols || lineWidth >= scRows)
+        pm_error("Absurdly large -linewidth value (%f)", lineWidth);
 }
 
 
 
-int
-main(int argc, char ** argv) {
-    FILE*   fp;
-    bit*    bits;
-    int             row;
-    int             col;
-    int         rows;
-    int             cols;
-    int             format;
-    int             white;
-    int             black;
-    const char*   name;
-    float   dpi = 300.0;
-    float   sc_rows;
-    float   sc_cols;
-    int             i;
-    const char*   const usage = "[ -dpi n ] [ pbmfile ]";
-
-
-	pbm_init(&argc, argv);
-
-    i = 1;
-    if (i < argc && streq(argv[i], "-dpi")) {
-        if (i == argc - 1)
-            pm_usage(usage);
-        sscanf(argv[i + 1], "%f", &dpi);
-        i += 2;
-    }
+static void
+doRaster(FILE *       const ifP,
+         unsigned int const cols,
+         unsigned int const rows,
+         int          const format,
+         FILE *       const ofP) {
 
-    if (i < argc - 1)
-        pm_usage(usage);
+    bit *        bitrow;
+    unsigned int row;
+    unsigned int vertexCt;
+        /* Number of vertices drawn since last stroke command */
 
-    if (i == argc) {
-        name = "noname";
-        fp = stdin;
-    } else {
-        name = argv[i];
-        fp = pm_openr(name);
-    }
-    pbm_readpbminit(fp, &cols, &rows, &format);
-    bits = pbm_allocrow(cols);
-
-    sc_rows = (float)rows / dpi * 72.0;
-    sc_cols = (float)cols / dpi * 72.0;
-
-    puts("%!PS-Adobe-2.0 EPSF-2.0");
-    puts("%%Creator: pbmtolps");
-    printf("%%%%Title: %s\n", name);
-    printf("%%%%BoundingBox: %d %d %d %d\n",
-           (int)(305.5 - sc_cols / 2.0),
-           (int)(395.5 - sc_rows / 2.0),
-           (int)(306.5 + sc_cols / 2.0),
-           (int)(396.5 + sc_rows / 2.0));
-    puts("%%EndComments");
-    puts("%%EndProlog");
-    puts("gsave");
-
-    printf("%f %f translate\n", 306.0 - sc_cols / 2.0, 396.0 + sc_rows / 2.0);
-    printf("72 %f div dup neg scale\n", dpi);
-    puts("/a { 0 rmoveto 0 rlineto } def");
-    puts("/b { 0 row 1 add dup /row exch def moveto } def");
-    puts("/c { a b } def");
-    puts("/m { currentpoint stroke newpath moveto a } def");
-    puts("/n { currentpoint stroke newpath moveto b } def");
-    puts("/o { currentpoint stroke newpath moveto c } def");
-    puts("/row 0 def");
-    puts("newpath 0 0 moveto");
-
-    for (row = 0; row < rows; row++) {
-        pbm_readpbmrow(fp, bits, cols, format);
-        /* output white-strip+black-strip sequences */
-        for (col = 0; col < cols; ) {
-            for (white = 0; col < cols && bits[col] == PBM_WHITE; col++)
-                white++;
-            for (black = 0; col < cols && bits[col] == PBM_BLACK; col++)
-                black++;
+    bitrow = pbm_allocrow(cols);
+
+    for (row = 0, vertexCt = 0; row < rows; ++row) {
+        unsigned int col;
+        bool firstRun;
 
-            if (black != 0)
-                addstrip(white, black);
+        firstRun = true;  /* initial value */
+
+        pbm_readpbmrow(ifP, bitrow, cols, format);
+
+        /* output white-strip + black-strip sequences */
+
+        for (col = 0; col < cols; ) {
+            unsigned int whiteCt;
+            unsigned int blackCt;
+
+            for (whiteCt = 0; col < cols && bitrow[col] == PBM_WHITE; ++col)
+                ++whiteCt;
+            for (blackCt = 0; col < cols && bitrow[col] == PBM_BLACK; ++col)
+                ++blackCt;
+
+            if (blackCt > 0) {
+                if (vertexCt > MAX_PATH_VERTICES) {
+                    printf("m ");
+                    vertexCt = 0;
+                }
+
+                if (firstRun) {
+                    printf("%u %u moveto %u 0 rlineto\n",
+                           whiteCt, row, blackCt);
+                    firstRun = false;
+                } else
+                    printf("%u %u a\n", blackCt, whiteCt);
+
+                vertexCt += 2;
+            }
         }
-        nextline();
     }
-    puts("stroke grestore showpage");
-    puts("%%Trailer");
+    pbm_freerow(bitrow);
+}
+
+
+
+static void
+pbmtolps(FILE *             const ifP,
+         FILE *             const ofP,
+         struct CmdlineInfo const cmdline) {
+
+    const char * const psName =
+        cmdline.inputFileSpec ? cmdline.inputFileName : "noname";
+
+    int          rows;
+    int          cols;
+    int          format;
+    float        scRows, scCols;
+        /* Dimensions of the printed image in points */
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    scRows = (float) rows / (cmdline.dpi / 72.0);
+    scCols = (float) cols / (cmdline.dpi / 72.0);
+
+    if (cmdline.lineWidthSpec)
+        validateLineWidth(scCols, scRows, cmdline.lineWidth);
+
+    fputs("%!PS-Adobe-2.0 EPSF-2.0\n", ofP);
+    fputs("%%Creator: pbmtolps\n", ofP);
+    fprintf(ofP, "%%%%Title: %s\n", psName);
+    fprintf(ofP, "%%%%BoundingBox: %d %d %d %d\n",
+           (int)(305.5 - scCols / 2.0),
+           (int)(395.5 - scRows / 2.0),
+           (int)(306.5 + scCols / 2.0),
+           (int)(396.5 + scRows / 2.0));
+    fputs("%%EndComments\n", ofP);
+    fputs("%%EndProlog\n", ofP);
+    fputs("gsave\n", ofP);
+
+    fprintf(ofP, "%f %f translate\n",
+            306.0 - scCols / 2.0, 396.0 + scRows / 2.0);
+    fprintf(ofP, "72 %f div dup neg scale\n", cmdline.dpi);
+
+    if (cmdline.lineWidthSpec)
+        fprintf(ofP, "%f setlinewidth\n", cmdline.lineWidth);
+
+    fputs("/a { 0 rmoveto 0 rlineto } def\n", ofP);
+    fputs("/m { currentpoint stroke newpath moveto } def\n", ofP);
+    fputs("newpath 0 0 moveto\n", ofP);
+
+    doRaster(ifP, cols, rows, format, ofP);
+
+    fputs("stroke grestore showpage\n", ofP);
+    fputs("%%Trailer\n", ofP);
+}
+
+
+
+int
+main(int argc, const char *argv[]) {
+    FILE *  ifP;
+    struct CmdlineInfo cmdline;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFileName);
+
+    pbmtolps(ifP, stdout, cmdline);
 
-    pm_close(fp);
+    pm_close(ifP);
 
-    exit(0);
+    return 0;
 }