about summary refs log tree commit diff
path: root/converter/pgm
diff options
context:
space:
mode:
authorgiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
committergiraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8>2006-08-19 03:12:28 +0000
commit1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch)
tree64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/pgm
downloadnetpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.gz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.tar.xz
netpbm-mirror-1fd361a1ea06e44286c213ca1f814f49306fdc43.zip
Create Subversion repository
git-svn-id: http://svn.code.sf.net/p/netpbm/code/trunk@1 9d0c8265-081b-0410-96cb-a4ca84ce46f8
Diffstat (limited to 'converter/pgm')
-rw-r--r--converter/pgm/Makefile23
-rw-r--r--converter/pgm/asciitopgm.c163
-rw-r--r--converter/pgm/bioradtopgm.c152
-rw-r--r--converter/pgm/fstopgm.c138
-rw-r--r--converter/pgm/hipstopgm.c181
-rw-r--r--converter/pgm/lispmtopgm.c172
-rw-r--r--converter/pgm/pgmtofs.c153
-rw-r--r--converter/pgm/pgmtolispm.c148
-rw-r--r--converter/pgm/pgmtopgm.c44
-rw-r--r--converter/pgm/psidtopgm.c128
-rw-r--r--converter/pgm/rawtopgm.c284
-rw-r--r--converter/pgm/sbigtopgm.c208
-rw-r--r--converter/pgm/spottopgm.c231
13 files changed, 2025 insertions, 0 deletions
diff --git a/converter/pgm/Makefile b/converter/pgm/Makefile
new file mode 100644
index 00000000..f562fe92
--- /dev/null
+++ b/converter/pgm/Makefile
@@ -0,0 +1,23 @@
+ifeq ($(SRCDIR)x,x)
+  SRCDIR = $(CURDIR)/../..
+  BUILDDIR = $(SRCDIR)
+endif
+SUBDIR = converter/pgm
+VPATH=.:$(SRCDIR)/$(SUBDIR)
+
+include $(BUILDDIR)/Makefile.config
+
+PORTBINARIES =	asciitopgm bioradtopgm fstopgm hipstopgm \
+		lispmtopgm pgmtofs pgmtolispm pgmtopgm \
+	        psidtopgm spottopgm sbigtopgm
+MATHBINARIES =	rawtopgm
+BINARIES =	$(PORTBINARIES) $(MATHBINARIES)
+
+OBJECTS = $(BINARIES:%=%.o)
+MERGEBINARIES = $(BINARIES)
+MERGE_OBJECTS = $(MERGEBINARIES:%=%.o2)
+
+.PHONY: all
+all: $(BINARIES)
+
+include $(SRCDIR)/Makefile.common
diff --git a/converter/pgm/asciitopgm.c b/converter/pgm/asciitopgm.c
new file mode 100644
index 00000000..b6b9c9a7
--- /dev/null
+++ b/converter/pgm/asciitopgm.c
@@ -0,0 +1,163 @@
+/* asciitopgm.c - read an ASCII graphics file and produce a portable graymap
+**
+** Copyright (C) 1989 by Wilson H. Bent, Jr
+**
+** - Based on fstopgm.c and other works which bear the following notice:
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <string.h>
+
+#include "pm_c_util.h"
+#include "pgm.h"
+#include "mallocvar.h"
+#include "nstring.h"
+
+static char gmap [128] = {
+/*00 nul-bel*/  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*08 bs -si */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*10 dle-etb*/  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*18 can-us */  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/*20 sp - ' */  0x00, 0x21, 0x1b, 0x7f, 0x70, 0x25, 0x20, 0x0a,
+/*28  ( - / */  0x11, 0x11, 0x2a, 0x2b, 0x0b, 0x13, 0x04, 0x10,
+/*30  0 - 7 */  0x30, 0x28, 0x32, 0x68, 0x39, 0x35, 0x39, 0x16,
+/*38  8 - ? */  0x38, 0x39, 0x14, 0x15, 0x11, 0x1c, 0x11, 0x3f,
+/*40  @ - G */  0x40, 0x49, 0x52, 0x18, 0x44, 0x3c, 0x38, 0x38,
+/*48  H - O */  0x55, 0x28, 0x2a, 0x70, 0x16, 0x7f, 0x70, 0x14,
+/*50  P - W */  0x60, 0x20, 0x62, 0x53, 0x1a, 0x55, 0x36, 0x57,
+/*58  X - _ */  0x50, 0x4c, 0x5a, 0x24, 0x10, 0x24, 0x5e, 0x13,
+/*60  ` - g */  0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+/*68  h - o */  0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x2a,
+/*70  p - w */  0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+/*78  x -del*/  0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+};
+
+static gray maxval = 127;
+
+int
+main( argc, argv )
+    int argc;
+    char *argv[];
+{
+    FILE *ifd;
+    register gray **grays;
+    int argn, row;
+    register int c, i;
+    int rows = 0, cols = 0;
+    int divisor = 1;
+    bool warned;
+    int *obuf;
+    const char * const usage = "[-d <val>] height width [asciifile]";
+
+    pgm_init( &argc, argv );
+
+    warned = FALSE;
+
+    argn = 1;
+
+    if ( argc < 3 || argc > 6 )
+        pm_usage( usage );
+
+    if ( argv[argn][0] == '-' )
+    {
+        if ( STREQ( argv[argn], "-d" ) )
+        {
+            if ( argc == argn + 1 )
+                pm_usage( usage );
+            if ( sscanf( argv[argn+1], "%d", &divisor ) != 1 )
+                pm_usage( usage );
+            argn += 2;
+        }
+        else
+            pm_usage( usage );
+    }
+
+    if ( sscanf( argv[argn++], "%d", &rows ) != 1 )
+        pm_usage( usage );
+    if ( sscanf( argv[argn++], "%d", &cols ) != 1 )
+        pm_usage( usage );
+    if ( rows < 1 )
+        pm_error( "height is less than 1" );
+    if ( cols < 1 )
+        pm_error( "width is less than 1" );
+
+    if ( argc > argn + 1 )
+        pm_usage( usage );
+
+    if ( argc == argn + 1 )
+        ifd = pm_openr( argv[argn] );
+    else
+        ifd = stdin;
+
+    /* Here's where the work is done:
+     * - Usually, the graymap value of the input char is summed into grays
+     * - For a 'normal' newline, the current row is adjusted by the divisor
+     *   and the current row is incremented
+     * - If the first char in the input line is a '+', then the current row
+     *   stays the same to allow 'overstriking'
+     * NOTE that we assume the user specified a sufficiently large width!
+     */
+    MALLOCARRAY( obuf, cols );
+    if ( obuf == NULL )
+        pm_error( "Unable to allocate memory for %d columns.", cols);
+    else {
+        unsigned int col;
+        for (col = 0; col < cols; ++col) obuf[col] = 0;
+    }
+    grays = pgm_allocarray( cols, rows );
+    row = i = 0;
+    while ( row < rows )
+    {
+        switch (c = getc (ifd))
+        {
+        case EOF:
+            goto line_done;
+        case '\n':
+            if ((c = getc (ifd)) == EOF)
+                goto line_done;
+            if (c == '+')
+                i = 0;
+            else
+            {
+            line_done:
+                for (i = 0; i < cols; ++i)
+                    grays[row][i] = maxval - (obuf[i] / divisor);
+                {
+                    unsigned int col;
+                    for (col = 0; col < cols; ++col) obuf[col] = 0;
+                }
+                i = 0;
+                ++row;
+                if ( row >= rows )
+                    break;
+                if (c != EOF)
+                    obuf[i++] += gmap[c];
+            }
+            break;
+        default:
+            if (c > 0x7f)       /* !isascii(c) */
+            {
+                if (!warned)
+                {
+                    pm_message("Warning: non-ASCII char(s) in input");
+                    warned = TRUE;
+                }
+                c &= 0x7f;      /* toascii(c) */
+            }
+            obuf[i++] += gmap[c];
+            break;
+        }
+    }
+    pm_close( ifd );
+
+    pgm_writepgm( stdout, grays, cols, rows, maxval, 0 );
+
+    return 0;
+}
diff --git a/converter/pgm/bioradtopgm.c b/converter/pgm/bioradtopgm.c
new file mode 100644
index 00000000..e0bc3584
--- /dev/null
+++ b/converter/pgm/bioradtopgm.c
@@ -0,0 +1,152 @@
+/* bioradtopgm.c - convert a Biorad confocal image into a portable graymap
+**
+** Copyright (C) 1993 by Oliver Trepte, oliver@fysik4.kth.se
+**
+** Derived from the pbmplus package,
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <ctype.h>
+
+#include "pgm.h"
+#include "nstring.h"
+
+#define BYTE unsigned char
+#define BIORAD_HEADER_LENGTH 76
+#define BYTE_TO_WORD(lsb,msb) (((BYTE) lsb) + (((BYTE) msb) << 8))
+
+int
+main( argc, argv )
+    int argc;
+    char* argv[];
+    {
+    FILE* ifp;
+    gray* grayrow;
+    register gray* gP;
+    int argn, row, i;
+    register int col, val, val2;
+    int rows=0, cols=0, image_num= -1, image_count, byte_word, check_word;
+    int maxval;
+    BYTE buf[BIORAD_HEADER_LENGTH];
+    const char* const usage = "[-image#] [Bioradfile]";
+
+
+    pgm_init( &argc, argv );
+
+    argn = 1;
+
+    while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
+    {
+	if ( ISDIGIT( argv[argn][1] ))
+	{
+	    image_num = atoi( (argv[argn]+1) );
+	}
+	else
+	    pm_usage( usage );
+	++argn;
+    }
+
+    if ( argn < argc )
+	{
+	ifp = pm_openr( argv[argn] );
+	++argn;
+	}
+    else
+	ifp = stdin;
+
+    if ( argn != argc )
+	pm_usage( usage );
+
+    for ( i = 0; i < BIORAD_HEADER_LENGTH; ++i )
+    {
+	val = getc( ifp );
+	if ( val == EOF )
+	    pm_error( "EOF / read error" );
+	buf[ i ] = val;
+    }
+
+    cols = BYTE_TO_WORD(buf[0], buf[1]);
+    rows = BYTE_TO_WORD(buf[2], buf[3]);
+    image_count = BYTE_TO_WORD(buf[4], buf[5]);
+    byte_word = BYTE_TO_WORD(buf[14], buf[15]);
+    check_word = BYTE_TO_WORD(buf[54], buf[55]);
+
+    if ( check_word != 12345 )
+	pm_error( "Not a Biorad file" );
+
+    if ( cols <= 0 )
+	pm_error( "Strange image size, cols = %d", cols);
+
+    if ( rows <= 0 )
+	pm_error( "Strange image size, rows = %d", rows);
+
+    if ( image_count <= 0 )
+	pm_error( "Number of images in file is %d", image_count);
+
+    if ( byte_word )
+	maxval = 255;
+    else
+    {
+	maxval = 65535;   /* Perhaps this should be something else */
+
+    }
+
+    pm_message( "Image size: %d cols, %d rows", cols, rows);
+    pm_message( "%s",
+	       (byte_word) ? "Byte image (8 bits)" : "Word image (16 bits)");
+
+    if ( image_num < 0 )
+	pm_message( "Input contains %d image%c",
+		   image_count, (image_count > 1) ? 's' : '\0');
+    else
+    {
+	if ( image_num >= image_count )
+	    pm_error( "Cannot extract image %d, input contains only %d image%s",
+		     image_num, image_count, (image_count > 1) ? "s" : "" );
+	for ( i = (byte_word) ? image_num : image_num*2 ; i > 0 ; --i ) {
+	    for ( row = 0; row < rows; ++row)
+		for ( col = 0; col < cols; ++col )
+		{
+		    val = getc( ifp );
+		    if ( val == EOF ) {
+			pm_error( "EOF / read error" );
+		    }
+		}
+	}
+
+	pgm_writepgminit( stdout, cols, rows, (gray) maxval, 0 );
+	grayrow = pgm_allocrow( cols );
+
+	for ( row = 0; row < rows; ++row)
+	{
+	    for ( col = 0, gP = grayrow; col < cols; ++col )
+	    {
+		val = getc( ifp );
+		if ( val == EOF )
+		    pm_error( "EOF / read error" );
+		if (byte_word)
+		    *gP++ = val;
+		else
+		{
+		    val2 = getc( ifp );
+		    if ( val2 == EOF )
+			pm_error( "EOF / read error" );
+		    *gP++ = BYTE_TO_WORD(val, val2);
+		}
+	    }
+	    pgm_writepgmrow( stdout, grayrow, cols, (gray) maxval, 0 );
+	}
+
+	pm_close( ifp );
+	pm_close( stdout );
+
+    }
+    exit( 0 );
+}
diff --git a/converter/pgm/fstopgm.c b/converter/pgm/fstopgm.c
new file mode 100644
index 00000000..2c636f41
--- /dev/null
+++ b/converter/pgm/fstopgm.c
@@ -0,0 +1,138 @@
+/* fstopgm.c - read a Usenix FaceSaver(tm) file and produce a portable graymap
+**
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <string.h>
+
+#include "pgm.h"
+
+static int gethexit ARGS(( FILE* ifp ));
+
+int
+main( argc, argv )
+int argc;
+char *argv[];
+    {
+    FILE *ifp;
+    register gray **grays, *gP;
+    int argn, row;
+    register int col;
+    int maxval;
+    int rows = 0, cols = 0, depth = 0, xrows = 0, xcols = 0, xdepth = 0;
+#define STRSIZE 1000
+    char buf[STRSIZE], firstname[STRSIZE], lastname[STRSIZE], email[STRSIZE];
+
+
+    pgm_init( &argc, argv );
+
+    argn = 1;
+
+    if ( argn < argc )
+	{
+	ifp = pm_openr( argv[argn] );
+	argn++;
+	}
+    else
+	ifp = stdin;
+
+    if ( argn != argc )
+	pm_usage( "[fsfile]" );
+
+    /* Read the FaceSaver(tm) header. */
+    for ( ; ; )
+	{
+	if ( fgets( buf, STRSIZE, ifp ) == (char *) 0 )
+	    pm_error( "error reading header" );
+
+	/* Blank line ends header. */
+	if ( strlen( buf ) == 1 )
+	    break;
+
+	if ( sscanf( buf, "FirstName: %[^\n]", firstname ) == 1 )
+	    ;
+	else if ( sscanf( buf, "LastName: %[^\n]", lastname ) == 1 )
+	    ;
+	else if ( sscanf( buf, "E-mail: %[^\n]", email ) == 1 )
+	    ;
+	else if ( sscanf( buf, "PicData: %d %d %d\n",
+			  &cols, &rows, &depth ) == 3 )
+	    {
+	    if ( depth != 8 )
+		pm_error(
+		    "can't handle 'PicData' depth other than 8" );
+	    }
+	else if ( sscanf( buf, "Image: %d %d %d\n",
+			  &xcols, &xrows, &xdepth ) == 3 )
+	    {
+	    if ( xdepth != 8 )
+		pm_error(
+		    "can't handle 'Image' depth other than 8" );
+	    }
+	}
+    if ( cols <= 0 || rows <= 0 )
+	pm_error( "invalid header" );
+    maxval = pm_bitstomaxval( depth );
+    if ( maxval > PGM_OVERALLMAXVAL )
+	pm_error( "depth %d is too large.  Our maximum is %d",
+              maxval, PGM_OVERALLMAXVAL);
+    if ( xcols != 0 && xrows != 0 && ( xcols != cols || xrows != rows ) )
+	{
+	float rowratio, colratio;
+
+	rowratio = (float) xrows / (float) rows;
+	colratio = (float) xcols / (float) cols;
+	pm_message(
+	    "warning, non-square pixels; to fix do a 'pamscale -%cscale %g'",
+	    rowratio > colratio ? 'y' : 'x',
+	    rowratio > colratio ? rowratio / colratio : colratio / rowratio );
+	}
+
+    /* Now read the hex bits. */
+    grays = pgm_allocarray( cols, rows );
+    for ( row = rows - 1; row >= 0; row--)
+	{
+	for ( col = 0, gP = grays[row]; col < cols; col++, gP++ )
+	    {
+	    *gP = gethexit( ifp ) << 4;
+	    *gP += gethexit( ifp );
+	    }
+	}
+    pm_close( ifp );
+
+    /* And write out the graymap. */
+    pgm_writepgm( stdout, grays, cols, rows, (gray) maxval, 0 );
+    pm_close( stdout );
+
+    exit( 0 );
+    }
+
+static int
+gethexit( ifp )
+FILE *ifp;
+    {
+    register int i;
+    register char c;
+
+    for ( ; ; )
+	{
+	i = getc( ifp );
+	if ( i == EOF )
+	    pm_error( "EOF / read error" );
+	c = (char) i;
+	if ( c >= '0' && c <= '9' )
+	    return c - '0';
+	else if ( c >= 'A' && c <= 'F' )
+	    return c - 'A' + 10;
+	else if ( c >= 'a' && c <= 'f' )
+	    return c - 'a' + 10;
+	/* Else ignore - whitespace. */
+	}
+    }
diff --git a/converter/pgm/hipstopgm.c b/converter/pgm/hipstopgm.c
new file mode 100644
index 00000000..826a8511
--- /dev/null
+++ b/converter/pgm/hipstopgm.c
@@ -0,0 +1,181 @@
+/* hipstopgm.c - read a HIPS file and produce a portable graymap
+**
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <string.h>
+
+#include "nstring.h"
+#include "pgm.h"
+
+struct HIPS_Header {
+    char* orig_name;	/* An indication of the originator of this sequence. */
+    char* seq_name;	/* The sequence name. */
+    int num_frame;	/* The number of frames in this sequence. */
+    char* orig_date;	/* The date the sequence was originated. */
+    int rows;		/* The number of rows in each image, the height. */
+    int cols;		/* The number of columns in each image, the width. */
+    int bits_per_pixel;	/* The number of significant bits per pixel. */
+    int bit_packing;	/* Nonzero if the bits were packed such as to
+                           eliminate any unused bits resulting from a
+                           bits_per_pixel value which was not an even
+                           multiple of eight. */
+    int pixel_format;	/* An indication of the format of each pixel. */
+    char* seq_history;	/* A description of the sequence of transformations
+                           leading up to the current image. */
+    char* seq_desc;	/* A free form description of the contents of the
+                       sequence. */
+};
+#define HIPS_PFBYTE 0
+#define HIPS_PFSHORT 1
+#define HIPS_PFINT 2
+#define HIPS_PFFLOAT 3
+#define HIPS_PFCOMPLEX 4
+
+
+
+static void
+read_line(FILE * const fd,
+          char * const buf,
+          int    const size) {
+
+    if (fgets( buf, size, fd ) == NULL)
+        pm_error("error reading header");
+}
+
+
+
+
+static void
+read_hips_header( fd, hP )
+    FILE* fd;
+    struct HIPS_Header* hP;
+{
+    char buf[5000];
+
+    /* Read and toss orig_name. */
+    read_line( fd, buf, 5000 );
+
+    /* Read and toss seq_name. */
+    read_line( fd, buf, 5000 );
+
+    /* Read num_frame. */
+    read_line( fd, buf, 5000 );
+    hP->num_frame = atoi( buf );
+
+    /* Read and toss orig_date. */
+    read_line( fd, buf, 5000 );
+
+    /* Read rows. */
+    read_line( fd, buf, 5000 );
+    hP->rows = atoi( buf );
+
+    /* Read cols. */
+    read_line( fd, buf, 5000 );
+    hP->cols = atoi( buf );
+
+    /* Read bits_per_pixel. */
+    read_line( fd, buf, 5000 );
+    hP->bits_per_pixel = atoi( buf );
+
+    /* Read bit_packing. */
+    read_line( fd, buf, 5000 );
+    hP->bit_packing = atoi( buf );
+
+    /* Read pixel_format. */
+    read_line( fd, buf, 5000 );
+    hP->pixel_format = atoi( buf );
+
+    /* Now read and toss lines until we get one with just a period. */
+    do
+	{
+        read_line( fd, buf, 5000 );
+	}
+    while ( !STREQ( buf, ".\n" ) );
+}
+
+
+
+int
+main(int argc, char * argv[]) {
+
+    FILE* ifp;
+    gray* grayrow;
+    register gray* gP;
+    int argn, row;
+    register int col;
+    int maxval;
+    int rows, cols;
+    struct HIPS_Header h;
+
+
+    pgm_init( &argc, argv );
+
+    argn = 1;
+
+    if ( argn < argc )
+	{
+        ifp = pm_openr( argv[argn] );
+        argn++;
+	}
+    else
+        ifp = stdin;
+
+    if ( argn != argc )
+        pm_usage( "[hipsfile]" );
+
+    read_hips_header( ifp, &h );
+
+    cols = h.cols;
+    rows = h.rows * h.num_frame;
+
+    switch ( h.pixel_format )
+	{
+	case HIPS_PFBYTE:
+        if ( h.bits_per_pixel != 8 )
+            pm_error(
+                "can't handle unusual bits_per_pixel %d", h.bits_per_pixel );
+        if ( h.bit_packing != 0 )
+            pm_error( "can't handle bit_packing" );
+        maxval = 255;
+        break;
+
+	default:
+        pm_error( "unknown pixel format %d", h.pixel_format );
+	}
+
+    pgm_writepgminit( stdout, cols, rows, (gray) maxval, 0 );
+    grayrow = pgm_allocrow( cols );
+    for ( row = 0; row < rows; row++)
+	{
+        for ( col = 0, gP = grayrow; col < cols; col++, gP++ )
+	    {
+            int ich;
+
+            switch ( h.pixel_format )
+            {
+            case HIPS_PFBYTE:
+                ich = getc( ifp );
+                if ( ich == EOF )
+                    pm_error( "EOF / read error" );
+                *gP = (gray) ich;
+                break;
+
+            default:
+                pm_error( "can't happen" );
+            }
+	    }
+        pgm_writepgmrow( stdout, grayrow, cols, (gray) maxval, 0 );
+	}
+    pm_close( ifp );
+    pm_close( stdout );
+
+    return 0;
+}
diff --git a/converter/pgm/lispmtopgm.c b/converter/pgm/lispmtopgm.c
new file mode 100644
index 00000000..7b98ef00
--- /dev/null
+++ b/converter/pgm/lispmtopgm.c
@@ -0,0 +1,172 @@
+/* lispmtopgm.c - read a file written by the tv:write-bit-array-file function
+** of TI Explorer and Symbolics Lisp Machines, and write a PGM.
+**
+** Written by Jamie Zawinski based on code (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+**
+**   When one writes a multi-plane bitmap with tv:write-bit-array-file, it is
+**   usually a color image; but a color map is not written in the file, so we
+**   treat this as a graymap instead.  Since the pgm reader can also read pbms,
+**   this doesn't matter if you're using only single plane images.
+*/
+
+#include <stdio.h>
+#include <string.h>
+
+#include "nstring.h"
+#include "pgm.h"
+
+#define LISPM_MAGIC  "This is a BitMap file"
+
+static void getinit ARGS(( FILE* file, short* colsP, short* rowsP, short* depthP, short* padrightP ));
+static int depth_to_word_size ARGS(( int depth ));
+static unsigned int getval ARGS(( FILE* file ));
+
+int
+main( argc, argv )
+    int argc;
+    char* argv[];
+    {
+    FILE* ifp;
+    gray* grayrow;
+    register gray* gP;
+    short rows, cols, padright, row, col;
+    short depth;
+    int maxval;
+
+
+    pgm_init( &argc, argv );
+
+    if ( argc > 2 )
+	pm_usage( "[lispmfile]" );
+
+    if ( argc == 2 )
+        ifp = pm_openr( argv[1] );
+    else
+	ifp = stdin;
+
+    getinit( ifp, &cols, &rows, &depth, &padright );
+    maxval = 1 << depth;
+
+    if ( maxval > PGM_OVERALLMAXVAL )
+        pm_error( "depth (%d bits) is too large", depth);
+
+    pgm_writepgminit( stdout, cols, rows, (gray) maxval, 0 );
+    grayrow = pgm_allocrow( ( cols + 7 ) / 8 * 8 );
+
+    for ( row = 0; row < rows; ++row )
+	{
+        for ( col = 0, gP = grayrow; col < cols; ++col, ++gP )
+	    *gP = getval( ifp );
+	pgm_writepgmrow( stdout, grayrow, cols, (gray) maxval, 0 );
+	}
+    pm_close( ifp );
+    pm_close( stdout );
+    exit( 0 );
+    }
+
+static long item, bitmask;
+static unsigned int bitsperitem, maxbitsperitem, bitshift;
+
+static void
+getinit( file, colsP, rowsP, depthP, padrightP )
+    FILE* file;
+    short* colsP;
+    short* rowsP;
+    short* padrightP;
+    short* depthP;
+    {
+    short cols_32;
+    char magic[sizeof(LISPM_MAGIC)];
+    int i;
+
+    for ( i = 0; i < sizeof(magic)-1; ++i )
+        magic[i] = getc( file );
+    magic[i]='\0';
+    if (!STREQ(LISPM_MAGIC, magic))
+        pm_error( "bad id string in Lispm file" );
+    
+    if ( pm_readlittleshort( file, colsP ) == -1 )
+        pm_error( "EOF / read error" );
+    if ( pm_readlittleshort( file, rowsP ) == -1 )
+        pm_error( "EOF / read error" );
+    if ( pm_readlittleshort( file, &cols_32 ) == -1 )
+        pm_error( "EOF / read error" );
+    *depthP = getc( file );
+    
+    if ( *depthP == 0 )
+	*depthP = 1;	/* very old file */
+    
+    *padrightP = ( ( *colsP + 31 ) / 32 ) * 32 - *colsP;
+    
+    if ( *colsP != (cols_32 - *padrightP) ) {
+/*    pm_message( "inconsistent input: Width and Width(mod32) fields don't agree" );  */
+/*    *padrightP = cols_32 - *colsP;   */ /*    hmmmm....   */
+      /* This is a dilemma.  Usually the output is rounded up to mod32, but not always.
+       * For the Lispm code to not round up, the array size must be the same size as the
+       * portion being written - that is, the array itself must be an odd size, not just
+       * the selected portion.  Since arrays that are odd sizes can't be handed to bitblt,
+       * such arrays are probably not image data - so punt on it for now.
+       *
+       * Also, the lispm code for saving bitmaps has a bug, in that if you are writing a
+       * bitmap which is not mod32 across, the file may be up to 7 bits too short!  They
+       * round down instead of up.
+       *
+       * The code in 'pgmtolispm.c' always rounds up to mod32, which is totally reasonable.
+       */
+      }
+    bitsperitem = 0;
+    maxbitsperitem = depth_to_word_size( *depthP );
+    bitmask = ( 1 << maxbitsperitem ) - 1;		/* for depth=3, mask=00000111 */
+
+    for ( i = 0; i < 9; ++i )
+	getc( file );	/* discard bytes reserved for future use */
+    }
+
+static int
+depth_to_word_size (depth)	
+     int depth;			
+     /* Lispm architecture specific - if a bitmap is written    */
+     /* out with a depth of 5, it really has a depth of 8, and  */
+     /* is stored that way in the file.			   */
+{				
+    if (depth==0 || depth==1)	return ( 1);
+    else if (depth ==  2)	return ( 2);
+    else if (depth <=  4)	return ( 4);
+    else if (depth <=  8)	return ( 8);
+    else if (depth <= 16)	return (16);
+    else if (depth <= 32)	return (32);
+    else {
+      pm_error( "depth was %d, which is not in the range 1-32.", depth );
+      /* Should never reach here */
+      return(-1);
+  }
+}
+
+
+
+static unsigned int
+getval( file )
+    FILE* file;
+    {
+    unsigned int b;
+
+    if ( bitsperitem == 0 )
+	{
+	if ( pm_readlittlelong( file, &item ) == -1 )
+	    pm_error( "EOF / read error" );
+	bitsperitem = 32;
+	bitshift = 0;
+	item = ~item;
+	}
+    b = ( ( item >> bitshift ) & bitmask );
+    bitsperitem = bitsperitem - maxbitsperitem;
+    bitshift = bitshift + maxbitsperitem;
+    return b;
+    }
diff --git a/converter/pgm/pgmtofs.c b/converter/pgm/pgmtofs.c
new file mode 100644
index 00000000..b34d77c4
--- /dev/null
+++ b/converter/pgm/pgmtofs.c
@@ -0,0 +1,153 @@
+/* pgmtofs.c - convert portable graymap to Usenix FaceSaver(tm) format
+**
+** Copyright (C) 1991 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include "pgm.h"
+
+static void putinit ARGS(( int cols, int rows, int bps ));
+static void putitem ARGS(( void ));
+static void putgray ARGS(( gray g ));
+static void putrest ARGS(( void ));
+
+int
+main( argc, argv )
+    int argc;
+    char* argv[];
+{
+    FILE* ifp;
+    gray** grays;
+    register gray* gP;
+    int argn, rows, cols, bps, padright, row, col;
+    gray maxval, nmaxval;
+    const char* const usage = "[pgmfile]";
+
+
+    pgm_init( &argc, argv );
+
+    argn = 1;
+
+    if ( argn < argc )
+	{
+        ifp = pm_openr( argv[argn] );
+        ++argn;
+	}
+    else
+	{
+        ifp = stdin;
+	}
+
+    if ( argn != argc )
+        pm_usage( usage );
+
+    grays = pgm_readpgm( ifp, &cols, &rows, &maxval );
+    pm_close( ifp );
+
+    /* Figure out bps. */
+    bps = pm_maxvaltobits( (int) maxval );
+    if ( bps > 2 && bps < 4 )
+        bps = 4;
+    else if ( bps > 4 && bps < 8 )
+        bps = 8;
+    else if ( bps > 8 )
+        pm_error(
+            "maxval of %d is too large for FaceSaver(tm)", maxval );
+    nmaxval = pm_bitstomaxval( bps );
+    
+    /* Compute padding to round cols * bps up to the nearest multiple of 8. */
+    padright = ( ( cols * bps + 7 ) / 8 ) * 8 - cols * bps;
+
+    putinit( cols, rows, bps );
+    for ( row = rows - 1; row >= 0; --row )
+	{
+        for ( col = 0, gP = grays[row]; col < cols; ++col, ++gP )
+	    {
+            if ( maxval != nmaxval )
+                *gP = (int) *gP * nmaxval / maxval;
+            putgray( *gP );
+	    }
+        for ( col = 0; col < padright; ++col )
+            putgray( 0 );
+    }
+
+    putrest( );
+
+    exit( 0 );
+}
+
+
+static int bitspersample, item, bitsperitem, bitshift, itemsperline, items;
+
+static void
+putinit( cols, rows, bps )
+    int cols, rows, bps;
+{
+    printf( "FirstName: \n" );
+    printf( "LastName: \n" );
+    printf( "E-mail: \n" );
+    printf( "Telephone: \n" );
+    printf( "Company: \n" );
+    printf( "Address1: \n" );
+    printf( "Address2: \n" );
+    printf( "CityStateZip: \n" );
+    printf( "Date: \n" );
+    printf( "PicData: %d %d %d\n", cols, rows, bps );
+    printf( "Image: %d %d %d\n", cols, rows, bps );
+    printf( "\n" );
+
+    bitspersample = bps;
+    itemsperline = items = 0;
+    item = 0;
+    bitsperitem = 0;
+    bitshift = 8 - bitspersample;
+}
+
+static void
+putitem( )
+{
+    const char* const hexits = "0123456789abcdef";
+
+    if ( itemsperline == 30 )
+	{
+        putchar( '\n' );
+        itemsperline = 0;
+	}
+    putchar( hexits[item >> 4] );
+    putchar( hexits[item & 15] );
+    ++itemsperline;
+    ++items;
+    item = 0;
+    bitsperitem = 0;
+    bitshift = 8 - bitspersample;
+}
+
+#if __STDC__
+static void
+putgray( gray g )
+#else /*__STDC__*/
+    static void
+putgray( g )
+    gray g;
+#endif /*__STDC__*/
+{
+    if ( bitsperitem == 8 )
+        putitem( );
+    item += g << bitshift;
+    bitsperitem += bitspersample;
+    bitshift -= bitspersample;
+}
+
+static void
+putrest( )
+{
+    if ( bitsperitem > 0 )
+        putitem( );
+    printf( "\n" );
+}
diff --git a/converter/pgm/pgmtolispm.c b/converter/pgm/pgmtolispm.c
new file mode 100644
index 00000000..02f2fd1e
--- /dev/null
+++ b/converter/pgm/pgmtolispm.c
@@ -0,0 +1,148 @@
+/* pgmtolispm.c - read a pgm and write a file acceptable to the 
+** tv:read-bit-array-file function of TI Explorer and Symbolics Lisp Machines.
+**
+** Written by Jamie Zawinski based on code (C) 1988 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+**
+**   When one writes a multi-plane bitmap with tv:write-bit-array-file, it is
+**   usually a color image; but a color map is not written in the file, so we
+**   treat this as a graymap instead.  To convert a color image to Lispm 
+**   format, you must convert it to a pgm, and hand-edit a color map...  Ick.
+*/
+
+#include <stdio.h>
+#include "pgm.h"
+
+#define LISPM_MAGIC  "This is a BitMap file"
+
+static void putinit ARGS(( int cols, int rows, int depth ));
+static int depth_to_word_size ARGS(( int depth ));
+static void putval ARGS(( gray b ));
+static void putrest ARGS(( void ));
+static void putitem ARGS(( void ));
+
+int
+main( argc, argv )
+    int argc;
+    char* argv[];
+    {
+    FILE* ifp;
+    gray *grayrow;
+    register gray* gP;
+    int rows, cols, depth, format, padright, row, col;
+    gray maxval;
+
+
+    pgm_init( &argc, argv );
+
+    if ( argc > 2 )
+	pm_usage( "[pgmfile]" );
+    if ( argc == 2 )
+	ifp = pm_openr( argv[1] );
+    else
+	ifp = stdin;
+
+    pgm_readpgminit( ifp, &cols, &rows, &maxval, &format );
+    grayrow = pgm_allocrow( cols );
+    depth = pm_maxvaltobits( maxval );
+
+    /* Compute padding to round cols up to the nearest multiple of 32. */
+    padright = ( ( cols + 31 ) / 32 ) * 32 - cols;
+
+    putinit( cols, rows, depth );
+    for ( row = 0; row < rows; ++row )
+	{
+	pgm_readpgmrow( ifp, grayrow, cols, maxval, format );
+        for ( col = 0, gP = grayrow; col < cols; ++col, ++gP )
+	    putval( *gP );
+	for ( col = 0; col < padright; ++col )
+	    putval( 0 );
+        }
+
+    pm_close( ifp );
+
+    putrest( );
+
+    exit( 0 );
+    }
+
+static unsigned int item;
+static unsigned int bitsperitem, maxbitsperitem, bitshift;
+
+static void
+putinit( cols, rows, depth )
+    int cols, rows, depth;
+    {
+    int i;
+    int cols32 = ( ( cols + 31 ) / 32 ) * 32;	/* Lispms are able to write bit files that are not mod32 wide, but we   */
+						/* don't.  This should be ok, since bit arrays which are not mod32 wide */
+    printf(LISPM_MAGIC);			/* are pretty useless on a lispm (can't hand them to bitblt).		*/
+    pm_writelittleshort( stdout, cols );
+    pm_writelittleshort( stdout, rows );
+    pm_writelittleshort( stdout, cols32 );
+    putchar(depth & 0xFF);
+
+    for ( i = 0; i < 9; ++i )
+	putchar( 0 );	/* pad bytes */
+
+    item = 0;
+    bitsperitem = 0;
+    maxbitsperitem = depth_to_word_size( depth );
+    bitshift = 0;
+    }
+
+static int
+depth_to_word_size (depth)	/* Lispm architecture specific - if a bitmap is written    */
+  int depth;			/* out with a depth of 5, it really has a depth of 8, and  */
+{				/* is stored that way in the file.			   */
+    if (depth==0 || depth==1)	return ( 1);
+    else if (depth ==  2)	return ( 2);
+    else if (depth <=  4)	return ( 4);
+    else if (depth <=  8)	return ( 8);
+    else if (depth <= 16)	return (16);
+    else if (depth <= 32)	return (32);
+    else {
+      pm_error( "depth was %d, which is not in the range 1-32", depth );
+      return(-1);  /* Should never reach here */
+  }
+}
+
+
+
+#if __STDC__
+static void
+putval( gray b )
+#else /*__STDC__*/
+static void
+putval( b )
+gray b;
+#endif /*__STDC__*/
+    {
+    if ( bitsperitem == 32 )
+	putitem( );
+    item = item | ( b << bitshift );
+    bitsperitem = bitsperitem + maxbitsperitem;
+    bitshift = bitshift + maxbitsperitem;
+    }
+
+static void
+putrest( )
+    {
+    if ( bitsperitem > 0 )
+	putitem( );
+    }
+
+static void
+putitem( )
+    {
+    pm_writelittlelong( stdout, ~item );
+    item = 0;
+    bitsperitem = 0;
+    bitshift = 0;
+    }
diff --git a/converter/pgm/pgmtopgm.c b/converter/pgm/pgmtopgm.c
new file mode 100644
index 00000000..c65e98e0
--- /dev/null
+++ b/converter/pgm/pgmtopgm.c
@@ -0,0 +1,44 @@
+/*----------------------------------------------------------------------------
+                               pgmtopgm
+------------------------------------------------------------------------------
+  Part of the Netpbm package.
+
+  Copy PGM image from Standard Input to Standard Output
+
+
+  By Bryan Henderson, San Jose CA 2002.09.07
+
+  Contributed to the public domain by its author 2002.09.07
+-----------------------------------------------------------------------------*/
+
+#include "pgm.h"
+
+int
+main(int argc, char *argv[]) {
+    int format;
+    int rows, cols;
+    gray maxval;
+    int row;
+    gray* grayrow;
+    
+    pgm_init(&argc, argv);
+    
+    if (argc-1 != 0)
+        pm_error("Program takes no arguments.  Input is from Standard Input");
+
+    pgm_readpgminit(stdin, &cols, &rows, &maxval, &format);
+
+    pgm_writepgminit(stdout, cols, rows, maxval, 0);
+
+    grayrow = pgm_allocrow(cols);
+
+    for (row = 0; row < rows; row++) {
+        pgm_readpgmrow(stdin, grayrow, cols, maxval, format);
+        pgm_writepgmrow(stdout, grayrow, cols, maxval, 0);
+    }
+    pgm_freerow(grayrow);
+
+    pm_close(stdin);
+
+    return 0;
+}
diff --git a/converter/pgm/psidtopgm.c b/converter/pgm/psidtopgm.c
new file mode 100644
index 00000000..07417d1b
--- /dev/null
+++ b/converter/pgm/psidtopgm.c
@@ -0,0 +1,128 @@
+/* psidtopgm.c - convert PostScript "image" data into a portable graymap
+**
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include "pgm.h"
+
+
+static int
+gethexit(FILE * const ifp) {
+
+    for ( ; ; ) {
+        int const i = getc(ifp);
+        if (i == EOF)
+            pm_error("EOF / read error");
+        else {
+            char const c = (char) i;
+            if (c >= '0' && c <= '9')
+                return c - '0';
+            else if (c >= 'A' && c <= 'F')
+                return c - 'A' + 10;
+            else if (c >= 'a' && c <= 'f')
+                return c - 'a' + 10;
+            /* Else ignore - whitespace. */
+        }
+    }
+}
+
+
+
+int
+main(int     argc,
+     char ** argv) {
+
+    FILE * ifP;
+    gray * grayrow;
+    int argn, row;
+    gray maxval;
+    int rows, cols, bitspersample;
+
+    pgm_init(&argc, argv);
+
+    argn = 1;
+    
+    if (argn + 3 > argc)
+        pm_error("Too few arguments");
+
+    cols = atoi(argv[argn++]);
+    rows = atoi(argv[argn++]);
+    bitspersample = atoi(argv[argn++]);
+    if (cols <= 0)
+        pm_error("Columns must be positive.  You specified %d",
+                 cols);
+    if (rows <= 0)
+        pm_error("Rows must be positive.  You specified %d",
+                 rows);
+    if (bitspersample <= 0)
+        pm_error("Bits per sample must be positive.  You specified %d",
+                 bitspersample);
+
+    if (argn < argc)
+        ifP = pm_openr(argv[argn++]);
+    else
+        ifP = stdin;
+
+    if (argn != argc)
+        pm_error("Too many arguments");
+
+    maxval = pm_bitstomaxval(bitspersample);
+    if (maxval > PGM_OVERALLMAXVAL)
+        pm_error("bits/sample (%d) is too large.", bitspersample);
+
+    pgm_writepgminit(stdout, cols, rows, maxval, 0);
+    grayrow = pgm_allocrow((cols + 7) / 8 * 8);
+    for (row = 0; row < rows; ++row) {
+        unsigned int col;
+        for (col = 0; col < cols; ) {
+            int val;
+            val = gethexit(ifP) << 4;
+            val += gethexit(ifP);
+            switch (bitspersample) {
+            case 1:
+                grayrow[col++] = val >> 7;
+                grayrow[col++] = ( val >> 6 ) & 0x1;
+                grayrow[col++] = ( val >> 5 ) & 0x1;
+                grayrow[col++] = ( val >> 4 ) & 0x1;
+                grayrow[col++] = ( val >> 3 ) & 0x1;
+                grayrow[col++] = ( val >> 2 ) & 0x1;
+                grayrow[col++] = ( val >> 1 ) & 0x1;
+                grayrow[col++] = val & 0x1;
+                break;
+
+            case 2:
+                grayrow[col++] = val >> 6;
+                grayrow[col++] = ( val >> 4 ) & 0x3;
+                grayrow[col++] = ( val >> 2 ) & 0x3;
+                grayrow[col++] = val & 0x3;
+                break;
+
+            case 4:
+                grayrow[col++] = val >> 4;
+                grayrow[col++] = val & 0xf;
+                break;
+
+            case 8:
+                grayrow[col++] = val;
+                break;
+
+            default:
+                pm_error("This program does not know how to interpret a"
+                         "%d bitspersample image", bitspersample );
+            }
+        }
+        pgm_writepgmrow(stdout, grayrow, cols, (gray) maxval, 0);
+    }
+    pgm_freerow(grayrow);
+    pm_close(ifP);
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/converter/pgm/rawtopgm.c b/converter/pgm/rawtopgm.c
new file mode 100644
index 00000000..c91c6178
--- /dev/null
+++ b/converter/pgm/rawtopgm.c
@@ -0,0 +1,284 @@
+/* rawtopgm.c - convert raw grayscale bytes into a portable graymap
+**
+** Copyright (C) 1989 by Jef Poskanzer.
+**
+** Permission to use, copy, modify, and distribute this software and its
+** documentation for any purpose and without fee is hereby granted, provided
+** that the above copyright notice appear in all copies and that both that
+** copyright notice and this permission notice appear in supporting
+** documentation.  This software is provided "as is" without express or
+** implied warranty.
+*/
+
+#include <math.h>
+#include "pgm.h"
+#include "shhopt.h"
+
+struct cmdline_info {
+    /* All the information the user supplied in the command line,
+       in a form easy for the program to use.
+    */
+    const char *input_filespec;  /* Filespec of input file */
+    unsigned int headerskip;
+    float rowskip;
+    int bottomfirst;  /* the -bottomfirst/-bt option */
+    int autosize;  /* User wants us to figure out the size */
+    int width;
+    int height;
+    int bpp;
+      /* bytes per pixel in input format.  1 or 2 */
+    int littleendian;
+      /* logical: samples in input are least significant byte first */
+    int maxval;  /* -maxval option, or -1 if none */
+};
+
+
+static void
+parse_command_line(int argc, char ** argv,
+                   struct cmdline_info *cmdline_p) {
+/*----------------------------------------------------------------------------
+   Note that the file spec array we return is stored in the storage that
+   was passed to us as the argv array.
+-----------------------------------------------------------------------------*/
+    optStruct *option_def = malloc(100*sizeof(optStruct));
+        /* Instructions to OptParseOptions2 on how to parse our options.
+         */
+    optStruct2 opt;
+
+    unsigned int option_def_index;
+
+    option_def_index = 0;   /* incremented by OPTENTRY */
+    OPTENTRY(0,   "bottomfirst",   OPT_FLAG,   &cmdline_p->bottomfirst,    0);
+    OPTENTRY(0,   "bt",            OPT_FLAG,   &cmdline_p->bottomfirst,    0);
+    OPTENTRY(0,   "topbottom",     OPT_FLAG,   &cmdline_p->bottomfirst,    0);
+    OPTENTRY(0,   "tb",            OPT_FLAG,   &cmdline_p->bottomfirst,    0);
+    OPTENTRY(0,   "headerskip",    OPT_UINT,   &cmdline_p->headerskip,     0);
+    OPTENTRY(0,   "rowskip",       OPT_FLOAT,  &cmdline_p->rowskip,        0);
+    OPTENTRY(0,   "bpp",           OPT_INT,    &cmdline_p->bpp,            0);
+    OPTENTRY(0,   "littleendian",  OPT_FLAG,   &cmdline_p->littleendian,   0);
+    OPTENTRY(0,   "maxval",        OPT_UINT,   &cmdline_p->maxval,         0);
+
+    /* Set the defaults */
+    cmdline_p->bottomfirst = FALSE;
+    cmdline_p->headerskip = 0;
+    cmdline_p->rowskip = 0.0;
+    cmdline_p->bpp = 1;
+    cmdline_p->littleendian = 0;
+    cmdline_p->maxval = -1;
+
+    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 */
+
+    optParseOptions2(&argc, argv, opt, 0);
+        /* Uses and sets argc, argv, and some of *cmdline_p and others. */
+
+    if (argc-1 == 0) {
+        cmdline_p->input_filespec = "-";
+        cmdline_p->autosize = TRUE;
+    } else if (argc-1 == 1) {
+        cmdline_p->input_filespec = argv[1];
+        cmdline_p->autosize = TRUE;
+    } else if (argc-1 == 2) {
+        cmdline_p->input_filespec = "-";
+        cmdline_p->autosize = FALSE;
+        cmdline_p->width = atoi(argv[1]);
+        cmdline_p->height = atoi(argv[2]);
+    } else if (argc-1 == 3) {
+        cmdline_p->input_filespec = argv[3];
+        cmdline_p->autosize = FALSE;
+        cmdline_p->width = atoi(argv[1]);
+        cmdline_p->height = atoi(argv[2]);
+    } else
+        pm_error("Program takes zero, one, two, or three arguments.  You "
+                 "specified %d", argc-1);
+
+    if (cmdline_p->bpp != 1 && cmdline_p->bpp != 2) 
+        pm_error("Bytes per pixel (-bpp) must be 1 or 2.  You specified %d.",
+                 cmdline_p->bpp);
+
+    if (cmdline_p->maxval == 0)
+        pm_error("Maxval (-maxval) may not be zero.");
+
+    if (cmdline_p->maxval > 255 && cmdline_p->bpp == 1)
+        pm_error("You have specified one byte per pixel, but a maxval "
+                 "too large to fit in one byte: %d", cmdline_p->maxval);
+    if (cmdline_p->maxval > 65535)
+        pm_error("Maxval must be less than 65536.  You specified %d.",
+                 cmdline_p->maxval);
+
+    if (cmdline_p->width <= 0) 
+        pm_error("Width must be a positive number.");
+    if (cmdline_p->height <= 0) 
+        pm_error("Height must be a positive number.");
+
+    if (cmdline_p->rowskip && cmdline_p->autosize)
+        pm_error("If you specify -rowskip, you must also give the image "
+                 "dimensions.");
+    if (cmdline_p->rowskip && cmdline_p->bottomfirst)
+        pm_error("You canot specify both -rowskip and -bottomfirst.  This is "
+                 "a limitation of this program.");
+
+}
+
+
+
+static void
+compute_image_size(const struct cmdline_info cmdline, const long nread,
+                   int * const rows_p, int * const cols_p) {
+
+    if (cmdline.autosize) {
+        int sqrt_trunc = 
+            (int) sqrt((double) (nread-cmdline.headerskip));
+        if (sqrt_trunc*sqrt_trunc+cmdline.headerskip != nread) 
+            pm_error( "You must specify the dimensions of the image unless "
+                      "it is a quadratic image.  This one is not quadratic: "
+                      "The number of "
+                      "pixels in the input is %ld, which is not a perfect "
+                      "square.", nread-cmdline.headerskip);
+        *rows_p = *cols_p = sqrt_trunc;
+        pm_message( "Image size: %d cols, %d rows", *cols_p, *rows_p);
+    } else {
+        *rows_p = cmdline.height;
+        *cols_p = cmdline.width;
+    }
+}
+
+
+
+static void
+skip_header(FILE *ifp, const int headerskip) {
+    int i;
+
+    for ( i = 0; i < headerskip; ++i ) {
+        /* Read a byte out of the file */
+        int val;
+        val = getc( ifp );
+        if ( val == EOF )
+            pm_error("EOF / read error reading Byte %d in the header", i );
+    }
+}
+
+
+
+static gray
+read_from_file(FILE *ifp, const int bpp, const int row, const int col,
+               const int littleendian) {
+/*----------------------------------------------------------------------------
+   Return the next sample value from the input file 'ifp', assuming the
+   input stream is 'bpp' bytes per pixel (1 or 2).  In the case of two
+   bytes, if 'littleendian', assume least significant byte is first.
+   Otherwise, assume MSB first.
+   
+   In error messages, say this is Column 'col', Row 'row'.  Exit program if
+   error.
+-----------------------------------------------------------------------------*/
+    gray retval;
+
+    if (bpp == 1) {
+        int val;
+        val = getc(ifp);
+        if (val == EOF)
+            pm_error( "EOF / read error at Row %d Column %d",
+                      row, col);
+        retval = (gray) val;
+    } else {
+        short val;
+        int rc;
+        rc = littleendian ? 
+            pm_readlittleshort(ifp, &val) : pm_readbigshort(ifp, &val);
+        if (rc != 0)
+            pm_error( "EOF / read error at Row %d Column %d",
+                      row, col);
+        retval = (gray) val;
+    }
+    return retval;
+}
+
+
+
+int
+main(int argc, char *argv[] ) {
+
+    struct cmdline_info cmdline;
+    FILE* ifp;
+    gray* grayrow;
+    int rows, cols;
+    gray maxval;
+    char* buf;
+    /* pixels_1 and pixels_2 are the array of pixels in the input buffer
+       (assuming we are using an input buffer).  pixels_1 is the array
+       as if the pixels are one byte each.  pixels_2 is the array as if
+       they are two bytes each.
+       */
+    unsigned char *pixels_1;  
+    unsigned short *pixels_2;
+    long nread;
+    int row;
+    float toskip;
+
+    pgm_init( &argc, argv );
+
+    parse_command_line(argc, argv, &cmdline);
+
+    ifp = pm_openr(cmdline.input_filespec);
+
+    if (cmdline.autosize || cmdline.bottomfirst) {
+        buf = pm_read_unknown_size( ifp, &nread );
+        pixels_1 = (unsigned char *) buf;
+        pixels_2 = (unsigned short *) buf;
+    } else
+        buf = NULL;
+
+    compute_image_size(cmdline, nread, &rows, &cols);
+
+    if (!buf)
+        skip_header(ifp, cmdline.headerskip);
+
+    toskip = 0.00001;
+
+    if (cmdline.maxval == -1)
+        maxval = (cmdline.bpp == 1 ? (gray) 255 : (gray) 65535);
+    else
+        maxval = (gray) cmdline.maxval;
+
+    pgm_writepgminit( stdout, cols, rows, maxval, 0 );
+    grayrow = pgm_allocrow( cols );
+
+    for ( row = 0; row < rows; ++row) {
+        int col;
+        unsigned int rowpos; /* index of this row in pixel array */
+        if (cmdline.bottomfirst)
+            rowpos = (rows-row-1) * cols;
+        else
+            rowpos = row * cols;
+
+        for ( col = 0; col < cols; ++col )
+            if (buf) {
+                if (cmdline.bpp == 1)
+                    grayrow[col] = pixels_1[rowpos+col];
+                else
+                    grayrow[col] = pixels_2[rowpos+col];
+            } else {
+                grayrow[col] = read_from_file(ifp, cmdline.bpp, 
+                                              row, col,
+                                              cmdline.littleendian);
+            }
+        for ( toskip += cmdline.rowskip; toskip >= 1.0; toskip -= 1.0 ) {
+            /* Note that if we're using a buffer, cmdline.rowskip is zero */
+            int val;
+            val = getc( ifp );
+            if ( val == EOF )
+                pm_error( "EOF / read error skipping bytes at the end "
+                          "of Row %d.", row);
+        }
+        pgm_writepgmrow( stdout, grayrow, cols, maxval, 0 );
+    }
+    
+    if (buf)
+        free(buf);
+    pm_close( ifp );
+    pm_close( stdout );
+
+    exit( 0 );
+}
diff --git a/converter/pgm/sbigtopgm.c b/converter/pgm/sbigtopgm.c
new file mode 100644
index 00000000..bb3cb6fe
--- /dev/null
+++ b/converter/pgm/sbigtopgm.c
@@ -0,0 +1,208 @@
+/*
+
+    sbigtopgm.c - read a Santa Barbara Instruments Group CCDOPS file
+
+    Note: All SBIG CCD astronomical cameras produce 14 bits or
+	  (the ST-4 and ST-5) or 16 bits (ST-6 and later) per pixel.
+
+		  Copyright (C) 1998 by John Walker
+		       http://www.fourmilab.ch/
+
+    If you find yourself having to add functionality included subsequent
+    to the implementation of this program, you can probably find
+    documentation of any changes to the SBIG file format on their
+    Web site: http://www.sbig.com/
+
+    Permission to use, copy, modify, and distribute this software and
+    its documentation for any purpose and without fee is hereby
+    granted, provided that the above copyright notice appear in all
+    copies and that both that copyright notice and this permission
+    notice appear in supporting documentation.	This software is
+    provided "as is" without express or implied warranty.
+
+*/
+
+#include <string.h>
+
+#include "pgm.h"
+#include "nstring.h"
+
+#define SBIG_HEADER_LENGTH  2048      /* File header length */
+
+/*  looseCanon	--  Canonicalize a line from the file header so
+		    items more sloppily formatted than those
+		    written by CCDOPS are still accepted.  */
+
+static void looseCanon(cp)
+  char *cp;
+{
+    char *op = cp;
+    char c;
+    
+    while ((c = *cp++) != 0) {
+	if (!ISSPACE(c)) {
+	    if (ISUPPER(c)) {
+		c = tolower(c);
+	    }
+	    *op++ = c;
+	}
+    }
+    *op++ = 0;
+}
+
+int main(argc, argv)
+  int argc;
+  char* argv[];
+{
+    FILE *ifp;
+    gray *grayrow;
+    register gray *gP;
+    int argn, row;
+    register int col;
+    int maxval;
+    int comp, rows, cols;
+    char header[SBIG_HEADER_LENGTH];
+    char *hdr;
+    static char camera[80] = "ST-?";
+
+    pgm_init(&argc, argv);
+
+    argn = 1;
+
+    if (argn < argc) {
+	ifp = pm_openr(argv[argn]);
+	argn++;
+    } else {
+	ifp = stdin;
+    }
+
+    if (argn != argc)
+        pm_usage( "[sbigfile]" );
+
+    if (fread(header, SBIG_HEADER_LENGTH, 1, ifp) < 1) {
+        pm_error("error reading SBIG file header");
+    }
+
+    /*	Walk through the header and parse relevant parameters.	*/
+
+    comp = -1;
+    cols = -1;
+    rows = -1;
+
+    /*	The SBIG header specification equivalent to maxval is
+        "Sat_level", the saturation level of the image.  This
+	specification is optional, and was not included in files
+	written by early versions of CCDOPS. It was introduced when it
+	became necessary to distinguish 14-bit images with a Sat_level
+	of 16383 from 16-bit images which saturate at 65535.  In
+	addition, co-adding images or capturing with Track and
+	Accumulate can increase the saturation level.  Since files
+        which don't have a Sat_level line in the header were most
+	probably written by early drivers for the ST-4 or ST-5, it
+	might seem reasonable to make the default for maxval 16383,
+	the correct value for those cameras.  I chose instead to use
+	65535 as the default because the overwhelming majority of
+        cameras in use today are 16 bit, and it's possible some
+        non-SBIG software may omit the "optional" Sat_level
+	specification.	Also, no harm is done if a larger maxval is
+	specified than appears in the image--a simple contrast stretch
+	will adjust pixels to use the full 0 to maxval range.  The
+	converse, pixels having values greater than maxval, results in
+	an invalid file which may cause problems in programs which
+	attempt to process it.	*/
+
+    maxval = 65535;
+
+    hdr = header;
+
+    for (;;) {
+        char *cp = strchr(hdr, '\n');
+
+	if (cp == NULL) {
+            pm_error("malformed SBIG file header at character %d", hdr - header);
+	}
+	*cp = 0;
+        if (strncmp(hdr, "ST-", 3) == 0) {
+            char *ep = strchr(hdr + 3, ' ');
+
+	    if (ep != NULL) {
+		*ep = 0;
+		strcpy(camera, hdr);
+                *ep = ' ';
+	    }
+	}
+	looseCanon(hdr);
+        if (strncmp(hdr, "st-", 3) == 0) {
+            comp = strstr(hdr, "compressed") != NULL;
+        } else if (strncmp(hdr, "height=", 7) == 0) {
+	    rows = atoi(hdr + 7);
+        } else if (strncmp(hdr, "width=", 6) == 0) {
+	    cols = atoi(hdr + 6);
+        } else if (strncmp(hdr, "sat_level=", 10) == 0) {
+	    maxval = atoi(hdr + 10);
+        } else if (STREQ(hdr, "end")) {
+	    break;
+	}
+	hdr = cp + 1;
+    }
+
+    if ((comp == -1) || (rows == -1) || (cols == -1)) {
+        pm_error("required specification missing from SBIG file header");
+    }
+
+    fprintf(stderr, "SBIG %s %dx%d %s image, saturation level = %d.\n",
+        camera, cols, rows, comp ? "compressed" : "uncompressed", maxval);
+
+    if (maxval > PGM_OVERALLMAXVAL) {
+        pm_error("Saturation level (%d levels) is too large.\n"
+                 "This program's limit is %d.", maxval, PGM_OVERALLMAXVAL);
+    }
+
+    pgm_writepgminit(stdout, cols, rows, (gray) maxval, 0);
+    grayrow = pgm_allocrow(cols);
+
+#define DOSINT(fp) ((getc(fp) & 0xFF) | (getc(fp) << 8))
+
+    for (row = 0; row < rows; row++) {
+	int compthis = comp;
+
+	if (comp) {
+	    int rowlen = DOSINT(ifp); /* Compressed row length */
+
+	    /*	If compression results in a row length >= the uncompressed
+		row length, that row is output uncompressed.  We detect this
+		by observing that the compressed row length is equal to
+		that of an uncompressed row.  */
+
+	    if (rowlen == cols * 2) {
+		compthis = 0;
+	    }
+	}
+	for (col = 0, gP = grayrow; col < cols; col++, gP++) {
+	    gray g;
+
+	    if (compthis) {
+
+		if (col == 0) {
+		    g = DOSINT(ifp);
+		} else {
+		    int delta = getc(ifp);
+
+		    if (delta == 0x80) {
+			g = DOSINT(ifp);
+		    } else {
+			g += ((signed char) delta);
+		    }
+		}
+	    } else {
+		g = DOSINT(ifp);
+	    }
+	    *gP = g;
+	}
+	pgm_writepgmrow(stdout, grayrow, cols, (gray) maxval, 0);
+    }
+    pm_close(ifp);
+    pm_close(stdout);
+
+    return 0;
+}
diff --git a/converter/pgm/spottopgm.c b/converter/pgm/spottopgm.c
new file mode 100644
index 00000000..59240ba8
--- /dev/null
+++ b/converter/pgm/spottopgm.c
@@ -0,0 +1,231 @@
+/* Spottopgm: Convert a SPOT satellite image to PGM format.
+ *
+ * Usage: spottopgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] inputfile
+ *
+ * Author: Warren Toomey, 1992.
+ */
+
+#include <stdio.h>
+#include "pgm.h"
+
+/* Global variables */
+
+static FILE *spotfile;          /* The input file */
+static char linebuf[12000];        /* The line buffer */
+
+static long Firstline = 0,     /* The rectangle the user wants */
+    Lastline = 3000,   /* cut out of the image */
+    Firstcol = 0,
+    Lastcol = 0;
+static long Diff = 0;          /* Firstcol - Lastcol */
+static char *Bufptr;           /* Pointer into the input image */
+static int Color = 1;          /* Either 1, 2 or 3 */
+static int Colbool = 0;        /* 1 if color */
+
+
+/* Get_image extracts the pixel data from one line
+ * (i.e one record) in the SPOT input file. A SPOT image
+ * record has a header, data and trailer. The data lengths
+ * are fixed at 3960, 5400, 8640 or 10980 bytes.
+ *
+ * When we arrive here we have read in 12 bytes of the record.
+ * We then read in the rest of the record. We find the trailer
+ * and from that determine the number of pixels on the line.
+ *
+ * If the image is really color i.e interleaved 3 colors, we
+ * convert a line if its spectral sequence is the same as the one
+ * requested by the user (i.e 1, 2 or 3). I could create a ppm file
+ * but I couldn't be bothered with the rearranging of the data.
+ */
+static int 
+get_image(long length)
+{
+    int cnt;
+    struct Linehdr        /* Each line begins with the 12 bytes */
+    {             /* we have already, plus these 20 bytes */
+        long linenum;       /* The line number of the record */
+        short recseq;       /* The record sequence number */
+        short spectseq;     /* The spectral number of the line */
+        long linetime;      /* Time it was recorded (in ms). */
+        long leftpixmar;        /* The pixel number of the 1st pixel */
+        long rightpixmar;       /* The pixel number of the last pixel */
+    } linehdr;
+    long numpixels;       /* Number of pixels on the line */
+
+    /* Get the details of this line */
+    if (pm_readbiglong (spotfile, &linehdr.linenum) == -1
+        || pm_readbigshort (spotfile, &linehdr.recseq) == -1
+        || pm_readbigshort (spotfile, &linehdr.spectseq) == -1
+        || pm_readbiglong (spotfile, &linehdr.linetime) == -1
+        || pm_readbiglong (spotfile, &linehdr.leftpixmar) == -1
+        || pm_readbiglong (spotfile, &linehdr.rightpixmar) == -1)
+        pm_error ("EOF / read error reading line header");
+
+    /* Now read in the line data */
+    cnt = length - 20 - 88;
+    cnt = fread(linebuf, 1, cnt, spotfile);
+
+    if (!Diff)
+    {
+        cnt += 28;
+        if (fseek (spotfile, 24, 1) == EOF)
+            pm_error ("seek error");
+        if (pm_readbiglong (spotfile, &numpixels) == -1)
+            pm_error ("EOF / read error reading line ender");
+    
+        /* Determine the picture size */
+        Bufptr = &linebuf[Firstcol];
+        if (Lastcol == 0 || Lastcol > numpixels)
+            Lastcol = numpixels;
+        Diff = Lastcol - Firstcol;
+        /* Print out the header */
+        printf("P5\n%ld %ld\n255\n", Diff, Lastline - Firstline);
+        /* Inform about the image size */
+        if (Colbool) fprintf(stderr, "Color image, ");
+        fprintf(stderr, "%ld pixels wide\n", numpixels);
+    }
+
+    /* Output the line */
+    if (linehdr.linenum >= Firstline && linehdr.linenum <= Lastline
+        && linehdr.spectseq == Color)
+        fwrite(Bufptr, 1, Diff, stdout);
+    if (linehdr.linenum > Lastline) exit(0);
+
+#ifdef DEBUG
+    fprintf(stderr,
+            "Line %4d, %3d, %3d, time %4d, l/r "
+            "pixmar %4d %4d len %d pixnum %d\n",
+            linehdr.linenum, linehdr.recseq, 
+            linehdr.spectseq, linehdr.linetime,
+            linehdr.leftpixmar, linehdr.rightpixmar, length, numpixels);
+#endif
+    /* And return the amount to seek */
+    return (length - 20 - cnt);
+}
+
+
+
+/* The image header tells us if the image is in monochrome or color, and
+ * if the latter, if the input colors are interleaved. If interleaved
+ * color, lines are interleaved R, G, B, R, G, B etc. Technically, some
+ * interleaving of infra-red, visible and ultra-violet.
+ *
+ * In the description field below,
+ *  element 0 == P --> monochrome
+ *  element 0 == X --> color
+ *  element 9 == S --> sequential (i.e only one color here)
+ *  element 9 == I --> interleaved (1 or more colors)
+ */
+static int 
+get_imghdr(int length)
+{
+    struct Imghdr
+    {
+        long linewidth;
+        char dummy1[36];
+        char description[16];   /* Type of image */
+    } header;
+
+    if (pm_readbiglong (spotfile, &header.linewidth) == -1)
+        pm_error ("EOF / read error reading header");
+#ifdef DEBUG
+    if (fread (header.dummy1, 1, 36, spotfile) != 36)
+        pm_error ("EOF / read error reading header");
+#else
+    if (fseek (spotfile, 36, 1) == EOF)
+        pm_error ("seek error");
+#endif
+    if (fread (header.description, 1, 16, spotfile) != 16)
+        pm_error ("EOF / read error reading header");
+
+    /* Determine mono or color */
+    if (header.description[0] == 'X' && header.description[9] == 'S')
+        Colbool = 1;
+    else Colbool = 0;
+
+#ifdef DEBUG
+    fprintf(stderr, "Dummy str is >%s<\n", header.dummy1);
+    fprintf(stderr, "Imghdr str is >%s<, col %d\n", 
+            header.description, Colbool);
+#endif
+    /* Return the amount to fseek */
+    return (length - 56);
+}
+
+
+static void
+usage()
+{
+    fprintf(stderr,
+            "Usage: spottopgm [-1|2|3] [Firstcol Firstline Lastcol Lastline] "
+            "input_file\n");
+    exit(1);
+}
+
+int
+main(int argc, char *argv[])
+{
+    struct Record             /* A SPOT image is broken up into */
+    {                 /* records with the following fields */
+        long record;            /* The record number (1, 2, 3...) */
+        unsigned char sub1;         /* Record sub type 1 */
+        unsigned char type;         /* The record type */
+        unsigned char sub2;         /* Record sub type 2 */
+        unsigned char sub3;         /* Record sub type 3 */
+        long length;            /* Record length in bytes */
+    } arecord;
+
+    pgm_init( &argc, argv );
+   
+    switch (argc)
+    {
+    case 7:
+        Color= -(atoi(argv[1]));      /* Get the color to extract */
+        argv++;
+    case 6:
+        Firstcol = atoi(argv[1]);     /* Get the rectangle to extract */
+        Firstline = atoi(argv[2]);
+        Lastcol = atoi(argv[3]);
+        Lastline = atoi(argv[4]);
+        argv += 4;
+        goto openfile;            /* Yuk, a goto! */
+    case 3:
+        Color= -(atoi(argv[1]));      /* Get the color to extract */
+        argv++;
+    case 2:
+    openfile:
+    spotfile = fopen(argv[1], "rb");  /* Open the input file */
+    if (spotfile == NULL) { perror("fopen"); exit(1); }
+    break;
+    default:
+        usage();
+    }
+
+    while (1)             /* Get a record */
+    {
+        if (pm_readbiglong (spotfile, &arecord.record) == -1)
+            break;
+        arecord.sub1 = fgetc (spotfile);
+        arecord.type = fgetc (spotfile);
+        arecord.sub2 = fgetc (spotfile);
+        arecord.sub3 = fgetc (spotfile);
+        if (pm_readbiglong (spotfile, &arecord.length) == -1)
+            pm_error ("EOF / read error reading a record");
+
+        arecord.length -= 12;   /* Subtract header size as well */
+        if (arecord.type == 0355 && arecord.sub1 == 0355)
+            arecord.length = get_image(arecord.length);
+        else if (arecord.type == 0300 && arecord.sub1 == 077)
+            arecord.length = get_imghdr(arecord.length);
+#ifdef DEBUG
+        else
+            fprintf(stderr, 
+                    "Rcrd %3d, type %03o, stype %03o %03o %03o, length %d\n",
+                    arecord.record, arecord.type, arecord.sub1, arecord.sub2,
+                    (int) arecord.sub3 & 0xff, arecord.length);
+#endif
+        /* Seek to next record */
+        fseek(spotfile, arecord.length, 1);
+    }
+    exit (0);
+}