[net.sources.mac] MacPaint to Imagen conversion and smoothing

petsche@princeton.UUCP (Thomas Petsche) (09/20/85)

  This is an updated and improved version of a previously posted
MacPaint to Impress convertion program.  It now allows the user
to perform smoothing on images that are full or half size.
   The smoothing  program is at least three times as fast as the
program on which it was based and produces a files that is six
times smaller than a bitmap would be.

   Send any comments to me at:
 		allegra!princeton!ivy!petsche

		Thomas Petsche
		EE Dept.
		Princeton University
		Princeton, NJ 08544

----------------------------- cut here --------------------------
#! /bin/sh
: Run this shell script with "sh" not "csh"
PATH=:/bin:/usr/bin:/usr/ucb
export PATH
all=FALSE
if [ $1x = -ax ]; then
	all=TRUE
fi
/bin/echo 'Extracting paintimp.1l'
sed 's/^X//' <<'//go.sysin dd *' >paintimp.1l
X.TH PAINTIMP local "8 December 1984"
X.UC 4
X.SH NAME
paintimp \- translate MacPaint document to imPress
X.SH SYNOPSIS
X.B paintimp
file
X.br
X.B paintimp
[
X.B \-v
] [
[
X.B \-d
] [
X.B \-<res>
] [
X.B \-P<printer>
] [ 
X.B \-s <scale>
] [
X.B \-f\fR[sval]
]
X.br
[ 
X.B \-x <origin x>
] 
X.po +9
[ 
X.B \-y <origin y>
] 
X.B file ...
X.br
X.po -9
X.SH DESCRIPTION
X.I Paintimp
translates a MacPaint document, uploaded from a MacIntosh via
X.I macget
(local), to imPress language and spools it for printing on a laser printer.
X.I Paintimp
knows about three types of Imagen laser printers: 240, 300 and 480.
These numbers are the dots-per-inch resolution of the printer,
X.I paintimp
uses the resolution to calculate scaling factors and default printer. 
Default resolution is 300.
X.PP
If the output of
X.I paintimp 
hasn't been redirected nor piped, then it automatically spools its 
output for the laser printer via lpr.  The default printer name is
imagen.  The -P option may be used to specify a
different printer (see below).
X.PP 
The order of command line arguments is not important, except that all
options must precede the file name(s).
X.br
The available command line options are:
X.TP
X.I \-<res>
Specifies the laser printer resolution.  Allowable values are 240, 300
and 480.  Default resolution is 300.  If stdout hasn't been redirected,
and no -P option was specified, the resolution is concatenated with `ip'
to produce a printer name (i.e. ip300)  This of course assumes printers
are named with this convention, use the -P option to override this default.
X.TP
X.I \-d
Specifies duplex (side-by-side) mode.  It rotates the image 90 degrees
clockwise on the page,
the paper is logically divided into two 8 1/2" by 5 1/2" pages, two images
are printed side-by-side on each sheet.  This yeilds approximately 60%
reduction of each image.  This option doesn't work on the IMPRINT-10 (240)
laser printer.
X.TP
X.I \-s <scale>
Overrides the default scaling factor as determined by resolution and
orientation.  This is useful in conjuction with the -x and -y options
for enlarging, reducing and positioning images.  Be aware that enlarging
an image will probably push part of it off the page.  The smallest
scaling factor is 1, largest is 8.
X.br
The scaling factor n is used to define the size of the glyphs used on
the Imagen, each dot in the MacPaint image is printed as an n by n 
rectangle of dots on the Imagen page.
X.br
If the smoothing filter is used, the scale must be chosen as 2 or 4.
The defualt scale, when using the filter, is 2.
X.TP
X.I \-f[sval]
Runs the macpaint document through a smoothing filter so that it
appears less jaggy. The default magnification is 2 (optional 4), the
orientation must be portrait, and the multiple images per page feature
must be turned off.
X.br
The optional numeric parameter
X.I sval
controls the sensitivity of the filter.
Eight is the theoretically correct value, although six (the default)
seems to produce ``smoother'' looking pictures.  Reasonable values are
from about four to twelve.
X.TP
X.I \-x <origin x>
Overrides the default x cooridinate of the image origin on the page.
The x values start at zero on the left edge of the page and increase to the
right.  The default is determined by scaling and orientation, it is
calculated such that the image is centered on the page.
X.br
X.IB NOTE
that in landscape mode the origin is specified in the upper RIGHT corner
rather than the upper left.  After the origin is specified in normal
coordinates the axes are flipped, image height (y) then runs along the
old x axis (in the negative direction), and width (x) runs along the
old y axis.  A little experimentation will show how this works.
X.TP
X.I \-y <origin y>
Overrides the default y coordinate of the image origin.  Y coordinates
start at the top of the page and increase toward the bottom. 
You can specify
just one of
X.I \-x
or
X.I \-y,
the default will be used for the absent one.
X.br
Specifying 0 for either has no effect, this tells the program to use the 
default value.  Use 1,1 to place the image in the extreme upper left, 
paper feeding is not precise to within a pixel anyway.
X.TP
X.I \-P<printer>
Specifies the printer device to which the output should be sent.  This option
is not parsed, simply passed on to
X.I lpr (1)
when it is spawned.  This is provided as a convenience, if it is neccessary
to provide other options to
X.I lpr
, pipe the output of
X.I paintimp
into
X.I lpr
giving the appropriate options.  In this case any
X.I \-P
option given to
X.I paintimp
is ignored.
X.TP
X.I \-S
The file is a Macintosh screen dump, created using SHIFT-COMMAND-3.
X.TP
X.I file ...
Any remaining arguments are assumed to be names of MacPaint documents
and are processed in the order given.  The special name \- indicates 
that stdin should be read as a MacPaint document, it may be used in
conjuction with other file specifications.
X.SH FEATURES
X.I Paintimp
does not send the MacPaint image to the Imagen as a raster image,
it defines 255 glyphs with all the possible bit patterns producable
in one byte (don't need one for 0, imPress has a space command).  It
then sends the MacPaint file a byte (8 dots) at a time.  This is much
more efficient and easier for the Imagen to deal with.
X.I Paintimp
also uses a compresion scheme to replace runs of whitespace with imPress
postioning commands.  It greatly reduces the size of the spool file
and increases printing throughput.
X.SH CAVEATS
X.I Paintimp
doesn't do any clipping, if images are manipulated so that the bottom or
side runs off the edge, the Imagen will complain about missed scan lines
or glyphs off page.
X.br
Remember that landscape mode prints two images per page, if an image is 
enlarged so that the top part extends across the entire width of the
page (-s 5 is good for that by the way), and a second file was specified
on the command line, the second image will miss the page entirely.
X.br
Some images may not print correctly.
On the IMPRINT-10 blank scan lines may be inserted, on the 8/300 in 
landscape mode fragments of the image may appear in the wrong place.  This
doesn't seem to be a bug in
X.I paintimp
, perhaps idiosyncrasies of the imPress compiler on the Imagen.
X.br
This verion of
X.I paintimp 
has not been tested on a 480dpi printer, we don't have one at UT
X.SH SEE ALSO
macget(local)  lpr (1)
X.SH AUTHOR
Dave Johnson, Brown 7/29/84 (original author)
X.br
Ron Hitchens, U of Texas 12/07/84  (revised and expanded)
X.br
Kaare Christian, The Rockefeller University  (author of original filter)
X.br
Thomas Petsche, Princeton University 8/23/85 (added filter to this version)
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 paintimp.1l
	/bin/echo -n '	'; /bin/ls -ld paintimp.1l
fi
/bin/echo 'Extracting paintimp.c'
sed 's/^X//' <<'//go.sysin dd *' >paintimp.c
#ifndef lint
static	char sccsid[] = "@(#)paintimp.c	1.4 12/20/84 (UT)";
#endif

X/*
 * paintimp -- read macpaint document and output impress document 
 *
 * Dave Johnson, Brown University Computer Science
 *
 * (c) 1984 Brown University 
 * may be used but not sold without permission
 *
 * created ddj 5/06/84 for sun's rasterfile.h format (macfilter.c)
 * revised ddj 7/29/84 -- generate Impress format glyphs and data
 **** mods made by Ron Hitchens @ University of Texas CS
 * overhauled Rh 12/6/84 -- added @document headers
			open a pipe to lpr if stdout not redirected
			rework options, assume printer path from resolution
			added options for specifying scale and origin
			added whitespace compression scheme
			added informative messages to the user
			misc cleanup for lint
 * revised ddj 12/10/84-- added blank space and line suppression code
 * revised ddj 1/06/84 -- reworked page layout code:
			print in landscape mode if bitmap is wider than tall
			compute scale from bitmap size if not specified
			verify bitmap will fit in image space
			added verbose option to print user messages
			cleaned up code organization
 *
 * modifications made by Thomas Petsche @ Princeton University
 * revised tp 8/23/85 -- modified to allow use of smoothing filter written
 *			by Kaare Christian.  Added "-f" flag to specify
 *			smoothing.  Mods made to main, paintfilter,
 *			setup_scale, also changed default printer to
 *			imagen.   Connection to the filter is through
 * 			put_filter_image (part of filter file); the
 *			filter uses putbits for output.
 */

#include <stdio.h>

#define MACPAINT_HDRSIZE	512
#define MACRASTER_BITWIDTH	576

#define	MACPAINT_BITWIDTH	576
#define	MACPAINT_BITHEIGHT	720

#define	MACSCREEN_BITWIDTH	512
#define	MACSCREEN_BITHEIGHT	342

#define RES_240 0
#define RES_300 1
#define RES_480 2

#define DEF_RES 300	/* set what's convenient for your installation */

#define EOL -2		/* ala stdio EOF, must be passed as int */
#define BOP -3		/* ditto, for beginning of page */

typedef struct _point {
	int h;
	int v;
} point;

int filter = 0;
int smoothval = 6;
int twoup = 0;
int landscape = 0;
int screendump = 0;
int verbose = 0;
int res = DEF_RES;
int res_ind;
int scale = 0;
int width;
int height;
int glyph_width = 8;
point origin;
char *lp = NULL;

char usage[] =
"paintimp [-res] [-v] [-d] [-S] [-s n] [-x n] [-y n] [-f[sval]][-Pprinter] file ...";

char badeof[] = "Unexpected EOF. Going on to next image.\n";
char scalemsg[] = "Only scale = 2 or 4 possible with smoothing filter.\n";

main(ac, av)
char **av;
{
	char *name;

	origin.h = -1;  origin.v = -1;
	ac--; av++;
	while (ac && av[0][0] == '-' && av[0][1]) {
		switch (av[0][1]) {
		case '2':		/* kinda cheesy but it works */
		case '3':
		case '4':
			res = atoi(&av[0][1]);
			break;

		case 'S':
			screendump = 1;	/* image is macscreen sized */
			break;

		case 'd':
			twoup = 1;	/* set duplex layout */
			break;

		case 'v':
			verbose = 1;	/* set verbose mode */
			break;

		case 's':
			ac--;  av++;
			if (!ac) goto bad_usage;
			scale = atoi (av [0]);
			if( filter && scale != 4  && scale != 2 )
				{
				fprintf( stderr, scalemsg );
				exit(1);
				}
			break;

		case 'f':
			filter = 1;
			if( av[0][2] != 0 )
				smoothval = atoi(&av[0][2]);
			if( smoothval < 3 || smoothval > 16 )
				smoothval = 6;
			if( scale != 2 && scale != 4 )
				scale = 2;
			break;

		case 'x':
			ac--;  av++;
			if (!ac) goto bad_usage;
			origin.h = atoi (av [0]);
			break;

		case 'y':
			ac--;  av++;
			if (!ac) goto bad_usage;
			origin.v = atoi (av [0]);
			break;

		case 'P':
			lp = av[0];	/* propogate on to lpr filter */
			break;
			
		default:
			goto bad_usage;
		}
		ac--; av++;
	}

	switch (res)
		{
		case 240:
			res_ind = RES_240;
			break;
		case 300:
			res_ind = RES_300;
			break;
		case 480:
			res_ind = RES_480;
			break;
		default:
			fprintf(stderr, "illegal resolution %d;", res);
			fprintf(stderr, " use {240,300,480}\n");
			goto bad_usage;
		}
	if (ac == 0) {
		fprintf(stderr, "no files specified; use '-' for stdin\n");
		goto bad_usage;
	}

	write_imphdr(av[0]);	/* also starts spooling to lpr */
	get_sizes();
	setup_images();
	setup_scale();
	if (verbose) inform_user();
	while (ac) {
		name = av[0];
		if (verbose) fprintf(stderr, "Converting %s\n", name);
		paintfilter(name);
		ac--; av++;
	}
	finish_images();
	if (verbose) fprintf(stderr, "Finished\n");
	exit(0);
bad_usage:
	fprintf(stderr, "usage: %s\n", usage);
	exit(1);
}

X/* print out vital statistics */
inform_user()
{
	fprintf(stderr, "Resolution=%d", res);
	if (twoup) fprintf(stderr, ", duplex (side-by-side) mode");
	fprintf(stderr, "\nScaling=%d\n", scale);
	fprintf(stderr, "Origin: x=%d, y=%d\n", origin.h, origin.v);
}

X/* covert from macpaint to impress */

paintfilter(name)
char *name;
{
	register int x, y;
	FILE *fp;
	int c;

	if (name[0] == '-')
		fp = stdin;
	else
		fp = fopen(name, "r");
	if (fp == NULL) {
		perror(name);
		return;
	}

	(void) fseek(fp, (long)MACPAINT_HDRSIZE, 0);
	begin_image();				/* begin a new page */


	if( filter )
		put_filter_image(fp);

	else
		{
		for (y = 0; y < height; y++)
			{
			for (x = 0; x < MACRASTER_BITWIDTH/8; x++)
				{
				if ((c = getbits(fp)) == EOF)
					{
					fprintf(stderr, "Unexpected EOF, stopped.\n");
					y = height;
					break;
					}
				putbits(c);
				}
			putbits(EOL);
			}
		}

	end_image();				/* end the page */
	(void) fclose(fp);			/* finished with this input */
}

X/* macpaint input routines */

get_sizes()
{
	if (screendump) {
		width = MACSCREEN_BITWIDTH;
		height = MACSCREEN_BITHEIGHT;
	}
	else {
		width = MACPAINT_BITWIDTH;
		height = MACPAINT_BITHEIGHT;
	}
	if (width > height)
		landscape = 1;
}

getbits(fp)
FILE *fp;
{
	/* This routine expands the packbits encoded MacPaint file,
	   delivering one byte per call */

	static int count, rep, chr;
	int c;

	if (rep) {
		rep--;
		return chr;
	}
	if (count) {
		count--;
		return getc(fp);
	}
	c = getc(fp);
	if (c & 0x80) {			/* repeated character count */
		rep = 0x100 - c;	/* byte length 2's comp + 1 */
					/* allow for this call */
		chr = getc(fp);		/* character to repeat */
		return chr;
	}
	else {
		count = c;		/* already counted this char */
		return getc(fp);
	}
}

X/* impress output routines */

write_imphdr(firstname)
char *firstname;
{
	char *getenv();
	char *strcpy(), *ctime(), cimptime[26];
	char lpr [64], lpname[16];
	long time(), imptime;
	FILE *popen();

	/* if stdout is going to the terminal, call lpr to spool the
	   output, otherwise assume it's being piped somewhere else
	   or directed into a file */
	if (isatty (fileno (stdout)))
	{
		if (!lp) {
			/* assumes printer is named imagen */
			(void) sprintf (lpname, "-Pimagen");
			lp = lpname;
		}
		(void) sprintf (lpr, "lpr %s", lp);
		/* disconnect stdout from the tty and pipe it to lpr */
		(void) fclose (stdout);
		if (popen (lpr, "w") == NULL) {
			fprintf(stderr, "%s failed, giving up\n", lpr);
			exit(2);
		}
		if( verbose )fprintf(stderr, "Spooling to %s\n", lp+2);
	}

	/* imPress job command options */
	imptime = time(0l);			/* get time in internal form */
	(void) strcpy (cimptime, ctime(&imptime));/* put time in string form */
	cimptime[24] = '\0';			/* nullify \n in time string */
	printf("@document(language impress, pagereversal off");
		/* no reversal, that's a lot of stuff to buffer up */
	if (firstname[0] == '-')
		printf(", name \"MacPaint Document\"");
	else
		printf(", name \"%s\"", firstname);
	printf(", owner \"%s\"", getenv("USER"));
	printf(", spooldate \"%s\")", cimptime);
}

#define IMP_SP		128
#define IMP_CRLF	197
#define IMP_SET_FAMILY	207

#define IMP_SET_ABS_H	135
#define IMP_SET_REL_H	136
#define IMP_SET_ABS_V	137
#define IMP_SET_REL_V	138
#define IMP_BGLY	199

#define IMP_SET_HV_SYSTEM 205
#define IMP_SET_IL	208
#define IMP_SET_BOL	209
#define IMP_SET_SP	210
#define IMP_ENDPAGE	219
#define IMP_EOF		255

putbits(c)
int c;
{
	static int spaces = 0, lines = 0;

	switch (c) {
	case BOP:
		lines = 0;
		spaces = 0;
		break;

	case EOL:
		lines++;
		spaces = 0;
		break;
	
	case 0:			/* blank */
		spaces++;
		break;

	default:
		if (lines) {
			putlines(lines);
			lines = 0;
		}
		if (spaces) {
			putspaces(spaces);
			spaces = 0;
		}
		putglyph(c);
		break;
	}
}

#define FAMILY_MASK 0x80
#define MEMBER_MASK 0x7f
#define BYTE_MASK 0xff

putlines(lines)
register int lines;
{
	if (lines < 5) {
		while (lines--)
			putchar(IMP_CRLF);
	}
	else {
		putchar(IMP_CRLF);
		set_rel_v((lines - 1) * scale);
	}
}

putspaces(spaces)
register int spaces;
{
	if (spaces < 4) {
		while (spaces--)
			putchar(IMP_SP);
	}
	else {
		set_rel_h(spaces * glyph_width );
	}
}

X/* this routine outputs a byte to the imagen, switching glyph
   families if necessary */

putglyph(g)
int g;
{
	static int curfam = 0;	/* family of previous glyph */
	int family;

	family = ((g & FAMILY_MASK) != 0);	/* family of g */
	if (curfam != family) {
		curfam = family;
		putchar(IMP_SET_FAMILY);
		putchar(family & BYTE_MASK);
	}
	putchar(g & MEMBER_MASK);	/* lower 7 bits of the char */
}

#define ORG_CURRENT 3
#define AXES_NOP 0
#define ORIENT_NORMAL 4
#define ORIENT_ROTATE 5
#define ROUND32(n) (((n)/32)*32)

static point image_space;
int rotated = 0;
static int imageno = 0;

X/* determine orientation and available image size on output page */
X/* pixel size rounded down to multiple of 32 for imagen bitmaps */

setup_images()
{
	int hv_system;
	point o;

	if (twoup != landscape)
		rotated = 1;
	if (rotated) {
		/*	 h->
		    +-----------+
		   v|\org |     |
		   ||           |
		   V|     |     |
		    +-----------+
		 */
		image_space.v = ROUND32((17 * res) / 2);/* 8.5 inches */
		image_space.h = ROUND32(11 * res);	/* 11 inches */
		if (twoup) {
			image_space.h /= 2;		/* 5.5 inches */
		}

		o.v = 0;		/* new origin in old coordinates */
		o.h = image_space.v;	/* 8.5 inches */
		set_abs_pos(o);

		hv_system = (ORG_CURRENT<<5) | (AXES_NOP<<3) | ORIENT_ROTATE;
		putchar(IMP_SET_HV_SYSTEM);
		putchar(hv_system);

		o.h = 0;	/* goto new origin in new coordinates */
		set_abs_pos(o);
	}
	else {
		/*   h->
		    +-------+
		   v|\org   |
		   ||	    |
		   V| - - - |
		    |	    |
		    |	    |
		    +-------+
		 */
		image_space.h = ROUND32((17 * res) / 2);/* 8.5 inches */
		image_space.v = ROUND32(11 * res);	/* 11 inches */
		if (twoup) {
			image_space.v /= 2;		/* 5.5 inches */
		}

		o.h = 0;
		o.v = 0;
		set_abs_pos(o);

		hv_system = (ORG_CURRENT<<5) | (AXES_NOP<<3) | ORIENT_NORMAL;
		putchar(IMP_SET_HV_SYSTEM);
		putchar(hv_system);
	}
}

X/* select best scale if not given, perform scale-dependent initializations */
X/* each MacPaint dot becomes an scale-square rectangle of imagen dots */

setup_scale()
	{
	int tmp;

	/* start large and cut it down if it won't fit */
	/* low level routines are limited to scale of 8 */
	if (scale <= 0) scale = 8;		/* let's be reasonable... */
	if (scale > 8) scale = 8;

	tmp = image_space.h / width;
	if (tmp < scale)
		scale = tmp;
	tmp = image_space.v / height;
	if (tmp < scale)
		scale = tmp;
	if (scale <= 0) {
		fprintf(stderr, "bitmap too large for page\n");
		exit(3);
	}
	/* bitmap will now fit in image_space */

	if( filter )
		{
		if( scale == 4 )
			write_filter_glyphs();
		else
			write_filter_glyphs2();
		glyph_width = 3 * scale;
		}
	else
		{
		write_glyphs();
		glyph_width = scale * 8;
		}

	putchar(IMP_SET_SP);
	putshort(glyph_width);
	putchar(IMP_SET_IL);
	putshort(scale);

				/* center bitmap */
				/* unless valid origin specified by user */
	if (origin.h < 0 || (origin.h + width * scale) > image_space.h)
		origin.h = (image_space.h - width * scale) / 2;
	if (origin.v < 0 || (origin.v + height * scale) > image_space.v)
		origin.v = (image_space.v - height * scale) / 2;
	}

begin_image()
{
	point o;

	imageno++;		/* count pictures */
	o.h = origin.h;
	o.v = origin.v;
	if (twoup && !(imageno & 1)) {
		/* shift second image down or over by half page */
		if (landscape)
			o.v += image_space.v;
		else
			o.h += image_space.h;
	}
	putbits(BOP);		/* prime putbits to reset spaces, lines */
	putchar(IMP_SET_BOL);
	putshort(o.h);
	set_abs_pos(o);
}

end_image()
{
	if (twoup && (imageno & 1))
		return;
	putchar(IMP_ENDPAGE);
}

finish_images()
{
	if (twoup && (imageno & 1))
		putchar(IMP_ENDPAGE);
	putchar(IMP_EOF);
}

set_abs_pos(pt)
point pt;
{
	putchar(IMP_SET_ABS_H);
	putshort(pt.h);
	putchar(IMP_SET_ABS_V);
	putshort(pt.v);
}

set_rel_v(incr)
int incr;
{
	putchar(IMP_SET_REL_V);
	putshort(incr);
}

set_rel_h(incr)
int incr;
{
	putchar(IMP_SET_REL_H);
	putshort(incr);
}

write_glyphs()		/* send the dot pattern glyphs to the imagen */
{
	register int glyph;

	if( verbose ) fprintf (stderr, "Loading dot patterns\n");
	for (glyph = 1; glyph <= 255; glyph++) {
		write_glyph(glyph);
	}
}

char bits[8];		/* code assumes scale <= 8 */

write_glyph(g)
register int g;
{
	register int i, j;
	register int b, xpos;
	int bit;

	if (rotated) {
		putchar(IMP_BGLY);
		g |= (1 << 14);		/* rotate 90 degrees clockwise */
		putshort(g);		/* family & member to define */
		putshort(scale*8);	/* advance width in h diretion */
		putshort(scale);	/* x bit width of glyph */
		putshort(0);		/* left offset */
		putshort(scale*8);	/* y bit height of glyph */
		putshort(0);		/* top offset */
		for (b = 0x80; b; b >>= 1) {
			bits[0] = 0;
			bit = g & b;
			for (i = 0; i < scale; i++)
				if (bit) setbit(i);
			for (i = 0; i < scale; i++)
				putchar(bits[0] & BYTE_MASK);
		}
	}
	else {
		putchar(IMP_BGLY);
		putshort(g);		/* family & member to define */
		putshort(scale*8);	/* advance width in h direction */
		putshort(scale*8);	/* x bit width of glyph */
		putshort(0);		/* left offset */
		putshort(scale);	/* y bit height of glyph */
		putshort(0);		/* top offset */
		xpos = 0;
		for (i = 0; i < scale; i++)
			bits[i] = 0;
		for (b = 0x80; b; b >>= 1) {
			bit = g & b;
			for (i = 0; i < scale; i++, xpos++)
				if (bit) setbit(xpos);
		}
		for (j = 0; j < scale; j++) {
			for (i = 0; i < scale; i++)
				putchar(bits[i] & BYTE_MASK);
		}
	}
}

setbit(x)
int x;
{
	int bitno;
	char *bitp;
	
	bitno = 7 - (x % 8);
	bitp = &bits[x / 8];
	*bitp |= (1 << bitno);
}

putshort(s)
int s;
{
	putchar((s >> 8) & BYTE_MASK);
	putchar(s & BYTE_MASK);
}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 sunkeys.c
	/bin/echo -n '	'; /bin/ls -ld sunkeys.c
fi
/bin/echo 'Extracting filter.c'
sed 's/^X//' <<'//go.sysin dd *' >filter.c
X/*
 *  These subroutines implement a smoothing filter for MacPaint
 * documents printed on a laser printer with a final resolution 
 * that is two or four times that of the original image.
 *
 *  The algorithm used to defined the glyphs for the smoothed
 * image is taken from the filter program written by
 * Kaare Christian.  These subroutines, combined with Dave
 * Johnsons paintimp routines, produce a file that is a factor
 * of 2 (for a scale of 2) or 6 (for a scale of 4) smaller
 * than a bitmap would be.  The entire paintimp program runs
 * in approximately 30% of the time required by a version of
 * Christian's program as modified by Chris Toulson.
 *
 *  Thomas Petsche
 *  Electrical Engineering Dept.
 *  Princeton University
 *  Princeton, NJ
 *
 *  uucp:  allegra!princeton!ivy!petsche
 */



#include <stdio.h>
#define MAC_SCANLINE_BITS 576
#define MB MAC_SCANLINE_BITS
#define QB MB*4
#define OB (MB/2)
#define LP_WIDTH 78
#define	EOL	-2
#define	IMP_BGLY	199


extern	int	smoothval;	/* smoothing threshold (3-16) */
extern	int	rotated;
extern	int	height;
extern	char	badeof[];

struct
	{
	int	blank;
	char	b[MB/8];
	} lbuf[2] = { {1,NULL}, {1,NULL} };
char	*lptr = lbuf[1].b;


put_filter_image(fp)
FILE	*fp;
	{
	register int c, byte, rep, x, y;

	for( y=0; y<height; y++ )
		{
		x=0;
		while( x < MB/8 )
			{
			if( (c = getc(fp)) == EOF )
				{
				fprintf( stderr, badeof );
				return(-1);
				}
			if( c & 0x80 )
				{
				rep = 257 - c;
				if( (byte = getc(fp)) == EOF )
					{
					fprintf( stderr, badeof );
					return(-1);
					}
				x += rep;
				if( byte )  lbuf[1].blank = 0;
				while( rep-- )
					*lptr++ = byte;
				}
			else
				{
				x += c+1;
				while( c-- >= 0 )
					{
					if( (byte = getc(fp)) == EOF )
						{
						fprintf( stderr, badeof );
						return(-1);
						}
					if( byte )  lbuf[1].blank = 0;
					*lptr++ = byte;
					}
				}
			}
		put_lines();		/* write the lines of the filtered image */
		lbuf[0] = lbuf[1];	/* copy the bottom line to the top */
		lbuf[1].blank = 1;	/* assume new line is blank */
		lptr = lbuf[1].b;
		}
	return(0);
	}


put_lines()
	{
	register int	i;

	if( lbuf[0].blank && lbuf[1].blank )
		{
		putbits(EOL);
		return;
		}

	for( i=0; i<MB/8; i+=3 )
		{
		putbits( (lbuf[0].b[i]&0xf0) | ((lbuf[1].b[i]&0xf0)>>4) );
		putbits( ((lbuf[0].b[i]&0x1e)<<3) | ((lbuf[1].b[i]&0x1e)>>1) );
		putbits( ((lbuf[0].b[i]&0x03)<<6) | ((lbuf[0].b[i+1]&0xc0)>>2)
			| ((lbuf[1].b[i]&0x03)<<2) | ((lbuf[1].b[i+1]&0xc0)>>6) );
		putbits( ((lbuf[0].b[i+1]&0x78)<<1) | ((lbuf[1].b[i+1]&0x78)>>3) );
		putbits( ((lbuf[0].b[i+1]&0x0f)<<4) | (lbuf[1].b[i+1]&0x0f) );
		putbits( ((lbuf[0].b[i+1]&0x01)<<7) | ((lbuf[0].b[i+2]&0xe0)>>1)
			| ((lbuf[1].b[i+1]&0x01)<<3) | ((lbuf[1].b[i+2]&0xe0)>>5) );
		putbits( ((lbuf[0].b[i+2]&0x3c)<<2) | ((lbuf[1].b[i+2]&0x3c)>>2) );
		putbits( ((lbuf[0].b[i+2]&0x07)<<5) | ((lbuf[0].b[i+3]&0x80)>>3)
			| ((lbuf[1].b[i+2]&0x07)<<1) | ((lbuf[1].b[i+3]&0x80)>>7) );
		}
	putbits(EOL);
	}

X/*
 * this table provides the weighting of any point in the 2x2 area
 * based on the corner point values.  Each line corresponds to one
 * of the 16 possible combinations of the 4 corner points.  The
 * values on a line are taken 2 at a time and inserted in the 
 * glyph buffer.
 * The area concerned is as follows:
 *
 *          * * 0
 *          * * .
 *          0 . 0
 * where the 0's (and the upper left hand *)are the points in the
 * original image, and the *'s are the points in the new image.
 */

static	char	w2[68] = {
	0,	0,	0,	0,
	0,	0,	0,	4,
	0,	0,	8,	4,
	0,	0,	8,	8,
	0,	8,	0,	4,
	0,	8,	0,	8,
	0,	8,	8,	8,
	0,	8,	8,	12,
	16,	8,	8,	4,
	16,	8,	8,	8,
	16,	8,	16,	8,
	16,	8,	16,	12,
	16,	16,	8,	8,
	16,	16,	8,	12,
	16,	16,	16,	12,
	16,	16,	16,	16 };


X/*
 * here we define the glyphs to be used later.
 * The idea is this, each 2x6 area of the filtered image, is
 * uniquely determined by the values at 8 points (the 0's in the
 * picture):
 *            0 * 0 * 0 * 0
 *            * * * * * * . 
 *            0 . 0 . 0 . 0
 * (the two zeros on the right and the third line are not
 * included in the new 2x6 area)
 * the values in the picture are chosen for 2x2 areas of the new
 * picture based on the values in the 2x2 areas of the old.
 * These 4x4 areas are computed based on the wieghts in w2 defined
 * above and the value of the threshold smoothval.  3 2x2 areas
 * are then combined into the final 2x6 area that becomes a glyph
 *
 * The bits in the glyph names correspond to the positions in a
 * 2x4 area of the original image in the following way:
 *            1 2 3 4
 *            5 6 7 8
 * where 1 is the MSB and 8 is the LSB
 */


write_filter_glyphs2()
	{
	register int i,j, val;
	short	int	tmp[2][3];
	int	glyph_line[2];
	register char	*q;

	for( i=0; i<256; i++ )
		{
				/* first insert the values from w2 into the */
				/* appropriate places and lines */
		q = &w2[ ((i&0xC0)>>2) | (i&0x0C) ];	/* 0 * 0 . . . */
		tmp[0][0] = ((short int *)q)[0];	/* * * . . . . */
		tmp[1][0] = ((short int *)q)[1];	/* 0 * 0 . . . */

		q = &w2[ ((i&0x60)>>1) | ((i&0x06)<<1)];	/* . . 0 * 0 . */
		tmp[0][1] = ((short int *)q)[0];		/* . . * * . . */
		tmp[1][1] = ((short int *)q)[1];		/* . . 0 * 0 . */

		q = &w2[ (i&0x30) | ((i&0x03)<<2) ];		/* . . . . 0 * (0) */
		tmp[0][2] = ((short int *)q)[0];			/* . . . . * * (.) */
		tmp[1][2] = ((short int *)q)[1];			/* . . . . 0 . (0) */

							/* now apply the threshold and compress */
							/* each pixel into one bit */
		for( j=0; j<2; j++ )
			{
			q = &tmp[j][0];
			val=0;

			if( *q++ > (char)smoothval )  val += 0x020;
			if( *q++ > (char)smoothval )  val += 0x010;
			if( *q++ > (char)smoothval )  val += 0x008;
			if( *q++ > (char)smoothval )  val += 0x004;
			if( *q++ > (char)smoothval )  val += 0x002;
			if( *q++ > (char)smoothval )  val += 0x001;

			glyph_line[j] = val;
			}
		
		write_filter_glyph2( i, glyph_line );
		}
	}



X/*
 * this subroutine writes the previously calculated glyph, with
 * the appropriate housekeeping data, to the Imagen
 */


write_filter_glyph2( name, lines )
int	name;
int	lines[2];
	{
	register int i;

	if( rotated )
		{
		fprintf( stderr, "Can't do rotated image with filter.\n" );
		exit( 1 );

		putchar( IMP_BGLY );
		putshort( name | (1<<14) );		/* family & member, rotated */
		putshort( 6 );			/* advance width in h direction */
		putshort( 2 );			/* x bit width */
		putshort( 0 );			/* left offset */
		putshort( 6 );			/* y bit height */
		putshort( 0 );			/* top offset */

		putchar( ((lines[0]&0x01)<<1) | (lines[1]&0x01) );
		putchar( (lines[0]&0x02) | ((lines[1]&0x02)>>1) );
		putchar( ((lines[0]&0x04)<<1) | ((lines[1]&0x04)>>2) );
		putchar( ((lines[0]&0x08)<<2) | ((lines[1]&0x08)>>3) );
		putchar( ((lines[0]&0x10)<<3) | ((lines[1]&0x10)>>4) );
		putchar( ((lines[0]&0x20)<<4) | ((lines[1]&0x20)>>5) );

		}

	else
		{
		putchar(IMP_BGLY);
		putshort(name);
		putshort(6);
		putshort(6);
		putshort(0);
		putshort(2);
		putshort(0);

		for( i=0; i<2; i++ )
			putchar( lines[i] & 0x03f );
		}
	}

X/* this table provides the weighting of the any point in the 4x4 area
 * based on the corner point values. Each line corresponds to 1 of the 16
 * possible combinations of the 4 corner points. The values on a line,
 * taken 4 at a time correspond to the values to insert row by row into
 * the 4x4 area of the line buffers.
 */
static char w[256] = {
  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
  0,  0,  0,  0,  0,  1,  2,  3,  0,  2,  4,  6,  0,  3,  6,  9,
  0,  0,  0,  0,  4,  3,  2,  1,  8,  6,  4,  2, 12,  9,  6,  3,
  0,  0,  0,  0,  4,  4,  4,  4,  8,  8,  8,  8, 12, 12, 12, 12,
  0,  4,  8, 12,  0,  3,  6,  9,  0,  2,  4,  6,  0,  1,  2,  3,
  0,  4,  8, 12,  0,  4,  8, 12,  0,  4,  8, 12,  0,  4,  8, 12,
  0,  4,  8, 12,  4,  6,  8, 10,  8,  8,  8,  8, 12, 10,  8,  6,
  0,  4,  8, 12,  4,  7, 10, 13,  8, 10, 12, 14, 12, 13, 14, 15,
 16, 12,  8,  4, 12,  9,  6,  3,  8,  6,  4,  2,  4,  3,  2,  1,
 16, 12,  8,  4, 12, 10,  8,  6,  8,  8,  8,  8,  4,  6,  8, 10,
 16, 12,  8,  4, 16, 12,  8,  4, 16, 12,  8,  4, 16, 12,  8,  4,
 16, 12,  8,  4, 16, 13, 10,  7, 16, 14, 12, 10, 16, 15, 14, 13,
 16, 16, 16, 16, 12, 12, 12, 12,  8,  8,  8,  8,  4,  4,  4,  4,
 16, 16, 16, 16, 12, 13, 14, 15,  8, 10, 12, 14,  4,  7, 10, 13,
 16, 16, 16, 16, 16, 15, 14, 13, 16, 14, 12, 10, 16, 13, 10,  7,
 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16 };


X/*
 * here we calculate the glyphs based on w define above.
 *  See the comments for w2, write_filter_glyphs2(), and
 * write_filter_glyph2() for a more complete explanation.
 *  Here we are defining a glyph which covers a 4x12 area
 * of the filtered image based on a 2x4 area of the original
 * The area is:
 *             0 * * * 0 * * * 0 * * * 0
 *             * * * * * * * * * * * *
 *             * * * * * * * * * * * *
 *             0 * * * 0 * * * 0 * * * 0
 */




write_filter_glyphs()
	{
	register int i,j, val;
	int	tmp[4][4], glyph_line[4];
	register char	*q;

	for( i=0; i<256; i++ )
		{
		q = &w[ (i&0xC0) | ((i&0x0C)<<2) ];
		tmp[0][0] = ((int *)q)[0];
		tmp[1][0] = ((int *)q)[1];
		tmp[2][0] = ((int *)q)[2];
		tmp[3][0] = ((int *)q)[3];

		q = &w[ ((i&0x60)<<1) | ((i&0x06)<<3)];
		tmp[0][1] = ((int *)q)[0];
		tmp[1][1] = ((int *)q)[1];
		tmp[2][1] = ((int *)q)[2];
		tmp[3][1] = ((int *)q)[3];

		q = &w[ ((i&0x30)<<2) | ((i&0x03)<<4) ];
		tmp[0][2] = ((int *)q)[0];
		tmp[1][2] = ((int *)q)[1];
		tmp[2][2] = ((int *)q)[2];
		tmp[3][2] = ((int *)q)[3];

		for( j=0; j<4; j++ )
			{
			q = &tmp[j][0];
			val=0;

			if( *q++ > (char)smoothval )  val += 0x800;
			if( *q++ > (char)smoothval )  val += 0x400;
			if( *q++ > (char)smoothval )  val += 0x200;
			if( *q++ > (char)smoothval )  val += 0x100;
			if( *q++ > (char)smoothval )  val += 0x080;
			if( *q++ > (char)smoothval )  val += 0x040;
			if( *q++ > (char)smoothval )  val += 0x020;
			if( *q++ > (char)smoothval )  val += 0x010;
			if( *q++ > (char)smoothval )  val += 0x008;
			if( *q++ > (char)smoothval )  val += 0x004;
			if( *q++ > (char)smoothval )  val += 0x002;
			if( *q++ > (char)smoothval )  val += 0x001;

			glyph_line[j] = val;
			}
		
		write_filter_glyph( i, glyph_line );
		}
	}

X/*
 * here we write the previously defined glyphs, along with
 * some housekeeping information, to the Imagen.
 */


write_filter_glyph( name, lines )
int	name;
int	lines[4];
	{
	register int i;

	if( rotated )
		{
		fprintf( stderr, "Can't do rotated image with filter.\n" );
		exit(1);
		}

	else
		{
		putchar(IMP_BGLY);
		putshort(name);
		putshort(12);
		putshort(12);
		putshort(0);
		putshort(4);
		putshort(0);

		for( i=0; i<4; i++ )
			putshort( lines[i] & 0x0fff );
		}
	}
//go.sysin dd *
made=TRUE
if [ $made = TRUE ]; then
	/bin/chmod 644 filter.c
	/bin/echo -n '	'; /bin/ls -ld filter.c
fi