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