[comp.sys.atari.st] cbw2ps.c - Compressed B&W screen to Postscript

braner@batcomputer.tn.cornell.edu (braner) (12/06/86)

/*
 * Compressed ST screen (monochrome) to Postscript filter.
 *
 * By Moshe Braner, 861116.
 *
 * Postscript stuff from:
 *	Cwru standard bitmap image to PostScript filter,
 *	by J. R. Bammi.
 *
 * WARNING: assumes ASCII.
 *
 * Usage:
 *
 *  cbw2ps [-s xsize ysize] [-t transx transy] [-r rot] [-l] [-i] file
 *
 *	-s xsize ysize = size of postscript image - default 8.533 x 5.333"
 *	-1		= 1 dot per pixel	  - 2.133 x 1.333 inches
 *	-2		= 2 dots per pixel	  - 4.267 x 2.667
 *	-3		= 3 dots per pixel	  - 6.4   x 4
 *	-4		= 4 dots per pixel	  - 8.533 x 5.333 (default)
 *	-5		= 5 dots per pixel	  - 10.67 x 6.667
 *	-t transx transy = translate image	  - default 0.25 0.5 inches
 *	-r rotate	= rotate image		  - default 0 degrees
 *	-l		= landscape (== -r 90)	  - default portrait
 *	-i		= inverse image		  - default no inverse
 */

#include <stdio.h>

#define	OK	0
#define	ERROR	-1

FILE	*fp, *fopen();
char	scrn[32000];	/* virtual screen buffer		*/
char	*scrnptr;	/* target address for next decoded byte	*/
long	chksum;		/* chksum on input file			*/
int	rows;
int	cols;
int	row;
int	col;
int	bferr = 0;

main(argc,argv)
	int argc;
	char **argv;
{
	int land, inv;
	char *filename;
	double sizex, sizey, transx, transy, rotate;
	extern double atof();
		
	fp = stdin;
	land = 0;
	inv = 0;
	filename = "STDIN";
	sizex = 8.533333;
	sizey = 5.333333;
	transx = 0.25;
	transy = 0.5;
	rotate = 0.0;
		
	while(--argc > 0) {
		++argv;
		if((*argv)[0] == '-') {
			switch((*argv)[1]) {

			    case 'l':
			    case 'L':
				land = 1;
				break;

			    case 's':
			    case 'S':
				sizex = atof(*++argv);
				sizey = atof(*++argv);
				argc -= 2;
				break;

			    case 't':
			    case 'T':
				transx = atof(*++argv);
				transy = atof(*++argv);
				argc -= 2;
				break;

			    case 'r':
			    case 'R':
				rotate = atof(*++argv);
				argc--;
				break;

			    case 'I':
			    case 'i':
				inv = 1;
				break;

			    case '1':
				sizex = 2.133333;
				sizey = 1.333333;
				break;

			    case '2':
				sizex = 4.26667;
				sizey = 2.66667;
				break;

			    case '3':
				sizex = 6.4;
				sizey = 4.0;
				break;

			    case '4':
				sizex = 8.533333;
				sizey = 5.333333;
				break;

			    case '5':
				sizex = 10.66667;
				sizey = 6.66667;
				break;

			    default:
				fprintf(stderr,
					"Illegal switch \'%c\' - ignored\n",
					(*argv)[1]);
			}
		} else {
			if((fp = fopen(*argv, "r")) == (FILE *)NULL) {
				fprintf(stderr,"Cannot open %s\n",*argv);
				exit(1);
			}
			filename = *argv;
		}
	}
	process(land,inv,filename,sizex,sizey,transx,transy,rotate);
}

process(land, inv, filename, sizex, sizey, transx, transy, rotate)
	int land, inv;
	char *filename;
	double sizex, sizey, transx, transy, rotate;
{
	int bpp, xmax, ymax, junk;
	register long  i;
	long bytes, origsum;
	register unsigned int c, s, out, mask;
	register int j, bpb, shift, k;
	extern unsigned int decode3();

	c = fgetb() - 0x10;
	chksum = ((long) c)&0x03;
	if (c != 2) {
		fprintf(stderr,
			"%s not a monochrome image!\n",filename);
		exit(1);
	}

	bpp = 1;
	ymax = 400;
	xmax = 640;

	/* Scan off color table */

	c = decode3();
	chksum += ((long) c)&0xFFFF;
	if ((c & 0x01) == 1)
		inv = (! inv);
	for(i = 0; i < 15; i++)
		chksum += ((long) decode3())&0xFFFF;

	/* decode the image itself */

	rows = 400;
	cols = 80;
	row = 0;
	col = 0;
	scrnptr = scrn;
	while ((c=fgetb()) != ERROR) {
		if (c > 0x0F)
			s = reps(c);
		else
			s = uniq(c);
		if (s != OK)
			break;
	}

	/* read original checksum */

	origsum = (((long) decode3())&0xFFFF) << 16;
	origsum += ((long) decode3())&0xFFFF;
	if (bferr) {
		fprintf(stderr,"Error while reading %s\n",
			filename);
		exit(3);
	} else if (chksum != origsum) {
		fprintf(stderr,"Checksum doesn't fit!\n");
		exit(3);
	}

	fclose(fp);

	/* Put out header */

	printf("%%!\n/inch {72 mul} def\n");
	printf("/picstr 1 string def\n");
	printf("/bpp %d def\n",bpp);
	printf("/scanlines %d def\n",ymax);
	printf("/scansize %d def\n", xmax);
	printf("/bitmapx\n{");
	printf(" %d %d %d [%d 0 0 %d 0 %d]",
		xmax, ymax, bpp, xmax,-ymax,ymax);
	printf(" {currentfile picstr readhexstring pop} image\n} def\n");
	printf("gsave\n");
	printf("%f inch %f inch translate\n",transx, transy);
	printf("%f rotate\n", (land == 1)? 90.0+rotate : rotate );
	printf("%f inch %f inch scale\n", sizex, sizey);
	printf("/clipathx\n{\tnewpath\n\t0 0 moveto\n\t%f 0 inch", sizex);
	printf(" lineto\n\t%f inch %f inch lineto\n\t0 %f inch lineto\n",
	       sizex, sizey, sizey);
	printf("\tclosepath } def\nclipathx clip\n");
	printf("bitmapx\n");

	/* put out bit map data */

	scrnptr = scrn;
	k = 0;
	for (i=0; i<32000; i++) {
		out = *scrnptr++;
		printf ("%02x",
			(unsigned int)(((inv == 1)? ~out : out)
			 & (unsigned int)0x00ff));
		if (++k & 16) {
			putchar('\n');
			k = 0;
		} else
		    putchar(' ');
	}
	printf("grestore\n");
	printf("showpage\n");
}

/*
 * Read a byte from the input file, translate it.
 * Skip control chars and white space, etc.
 */
int
fgetb()
{
	register int    c;
again:
	if (bferr)
		return (ERROR);
	c = getc(fp);
	if (c == EOF)
		bferr = 1;
	if (c < ',' || c > 'z')
		goto again;
	if (c < 'a')
		return (c - ' ');
	if (c < 'm')
		return (c - 'a');
	if (c < 'v')
		return (c - 0x55);
	return (c - 0x3B);
}

/*
 * Decode one (16-bit) word out of 3 bytes of the input file.
 */
unsigned int
decode3()
{
	register unsigned int c;
	register unsigned int dummy;	/* avoid a Megamax bug */

	c = (fgetb() << 12);
	c |= (fgetb() << 6);
	c |= fgetb();
	return (c);
}

/*
 * Put a decoded byte into the screen buffer.
 */
int
putbyte(b)
	int	b;
{
	*scrnptr = (char) b;
	scrnptr += cols;
	if (++row >= rows) {
		if (++col >= cols) {
			return (ERROR);
		}
		scrnptr = scrn + col;
		row = 0;
	}
	return (OK);
}

/*
 * Handle a pair of decoded screen bytes.
 */
int
putword(w)
	register unsigned int w;
{
	register unsigned int dummy;	/* avoid a Megamax bug */

	chksum += ((long) w)&0xFFFF;
	if (putbyte((w>>8) & 0xFF) == ERROR)
		return (ERROR);
	return (putbyte(w & 0xFF));
}

/*
 * Decode 2 screen bytes.
 */
int
uniq(c)
	register unsigned int c;
{
	register unsigned int dummy;	/* avoid a Megamax bug */

	c <<= 12;
	c |= (fgetb() << 6);
	c |= fgetb();
	if (bferr)
		return (ERROR);
	return (putword(c));
}

/*
 * Decode a 4-byte repetition code.
 */
int
reps(b)
	register unsigned int b;
{
	register unsigned int c;

	b = ((b-0x10) << 2);
	c = fgetb();
	b |= (c >> 4);
	c <<= 12;
	c |= (fgetb() << 6);
	c |= fgetb();
	if (bferr)
		return (ERROR);
	while (b--) {
		if (putword(c) == ERROR)
			return (ERROR);
	}
	return (OK);
}