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