/* pbmtogo.c - read a portable bitmap and produce a GraphOn terminal raster file ** ** Rev 1.1 was based on pbmtolj.c ** ** Bo Thide', Swedish Institute of Space Physics, bt@irfu.se ** ** ** $Log: pbmtogo.c,v $ * Revision 1.5 89/11/25 00:24:12 00:24:12 root (Bo Thide) * Bug found: The byte after 64 repeated bytes sometimes lost. Fixed. * * Revision 1.4 89/11/24 14:56:04 14:56:04 root (Bo Thide) * Fixed the command line parsing since pbmtogo now always uses 2D * compression. Added a few comments to the source. * * Revision 1.3 89/11/24 13:43:43 13:43:43 root (Bo Thide) * Added support for > 63 repeated bytes and > 62 repeated lines in * the 2D compression scheme. * * Revision 1.2 89/11/15 01:04:47 01:04:47 root (Bo Thide) * First version that works reasonably well with GraphOn 2D runlength * encoding/compression. * * Revision 1.1 89/11/02 23:25:25 23:25:25 root (Bo Thide) * Initial revision * ** ** Copyright (C) 1988, 1989 by Jef Poskanzer, Michael Haberler, and Bo Thide'. ** ** 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. */ #include #include #include "pbm.h" #define TRUE 1 #define BUFSIZE 132 /* GraphOn has 132 byte/1056 bit wide raster lines */ #define REPEAT_CURRENT_LINE_MASK 0x00 #define SKIP_AND_PLOT_MASK 0x40 #define REPEAT_PLOT_MASK 0x80 #define PLOT_ARBITRARY_DATA_MASK 0xc0 #define MAX_REPEAT 64 static unsigned char *scanlineptr; /* Pointer to current scan line byte */ static void putinit ARGS(( void )); static void putbit ARGS(( bit b )); static void putrest ARGS(( void )); static void putitem ARGS(( void )); int main( argc, argv ) int argc; char* argv[]; { FILE* ifp; bit* bitrow; register bit* bP; int argn, rows, cols, format, rucols, padright, row, col; int nbyte, bytesperrow, ecount, ucount, nout, i, linerepeat; int olditem; unsigned char oldscanline[BUFSIZE]; unsigned char newscanline[BUFSIZE]; unsigned char diff[BUFSIZE]; unsigned char buffer[BUFSIZE]; unsigned char outbuffer[2*(BUFSIZE+1)]; /* Worst case. Should malloc */ const char* usage = "[-c] [pbmfile]"; pbm_init( &argc, argv ); argn = 2; /* Check for flags. */ if (argc > argn + 1) pm_usage(usage); if (argc == argn) ifp = pm_openr( argv[argn-1] ); else ifp = stdin; pbm_readpbminit(ifp, &cols, &rows, &format); bitrow = pbm_allocrow(cols); /* Round cols up to the nearest multiple of 8. */ rucols = ( cols + 7 ) / 8; bytesperrow = rucols; /* GraphOn uses bytes */ rucols = rucols * 8; padright = rucols - cols; for (i = 0; i < BUFSIZE; ++i ) buffer[i] = 0; putinit(); /* Start donwloading screen raster */ printf("\033P0;1;0;4;1;%d;%d;1!R1/", rows, rucols); linerepeat = 63; /* 63 means "Start new picture" */ nout = 0; /* To prevent compiler warning */ for (row = 0; row < rows; row++) { /* Store scan line data in the new scan line vector */ scanlineptr = newscanline; pbm_readpbmrow(ifp, bitrow, cols, format); /* Transfer raster graphics */ for (col = 0, bP = bitrow; col < cols; col++, bP++) putbit(*bP); for (col = 0; col < padright; col++) putbit(0); /* XOR data from the new scan line with data from old scan line */ for (i = 0; i < bytesperrow; i++) diff[i] = oldscanline[i]^newscanline[i]; /* ** If the difference map is different from current internal buffer, ** encode the difference and put it in the output buffer. ** Else, increase the counter for the current buffer by one. */ if ((memcmp(buffer, diff, bytesperrow) != 0) || (row == 0)) { /* **Since the data in the buffer has changed, send the **scan line repeat count to cause the old line(s) to **be plotted on the screen, copy the new data into **the internal buffer, and reset the counters. */ putchar(linerepeat); for (i = 0; i < bytesperrow; ++i) buffer[i] = diff[i]; nbyte = 0; /* Internal buffer byte counter */ nout = 0; /* Output buffer byte counter */ /* Run length encode the new internal buffr (= difference map) */ while (TRUE) { ucount = 0; /* Unique items counter */ do /* Find unique patterns */ { olditem = buffer[nbyte++]; ucount++; } while ((olditem != buffer[nbyte]) && (ucount < MIN(bytesperrow, MAX_REPEAT))); if ((ucount != MAX_REPEAT) && (nbyte != bytesperrow)) { /* Back up to the last truly unique pattern */ ucount--; nbyte--; } if (ucount > 0) { /* Output the unique patterns */ outbuffer[nout++] = (ucount-1) | PLOT_ARBITRARY_DATA_MASK; for (i = nbyte-ucount; i < nbyte; i++) outbuffer[nout++] = buffer[i]; } /* ** If we already are at the end of the current scan ** line, skip the rest of the encoding and start ** with a new scan line. */ if (nbyte >= bytesperrow) goto nextrow; ecount = 0; /* Equal items counter */ do /* Find equal patterns */ { olditem = buffer[nbyte++]; ecount++; } while ((olditem == buffer[nbyte]) && (ecount < MIN(bytesperrow, MAX_REPEAT))); if (ecount > 1) { /* More than 1 equal pattern */ if (olditem == '\0') { /* White patterns */ if (nbyte >= bytesperrow-1) { /* No more valid data ahead */ outbuffer[nout++] = (ecount-2) | SKIP_AND_PLOT_MASK; outbuffer[nout++] = buffer[nbyte-1]; } else { /* More valid data ahead */ outbuffer[nout++] = (ecount-1) | SKIP_AND_PLOT_MASK; outbuffer[nout++] = buffer[nbyte++]; } } else { /* Non-white patterns */ outbuffer[nout++] = (ecount-1) | REPEAT_PLOT_MASK; outbuffer[nout++] = olditem; } /* if (olditem == '\0') */ } /* if (ecount > 1) */ else nbyte--; /* No equal items found */ if (nbyte >= bytesperrow) goto nextrow; } /* while (TRUE) */ nextrow: printf("%d/", nout+1); /* Total bytes to xfer = nout+1 */ fflush(stdout); /* Output the plot data */ write(1, outbuffer, nout); /* Reset the counters */ linerepeat = 0; } else { linerepeat++; if (linerepeat == 62) /* 62 lines max, then restart */ { putchar(linerepeat); printf("%d/", nout+1); fflush(stdout); write(1, outbuffer, nout); linerepeat = 0; } } /* Now we are ready for a new scan line */ for (i = 0; i < bytesperrow; ++i) oldscanline[i] = newscanline[i]; } putchar(linerepeat); /* For the last line(s) to be plotted */ pm_close(ifp); putrest(); exit(0); } static int item, bitsperitem, bitshift; static void putinit() { /* Enter graphics window */ printf("\0331"); /* Erase graphics window */ printf("\033\014"); /* Set graphics window in raster mode */ printf("\033r"); /* Select standard Tek coding **/ printf("\033[=11l"); bitsperitem = 1; item = 0; bitshift = 7; } #if __STDC__ static void putbit(bit b) #else /*__STDC__*/ static void putbit(b) bit b; #endif /*__STDC__*/ { if (b == PBM_BLACK) item += 1 << bitshift; bitshift--; if (bitsperitem == 8) { putitem(); bitshift = 7; } bitsperitem++; } static void putrest() { if (bitsperitem > 1) putitem(); /* end raster downloading */ printf("\033\134"); /* Exit raster mode */ printf("\033t"); /* Exit graphics window printf("\0332"); */ } static void putitem() { *scanlineptr++ = item; bitsperitem = 0; item = 0; }