[net.sources.mac] MacPaint to QMS converter

steve@bnr-vpa.UUCP (Steve Saunders) (04/04/85)

This posting consists of a C program named "macqms" which enables
MacPaint documents to be converted to a format suitable for a
QMS 800 or 1200 laser printer.  It originally appeared a month or
so back on this same newsgroup with a disclaimer indicating the
interpolating filter used was a CPU hog.  An invitation was then
made to tame the beast.

We turned loose our super C programmer (Chris Toulson) and he has
produced a significant performance increase.  The original code
took 6-8 minutes to filter a MacPaint image on a VAX-11/780 running
VMS.  The updated code only requires about 30 seconds of CPU time
for the same task.

The code is designed to run under both Unix (we use EUNICE) and
VMS.  A compile time switch is available to select between the
two modes.  The code for "filter" requires an int be 32 bits. If
your machine has 16 bit ints then you will have to dive into the
code and convert those parts to longints.  This is mentioned in
the comments so don't be afraid.  One system difference over the
original code is that the output is now written to the file
"laser_printer:<filename>.qms".  This is great for VMS (it allows
spooled devices and DECnet transfers), but for Unix you may want
to do something else.

Good luck MacPainters!


Stephen R. Saunders
Bell-Northern Research
Nuns' Island, Verdun
Quebec, Canada

UUCP: {utzoo, utcs}!bnr-vpa!bnr-mtl!steve

Send comments/inquiries to:

Chris Toulson
Bell-Northern Research
Nuns' Island, Verdun
Quebec, Canada

UUCP: {utzoo, utcs}!bnr-vpa!bnr-mtl!chris


---------(cut here)--------------(cut here)---------------(cut here)------------
#!/bin/sh
# This is a shell archive, meaning:
# 1. Remove everything above the #!/bin/sh line.
# 2. Save the resulting text in a file.
# 3. Execute the file with /bin/sh (not csh) to create the files:
#	filter.c
#	macqms.c
#	macqms.l
# This archive created: Fri Mar 22 00:40:21 1985
export PATH; PATH=/bin:$PATH
echo shar: extracting "'filter.c'" '(10113 characters)'
if test -f 'filter.c'
then
	echo shar: over-writing existing file "'filter.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'filter.c'
X/*
X * A simple convolver that converts macpaint images into 4x resolution
X * with smoothing.  This reduces the jagginess of a macpaint image, so it
X * looks nicer on the qms laser printer.  This filter assumes a 4x
X * resolution increase, but it may be adaptable to other increments.
X * This code is separate from the macqms source so that it can be
X * adapted, with minimal change, to the other macintosh->whatever filters.
X * Adaptation of this filter to the imagen macpaint routine should be
X * trivial.
X * 
X * There are two connections between this filter and the macqms code:
X * 	1. The putdata routine. It accepts data in mac format, puts it
X * in local buffers, de-length codes as necessary, and calls do_filter at
X * the end of each line.
X * 	2. The sendline routine uses the stdout, which must be connected
X * properly by macqms routines. The macqms routines must send the proper
X * qms cmds before and after the data generated by this filter.
X * 
X * There is one dependency upon the qms device:
X * 	1. The sendline routine (and the two routines it calls, squeeze
X * and booltobin) are qms specific. These will need to be replaced for other
X * output devices.
X * 
X * This filter is attached to the macqms filter by intercepting output
X * calls at the lowest level.  Macqms was modified slightly to funnel all
X * output through one low level routine, which either does the output or
X * calls putdata to output the data via this filter.
X * 
X * I have done some performance tuning. More than 3x of speed improvement
X * has been realized since the first working version.  More tuning is
X * possible. Hint, hint.
X * 
X * My thanks go to Van Jacobson for the macqms.c program.
X * 
X * This filter may be distributed, only without charge, to anyone. This
X * notice must be attached, and all modifications must be duly noted
X * by their author in the revision history.  This filter may be used for
X * any purpose, except that it may not be sold, or incorporated into
X * any software that is sold.
X * 
X * Kaare Christian, The Rockefeller Univ.  1230 York Ave. NY NY 10021
X * uucp:cmcl2!rna!kc  212-570-7672
X * 
X * Revision History:
X * 	Created Jan 22, 1985 kc
X * 
X *	March 18, 1985: ct
X *
X * Heavily modified by Chris Toulson to run fast
X * on our VAX 11/780. Also, modified to run on either VMS - C compiler or
X * UNIX C compiler (we use EUNICE package). Output goes to the file "fdqms"
X * what ever it is. This routine seems to run at about 25 seconds CPU
X * on a 780 (30 secs with VMS C compiler) for typical images. This is
X * much faster than the 6-8 minutes it took originally. Since we run
X * VMS, I can make no claims about how it might run on a UNIX system but
X * it should be very fast there too. Note that the original algorithm is
X * unchanged, only the implementation was improved.
X *
X *				Chris Toulson
X *				Bell-Northern Research
X *				3 Place du Commerce
X *				Nuns' Island, Quebec
X *				Canada, H3E 1H6
X *
X *				{utzoo, utcs}!bnr-vpa!bnr-mtl!chris
X *
X */
X
X#include <stdio.h>
X#define MAC_SCANLINE_BITS 576
X#define MB MAC_SCANLINE_BITS
X#define QB MB*4
X#define OB (MB/2)
X#define LP_WIDTH 78
X
X
Xstatic struct qbuffer {
X	int blank;		/* true if blank line 			*/
X	char b[QB+1];		/* line buffer area			*/
X	} qbuf[5] = { 		/* the +1 simplifies makeline 		*/
X{1,'\0'},{1,'\0'},{1,'\0'},{1,'\0'},{1,'\0'} };
X
Xstatic char
X	outbuf[OB],		/* the re-packed output line		*/
X	*q4ptr=qbuf[4].b;	/* the input line pointer		*/
X
Xstatic int
X	col = 0;		/* curren column for output file	*/
X
Xextern int
X	smoothval;		/* smoothing threshold (3-16)		*/
Xextern FILE
X	*fdqms;			/* output file 				*/
X
X
X
X/*
X * the input side connection to the macintosh data, if flag is -1, process
X * the line. Otherwise flag is a repeat count.
X */
Xputdata( flag, byte )
X	int flag, byte;
X	{
X	register int f;
X
X	if( (f=flag) == -1 )
X		do_filter();
X	else
X		bintobool( f, byte );
X	}
X
X/*
X * make four scan lines from one
X */
Xstatic do_filter()
X	{
X	makelines();
X	sendlines();
X
X/*  roll the bottom line up from qbuf[4] to qbuf[0] */
X
X	qbuf[0] = qbuf[4];		/* copies whole structure! */
X
X/* get ready for the next line */
X
X	qbuf[4].blank = 1;
X	q4ptr = qbuf[4].b;
X	}
X
X
X/* this table provides the weighting of the any point in the 4x4 area
X * based on the corner point values. Each line corresponds to 1 of the 16
X * possible combinations of the 4 corner points. The values on a line,
X * taken 4 at a time correspond to the values to insert row by row into
X * the 4x4 area of the line buffers.
X */
Xstatic char w[256] = {
X  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
X  0,  0,  0,  0,  0,  1,  2,  3,  0,  2,  4,  6,  0,  3,  6,  9,
X  0,  0,  0,  0,  4,  3,  2,  1,  8,  6,  4,  2, 12,  9,  6,  3,
X  0,  0,  0,  0,  4,  4,  4,  4,  8,  8,  8,  8, 12, 12, 12, 12,
X  0,  4,  8, 12,  0,  3,  6,  9,  0,  2,  4,  6,  0,  1,  2,  3,
X  0,  4,  8, 12,  0,  4,  8, 12,  0,  4,  8, 12,  0,  4,  8, 12,
X  0,  4,  8, 12,  4,  6,  8, 10,  8,  8,  8,  8, 12, 10,  8,  6,
X  0,  4,  8, 12,  4,  7, 10, 13,  8, 10, 12, 14, 12, 13, 14, 15,
X 16, 12,  8,  4, 12,  9,  6,  3,  8,  6,  4,  2,  4,  3,  2,  1,
X 16, 12,  8,  4, 12, 10,  8,  6,  8,  8,  8,  8,  4,  6,  8, 10,
X 16, 12,  8,  4, 16, 12,  8,  4, 16, 12,  8,  4, 16, 12,  8,  4,
X 16, 12,  8,  4, 16, 13, 10,  7, 16, 14, 12, 10, 16, 15, 14, 13,
X 16, 16, 16, 16, 12, 12, 12, 12,  8,  8,  8,  8,  4,  4,  4,  4,
X 16, 16, 16, 16, 12, 13, 14, 15,  8, 10, 12, 14,  4,  7, 10, 13,
X 16, 16, 16, 16, 16, 15, 14, 13, 16, 14, 12, 10, 16, 13, 10,  7,
X 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 };
X
Xstatic makelines()
X	{
X	register char  *p0, *p1, *p2, *p3, *p4;
X	register char *q;
X
X/* check if all blank lines */
X	
X	if( qbuf[0].blank && qbuf[4].blank )
X		{
X		qbuf[1].blank = 1;
X		qbuf[2].blank = 1;
X		qbuf[3].blank = 1;
X		return;
X		}
X
X/* reset blank line flags */
X
X	qbuf[1].blank = 0;
X	qbuf[2].blank = 0;
X	qbuf[3].blank = 0;
X
X/* loop over each 4x4 pixel area, to get weightings, The code is somewhat
X * twisted, and assumes that an int is 4 bytes. Still, it very fast.
X */
X	p0 = qbuf[0].b;
X	p1 = qbuf[1].b;
X	p2 = qbuf[2].b;
X	p3 = qbuf[3].b;
X	p4 = qbuf[4].b;
X
X	for( ; p0 < &qbuf[0].b[QB]; p0 += 4 )
X		{
X		q = w;
X		if( p0[0] ) q += sizeof(w)/2;
X		if( p0[4] ) q += sizeof(w)/4;
X		if( p4[0] ) q += sizeof(w)/8;
X		if( p4[4] ) q += sizeof(w)/16;
X
X		*(int *)p0 = ((int *)q)[0]; /* pretend that p & q are ints */
X		*(int *)p1 = ((int *)q)[1];
X		*(int *)p2 = ((int *)q)[2];
X		*(int *)p3 = ((int *)q)[3];
X
X		p1 += 4;
X		p2 += 4;
X		p3 += 4;
X		p4 += 4;
X		}
X	}
X
X/*
X * Send an line of data to the qms, using quic compression techniques
X */
X
Xstatic sendlines()
X	{
X	register char *cptr, *p, *r;
X	register int val, v;
X	register struct qbuffer *n;
X	v = smoothval;
X
X/* do all 4 lines */
X 
X	for( n = qbuf; n < &qbuf[4]; ++n )
X		{
X
X/* if the line is blank, its simple */
X
X		if( n->blank )
X			{
X			if( (col += 5) > LP_WIDTH )
X				{
X				putc( '\n', fdqms );
X				col = 5;
X				}
X			fprintf( fdqms, "^D576" ); /* same as MAC_SCANLINE_BITS */
X			}
X
X		else
X			{
X/* pack 8 bytes from qbuf into an 8 bit byte in outbuf */
X
X			cptr = n->b;
X			for( p = outbuf, r = &outbuf[OB]; p < r; *p++ = val )
X				{
X				val = 0;
X
X/* the UNIX C compiler doesn't handle the (char)v properly, so: */
X#ifdef vax11c
X				if( *cptr++ > (char)v ) val += 0x80;
X				if( *cptr++ > (char)v ) val += 0x40;
X				if( *cptr++ > (char)v ) val += 0x20;
X				if( *cptr++ > (char)v ) val += 0x10;
X				if( *cptr++ > (char)v ) val += 0x8;
X				if( *cptr++ > (char)v ) val += 0x4;
X				if( *cptr++ > (char)v ) val += 0x2;
X				if( *cptr++ > (char)v ) val += 0x1;
X#else
X				if( *cptr++ > v ) val += 0x80;
X				if( *cptr++ > v ) val += 0x40;
X				if( *cptr++ > v ) val += 0x20;
X				if( *cptr++ > v ) val += 0x10;
X				if( *cptr++ > v ) val += 0x8;
X				if( *cptr++ > v ) val += 0x4;
X				if( *cptr++ > v ) val += 0x2;
X				if( *cptr++ > v ) val += 0x1;
X#endif
X				}
X
X/* now do the QMS run length coding */
X
X			squeeze();
X			}
X		}
X	}
X
X
X/*
X * qms compression (note - efficiency counts here)
X */
X
Xstatic squeeze()
X	{
X	register int n;
X	register int ch;
X	register char *p = outbuf, *q = p, *r = &outbuf[OB];
X	static char hex[] = "0123456789ABCDEF";
X
X	while( p < r )
X		{
X/* get a byte */
X		ch = *p++;
X
X/* get a repeat count */
X
X		while( (*p == (char)ch) && (p < r) ) ++p;
X
X/* runs of 3 or more are good for all black or all white, runs of 4 or more
X * are good for anything. We assume black and white runs are most common
X * If not, use 4 in the following test.
X */
X
X		if( ( n = p-q ) >= 3 )
X			{
X			if( (col += 7) > LP_WIDTH )
X				{
X				putc('\n', fdqms );
X				col = 7;
X				}
X
X/* choose the best output format */
X
X			if( (char)ch == 0 )
X				fprintf( fdqms, "^D%03d", n+n );
X			else if( (char)ch == -1 )
X				fprintf( fdqms, "^B%03d", n+n );
X			else
X				{
X				fprintf(fdqms,"^C%03d", n);
X				putc(hex[(ch>>4) & 15],fdqms);
X				putc(hex[ ch     & 15],fdqms);
X				}
X			}
X		else
X			{
X
X/* oh well, no compression, just send it n times */
X
X			for( ; n; --n )
X				{
X				if( (col += 2) > LP_WIDTH )
X					{
X					putc('\n',fdqms);
X					col = 2;
X					}
X				putc(hex[(ch>>4) & 15],fdqms);
X				putc(hex[ ch     & 15],fdqms);
X				}
X			}
X		q = p;
X		}
X	}
X
X
X/* convert binary to boolean. We spread them out at one bit every fourth
X * byte in qbuf[4].b. We copy the the resulting 32 bytes, f times if f is
X * greater than 1. q4ptr points to our current position in qbuf.
X */ 
Xstatic bintobool( f, b )
X	int f, b;
X	{
X	register struct n32 { char b[32]; } *t = (struct n32 *)q4ptr; 
X	register int byte = b;
X	register int flag = f;
X
X	if( byte ) qbuf[4].blank = 0;
X
X/* optimize for different compilers */
X#ifdef vax11c
X	t->b[0]  = (char)byte &(char)0x80;	t->b[4]  = (char)byte &0x40;
X	t->b[8]  = (char)byte &0x20;		t->b[12] = (char)byte &0x10;
X	t->b[16] = (char)byte &0x08;		t->b[20] = (char)byte &0x04;
X	t->b[24] = (char)byte &0x02;		t->b[28] = (char)byte &0x01;
X#else
X	t->b[0]  = byte &0x80;		t->b[4]  = byte &0x40;
X	t->b[8]  = byte &0x20;		t->b[12] = byte &0x10;
X	t->b[16] = byte &0x08;		t->b[20] = byte &0x04;
X	t->b[24] = byte &0x02;		t->b[28] = byte &0x01;
X#endif
X	++t;
X
X	for( ; --flag > 0;  ++t )
X		t[0] = t[-1];			/* 32 byte copy		*/
X
X/* set new input buffer pointer */
X
X	q4ptr = (char *)t;
X	}
X
SHAR_EOF
if test 10113 -ne "`wc -c 'filter.c'`"
then
	echo shar: error transmitting "'filter.c'" '(should have been 10113 characters)'
fi
echo shar: extracting "'macqms.c'" '(10029 characters)'
if test -f 'macqms.c'
then
	echo shar: over-writing existing file "'macqms.c'"
fi
sed 's/^X//' << \SHAR_EOF > 'macqms.c'
X/*
X     This filter converts MacPaint files into Quic files for printing
X     on an QMS-1200 or -800 laser printer.  It was written by Van
X     Jacobson of Lawrence Berkeley Laboratory (van@lbl-csam.arpa,
X     ...!ucbvax!lbl-csam!van) and is in the public domain.  It was
X     loosely based on macimp.c by Winkler@harvard which was in turn
X     based on MACimp for Tops-20 by Ed Pattermann, Stanford.
X
X     Usage:
X       macqms [-l] [-s] [-f[n]] [-x<xpos>] [-y<ypos>] [-m<mag>]
X		[-n<ipp>[,<ipr>]] [file ...]
X
X     '-l' prints in "landscape" orientation (default is "portrait"
X     orientation).  <xpos> and <ypos> are the position of the upper
X     left corner of the bitmap.  They are given in inches and default
X     to 0.41 and 0.70 (which will center a 576x720 image at mag 4).
X     <mag> is a magnification for the bitmap and can be any integer
X     >0.  The default is 4.  Magnifications larger than 4 may result in
X     bizarre images.  `-n<ipp>' prints <ipp> images-per-page.  The files
X     are printed `m' across by `n/m' down. "m" can be specified (e.g.,
X     "-n4,2") or it can be defaulted.  The default is the largest number
X     of images that will fit the current magnification & orientation.
X
X     Send enhancements and bug reports to van@lbl-csam.
X
X     History:      
X	21 August 1984  VJ - created. 
X	1  Jan 1985 Hacked to pipe output to lpr.
X		-s option writes standard out.
X		(Note site dependent LPR define and the qms_init proc) kc
X	22 jan 1985 Added output filtering. Controlled by the -f option. kc
X	14 mar 1985 removed LPR stuff, hacked for VMS C 		ct
X		Output is written to file "laser_printer:filename.qms"
X		which is a VMS filename. In our case, the QMS is a spooled
X		device and laser_printer is a logical name that translates
X		to the printer device name. This techique allows the
X		printer to exist on different DECnet node. (In that case,
X		laser_printer should have the node name in its definition.)
X		We run VMS and EUNICE so this works on either C compiler,
X		but, if you run pure UNIX you will need to change the
X		routine "open_qms_file" to do something more appropriate.
X		To me, this seems a cleaner interface than forking off
X		children to write to the printer. Removed the -s option. 
X
X					Chris Toulson
X					Bell-Northern Research
X					3 Place Du Commerce
X					Nuns' Island, Quebec
X					Canada, H3E 1H6
X					(514)-765-8888
X
X					{utzoo, utcs}!bnr-vpa!bnr-mtl!chris
X
X
X*/
X
X#include <stdio.h>
Xdouble atof();
X
X#define	MAC_HEADER_LENGTH	512
X#define	MAC_SCANLINES		720	/* number of scanlines in image */
X#define	MAC_SCANLINE_BITS	576	/* number of bits in a scanline */
X#define	MAC_SCANLINE_BYTES	(MAC_SCANLINE_BITS/8)
X
X#define LP_WIDTH 78		/* control output file line length	*/
XFILE 	*fdqms;			/* output file descriptor		*/
X
Xstatic int
X	mag=4,			/* horiz & vert magnification in dots 	*/
X	window=MAC_SCANLINE_BITS,/* horiz width of image in dots 	*/
X	initial_xpos = 410,	/* left margin position in inches*1000 	*/
X	initial_ypos = 700,	/* top margin position in inches*1000 	*/
X	orientation = 'P',	/* "portrait" orientation 		*/
X	qms_pagewidth = 8500,	/* in inches*1000 			*/
X	ipp = 1,		/* 1 image per page 			*/
X	ipr = 0,		/* default images per row 		*/
X	images = 0,		/* number of images on current page 	*/
X	xpos,			/* current image origin			*/
X	ypos,
X	xpos_incr,		/* current image size			*/
X	ypos_incr,
X	filter=0,		/* set means invoke the smoothing filter*/
X 	col = 0,		/* current output file column		*/
X	obytes,			/* scan line position			*/
X	scanline;		/* current scan line			*/
X
Xint
X	smoothval = 6;		/* filter smoothing threshold		*/
X
Xstatic char
X	usage[] =
X"usage: macqms [-l] [-f] [-m<mag>]\n\t\t[-x<xpos>] [-y<ypos>] [-n<ipp>] [file ..]\n";
X#define DEBUG 1
X
Xmain( ac, av )
X	int ac;
X	char **av;
X	{
X	register int i, argc = ac-1;
X	register char **argv = av+1;
X
X/* scan for command line options */
X
X#ifdef DEBUG
X	lib$init_timer();
X#endif
X	for ( i=0; i < argc; i++ )
X		{
X		if ( argv[i][0] != '-' )
X			break;
X
X		switch ( argv[i][1] )
X		{
X		case 'm':
X			mag = atoi( &argv[i][2] );
X			if ( mag <= 0 )
X				mag = 1;
X			break;
X		case 'l':
X			orientation = 'L';
X			qms_pagewidth = 11000;
X			break;
X		case 'x':
X			xpos = atof( &argv[i][2] )*1000.;
X			break;
X		case 'y':
X			ypos = atof( &argv[i][2] )*1000.;
X			break;
X		case 'n':
X			sscanf( &argv[i][2], "%d,%d", &ipp, &ipr );
X			break;
X		case 'f':
X			filter++;
X			if (argv[i][2] != 0)
X				smoothval = atoi(&argv[i][2]);
X			if ((smoothval < 3) || (smoothval > 16))
X				smoothval = 6;
X			break;
X		default:
X			fprintf( stderr, usage );
X			exit(1);
X		}
X	}
X	if ( i >= argc ) {
X
X/* no file arguments - send contents of stdin */
X
X		qms_init("macqms");
X		send_one_bitmap();
X		}
X	else {
X		qms_init(argv[i]);
X		for ( ; i < argc; i++ )
X			{
X			if ( freopen( argv[i], "r", stdin ) == NULL )
X				{
X				perror( argv[i] );
X				exit(2);
X				}
X			send_one_bitmap();
X			}
X		}
X
X/* if we have a partial page of images left over, eject it. */
X
X	if ( images > 0 )
X		qms_eject();
X
X	qms_end();
X
X#ifdef DEBUG
X	lib$show_timer();
X#endif
X	}
X
X
Xstatic send_one_bitmap()
X	{
X
X/* set initial position & switch to plot mode */
X
X	fprintf( fdqms,"^IT%05d^IJ%05d^P%04d\n", xpos, ypos, window );
X
X	throw_away_mac_header() ;
X	col = 0;
X	send_bitmap_data() ;
X
X/* exit plot mode & update the postion for the next picture, if any */
X
X	fprintf( fdqms, "^G\n" );
X
X	if ( ++images >= ipp )
X		qms_eject();
X	else
X		{
X		if( images % ipr )
X			xpos += xpos_incr;
X		else
X			{
X			xpos = initial_xpos;
X			ypos += ypos_incr;
X			}
X		}
X	}
X
Xstatic qms_eject()
X	{
X	if( (col += 2) > LP_WIDTH )
X		{
X		putc('\n', fdqms);
X		col = 0;
X		}
X	fprintf(fdqms,"^,\n");
X	xpos = initial_xpos;
X	ypos = initial_ypos;
X	images = 0;
X	}
X
Xstatic send_bitmap_data()
X	{
X	register int repeat_count, i;
X
X	obytes=0;
X	scanline=0;
X
X	while ( (repeat_count = getchar()) != EOF )
X		{
X		repeat_count &= 0xff;
X		if ( repeat_count >= 128 )
X			{
X			if ( repeat_count == 128 )
X				continue;
X
X/* this is a <repeat count><data to repeat> pair.  This
X * is almost identical to the qms compression scheme so
X * we just reformat slightly & write it out.
X */
X
X			repeat_count = 257 - repeat_count;
X			check_for_error( repeat_count );
X			printhex( repeat_count, nextbyte() );
X			}
X		else 
X			{
X
X/* this is a <count><count+1 bytes of data> sequence.
X * We just ship out the data.
X */
X			check_for_error( ++repeat_count );
X			while(  --repeat_count >= 0 )
X				printhex( 0, nextbyte() );
X			}
X
X		if ( obytes >= MAC_SCANLINE_BYTES )
X			{
X			if (filter)
X				putdata(-1,0);
X			if ( ++scanline >= MAC_SCANLINES )
X				break;
X			obytes = 0;
X			}
X		}
X	}
X
Xstatic check_for_error( b )
X	int b;
X	{
X	register int bytes = b;
X
X/* check that the result of putting "bytes" data bytes is <= 1
X * scan lines worth of data.
X */
X
X	if ( (obytes += bytes) > MAC_SCANLINE_BYTES )
X		{
X
X/* too many bytes - assume that we dropped some & output
X * filler for the previous scanline.
X */
X		fprintf(fdqms, "\n^C%03d00\n", MAC_SCANLINE_BYTES + bytes - obytes );
X
X		fprintf( stderr,
X			"macqms: %d bytes on scanline %d (input byte %D)\n",
X			obytes, scanline, ftell( stdin ) );
X
X		obytes = bytes;
X		scanline++;
X		}
X	}
X
Xstatic throw_away_mac_header()
X	{
X     	register int bytenum;
X
X	for ( bytenum = 0 ; bytenum < MAC_HEADER_LENGTH ; bytenum ++ ) 
X        	nextbyte() ;
X	}
X
Xstatic nextbyte()
X	{
X	register int byte;
X
X	if ( (byte = getchar()) == EOF ) 
X		{
X		fprintf( stderr,
X			"macqms: unexpected EOF reading macpaint file.\n" );
X		exit(1);
X		}
X	return (byte);
X	}
X
X
Xstatic printhex( r, b )
X	int r, b;
X	{
X	register int repeat = r, byte = b;
X	static char hex_tab[] = "0123456789ABCDEF";
X
X	if (filter)
X		putdata( repeat, byte );
X	else
X		{
X/* the old style:
X * print a byte as 2 hex digits.N.B.- the qms currently requires
X * that the digits be in *upper case* so we can't use printf.
X */
X		if (repeat)
X			{
X			if( (col += 7) > LP_WIDTH )
X				{
X				putc('\n', fdqms);
X				col = 7;
X				}
X			if( (char)byte == 0 )
X				fprintf(fdqms, "^D%03d", repeat+repeat );
X			else if( (char)byte == -1 )
X				fprintf(fdqms, "^B%03d", repeat+repeat );
X			else
X				{
X				fprintf(fdqms, "^C%03d", repeat );
X				putc( hex_tab[(byte>>4) & 0xf], fdqms);
X				putc( hex_tab[ byte     & 0xf], fdqms);
X				}
X			}
X		else
X			{
X			if( (col += 2) > LP_WIDTH )
X				{
X				putc('\n',fdqms);
X				col = 2;
X				}
X			putc( hex_tab[(byte>>4) & 0xf], fdqms);
X			putc( hex_tab[ byte     & 0xf], fdqms);
X			}
X		}
X	}
X
Xstatic qms_init( iname )
X	char *iname;
X	{
X
X/* switch to quic mode & make sure the qms 
X * is set up the way we expect.
X */
X	
X	if ( !open_qms_file(iname) )
X		{
X		perror("MACQMS");
X		exit(2);
X		}
X
X	fprintf(fdqms, "\n^PY^-\n^ISYNTAX00000^F^-" );
X
X/*  set the magnification */
X
X	if (!filter || mag != 4)
X		{
X		filter = 0;
X		fprintf(fdqms, "^IP%02d%02d", mag, mag );
X		}
X	else 
X		{
X		fprintf(fdqms, "^IP0101" );
X		window *= 4;
X		}
X
X/* set the portrait/landscape orientation */
X
X	fprintf(fdqms, "^IO%c\n", orientation );
X
X/* set the postioning stuff needed for multiple images per page */
X
X	xpos = initial_xpos;
X	ypos = initial_ypos;
X	ypos_incr = (mag * MAC_SCANLINES * 10) / 3; /* inches per image  */
X	xpos_incr = (mag * MAC_SCANLINE_BITS * 10) / 3;
X	if ( ipr <= 0 )
X		ipr = (qms_pagewidth - xpos) / xpos_incr;
X	}
X
Xstatic open_qms_file( n )
X	char *n;
X	{
X	char rootname[64];
X	register char *name = n,*p, *q;
X	char *strrchr();
X	register int f;
X
X/* get the root filename */
X
X/* this stuff is VMS filename syntax specific. Must re-write it for UNIX */
X
X
X	if( p = strrchr( name, ']' ) ) ++p;
X	else if( p = strrchr( name, ':' ) ) ++p;
X	else p = name;
X	q = rootname;
X	strcpy ( q, "laser_printer:" ); q = q + strlen(q);
X	while( *p && (*q = *p) != '.' ) {++q; ++p;};
X	strcpy( q, ".qms" );
X
X
X#ifdef vax11c	
X	if((f=creat(rootname,0755,"rfm=var","rat=cr"))<0
X#else
X	if((f=creat(rootname,0755,"txt"))<0	/* EUNICE only!		*/
X#endif
X	|| (fdqms = fdopen( f, "w" ))  == NULL )
X		{
X		fprintf(stderr,"can't open laser_printer:%s.qms;\n",rootname);
X		return(0);
X		}
X	return(1);
X	}
X
Xstatic qms_end()
X	{
X
X/* exit quic mode */
X
X	if( (col += 15) > LP_WIDTH )
X		{
X		putc('\n', fdqms);
X		col = 0;
X		}
X	fprintf(fdqms, "^-^IP0000^PN^-\n" );
X	}
X
SHAR_EOF
if test 10029 -ne "`wc -c 'macqms.c'`"
then
	echo shar: error transmitting "'macqms.c'" '(should have been 10029 characters)'
fi
echo shar: extracting "'macqms.l'" '(3119 characters)'
if test -f 'macqms.l'
then
	echo shar: over-writing existing file "'macqms.l'"
fi
sed 's/^X//' << \SHAR_EOF > 'macqms.l'
X.TH MACQMS local "12 August 1984"
X.UC 4
X.SH NAME
Xmacqms \- Convert Macintosh MacPaint file(s) to QMS Laser Printer format
X.SH SYNOPSIS
X.B macqms
X[ 
X.B \-l
X]
X[
X.B \-s
X]
X[
X.B \-f[n]
X]
X[
X.B \-m \fImag\fP
X]
X[
X.B \-x \fIxpos\fP
X]
X[
X.B \-y \fIypos\fP
X]
X[
X.B \-n \fIipp[,ipr]\fP
X]
X[ file ... ]
X.SH DESCRIPTION
X.B Macqms
Xconverts MacPaint document(s) into a file that can be printed on a
XQMS-1200 or QMS-800 laser printer.  If no file names are given, standard
Xinput is read.  The program
Xworks for files created by MacPaint and for Mac screen dumps created
Xwith OPTION-COMMAND-3.  It does
X.I not
Xwork for MacWrite documents.
X.PP
XCommand line options are:
X.TP
X.B \-l
Xspecifies
X.I landscape
Xorientation for the output.  The default is
X.I portrait
Xorientation.
X.TP
X.B -s
Xplaces the output on the standard output.  The default is to pipe the 
Xoutput to lpr.
X.TP
X.B \-f
Xruns the macpaint document through a smoothing filter so that it
Xappears less jaggy. The magnification must be the default (4), the
Xorientation must be portrait, and the multiple images per page feature
Xmust be turned off.
XThe optional numeric parameter
X.I n
Xcontrols the sensitivity of the filter.
XEight is the theoretically correct value, although six (the default)
Xseems to produce ``smoother'' looking pictures.  Reasonable values are
Xfrom about four to twelve.
XThis filter is very slow. Typical times (per image)
Xare six minutes on a lightly loaded VAX 780.  Much longer times (up to
Xthirty minutes of cpu time on a 750) have been observed. Typically the document increases in size by a factor of ten.
X.TP
X.B \-m \fIn\fP
Xspecifies a magnification factor.  By default, the MacPaint image is
Xmagnified by a factor of 4.  This just about fills the output page and
Xis about 30% larger than the screen image.
XThe magnification,
X.IR n ,
Xcan be any integer > 0.  However, at ``-m5'' and above the image might not fit
Xon the page and the QMS will do strange things to it.
X.TP
X.B \-x \fIpos\fP
Xpositions the left edge of the image.  The position,
X.IR pos ,
Xis given in \fIinches\fP.  The default is ``-x0.41''.
X.TP
X.B \-y \fIpos\fP
Xpositions the top edge of the image.  The default is ``-y0.70''.
X.sp
XDefault positions were chosen to center a
Xfull image on an 8.5 x 11 page at the default magnification.
X.TP
X.B \-n \fIipp[,ipr]\fP
Xprints multiple images on one page.  By default a page eject
Xis done between each MacPaint file printed.  This flag results in
X.I ipp
Ximages being printed on each page.  The number of images per row,
X.I ipr ,
Xcan be specified or will default the the maximum number of images that
Xwill fit across the page.  No space is inserted between multiple images
Xon a page so a large `composite' can be built up from smaller
Ximages.  Images are printed `row-wise'.  E.g.,
X.ce
Xmacqms -m2 -n4 f1 f2 f3 f4
Xwill print as
X.TS
Xcenter,allbox;
Xc c.
Xf1	f2
Xf3	f4
X.TE
X.SH AUTHOR
XVan Jacobson, Real Time Systems Group, Lawrence Berkeley Laboratory
X.SH SEE ALSO
Xmacget(local)
X.SH BUGS
XProbably.
XThe author obviously got hit by a bad case of ``creeping featurism''.
X
XThe filter is too slow.
XDoes anybody know how to speed up an eight million point convolver?
SHAR_EOF
if test 3119 -ne "`wc -c 'macqms.l'`"
then
	echo shar: error transmitting "'macqms.l'" '(should have been 3119 characters)'
fi
#	End of shell archive
exit 0
----------(the end)--------------(the end)-----------------(the end)------------