[net.sources] Mandelbrot set programs

bet@ecsvax.UUCP (Bennett E. Todd III) (09/14/85)

#!/bin/sh
# Cut above the preceeding line, or cut here if you must.
# This is a shar archive.  Extract with sh, not csh.
# The rest of this file will extract:
# mndlbrot.doc compute.c ibmcg4.c colorprn.c
sed 's/^X//' > mndlbrot.doc << '/*EOF'
XThis is a set of programs written in C for computing and displaying the
XMandelbrot set. The program "compute" generates a data file containing a
Xdescriptive header, followed by one byte per pixel, containing the count
Xof how many iterations were required to diverge. This work was based on
Xthe cover article of the August 1985 Scientific American, the Computer
XRecreations column. Please consult that article for a description of the
Xwhys and wherefores of this algorithm. The programs "ibmcg4" and
X"colorprn" display the resulting files on the IBM Color Graphics Adaptor
Xin 4 colors, and the IBM Personal Computer Color Printer in 8 colors,
Xrespectively. They should be reasonably easily modified for other
Xdevices, and aside from two short assembler subroutines "setup_scr()"
Xand "putpoint()" in ibmcg4, should be reasonably portable. These were
Xwritten under DeSmet C for the IBM-PC. The header of the data file is
Xterminated by a byte value 26 decimal, ^Z, which is the DOS EOF marker.
XThis shouldn't interfere with the program in other environments, and
Xenables you to read the header on a PC by simply typing "type file.pic",
Xas the type command stops at EOF. Feel free to rip out the \032 in the
Xfprintf and fscanf statements if you don't like this cuteness.
X
XThe arguments used to describe a picture are four: center and scale,
Xwhich are complex constants, and hpix and vpix, integers defining the
Xnumber of pixels horizontally and vertically respectively. Center is the
Xcomplex coordinates of the center of the picture. The picture runs from
Xreal(center)-real(scale) to real(center)+real(scale) on the real axis,
Xand similarly in the complex direction. I am open to suggestions for
Xmore meaningful input parameters to control these critters; this just
Xseemed simplest at the time (i.e. before I realized what is involved in
Xgenerating pictures with "true" proportions). Perhaps it should compute
Xthe imaginary scale factor, and you should also input what dimensions
Xthe hpix*vpix window will display as, or maybe the compute program
Xshould have the aspect ratios of various output devices wired in, or
Xsomething. Think about it and let me know what you come up with:-).
X
XI put some effort into making the programs completely controllable from
Xthe command line, using named parameters that can come in any order and
Xare prompted for if missing and like that. This is the first time I have
Xdone this, and the result has a lot of duplicated code. I would welcome
Xany cleaning up anyone could do on that part, which constitutes the vast
Xmajority of compute.c.
X
XThese programs were inspired by the program John White wrote, and he
Xhelp to debug them and speed them up. They are designed with a different
Xgoal from John's; his is exceedingly fast, many times faster than mine.
XI placed the highest priorities on portability and clarity, with speed
Xtaking a slow third. My programs aren't intended as competitors in any
Xsense to that which John wrote; they represent a different set of design
Xtradeoffs.
X
XThe display program ibmcg4 has two different color assignment schemes
Xselectable via compile time #ifdef code; I made an adaptive color
Xassignment that seemed to be reasonable, then John White gave me his,
Xwhich resolves much better detail in four colors. Colorprn uses adaptive
Xcolor assignment alone, though I used a little of John's color banding
Xapproach. These are probably the best place to try to improve the
Xappearance of the resulting pictures.
X
XFinal note: these programs are formatted with tabs every 4 columns, not 8.
X
XPlease send me any bug fixes and enhancements you might make to these; I
Xam continuing to work on them and will keep you informed of any
Ximprovements I make, if I get any indication of interest. Enjoy.
X
XBennett Todd
XDuke Computation Center
XDurham NC 27701
X+1 919 684 3695
XUUCP: ...{decvax,ihnp4,akgua}!mcnc!ecsvax!duccpc!bet
XBITNET: dbtodd@tucc
/*EOF
ls -l mndlbrot.doc
sed 's/^X//' > compute.c << '/*EOF'
X#include <stdio.h>
X/*
X * compute [name] [center=x+yi] [scale=x+yi] [hpix=n] [vpix=n] [like=name]
X * Build file name.pix, containing a header with the center, scale
X * and horizontal/vertical pixel info, followed by hpix*vpix bytes
X * containing the number of iterations required for the point to go
X * to infinity (up to 255). Any parameters not specified on the command
X * line are prompted for, after a one-line summery of the command line
X * syntax.
X * like=name allows you to set defaults to those of another picture, then
X * override them.
X */
X
X#define MAXNAMELEN 64 /* MS-DOS filename length limit */
X
X#ifndef FALSE
X#define FALSE 0
X#endif
X
X#ifndef TRUE
X#define TRUE 1
X#endif
X
X#define ISPREFIX(s1, s2) !strncmp((s1), (s2), strlen(s1))
X#define ISSUFFIX(s1, s2) !strcmp((s1), (s2)+strlen(s2)-strlen(s1))
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	int got_name = FALSE,
X		got_center = FALSE,
X		got_scale = FALSE,
X		got_hpix = FALSE,
X		got_vpix = FALSE;
X	char name[MAXNAMELEN],	/* picture name			*/
X		 iobuff[128];		/* kbd input buffer		*/
X	double center_r,		/* real part of center	*/
X		   center_i,		/* imaginary "			*/
X		   scale_r,			/* real part of scale	*/
X		   scale_i;			/* imaginary "			*/
X	int hpix,				/* # pixels horizontal	*/
X		vpix;				/* #   "    vertical	*/
X	double top_left_r,
X		   top_left_i,
X		   hstep,
X		   vstep;
X	int i,j;
X	FILE *fp, *fopen();
X
X	/* check for a "like" parameter; process it if found; */
X	for (i=1; i<argc; i++)
X		if (ISPREFIX("like=", argv[i])) {
X			if (ISSUFFIX(".pic", argv[i]))
X				strncpy(name, argv[i]+strlen("like="), MAXNAMELEN);
X			else {
X				strncpy(name, argv[i]+strlen("like="), MAXNAMELEN-4);
X				strcat(name, ".pic");
X			}
X			if ((fp = fopen(name, "r")) == NULL) {
X				fprintf(stderr, "compute: cannot open %s\n", name);
X				break;
X			}
X			if (fscanf(fp, "Centered at %lf+%lfi, scale %lf+%lfi, %dx%d\n\032",
X				&center_r, &center_i, &scale_r, &scale_i, &hpix, &vpix) != 6) {
X				fprintf(stderr, "compute: cannot parse header of %s\n", name);
X				break;
X			}
X			got_center=got_scale=got_hpix=got_vpix=TRUE;
X		}
X
X	/* for each argument */
X	for (argc--, argv++; argc; argc--, argv++) {
X		if (ISPREFIX("center=", *argv)) {
X			if (sscanf(*argv+7, "%lf+%lfi", &center_r, &center_i) != 2)
X				fprintf(stderr, "compute: cannot parse %s\n", *argv);
X			else
X				got_center = TRUE;
X		} else if (ISPREFIX("scale=", *argv)) {
X			if (sscanf(*argv+6, "%lf+%lfi", &scale_r, &scale_i) != 2)
X				fprintf(stderr, "compute: cannot parse %s\n", *argv);
X			else
X				got_scale = TRUE;
X		} else if (ISPREFIX("hpix=", *argv)) {
X			if (sscanf(*argv+5, "%d", &hpix) != 1)
X				fprintf(stderr, "compute: cannot parse %s\n", *argv);
X			else
X				got_hpix = TRUE;
X		} else if (ISPREFIX("vpix", *argv)) {
X			if (sscanf(*argv+5, "%d", &vpix) != 1)
X				fprintf(stderr, "compute: cannot parse %s\n", *argv);
X			else
X				got_vpix = TRUE;
X		} else if (index(*argv, '=') != NULL) {
X			if (!ISPREFIX("like=", *argv))
X				fprintf(stderr, "compute: cannot parse %s\n", *argv);
X		} else {
X			got_name = TRUE;
X			if (ISSUFFIX(".pic", *argv))
X				strncpy(name, *argv, MAXNAMELEN);
X			else {
X				strncpy(name, *argv, MAXNAMELEN-4);
X				strcat(name, ".pic");
X			}
X		}
X	} /* end of "for each argument" */
X
X	if (!(got_name&got_center&got_scale&got_hpix&got_vpix))
X		printf("syntax: compute [name] [center=x+yi] [scale=x+yi] [hpix=n] [vpix=n]\n");
X
X	if (got_name) {
X		if ((fp = fopen(name, "w")) == NULL) {
X			fprintf(stderr, "compute: cannot open %s\n", name);
X			got_name = FALSE;
X		}
X	}
X
Xget_name:
X	if (!got_name) {
X		printf("Name: ");
X		gets(iobuff);
X		if (ISSUFFIX(".pic", iobuff))
X			strncpy(name, iobuff, MAXNAMELEN);
X		else {
X			strncpy(name, iobuff, MAXNAMELEN-4);
X			strcat(name, ".pic");
X		}
X		if ((fp = fopen(name, "w")) == NULL) {
X			fprintf(stderr, "compute: cannot open %s\n", name);
X			got_name = FALSE;
X			goto get_name;
X		}
X	}
X
Xget_center:
X	if (!got_center) {
X		printf("Center: ");
X		gets(iobuff);
X		if (sscanf(iobuff, "%lf+%lfi", &center_r, &center_i) != 2) {
X			fprintf(stderr, "compute: cannot parse %s\n", iobuff);
X			got_center = FALSE;
X			goto get_center;
X		}
X	}
X
Xget_scale:
X	if (!got_scale) {
X		printf("Scale: ");
X		gets(iobuff);
X		if (sscanf(iobuff, "%lf+%lfi", &scale_r, &scale_i) != 2) {
X			fprintf(stderr, "compute: cannot parse %s\n", iobuff);
X			got_scale = FALSE;
X			goto get_scale;
X		}
X	}
X
Xget_hpix:
X	if (!got_hpix) {
X		printf("Hpix: ");
X		gets(iobuff);
X		if (sscanf(iobuff, "%d", &hpix) != 1) {
X			fprintf(stderr, "compute: cannot parse %s\n", iobuff);
X			got_hpix = FALSE;
X			goto get_hpix;
X		}
X	}
X
Xget_vpix:
X	if (!got_vpix) {
X		printf("Vpix: ");
X		gets(iobuff);
X		if (sscanf(iobuff, "%d", &vpix) != 1) {
X			fprintf(stderr, "compute: cannot parse %s\n", iobuff);
X			got_vpix = FALSE;
X			goto get_vpix;
X		}
X	}
X
X	printf("Generating %s centered at %lf+%lfi, scale %lf+%lfi, %dx%d\n",
X			name, center_r, center_i, scale_r, scale_i, hpix, vpix);
X
X	fprintf(fp, "Centered at %lf+%lfi, scale %lf+%lfi, %dx%d\n\032",
X				center_r, center_i, scale_r, scale_i, hpix, vpix);
X
X	top_left_r = center_r - scale_r;
X	top_left_i = center_i + scale_i;
X	hstep = 2*scale_r/hpix;
X	vstep = 2*scale_i/vpix;
X
X	for (i=0; i<vpix; i++)
X		for (j=0; j<hpix; j++)
X			fputc(compute(top_left_r+j*hstep, top_left_i-i*vstep), fp);
X
X	fclose(fp);
X}
X
Xcompute(c_r, c_i)
Xdouble c_r, c_i;
X{
X	double z_r = 0,
X		   z_i = 0,
X		   z_rs, z_is;
X	int iter = 0;
X
X	/* while (iter < 255 && |Z| < 2) */
X	while (iter < 255 && ((z_rs=z_r*z_r) + (z_is=z_i*z_i)) < 4) {
X		z_i = 2*z_r*z_i + c_i;
X		z_r = z_rs - z_is + c_r;
X		iter++;
X	}
X
X	return(iter);
X}
/*EOF
ls -l compute.c
sed 's/^X//' > ibmcg4.c << '/*EOF'
X#include <stdio.h>
X/*
X * ibmcg4 [name]
X * Display file name.pic created by compute on an IBM Color Graphics
X * Adaptor in 4 colors. Prompts for name if not given.
X */
X
X#define MAXNAMELEN 64 /* max filename length for MS-DOS */
X
X#define John_White_Colors
X
X#ifndef FALSE
X#define FALSE 0
X#endif
X
X#ifndef TRUE
X#define TRUE 1
X#endif
X
X#ifndef EOF
X#define EOF (-1)
X#endif
X
X#define ISSUFFIX(s1, s2) !strcmp((s1), (s2)+strlen(s2)-strlen(s1))
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	char name[MAXNAMELEN];
X	FILE *fp, *fopen();
X	int i, j, n;
X	double center_r,
X		   center_i,
X		   scale_r,
X		   scale_i;
X	int hpix, vpix;
X	char colormax[4];
X	long npix, count[256], temp_l;
X
X	if (argc == 2)
X		if (ISSUFFIX(".pic", argv[1]))
X			strncpy(name, argv[1], MAXNAMELEN);
X		else {
X			strncpy(name, argv[1], MAXNAMELEN-4);
X			strcat(name, ".pic");
X		}
X	else {
X		printf("syntax: ibmcg4 [name]\n");
X		printf("Name: ");
X		gets(name);
X	}
X	if (!ISSUFFIX(".pic", name))
X		strcat(name, ".pic");
X	while ((fp = fopen(name, "r")) == NULL) {
X		fprintf(stderr, "ibmcg4: cannot open %s\n", name);
X		printf("Name: ");
X		gets(name);
X		if (!ISSUFFIX(".pic", name))
X			strcat(name, ".pic");
X	}
X
X	if (fscanf(fp, "Centered at %lf+%lfi, scale %lf+%lfi, %dx%d\n\032",
X		&center_r, &center_i, &scale_r, &scale_i, &hpix, &vpix) != 6) {
X		fprintf(stderr, "ibmcg4: cannot parse header of %s\n", name);
X		exit(1);
X	}
X
X	npix = hpix*(long)vpix;
X
X#ifndef John_White_Colors
X	for (i=0; i<256; i++)
X		count[i] = 0;
X
X	for (temp_l = 0; temp_l < npix; temp_l++) {
X		if ((n=fgetc(fp)) == EOF) {
X			fprintf(stderr, "ibmcg4: too few pixels!\n");
X			exit(1);
X		}
X		count[n]++;
X	}
X
X	if (lseek(fp, -npix, 1) <= 0) {
X		fprintf(stderr, "ibmcg4: lseek funkiness!\n");
X		exit(1);
X	}
X
X	temp_l = 0;
X	for (i=0; temp_l < npix/3; i++)
X		temp_l += count[i];
X	colormax[0] = i;
X
X	while (temp_l < 2*npix/3)
X		temp_l += count[i++];
X	colormax[1] = i;
X
X	colormax[2] = 254;
X	colormax[3] = 255;
X#endif
X
X	setup_scr();
X	for (i=0; i<vpix; i++)
X		for (j=0; j<hpix; j++) {
X			if ((n=fgetc(fp)) == EOF) {
X				fprintf(stderr, "ibmcg4: too few pixels!\n");
X				exit(1);
X			}
X
X#ifndef John_White_Colors
X			if (n < colormax[0])
X				putpoint(i, j, 2);	/* Magenta	*/
X			else if (n < colormax[1])
X				putpoint(i, j, 1);	/* Cyan		*/
X			else if (n < colormax[2])
X				putpoint(i, j, 3);	/* White	*/
X			else
X				putpoint(i, j, 0);	/* Black	*/
X#else
X			putpoint(i, j, (n==255) ? 0 : /* Black */
X						   (n >127) ? 3 : /* White */
X						   (n&1) + 1);    /* Huh?  */
X#endif
X		}
X	getchar();
X}
X
Xsetup_scr()
X{
X#asm
X	xor		ax,ax	; set mode
X	mov		al,4	; 320x200 color
X	int		10h		; video_io (BIOS)
X
X	mov		ah,11	; set pallette
X	mov		bh,0	; background
X	mov		bl,0	; black
X	int		10h		; video_io (BIOS)
X
X	mov		ah,11	; set pallette
X	mov		bh,1	; pallette
X	mov		bl,1	; Cyan(1), Magenta(2), White(3)
X	int		10h		; video_io (BIOS)
X#
X}
X
Xputpoint(x, y, c)
Xint x,	/* [BP+4]	*/
X	y,	/* [BP+6]	*/
X	c;	/* [BP+8]	*/
X{
X#asm
X	mov		ah,12	; write dot
X	mov		al,[bp+8]
X	mov		dx,[bp+4]
X	mov		cx,[bp+6]
X	int		10h		; video_io
X#
X}
/*EOF
ls -l ibmcg4.c
sed 's/^X//' > colorprn.c << '/*EOF'
X#include <stdio.h>
X/*
X * colorprn [name] [outfile]
X * Display file name.pic created by compute on an
X * IBM Personal Computer Color Printer, in 16 colors.
X * Prompts for name if not given. Output goes to PRN: by default.
X */
X
X#define MAXNAMELEN 64 /* max filename length for MS-DOS */
X
X#ifndef FALSE
X#define FALSE 0
X#endif
X
X#ifndef TRUE
X#define TRUE 1
X#endif
X
X#ifndef EOF
X#define EOF (-1)
X#endif
X
X#define ISSUFFIX(s1, s2) !strcmp((s1), (s2)+strlen(s2)-strlen(s1))
X
X#define WHITE	0
X#define YELLOW	1
X#define MAGENTA	2
X#define CYAN	3
X#define	BLACK	4
X#define ORANGE	5
X#define GREEN	6
X#define VIOLET	7
X#define BROWN	8
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X	char name[MAXNAMELEN];
X	FILE *fp, *fo, *fopen();
X	int i, j, k, n, colormask;
X	double center_r,
X		   center_i,
X		   scale_r,
X		   scale_i;
X	int hpix, vpix;
X	char color[256];
X	long npix, count[256], temp_l;
X	char *obuff[9], *malloc();
X
X	/* get and open the file to print */
X	if (argc > 1)
X		if (ISSUFFIX(".pic", argv[1]))
X			strncpy(name, argv[1], MAXNAMELEN);
X		else {
X			strncpy(name, argv[1], MAXNAMELEN-4);
X			strcat(name, ".pic");
X		}
X	else {
X		printf("syntax: colorprn [name]\n");
X		printf("Name: ");
X		gets(name);
X	}
X	if (!ISSUFFIX(".pic", name))
X		strcat(name, ".pic");
X	while ((fp = fopen(name, "r")) == NULL) {
X		fprintf(stderr, "colorprn: cannot open %s\n", name);
X		printf("Name: ");
X		gets(name);
X		if (!ISSUFFIX(".pic", name))
X			strcat(name, ".pic");
X	}
X
X	/* snarf its parameters from its header */
X	if (fscanf(fp, "Centered at %lf+%lfi, scale %lf+%lfi, %dx%d\n\032",
X		&center_r, &center_i, &scale_r, &scale_i, &hpix, &vpix) != 6) {
X		fprintf(stderr, "colorprn: cannot parse header of %s\n", name);
X		exit(1);
X	}
X
X	/* set up the output file */
X	if (argc > 2) {
X		if ((fo = fopen(argv[2], "w")) == NULL) {
X			fprintf(stderr, "colorprn: cannot open %s\n", argv[2]);
X			exit(1);
X		}
X	} else
X		if ((fo = fopen("PRN:", "w")) == NULL) {
X			fprintf(stderr, "colorprn: cannot open PRN:\n");
X			exit(1);
X		}
X
X	/* number of pixels in the entire image */
X	npix = hpix*(long)vpix;
X
X	/* zero out frequency count buckets */
X	for (i=0; i<256; i++)
X		count[i] = 0;
X
X	/* collect a count of the frequency of occurrence of each byte value */
X	for (temp_l = 0; temp_l < npix; temp_l++) {
X		if ((n=fgetc(fp)) == EOF) {
X			fprintf(stderr, "colorprn: too few pixels!\n");
X			exit(1);
X		}
X		count[n]++;
X	}
X
X	/* rewind to the beginning of the image */
X	if (lseek(fp, -npix, 1) <= 0) {
X		fprintf(stderr, "colorprn: lseek funkiness!\n");
X		exit(1);
X	}
X
X	/* adaptively assign colors according to areas (from frequency count) */
X	temp_l = 0;
X	color[255] = BLACK;
X	for (i=254; temp_l < ((npix-count[255])/50); i--) {
X		color[i] = WHITE;
X		temp_l += count[i];
X	}
X	while (temp_l < ((npix-count[255])/20)) {
X		color[i] = YELLOW;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])/10)) {
X		color[i] = ORANGE;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])/8)) {
X		color[i] = MAGENTA;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])/6)) {
X		color[i] = GREEN;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])/4)) {
X		color[i] = CYAN;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])/3)) {
X		color[i] = VIOLET;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])/2)) {
X		color[i] = CYAN;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])*2/3)) {
X		color[i] = VIOLET;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])*3/4)) {
X		color[i] = CYAN;
X		temp_l += count[i--];
X	}
X	while (temp_l < ((npix-count[255])*5/6)) {
X		color[i] = VIOLET;
X		temp_l += count[i--];
X	}
X	while (i >= 0)
X		color[i--] = BROWN;
X
X	/* allocate color mapping and print line generation buffers */
X	for (i=0; i<9; i++)
X		if ((obuff[i] = malloc(hpix)) == NULL) {
X			fprintf(stderr, "colorprn: too little memory for obuff\n");
X			exit(1);
X		}
X
X	/* set printer aspect ratio to 1:1, with unidirectional printing */
X	fprintf(fo, "\033n\001\033U");
X
X	/* for each printer row (8 pix vertically) */
X	for (i=0; i<vpix; i+=8) {
X		/* zero out obuff */
X		for (j=0; j<9; j++)
X			for (k=0; k<hpix; k++)
X				obuff[j][k] = 0;
X
X		/* read in the pixel/color map */
X		for (j=0; j<8; j++) {
X			colormask = 128 >> j;
X			for (k=0; k<hpix; k++) {
X				if ((n=fgetc(fp)) == EOF) {
X					fprintf(stderr, "colorprn: too few pixels!\n");
X					exit(1);
X				}
X				obuff[color[n]][k] = obuff[color[n]][k] | colormask;
X			}
X		}
X
X		/* fold the overstruck colors onto their components */
X		for (k=0; k<hpix; k++) {
X			obuff[YELLOW][k] |= obuff[ORANGE][k] | obuff[GREEN][k];
X			obuff[MAGENTA][k] |= obuff[ORANGE][k]| obuff[VIOLET][k] | obuff[BROWN][k];
X			obuff[CYAN][k] |= obuff[GREEN][k] | obuff[VIOLET][k];
X			obuff[BLACK][k] |= obuff[BROWN][k];
X		}
X		/* scan each of the four colors; if any nonzeros are found write */
X		for (k=0; k<hpix; k++)
X			if (obuff[YELLOW][k]) {
X				fprintf(fo, "\033y\033L%c%c", hpix&255, hpix>>8);
X				if (fwrite(obuff[YELLOW], 1, hpix, fo) != hpix) {
X					fprintf(stderr, "colorprn: write error to %s %s\n",
X						(argc > 2) ? argv[2] :
X									 "PRN:",
X						(argc > 2) ? ", disk full?" :
X									 ", printer fault?");
X					exit(1);
X				}
X				fprintf(fo, "%c", 141);
X				break;
X			}
X		for (k=0; k<hpix; k++)
X			if (obuff[MAGENTA][k]) {
X				fprintf(fo, "\033m\033L%c%c", hpix&255, hpix>>8);
X				if (fwrite(obuff[MAGENTA], 1, hpix, fo) != hpix) {
X					fprintf(stderr, "colorprn: write error to %s %s\n",
X						(argc > 2) ? argv[2] :
X									 "PRN:",
X						(argc > 2) ? ", disk full?" :
X									 ", printer fault?");
X					exit(1);
X				}
X				fprintf(fo, "%c", 141);
X				break;
X			}
X		for (k=0; k<hpix; k++)
X			if (obuff[CYAN][k]) {
X				fprintf(fo, "\033c\033L%c%c", hpix&255, hpix>>8);
X				if (fwrite(obuff[CYAN], 1, hpix, fo) != hpix) {
X					fprintf(stderr, "colorprn: write error to %s %s\n",
X						(argc > 2) ? argv[2] :
X									 "PRN:",
X						(argc > 2) ? ", disk full?" :
X									 ", printer fault?");
X					exit(1);
X				}
X				fprintf(fo, "%c", 141);
X				break;
X			}
X		for (k=0; k<hpix; k++)
X			if (obuff[BLACK][k]) {
X				fprintf(fo, "\033b\033L%c%c", hpix&255, hpix>>8);
X				if (fwrite(obuff[BLACK], 1, hpix, fo) != hpix) {
X					fprintf(stderr, "colorprn: write error to %s %s\n",
X						(argc > 2) ? argv[2] :
X									 "PRN:",
X						(argc > 2) ? ", disk full?" :
X									 ", printer fault?");
X					exit(1);
X				}
X				fprintf(fo, "%c", 141);
X				break;
X			}
X
X		/* and advance to a new line -- 14/144 inch for graphics */
X		fprintf(fo, "\033J%c", 14);
X	}
X	fclose(fo);
X}
/*EOF
ls -l colorprn.c
exit
-- 

"Hypocrisy is the vaseline of social intercourse." (Who said that?)

Bennett Todd -- Duke Computation Center, Durham, NC 27706-7756; (919) 684-3695
UUCP: ...{decvax,seismo,philabs,ihnp4,akgua}!mcnc!ecsvax!duccpc!bet