janssen@parc.xerox.com (Bill Janssen) (02/15/91)
With Fred Hansen's help, I finished up the ATK <-> PBM converters. Here
they are, tested against the beta version of the new PBM release
(25Jan91). Here's a shar file of the two C files and the Imakefile I
used to build them:
#! /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:29:51 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, pbmtoatk.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'\" \(8870 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 = 1;
X for ( col = 0, bP = bitrow; col < cols; col++, bP++ )
X {
X if ( charcount >= 8 )
X {
X data++;
X charcount = 0;
X mask = 1;
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(filedes, rwidth, rheight, destaddr)
X int filedes;
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 register FILE *file;
X
X file = fdopen (filedes, "r");
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
X fclose (file);
X}
END_OF_FILE
if test 8870 -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'\" \(4538 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 fprintf (stderr, "cols is %d, rows is %d\n", cols, rows);
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 (row == 3)
X fprintf (stderr, "col %d (0x%x, %d, 0x%x, *bP is %d)\n", col,
X curbyte, curcount, newbyte, *bP);
X if (gather > 7)
X {
X if (row == 3)
X fprintf (stderr, "process_atk_byte (%d, 0x%x, stdout, %0x,
FALSE)\n", curcount, curbyte, newbyte);
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 if (row == 3)
X fprintf (stderr, "EOL: newbyte is 0x%x, gather is %d\n", newbyte, gather);
X newbyte = (newbyte << (8 - gather));
X if (row == 3)
X fprintf (stderr, "process_atk_byte (%d, 0x%x, stdout, 0x%x, TRUE)\n",
curcount, curbyte, newbyte);
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 4538 -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