janssen@parc.xerox.com (Bill Janssen) (02/15/91)
Pardon the earlier shar file. Some previous (non-working) versions of the code crept into it. Here are the actual working versions of the converters and Imakefile. Note that you may have to edit the Imakefile to define PBM_HOME properly. I've also sent these off to the PBM folks. Have fun! Bill #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh <file", e.g.. If this archive is complete, you # will see the following message at the end: # "End of shell archive." # Contents: Imakefile atktopbm.c pbmtoatk.c # Wrapped by janssen@holmes on Thu Feb 14 18:52:16 1991 PATH=/bin:/usr/bin:/usr/ucb ; export PATH if test -f 'Imakefile' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'Imakefile'\" else echo shar: Extracting \"'Imakefile'\" \(211 characters\) sed "s/^X//" >'Imakefile' <<'END_OF_FILE' XPBM_HOME = /import/pbmplus X XLOCALINCLUDES = -I${PBM_HOME}/pbm X XNormalObjectRule() X XProgramTarget (pbmtoatk, pbmtoatk.o, ${PBM_HOME}/pbm/libpbm.a,) XProgramTarget (atktopbm, atktopbm.o, ${PBM_HOME}/pbm/libpbm.a,) END_OF_FILE if test 211 -ne `wc -c <'Imakefile'`; then echo shar: \"'Imakefile'\" unpacked with wrong size! fi # end of 'Imakefile' fi if test -f 'atktopbm.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'atktopbm.c'\" else echo shar: Extracting \"'atktopbm.c'\" \(8801 characters\) sed "s/^X//" >'atktopbm.c' <<'END_OF_FILE' X/* atktopbm.c - read an Andrew raster object and produce a portable bitmap X*/ X X#include <stdio.h> X#include <sys/types.h> X#include "pbm.h" X Xvoid ReadATKRaster(); X Xmain( argc, argv ) Xint argc; Xchar *argv[]; X { X FILE *ifd; X register bit *bitrow, *bP; X int rows, cols, row, col, charcount; X unsigned char *data, mask; X X pbm_init ( &argc, argv ); X X if ( argc > 2 ) X pm_usage( "[raster obj]" ); X X if ( argc == 2 ) X ifd = pm_openr( argv[1] ); X else X ifd = stdin; X X ReadATKRaster( ifd, &cols, &rows, &data ); X X pm_close( ifd ); X X pbm_writepbminit( stdout, cols, rows ); X bitrow = pbm_allocrow( cols ); X X for ( row = 0; row < rows; row++ ) X { X charcount = 0; X mask = 0x80; X for ( col = 0, bP = bitrow; col < cols; col++, bP++ ) X { X if ( charcount >= 8 ) X { X data++; X charcount = 0; X mask = 0x80; X } X *bP = ( *data & mask ) ? PBM_BLACK : PBM_WHITE; X charcount++; X mask = mask >> 1; X } X data++; X pbm_writepbmrow( stdout, bitrow, cols ); X } X X exit( 0 ); X } X X/* readatkraster.c X X Routine for readingrasters in .raster form X (BE2 rasters version 2.) X X */ X X/* codes for data stream */ X#define WHITEZERO 'f' X#define WHITETWENTY 'z' X#define BLACKZERO 'F' X#define BLACKTWENTY 'Z' X#define OTHERZERO 0x1F X X#define WHITEBYTE 0x00 X#define BLACKBYTE 0xFF X X/* error codes (copied from $ANDREW/atk/basics/common/dataobj.ch) */ X/* return values from Read */ X#define dataobject_NOREADERROR 0 X#define dataobject_PREMATUREEOF 1 X#define dataobject_NOTBE2DATASTREAM 2 /* backward compatibility */ X#define dataobject_NOTATKDATASTREAM 2 /* preferred version */ X#define dataobject_MISSINGENDDATAMARKER 3 X#define dataobject_OBJECTCREATIONFAILED 4 X#define dataobject_BADFORMAT 5 X X X/* ReadRow(file, row, length) X Reads from 'file' the encoding of bytes to fill in 'row'. Row will be X truncated or padded (with WHITE) to exactly 'length' bytes. X X Returns the code that terminated the row. This may be X '|' correct end of line X '\0' if the length was satisfied (before a terminator) X EOF if the file ended X '\' '{' other recognized ends. X The '|' is the expected end and pads the row with WHITE. X The '\' and '{' are error conditions and may indicate the X beginning of some other portion of the data stream. X If the terminator is '\' or '{', it is left at the front of the input. X '|' is gobbled up. X*/ X/* macros to generate case entries for switch statement */ X#define case1(v) case v X#define case4(v) case v: case (v)+1: case (v)+2: case(v)+3 X#define case6(v) case4(v): case ((v)+4): case ((v)+5) X#define case8(v) case4(v): case4((v)+4) X X static long XReadRow(file, row, length) X register FILE *file; /* where to get them from */ X register unsigned char *row; /* where to put bytes */ X register long length; /* how many bytes in row must be filled */ X{ X /* Each input character is processed by the central loop. There are X some input codes which require two or three characters for completion; X these are handled by advancing the state machine. Errors are not X processed; instead the state machine is reset to the Ready state X whenever a character unacceptable to the curent state is read. */ X enum stateCode { X Ready, /* any input code is allowed */ X HexDigitPending, /* have seen the first of a hex digit pair */ X RepeatPending, /* repeat code has been seen: X must be followed by two hex digits */ X RepeatAndDigit}; /* have seen repeat code and its first X following digit */ X enum stateCode InputState; /* current state */ X register c; /* the current input character */ X register long repeatcount = 0; /* current repeat value */ X register long hexval; /* current hex value */ X long pendinghex = 0; /* the first of a pair of hex characters */ X X /* We cannot exit when length becomes zero because we need to check X to see if a row ending character follows. Thus length is checked only Xwhen we get X a data generating byte. If length then is zero, we ungetc the byte */ X X InputState = Ready; X while ((c=getc(file)) != EOF) X switch (c) { X X case8(0x0): X case8(0x8): X case8(0x10): X case8(0x18): X case1(' '): X /* control characters and space are legal and completely ignored */ X break; X case1(0x40): /* '@' */ X case1(0x5B): /* '[' */ X case4(0x5D): /* ']' '^' '_' '`' */ X case4(0x7D): /* '}' '~' DEL 0x80 */ X default: /* all above 0x80 */ X /* error code: Ignored at present. Reset InputState. */ X InputState = Ready; X break; X X case1(0x7B): /* '{' */ X case1(0x5C): /* '\\' */ X /* illegal end of line: exit anyway */ X ungetc(c, file); /* retain terminator in stream */ X /* DROP THROUGH */ X case1(0x7C): /* '|' */ X /* legal end of row: may have to pad */ X while (length-- > 0) X *row++ = WHITEBYTE; X return c; X X case1(0x21): X case6(0x22): X case8(0x28): X /* punctuation characters: repeat byte given by two succeeding hex chars */ X if (length <= 0) { X ungetc(c, file); X return('\0'); X } X repeatcount = c - OTHERZERO; X InputState = RepeatPending; X break; X X case8(0x30): X case8(0x38): X /* digit (or following punctuation) - hex digit */ X hexval = c - 0x30; X goto hexdigit; X case6(0x41): X /* A ... F - hex digit */ X hexval = c - (0x41 - 0xA); X goto hexdigit; X case6(0x61): X /* a ... f - hex digit */ X hexval = c - (0x61 - 0xA); X goto hexdigit; X X case8(0x67): X case8(0x6F): X case4(0x77): X /* g ... z - multiple WHITE bytes */ X if (length <= 0) { X ungetc(c, file); X return('\0'); X } X repeatcount = c - WHITEZERO; X hexval = WHITEBYTE; X goto store; X case8(0x47): X case8(0x4F): X case4(0x57): X /* G ... Z - multiple BLACK bytes */ X if (length <= 0) { X ungetc(c, file); X return('\0'); X } X repeatcount = c - BLACKZERO; X hexval = BLACKBYTE; X goto store; X Xhexdigit: X /* process a hex digit. Use InputState to determine X what to do with it. */ X if (length <= 0) { X ungetc(c, file); X return('\0'); X } X switch(InputState) { X case Ready: X InputState = HexDigitPending; X pendinghex = hexval << 4; X break; X case HexDigitPending: X hexval |= pendinghex; X repeatcount = 1; X goto store; X case RepeatPending: X InputState = RepeatAndDigit; X pendinghex = hexval << 4; X break; X case RepeatAndDigit: X hexval |= pendinghex; X goto store; X } X break; X Xstore: X /* generate byte(s) into the output row X Use repeatcount, depending on state. */ X if (length < repeatcount) X /* reduce repeat count if it would exceed X available space */ X repeatcount = length; X length -= repeatcount; /* do this before repeatcount-- */ X while (repeatcount-- > 0) X *row++ = hexval; X InputState = Ready; X break; X X } /* end of while( - )switch( - ) */ X return EOF; X} X#undef case1 X#undef case4 X#undef case6 X#undef case8 X Xvoid ReadATKRaster(file, rwidth, rheight, destaddr) X FILE *file; X unsigned char **destaddr; X int *rwidth, *rheight; X{ X register unsigned char *byteaddr; /* where to store next row */ X register long row, rowlen; /* count rows; byte length of row */ X long version, options, xscale, yscale, xoffset, yoffset, subwidth, subheight; X char keyword[6]; X long discardid, objectid; /* id read for the incoming pixel image */ X long tc; /* temp */ X long width, height; /* dimensions of image */ X long result; X X if (fscanf(file, "\\begindata{raster,%ld", &discardid) != 1 X || getc(file) != '}' || getc(file) != '\n') X pm_error ("input file not Andrew raster object", 0, 0, 0, 0, 0); X X fscanf(file, " %d ", &version); X if (version < 2) X pm_error ("version too old to parse", 0, 0, 0, 0, 0 ); X X /* ignore all these features: */ X fscanf(file, " %u %ld %ld %ld %ld %ld %ld", X &options, &xscale, &yscale, &xoffset, X &yoffset, &subwidth, &subheight); X X /* scan to end of line in case this is actually something beyond V2 */ X while (((tc=getc(file)) != '\n') && (tc != '\\') && (tc != EOF)) {} X X /* read the keyword */ X fscanf(file, " %5s", keyword); X if (strcmp(keyword, "bits") != 0) X pm_error ("keyword is not bits!", 0, 0, 0, 0, 0); X X fscanf(file, " %d %d %d ", &objectid, &width, &height); X X if (width < 1 || height < 1 || width > 1000000 || height > 1000000) X pm_error ("bad width or height", 0, 0, 0, 0, 0 ); X X *rwidth = width; X *rheight = height; X rowlen = (width + 7) / 8; X *destaddr = (unsigned char *) malloc (sizeof(unsigned char) * height * rowlen); X for (row = 0; row < height; row++) X { X long c; X X c = ReadRow(file, *destaddr + (row * rowlen), rowlen); X if (c != '|') X { X if (c == EOF) X pm_error ("premature EOF", 0, 0, 0, 0, 0 ); X else X pm_error ("bad format", 0, 0, 0, 0, 0 ); X break; X } X } X while (! feof(file) && getc(file) != '\\') {}; /* scan for \enddata */ X if (fscanf(file, "enddata{raster,%d", &discardid) != 1 X || getc(file) != '}' || getc(file) != '\n') X pm_error ("missing end-of-object marker", 0, 0, 0, 0, 0); X} END_OF_FILE if test 8801 -ne `wc -c <'atktopbm.c'`; then echo shar: \"'atktopbm.c'\" unpacked with wrong size! fi # end of 'atktopbm.c' fi if test -f 'pbmtoatk.c' -a "${1}" != "-c" ; then echo shar: Will not clobber existing file \"'pbmtoatk.c'\" else echo shar: Extracting \"'pbmtoatk.c'\" \(4009 characters\) sed "s/^X//" >'pbmtoatk.c' <<'END_OF_FILE' X/* pbmtoatk.c - read a portable bitmap and produce an ATK raster object X*/ X X#include <stdio.h> X#include "pbm.h" X#ifdef SYSV X#include <string.h> X#define index strchr X#else /*SYSV*/ X#include <strings.h> X#endif /*SYSV*/ X X#define DEFAULTSCALE (1<<16) X#define RASTERVERSION 2 X#define TRUE 1 X#define FALSE 0 X Xmain( argc, argv ) Xint argc; Xchar *argv[]; X { X FILE *ifd; X bit *bitrow; X register bit *bP; X int rows, cols, format, padright, row; X register int col; X char name[100], *cp; X static char hexchar[] = "0123456789abcdef"; X unsigned char curbyte, newbyte; X int curcount, gather, line; X X pbm_init ( &argc, argv ); X X if ( argc > 2 ) X pm_usage( "[pbmfile]" ); X X if ( argc == 2 ) X { X ifd = pm_openr( argv[1] ); X strcpy( name, argv[1] ); X if ( strcmp( name, "-" ) == 0 ) X strcpy( name, "noname" ); X X if ( ( cp = index( name, '.' ) ) != 0 ) X *cp = '\0'; X } X else X { X ifd = stdin; X strcpy( name, "noname" ); X } X X pbm_readpbminit( ifd, &cols, &rows, &format ); X bitrow = pbm_allocrow( cols ); X X /* Compute padding to round cols up to the nearest multiple of 16. */ X padright = ( ( cols + 15 ) / 16 ) * 16 - cols; X X printf ("\\begindata{raster,%d}\n", 1); X printf ("%ld %ld %ld %ld ", RASTERVERSION, X 0, DEFAULTSCALE, DEFAULTSCALE); X printf ("%ld %ld %ld %ld\n", X 0, 0, cols, rows); /* subraster */ X printf ("bits %ld %ld %ld\n", 1, cols, rows); X X for ( row = 0; row < rows; row++ ) X { X pbm_readpbmrow( ifd, bitrow, cols, format ); X bP = bitrow; X gather = 0; X newbyte = 0; X curbyte = 0; X curcount = 0; X col = 0; X while (col < cols) X { X if (gather > 7) X { X process_atk_byte (&curcount, &curbyte, stdout, newbyte, FALSE); X gather = 0; X newbyte = 0; X } X newbyte = (newbyte << 1) | (*bP++); X gather += 1; X col += 1; X } X X if (gather > 0) X { X newbyte = (newbyte << (8 - gather)); X process_atk_byte (&curcount, &curbyte, stdout, newbyte, TRUE); X } X } X X pm_close( ifd ); X X printf ("\\enddata{raster, %d}\n", 1); X X exit( 0 ); X } X Xwrite_atk_bytes (file, curbyte, curcount) X FILE *file; X unsigned char curbyte; X unsigned int curcount; X{ X /* codes for data stream */ X#define WHITEZERO 'f' X#define WHITETWENTY 'z' X#define BLACKZERO 'F' X#define BLACKTWENTY 'Z' X#define OTHERZERO 0x1F X X#define WHITEBYTE 0x00 X#define BLACKBYTE 0xFF X X /* WriteRow table for conversion of a byte value to two character hex representation */ X X static unsigned char hex[16] = { X '0', '1', '2', '3', '4', '5', '6', '7', X '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' X }; X X switch (curbyte) { X case WHITEBYTE: X while (curcount > 20) X fputc(WHITETWENTY, file), X curcount -= 20; X fputc(WHITEZERO + curcount, file); X break; X case BLACKBYTE: X while (curcount > 20) X fputc(BLACKTWENTY, file), X curcount -= 20; X fputc(BLACKZERO + curcount, file); X break; X default: X while (curcount > 16) X fputc(OTHERZERO+16, file), X fputc(hex[curbyte / 16], file), X fputc(hex[curbyte & 15], file), X curcount -= 16; X if (curcount > 1) X fputc(OTHERZERO+curcount, file); X else ; /* the byte written will represent a single instance */ X fputc(hex[curbyte / 16], file); X fputc(hex[curbyte & 15], file); X } X} X Xprocess_atk_byte (pcurcount, pcurbyte, file, newbyte, eolflag) Xint *pcurcount; Xunsigned char *pcurbyte; XFILE *file; Xunsigned char newbyte; Xint eolflag; X{ X int curcount = *pcurcount; X unsigned char curbyte = *pcurbyte; X X if (curcount < 1) X { X *pcurbyte = curbyte = newbyte; X *pcurcount = curcount = 1; X } X else if (newbyte == curbyte) X { X *pcurcount = (curcount += 1); X } X X if (curcount > 0 && newbyte != curbyte) X { X write_atk_bytes (file, curbyte, curcount); X *pcurcount = 1; X *pcurbyte = newbyte; X } X X if (eolflag) X { X write_atk_bytes (file, *pcurbyte, *pcurcount); X fprintf (file, " |\n"); X *pcurcount = 0; X *pcurbyte = 0; X } X} X END_OF_FILE if test 4009 -ne `wc -c <'pbmtoatk.c'`; then echo shar: \"'pbmtoatk.c'\" unpacked with wrong size! fi # end of 'pbmtoatk.c' fi echo shar: End of shell archive. exit 0
wjh+@ANDREW.CMU.EDU (Fred Hansen) (02/15/91)
Bill, Great work on the PBM stuff. Thanks for understanding, solving, finishing, and submitting it. FredH