about summary refs log tree commit diff
path: root/editor
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2016-06-26 18:15:09 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2016-06-26 18:15:09 +0000
commitaab4792db8e0adcaf63cf57a1f5e0b18666dae47 (patch)
treebbfa9c4e12783d2dfd785c4e10964366550e9a60 /editor
parentfe14f983ade44baa0794e4ce58a1a5334e46cf68 (diff)
downloadnetpbm-mirror-aab4792db8e0adcaf63cf57a1f5e0b18666dae47.tar.gz
netpbm-mirror-aab4792db8e0adcaf63cf57a1f5e0b18666dae47.tar.xz
netpbm-mirror-aab4792db8e0adcaf63cf57a1f5e0b18666dae47.zip
Promote Development to Advanced as Release 10.75.00
git-svn-id: http://svn.code.sf.net/p/netpbm/code/advanced@2803 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'editor')
-rw-r--r--editor/pamrubber.c2
-rwxr-xr-xeditor/pamstretch-gen8
-rw-r--r--editor/pamundice.c3
-rw-r--r--editor/pbmreduce.c514
-rw-r--r--editor/pgmmedian.c3
-rwxr-xr-xeditor/pnmmargin8
-rwxr-xr-xeditor/pnmquant19
-rwxr-xr-xeditor/pnmquantall15
-rwxr-xr-xeditor/ppmfade16
-rwxr-xr-xeditor/ppmquant13
-rwxr-xr-xeditor/ppmshadow38
-rw-r--r--editor/specialty/pampaintspill.c2
-rw-r--r--editor/specialty/pgmabel.c5
-rw-r--r--editor/specialty/ppmntsc.c3
14 files changed, 434 insertions, 215 deletions
diff --git a/editor/pamrubber.c b/editor/pamrubber.c
index 4378c340..e7abd789 100644
--- a/editor/pamrubber.c
+++ b/editor/pamrubber.c
@@ -1405,7 +1405,7 @@ main(int argc, const char ** const argv) {
 
     setGlobalCP(cmdline);
 
-    srand(cmdline.randseedSpec ? cmdline.randseed : time(NULL));
+    srand(cmdline.randseedSpec ? cmdline.randseed : pm_randseed());
 
     ifP = pm_openr(cmdline.fileName);
 
diff --git a/editor/pamstretch-gen b/editor/pamstretch-gen
index ba0e8188..dac3da7f 100755
--- a/editor/pamstretch-gen
+++ b/editor/pamstretch-gen
@@ -25,15 +25,17 @@
 # Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
 # 
 
+if [ "$1" = "--version" -o "$1" = "-version" ]; then
+        pamstretch --version; exit $?;
+fi
 
 if [ "$1" = "" ]; then
   echo 'usage: pamstretch-gen N [pnmfile]'
   exit 1
 fi
 
-tempdir="${TMPDIR-/tmp}/pamstretch-gen.$$"
-mkdir -m 0700 $tempdir || \
-  { echo "Could not create temporary file. Exiting."; exit 1;}
+tempdir=$(mktemp -d "${TMPDIR:-/tmp}/netpbm.XXXXXXXX") ||
+    ( echo "Could not create temporary file. Exiting." 1>&2; exit 1; ) 
 trap 'rm -rf $tempdir' 0 1 3 15
 
 tempfile=$tempdir/pnmig
diff --git a/editor/pamundice.c b/editor/pamundice.c
index 9a80e46d..dbe0a8df 100644
--- a/editor/pamundice.c
+++ b/editor/pamundice.c
@@ -271,12 +271,11 @@ computeInputFileName(const char *  const pattern,
                      const char ** const fileNameP) {
 
     struct buffer buffer;
-    unsigned int inCursor, outCursor;
+    unsigned int inCursor;
 
     buffer_init(&buffer);
 
     inCursor = 0;
-    outCursor = 0;
 
     while (pattern[inCursor] != '\0') {
         if (pattern[inCursor] == '%') {
diff --git a/editor/pbmreduce.c b/editor/pbmreduce.c
index ee4a4fbd..3a0968fe 100644
--- a/editor/pbmreduce.c
+++ b/editor/pbmreduce.c
@@ -10,203 +10,345 @@
 ** implied warranty.
 */
 
-#include <limits.h>
+#include "pm_c_util.h"
 #include "pbm.h"
 #include "mallocvar.h"
+#include "shhopt.h"
+#include <assert.h>
 
-int
-main( argc, argv )
-    int argc;
-    char* argv[];
-    {
-    FILE* ifp;
-    register bit** bitslice;
-    register bit* newbitrow;
-    register bit* nbP;
-    int argn, n, rows, cols, format, newrows, newcols;
-    int row, col, limitcol, subrow, subcol, count, direction;
-    const char* const usage = "[-floyd|-fs | -threshold] [-value <val>] N [pbmfile]";
-    int halftone;
-#define QT_FS 1
-#define QT_THRESH 2
 #define SCALE 1024
 #define HALFSCALE 512
-    long threshval, sum;
-    long* thiserr;  /* used for Floyd-Steinberg stuff */
-    long* nexterr;  /* used for Floyd-Steinberg stuff */
-    long* temperr;
-
-
-    pbm_init( &argc, argv );
-
-    argn = 1;
-    halftone = QT_FS;
-    threshval = HALFSCALE;
-
-    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
-	{
-	if ( pm_keymatch( argv[argn], "-fs", 2 ) ||
-	     pm_keymatch( argv[argn], "-floyd", 2 ) )
-	    halftone = QT_FS;
-	else if ( pm_keymatch( argv[argn], "-threshold", 2 ) )
-	    halftone = QT_THRESH;
-	else if ( pm_keymatch( argv[argn], "-value", 2 ) )
-	    {
-	    float f;
-
-	    ++argn;
-	    if ( argn == argc || sscanf( argv[argn], "%f", &f ) != 1 ||
-		 f < 0.0 || f > 1.0 )
-		pm_usage( usage );
-	    threshval = f * SCALE;
-	    }
-	else
-	    pm_usage( usage );
-	++argn;
-	}
-
-    if ( argn == argc )
-	pm_usage( usage );
-    if ( sscanf( argv[argn], "%d", &n ) != 1 )
-	pm_usage( usage );
-    if ( n < 2 )
-	pm_error( "N must be greater than 1" );
-    if (n > INT_MAX / n)
-        pm_error("Scale argument too large.  You specified %d", n);
-    ++argn;
-
-    if ( argn == argc )
-	ifp = stdin;
-    else
-	{
-	ifp = pm_openr( argv[argn] );
-	++argn;
-	}
-
-    if ( argn != argc )
-	pm_usage( usage );
-
-    pbm_readpbminit( ifp, &cols, &rows, &format );
-    bitslice = pbm_allocarray( cols, n );
-
-    newrows = rows / n;
-    newcols = cols / n;
+
+
+enum Halftone {QT_FS, QT_THRESH};
+
+struct CmdlineInfo {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *  inputFilespec;
+    enum Halftone halftone;
+    int           value;
+    unsigned int  randomseed;
+    unsigned int  randomseedSpec;
+    int           scale;
+};
+
+
+
+static void
+parseCommandLine(int argc, const char ** argv,
+                 struct CmdlineInfo *cmdlineP) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optEntry * option_def;
+        /* Instructions to pm_optParseOptions3 on how to parse our options.
+         */
+    optStruct3 opt;
+
+    unsigned int option_def_index;
+    unsigned int floydOpt, thresholdOpt;
+    unsigned int valueSpec;
+    float        value;
+
+    MALLOCARRAY_NOFAIL(option_def, 100);
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENT3(0, "floyd",       OPT_FLAG,  NULL,
+            &floydOpt,                      0);
+    OPTENT3(0, "fs",          OPT_FLAG,  NULL,
+            &floydOpt,                      0);
+    OPTENT3(0, "threshold",   OPT_FLAG,  NULL,
+            &thresholdOpt,                  0);
+    OPTENT3(0, "value",       OPT_FLOAT, &value,
+            &valueSpec,                     0);
+    OPTENT3(0, "randomseed",  OPT_UINT,  &cmdlineP->randomseed,
+            &cmdlineP->randomseedSpec,      0);
+
+    opt.opt_table = option_def;
+    opt.short_allowed = FALSE;  /* We have no short (old-fashioned) options */
+    opt.allowNegNum = FALSE;  /* We may have 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 (floydOpt + thresholdOpt == 0)
+        cmdlineP->halftone = QT_FS;
+    else if (!!floydOpt + !!thresholdOpt > 1)
+        pm_error("Cannot specify both floyd and threshold");
+    else {
+        if (floydOpt)
+            cmdlineP->halftone = QT_FS;
+        else {
+            cmdlineP->halftone = QT_THRESH;
+            if (cmdlineP->randomseedSpec)
+                pm_message("-randomseed value has no effect with -threshold");
+        }
+    }
+
+    if (!valueSpec)
+        cmdlineP->value = HALFSCALE;
+    else {
+        if (value < 0.0)
+            pm_error("-value cannot be negative.  You specified %f", value);
+        if (value > 1.0)
+            pm_error("-value cannot be greater than one.  You specified %f",
+                     value);
+        else
+            cmdlineP->value = value * SCALE;
+    }
+
+    if (argc-1 > 0) {
+        char * endptr;   /* ptr to 1st invalid character in scale arg */
+        unsigned int scale;
+
+        scale = strtol(argv[1], &endptr, 10);
+        if (*argv[1] == '\0') 
+            pm_error("Scale argument is a null string.  Must be a number.");
+        else if (*endptr != '\0')
+            pm_error("Scale argument contains non-numeric character '%c'.",
+                     *endptr);
+        else if (scale < 2)
+            pm_error("Scale argument must be at least 2.  "
+                     "You specified %d", scale);
+        else if (scale > INT_MAX / scale)
+            pm_error("Scale argument too large.  You specified %d", scale);
+        else 
+            cmdlineP->scale = scale;
+
+        if (argc-1 > 1) {
+            cmdlineP->inputFilespec = argv[2];
+
+            if (argc-1 > 2)
+                pm_error("Too many arguments (%d).  There are at most two "
+                         "non-option arguments: "
+                         "scale factor and the file name",
+                         argc-1);
+        } else
+            cmdlineP->inputFilespec = "-";
+    } else
+        pm_error("You must specify the scale factor as an argument");
+
+    free(option_def);
+}
+
+
+
+struct FS {
+  int * thiserr;
+  int * nexterr;
+};
+
+
+static void
+initializeFloydSteinberg(struct FS  * const fsP,
+                         int          const newcols,
+                         unsigned int const seed,
+                         bool         const seedSpec) {
+
+    unsigned int col;
+
+    MALLOCARRAY(fsP->thiserr, newcols + 2);
+    MALLOCARRAY(fsP->nexterr, newcols + 2);
+
+    if (fsP->thiserr == NULL || fsP->nexterr == NULL)
+        pm_error("out of memory");
+
+    srand(seedSpec ? seed : pm_randseed());
+
+    for (col = 0; col < newcols + 2; ++col)
+        fsP->thiserr[col] = (rand() % SCALE - HALFSCALE) / 4;
+        /* (random errors in [-SCALE/8 .. SCALE/8]) */
+}
+
+
+
+/*
+    Scanning method
+    
+    In Floyd-Steinberg dithering mode horizontal direction of scan alternates
+    between rows; this is called "serpentine scanning".
+    
+    Example input (14 x 7), N=3:
+    
+    111222333444xx    Fractional pixels on the right edge and bottom edge (x)
+    111222333444xx    are ignored; their values do not influence output. 
+    111222333444xx
+    888777666555xx
+    888777666555xx
+    888777666555xx
+    xxxxxxxxxxxxxx
+    
+    Output (4 x 2):
+    
+    1234
+    8765
+
+*/
+
+
+
+enum Direction { RIGHT_TO_LEFT, LEFT_TO_RIGHT };
+
+
+static enum Direction
+oppositeDir(enum Direction const arg) {
+
+    switch (arg) {
+    case LEFT_TO_RIGHT: return RIGHT_TO_LEFT;
+    case RIGHT_TO_LEFT: return LEFT_TO_RIGHT;
+    }
+    assert(false);  /* All cases handled above */
+}
+
+
+
+int
+main(int argc, const char * argv[]) {
+
+    FILE * ifP;
+    struct CmdlineInfo cmdline;
+    bit ** bitslice;
+    bit * newbitrow;
+    int rows, cols;
+    int format;
+    unsigned int newrows, newcols;
+    unsigned int row;
+    enum Direction direction;
+    struct FS fs;
+
+    pm_proginit(&argc, argv);
+
+    parseCommandLine(argc, argv, &cmdline);
+
+    ifP = pm_openr(cmdline.inputFilespec);
+
+    pbm_readpbminit(ifP, &cols, &rows, &format);
+
+    bitslice = pbm_allocarray(cols, cmdline.scale);
+
+    if (rows < cmdline.scale || cols < cmdline.scale)
+        pm_error("Scale argument (%u) too large for image", cmdline.scale);
+    else {
+        newrows = rows / cmdline.scale;
+        newcols = cols / cmdline.scale;
+    }
     pbm_writepbminit( stdout, newcols, newrows, 0 );
-    newbitrow = pbm_allocrow( newcols );
+    newbitrow = pbm_allocrow_packed( newcols );
 
-    if (halftone == QT_FS) {
-        unsigned int col;
-        /* Initialize Floyd-Steinberg. */
-        MALLOCARRAY(thiserr, newcols + 2);
-        MALLOCARRAY(nexterr, newcols + 2);
-        if (thiserr == NULL || nexterr == NULL)
-            pm_error("out of memory");
-
-        srand(pm_randseed());
-        for (col = 0; col < newcols + 2; ++col)
-            thiserr[col] = (rand() % SCALE - HALFSCALE) / 4;
-	    /* (random errors in [-SCALE/8 .. SCALE/8]) */
-	} else {
+    if (cmdline.halftone == QT_FS)
+        initializeFloydSteinberg(&fs, newcols,
+                                 cmdline.randomseed, cmdline.randomseedSpec);
+    else {
         /* These variables are meaningless in this case, and the values
            should never be used.
         */
-        thiserr = NULL;
-        nexterr = NULL;
+        fs.thiserr = NULL;
+        fs.nexterr = NULL;
     }
-    direction = 1;
-
-    for ( row = 0; row < newrows; ++row )
-	{
-	for ( subrow = 0; subrow < n; ++subrow )
-	    pbm_readpbmrow( ifp, bitslice[subrow], cols, format );
-
-	if ( halftone == QT_FS )
-	    for ( col = 0; col < newcols + 2; ++col )
-		nexterr[col] = 0;
-	if ( direction )
-	    {
-	    col = 0;
-	    limitcol = newcols;
-	    nbP = newbitrow;
-	    }
-	else
-	    {
-	    col = newcols - 1;
-	    limitcol = -1;
-	    nbP = &(newbitrow[col]);
-	    }
-
-	do
-	    {
-	    sum = 0;
-	    count = 0;
-	    for ( subrow = 0; subrow < n; ++subrow )
-		for ( subcol = 0; subcol < n; ++subcol )
-		    if ( row * n + subrow < rows && col * n + subcol < cols )
-			{
-			count += 1;
-			if ( bitslice[subrow][col * n + subcol] == PBM_WHITE )
-			    sum += 1;
-			}
-	    sum = ( sum * SCALE ) / count;
-
-	    if ( halftone == QT_FS )
-		sum += thiserr[col + 1];
-
-	    if ( sum >= threshval )
-		{
-		*nbP = PBM_WHITE;
-		if ( halftone == QT_FS )
-		    sum = sum - threshval - HALFSCALE;
-		}
-	    else
-		*nbP = PBM_BLACK;
-
-	    if ( halftone == QT_FS )
-		{
-		if ( direction )
-		    {
-		    thiserr[col + 2] += ( sum * 7 ) / 16;
-		    nexterr[col    ] += ( sum * 3 ) / 16;
-		    nexterr[col + 1] += ( sum * 5 ) / 16;
-		    nexterr[col + 2] += ( sum     ) / 16;
-		    }
-		else
-		    {
-		    thiserr[col    ] += ( sum * 7 ) / 16;
-		    nexterr[col + 2] += ( sum * 3 ) / 16;
-		    nexterr[col + 1] += ( sum * 5 ) / 16;
-		    nexterr[col    ] += ( sum     ) / 16;
-		    }
-		}
-	    if ( direction )
-		{
-		++col;
-		++nbP;
-		}
-	    else
-		{
-		--col;
-		--nbP;
-		}
-	    }
-	while ( col != limitcol );
-
-	pbm_writepbmrow( stdout, newbitrow, newcols, 0 );
-
-	if ( halftone == QT_FS )
-	    {
-	    temperr = thiserr;
-	    thiserr = nexterr;
-	    nexterr = temperr;
-	    direction = ! direction;
-	    }
-	}
-
-    pm_close( ifp );
-    pm_close( stdout );
-
-    exit( 0 );
+
+    for (row = 0, direction = LEFT_TO_RIGHT; row < newrows; ++row) {
+        unsigned int const colChars = pbm_packed_bytes(newcols);
+
+        unsigned int colChar;
+        unsigned int subrow;
+        unsigned int col;
+        int limitCol;
+        int startCol;
+        int step;
+   
+        for (colChar = 0; colChar < colChars; ++colChar)
+            newbitrow[colChar] = 0x00;  /* Clear to white */
+ 
+        for (subrow = 0; subrow < cmdline.scale; ++subrow)
+            pbm_readpbmrow(ifP, bitslice[subrow], cols, format);
+
+        if (cmdline.halftone == QT_FS) {
+            unsigned int col;
+            for (col = 0; col < newcols + 2; ++col)
+                fs.nexterr[col] = 0;
+        }
+        switch (direction) {
+        case LEFT_TO_RIGHT: {
+            startCol = 0;
+            limitCol = newcols;
+            step = +1;  
+        } break;
+        case RIGHT_TO_LEFT: {
+            startCol = newcols - 1;
+            limitCol = -1;
+            step = -1;
+        } break;
+        }
+
+        for (col = startCol; col != limitCol; col += step) {
+            int const n = cmdline.scale;
+            unsigned int sum;
+            int sumScaled;
+            unsigned int subrow;
+
+            for (subrow = 0, sum = 0; subrow < n; ++subrow) {
+                unsigned int subcol;
+                for (subcol = 0; subcol < n; ++subcol) {
+                    assert(row * n + subrow < rows);
+                    assert(col * n + subcol < cols);
+                    if (bitslice[subrow][col * n + subcol] == PBM_WHITE)
+                        ++sum;
+                }
+            }
+
+            sumScaled = (sum * SCALE) / (SQR(n));
+
+            if (cmdline.halftone == QT_FS)
+                sumScaled += fs.thiserr[col + 1];
+
+            if (sumScaled >= cmdline.value) {
+                if (cmdline.halftone == QT_FS)
+                    sumScaled = sumScaled - cmdline.value - HALFSCALE;
+            } else
+                newbitrow[col/8] |= (PBM_BLACK << (7 - col%8));
+
+            if (cmdline.halftone == QT_FS) {
+                switch (direction) {
+                case LEFT_TO_RIGHT: {
+                    fs.thiserr[col + 2] += ( sumScaled * 7 ) / 16;
+                    fs.nexterr[col    ] += ( sumScaled * 3 ) / 16;
+                    fs.nexterr[col + 1] += ( sumScaled * 5 ) / 16;
+                    fs.nexterr[col + 2] += ( sumScaled     ) / 16;
+                    break;
+                }
+                case RIGHT_TO_LEFT: {
+                    fs.thiserr[col    ] += ( sumScaled * 7 ) / 16;
+                    fs.nexterr[col + 2] += ( sumScaled * 3 ) / 16;
+                    fs.nexterr[col + 1] += ( sumScaled * 5 ) / 16;
+                    fs.nexterr[col    ] += ( sumScaled     ) / 16;
+                    break;
+                }
+                }
+            }
+        }
+
+        pbm_writepbmrow_packed(stdout, newbitrow, newcols, 0);
+
+        if (cmdline.halftone == QT_FS) {
+            int * const temperr = fs.thiserr;
+            fs.thiserr = fs.nexterr;
+            fs.nexterr = temperr;
+            direction  = oppositeDir(direction);
+        }
     }
 
+    free(fs.thiserr);
+    free(fs.nexterr);
+
+    pbm_freerow(newbitrow);
+    pbm_freearray(bitslice, cmdline.scale);
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
+}
+
 
diff --git a/editor/pgmmedian.c b/editor/pgmmedian.c
index 9d90b6b3..4648af68 100644
--- a/editor/pgmmedian.c
+++ b/editor/pgmmedian.c
@@ -132,13 +132,12 @@ select489(gray * const a,
 
     gray t;
     int i, j, l, r;
-    int ptmp, ttmp;
+    int ptmp;
 
     l = 0;
     r = n - 1;
     while ( r > l ) {
         t = a[parray[k]];
-        ttmp = parray[k];
         i = l;
         j = r;
         ptmp = parray[l];
diff --git a/editor/pnmmargin b/editor/pnmmargin
index 0f57d1d4..9dbe24b7 100755
--- a/editor/pnmmargin
+++ b/editor/pnmmargin
@@ -11,9 +11,8 @@
 # documentation.  This software is provided "as is" without express or
 # implied warranty.
 
-tempdir="${TMPDIR-/tmp}/pnmmargin.$$"
-mkdir -m 0700 $tempdir || \
-  { echo "Could not create temporary file. Exiting." 1>&2; exit 1;}
+tempdir=$(mktemp -d "${TMPDIR:-/tmp}/netpbm.XXXXXXXX") ||
+    ( echo "Could not create temporary file. Exiting." 1>&2; exit 1; ) 
 trap 'rm -rf $tempdir' 0 1 3 15
 
 tmp1=$tempdir/pnmm1
@@ -27,6 +26,9 @@ plainopt=""
 # Parse args.
 while true ; do
     case "$1" in
+        -version|--version )
+        pnmpad --version; exit $?;
+        ;;
         -p|-pl|-pla|-plai|-plain )
         plainopt="-plain"
         shift
diff --git a/editor/pnmquant b/editor/pnmquant
index 93d452cd..35a75e96 100755
--- a/editor/pnmquant
+++ b/editor/pnmquant
@@ -42,6 +42,21 @@ my ($TRUE, $FALSE) = (1,0);
 
 my ($SEEK_SET, $SEEK_CUR, $SEEK_END) = (0, 1, 2);
 
+
+
+sub doVersionHack($) {
+    my ($argvR) = @_;
+
+    my $arg1 = $argvR->[0];
+
+    if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) {
+        my $termStatus = system('pnmcolormap', '--version');
+        exit($termStatus == 0 ? 0 : 1);
+    }
+}
+
+
+
 sub tempFile($) {
 
     # We trust Perl's File::Temp to do a better job of creating the temp
@@ -93,7 +108,7 @@ sub parseCommandLine(@) {
               scalar(@ARGV), "\n");
         exit(1);
     } 
-    if (@ARGV < 1) {
+    elsif (@ARGV < 1) {
         print(STDERR 
               "You must specify the number of colors as an argument.\n");
         exit(1);
@@ -267,6 +282,8 @@ sub remap($$$$) {
 #                              MAIN PROGRAM
 ##############################################################################
 
+doVersionHack(\@ARGV);
+
 my $cmdlineR = parseCommandLine(@ARGV);
 
 openSeekableAsStdin($cmdlineR->{infile}); 
diff --git a/editor/pnmquantall b/editor/pnmquantall
index 0890383e..844fc13d 100755
--- a/editor/pnmquantall
+++ b/editor/pnmquantall
@@ -61,6 +61,19 @@ my $TRUE=1; my $FALSE = 0;
 
 
 
+sub doVersionHack($) {
+    my ($argvR) = @_;
+
+    my $arg1 = $argvR->[0];
+
+    if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) {
+        my $termStatus = system('pnmcolormap', '--version');
+        exit($termStatus == 0 ? 0 : 1);
+    }
+}
+
+
+
 sub parseArgs($$$$) {
     my ($argvR, $extR, $newColorCtR, $fileNamesR) = @_;
 
@@ -179,6 +192,8 @@ sub remapFiles($$$$) {
 
 my $progError;
 
+doVersionHack(\@ARGV);
+
 parseArgs(\@ARGV, \my $ext, \my $newColorCt, \my @fileNames);
 
 my ($colorMapFh, $colorMapFileName) = tempFile("pnm");
diff --git a/editor/ppmfade b/editor/ppmfade
index 027fc793..dcd7bf26 100755
--- a/editor/ppmfade
+++ b/editor/ppmfade
@@ -41,6 +41,19 @@ exec perl -w -x -S -- "$0" "$@"
 ##############################################################################
 use strict;
 
+sub doVersionHack($) {
+    my ($argvR) = @_;
+
+    my $arg1 = $argvR->[0];
+
+    if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) {
+        my $termStatus = system('ppmmix', '--version');
+        exit($termStatus == 0 ? 0 : 1);
+    }
+}
+
+
+
 my $SPREAD =  1;
 my $SHIFT =   2;
 my $RELIEF =  3;
@@ -59,6 +72,7 @@ my $base_name = "fade";		# default base name of output files
 my $image = "ppm";		# default output storage format
 my $mode = $SPREAD;		# default fading mode
 
+doVersionHack(\@ARGV);
 
 my $n;  # argument number
 
@@ -98,8 +112,6 @@ for ($n = 0; $n < @ARGV; $n++) {
         $mode = $BLOCK;
     } elsif ("$ARGV[$n]" eq "-mix") {
         $mode = $MIX;
-    } elsif ($ARGV[$n] eq "-help" || $ARGV[$n] eq "-h") {
-        usage();
     } else {
         print "Unknown argument: $ARGV[$n]\n";
         exit 100;
diff --git a/editor/ppmquant b/editor/ppmquant
index 57963982..fe8ca046 100755
--- a/editor/ppmquant
+++ b/editor/ppmquant
@@ -35,6 +35,19 @@ exec perl -w -x -S -- "$0" "$@"
 
 use strict;
 
+sub doVersionHack($) {
+    my ($argvR) = @_;
+
+    my $arg1 = $argvR->[0];
+
+    if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) {
+        my $termStatus = system('pnmquant', '--version');
+        exit($termStatus == 0 ? 0 : 1);
+    }
+}
+
+doVersionHack(\@ARGV);
+
 use Getopt::Long;
 
 my @ppmquantArgv = @ARGV;
diff --git a/editor/ppmshadow b/editor/ppmshadow
index 62cdf8b8..39a23df9 100755
--- a/editor/ppmshadow
+++ b/editor/ppmshadow
@@ -48,6 +48,7 @@ exec perl -w -x -S -- "$0" "$@"
 ##############################################################################
 
 use strict;
+use File::Temp;
 require 5.0;
 #  The good open() syntax, with the mode separate from the file name,
 #  came after 5.0.  So did mkdir() with default mode.
@@ -55,6 +56,20 @@ require 5.0;
 my $true=1; my $false=0;
 
 
+
+sub doVersionHack($) {
+    my ($argvR) = @_;
+
+    my $arg1 = $argvR->[0];
+
+    if (defined($arg1) && (($arg1 eq "--version") || ($arg1 eq "-version"))) {
+        my $termStatus = system('pamarith', '--version');
+        exit($termStatus == 0 ? 0 : 1);
+    }
+}
+
+
+
 sub getDimensions($) {
     my ($fileName) = @_;
 #-----------------------------------------------------------------------------
@@ -95,15 +110,10 @@ sub makeConvolutionKernel($$) {
 #                           MAINLINE
 ##############################################################################
 
-
-my $tmpdir = $ENV{TMPDIR} || "/tmp";
-my $ourtmp = "$tmpdir/ppmshadow$$";
-mkdir($ourtmp, 0777) or
-    die("Unable to create directory for temporary files '$ourtmp");
+doVersionHack(\@ARGV);
 
 #   Process command line options
 
-
 my $ifile; # Input file name
 my ($xoffset, $yoffset);
 
@@ -113,6 +123,7 @@ my $translucent = $false;            # Default not translucent
 
 while (@ARGV) {
     my $arg = shift;
+
     if ((substr($arg, 0, 1) eq '-') && (length($arg) > 1)) {
         my $opt;
         $opt = substr($arg, 1, 1);
@@ -142,6 +153,8 @@ while (@ARGV) {
             if ($yoffset < 0) {
                 $yoffset = -$xoffset;
             }
+        } else {
+            die("Unknown option '$opt'\n");
         }
     } else {
         if (defined $ifile) {
@@ -151,6 +164,19 @@ while (@ARGV) {
     }
 }
 
+# Create temporary directory
+
+my $tmpdir = $ENV{TMPDIR} || "/tmp";
+my $ourtmp;
+
+if ($keeptemp) {
+    $ourtmp = "$tmpdir/ppmshadow$$";
+    mkdir($ourtmp, 0777) or
+        die("Unable to create directory for temporary files '$ourtmp");
+} else {
+    $ourtmp = File::Temp::tempdir("$tmpdir/ppmshadowXXXX", UNLINK=>1);
+}
+
 #   Apply defaults for arguments not specified
 
 if (!(defined $xoffset)) {
diff --git a/editor/specialty/pampaintspill.c b/editor/specialty/pampaintspill.c
index 745c9b68..eb1888f7 100644
--- a/editor/specialty/pampaintspill.c
+++ b/editor/specialty/pampaintspill.c
@@ -253,7 +253,7 @@ locatePaintSources(struct pam *            const pamP,
     if (downsample > 0 && downsample < paintSources.size) {
         unsigned int i;
 
-        srand(time(NULL));
+        srand(pm_randseed());
 
         for (i = 0; i < downsample; ++i) {
             unsigned int const swapIdx =
diff --git a/editor/specialty/pgmabel.c b/editor/specialty/pgmabel.c
index 1764c5d7..1a6e481f 100644
--- a/editor/specialty/pgmabel.c
+++ b/editor/specialty/pgmabel.c
@@ -171,7 +171,6 @@ int main( argc, argv )
     float pixsize=0.1;
     /* no verbose, calculating both sides                                */
     int verb = FALSE, left = TRUE, right = TRUE;
-    int nologo = FALSE;
     const char* const usage = "[-help] [-axis N] [-factor N] [-pixsize N] [-left|-right] [-verbose] [pgmfile]";
 
     pgm_init( &argc, argv );
@@ -213,10 +212,6 @@ int main( argc, argv )
                 if ( right ) left = FALSE;
                 else pm_usage( usage );
             }
-        else if ( pm_keymatch( argv[argn], "-nologo", 4 ) )
-            {
-                nologo = TRUE;
-            }
         else
             pm_usage( usage );
         ++ argn;
diff --git a/editor/specialty/ppmntsc.c b/editor/specialty/ppmntsc.c
index a721b891..b44c64aa 100644
--- a/editor/specialty/ppmntsc.c
+++ b/editor/specialty/ppmntsc.c
@@ -392,14 +392,11 @@ convertOneImage(FILE *             const ifP,
         pixel * const inputRow = ppm_allocrow(cols);
         pixel * const outputRow = ppm_allocrow(cols);
 
-        pixel lastIllegalPixel;
-            /* Value of the illegal pixel we most recently processed */
         pixel black;
             /* A constant - black pixel */
 
         PPM_ASSIGN(black, 0, 0, 0);
 
-        PPM_ASSIGN(lastIllegalPixel, 0, 0, 0);  /* initial value */
         {
             unsigned int row;