/* 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 #include #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; }