diff options
author | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
---|---|---|
committer | giraffedata <giraffedata@9d0c8265-081b-0410-96cb-a4ca84ce46f8> | 2006-08-19 03:12:28 +0000 |
commit | 1fd361a1ea06e44286c213ca1f814f49306fdc43 (patch) | |
tree | 64c8c96cf54d8718847339a403e5e67b922e8c3f /converter/pgm | |
download | netpbm-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/Makefile | 23 | ||||
-rw-r--r-- | converter/pgm/asciitopgm.c | 163 | ||||
-rw-r--r-- | converter/pgm/bioradtopgm.c | 152 | ||||
-rw-r--r-- | converter/pgm/fstopgm.c | 138 | ||||
-rw-r--r-- | converter/pgm/hipstopgm.c | 181 | ||||
-rw-r--r-- | converter/pgm/lispmtopgm.c | 172 | ||||
-rw-r--r-- | converter/pgm/pgmtofs.c | 153 | ||||
-rw-r--r-- | converter/pgm/pgmtolispm.c | 148 | ||||
-rw-r--r-- | converter/pgm/pgmtopgm.c | 44 | ||||
-rw-r--r-- | converter/pgm/psidtopgm.c | 128 | ||||
-rw-r--r-- | converter/pgm/rawtopgm.c | 284 | ||||
-rw-r--r-- | converter/pgm/sbigtopgm.c | 208 | ||||
-rw-r--r-- | converter/pgm/spottopgm.c | 231 |
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); +} |