/* 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. ** ** Feb 2010 afu ** Added dimension check to prevent short int from overflowing ** Changed code style (ANSI-style function definitions, etc.) */ #include "pm.h" #include "pgm.h" #define LISPM_MAGIC "This is a BitMap file" #define INT16MAX 32767 static unsigned int item; static unsigned int bitsperitem, maxbitsperitem, bitshift; static unsigned int depth_to_word_size(unsigned int const 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. */ unsigned int const wordSize = depth == 1 ? 1 : depth == 2 ? 2 : depth <= 4 ? 4 : depth <= 8 ? 8 : depth <= 16 ? 16 : depth <= 32 ? 32 : 0; if (wordSize == 0) pm_error("depth was %u, which is not in the range 1-32", depth); return wordSize; } static void putinit(unsigned int const cols, unsigned int const rows, unsigned int const depth) { unsigned int const cols32 = ((cols + 31 ) / 32) * 32; unsigned int i; /* 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 */ /* are pretty useless on a lispm (can't hand them to bitblt). */ if (rows > INT16MAX || cols > INT16MAX || cols32 > INT16MAX) pm_error("Input image is too large."); printf(LISPM_MAGIC); 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 void putitem(void) { pm_writelittlelong(stdout, ~item); item = 0; bitsperitem = 0; bitshift = 0; } static void putval(gray const b) { if (bitsperitem == 32) putitem(); item = item | (b << bitshift); bitsperitem = bitsperitem + maxbitsperitem; bitshift = bitshift + maxbitsperitem; } static void putrest(void) { if (bitsperitem > 0) putitem(); } int main(int argc, const char * argv[]) { FILE * ifP; gray * grayrow; int rows; int cols; unsigned int depth; int format; unsigned int padright; unsigned int row; gray maxval; const char * inputFile; pm_proginit(&argc, argv); if (argc-1 < 1) inputFile = "-"; else { inputFile = argv[1]; if (argc-1 > 2) pm_error("Too many arguments. The only argument is the optional " "input file name"); } ifP = pm_openr(inputFile); 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) { unsigned int col; pgm_readpgmrow(ifP, grayrow, cols, maxval, format); for (col = 0; col < cols; ++col) putval(grayrow[col]); for (col = 0; col < padright; ++col) putval(0); } pm_close(ifP); putrest(); return 0; }