4.4BSD/usr/src/contrib/dipress/src/bin/dipress/bitmap.c

Compare this file to the similar file:
Show the results in this format:

/*
 * Copyright (c) 1984, 1985, 1986 Xerox Corp.
 *
 *  bitmap - routines that help build a bitmap of a graphical image
 *
 *  These are primarily used to implement all of the drawing primitives
 *  (except for lines)
 *
 *  HISTORY
 * 13-Aug-86  Lee Moore (lee) at Xerox Webster Research Center
 *	Rather than outputing an error message for devices that can't print
 *	big pixel arrays, the code now breaks up large pixel arrays into
 *	smaller ones.
 *
 * 04-Mar-86  Lee Moore (lee) at Xerox Webster Research Center
 *	Put in code to check the output device type.  Right now, if
 *	a bitmap is allocated that won't print then a warning message
 *	is produced.
 *
 *  28-aug-85 John Mellor-Crummey
 *	added flush_bitmap which is used instead
 *	of print_bitmap if current page is not outputted
 *
 *  17-jun-85  ed flint
 *	bitmap width(bm_width) must be multiple of 32
 *	bits for print services 12 (?)
 *
 *
 */

# include <stdio.h>
# include "iptokens.h"
# include "literal.h"
# include "operator.h"

# include "defs.h"
# include "externs.h"

# define    local	static
# define    No		0
# define    Yes		1

extern int drawidth;
extern double drawscale;

char *malloc();

local int minx;
local int miny;
local int maxx;
local int maxy;
local int bm_width;		/* in real bytes */
local int bm_size;
local unsigned char *bitmap;
local char  bm_active = No;

# define    scale_x(x)		x = (double)x * drawscale
# define    scale_y(y)		y = (double)y * drawscale

/*
 *  new_bitmap(x1, y1, x2, y2) - prepare for a new bitmap, the extreme x and y
 *				 values are x1, y1, x2, and y2.
 */

new_bitmap(stroke, x1, y1, x2, y2)

int stroke, x1, y1, x2, y2;

{
    int new_size;
    register int temp;

#ifdef DEBUG
    fprintf(stderr, "new_bitmap(%d, %d, %d, %d, %d)\n", stroke,x1, y1, x2, y2);
#endif
    drawidth = stroke * drawscale;
    scale_x(x1);
    scale_y(y1);
    scale_x(x2);
    scale_y(y2);
#ifdef DEBUG
    fprintf(stderr, "after scaling: width %d: %d, %d and %d, %d\n", drawidth, x1, y1, x2, y2);
#endif

    /* insure that x1, y1 is the lower left */
    if (x1 > x2)
    {
#ifdef DEBUG
	fprintf(stderr, "exchanging pairs ... ");
#endif
	temp = x1;	/* exchange x1 and x2 */
	x1   = x2;
	x2   = temp;
	temp = y1;	/* exchange y1 and y2 */
	y1   = y2;
	y2   = temp;
#ifdef DEBUG
	fprintf(stderr, "now %d, %d and %d, %d\n", x1, y1, x2, y2);
#endif
    }

    /* adjust the extremes to allow for pen thickness */
    temp = (drawidth + 1) / 2;
    x1 -= temp;
    y1 -= temp;
    x2 += temp;
    y2 += temp;

    if (!bm_active || !(x1 >= minx && y1 >= miny && x2 <= maxx && y2 <= maxy))
    {
	/* we need to set up a new map */
	/* but first, print the old one if it is still active */
#ifdef DEBUG
	fprintf(stderr, "setting up new map, bm_active is %d\n", bm_active);
#endif
	print_bitmap();

	minx = x1;
	miny = y1;
	maxx = x2;
	maxy = y2;

	bm_width = (y2 - y1 + 7) / 8;

	/* print services 12 (?) wants packed pixel vectors to produce each */
	/* scan line as a mutliple of 32 bits, this is backward compatible  */
	/* with previous versions of services				    */
	/* (the previous version of bitmap produced 16 bit multiples which  */
	/* will NOT work with services 12 (?) and beyond)		    */

	if ( bm_width%4 != 0 )
	{
	    bm_width= bm_width + (4 - bm_width%4);
	}

	new_size = (x2 - x1) * bm_width;

	if (new_size > bm_size)
	{
	    /* need to allocate a larger area for the bitmap */
	    if (bitmap != NULL)
		free((char *)bitmap);

	    /* check to see that this bitmap is printable */
	    if (new_size + 4 >= (1L << 16))
	    {
#ifdef notdef
		if (IPDeviceType == Xerox8044_Services8)
		    fprintf(stderr, "dipress: bitmap bigger than 2^16-1 -- won't print on a Xerox 8044 under services 8.0\n");
		else if (IPDeviceType == Xerox8044_Services9)
		    fprintf(stderr, "dipress: bitmap of %d is bigger than 2^16-1 -- won't print on a Xerox 8044 under services 9.0\n", new_size);
		else if (IPDeviceType == Xerox8044_Services10)
		    fprintf(stderr, "dipress: bitmap of %d is bigger than 2^16-1 -- won't print on a Xerox 8044 under services 10.0\n", new_size);
#endif
	    }

	    bitmap = (unsigned char *) malloc( (unsigned)(new_size) );
	    bm_size = new_size;
	}
#ifdef DEBUG
	fprintf(stderr, "bm_width %d, bm_size %d\n", bm_width, bm_size);
#endif
    
	bzero((char *)bitmap, bm_size);
    }
}

set_pixel(x, y)

int x;
int y;

{
    int mask;
    int half_drawidth;
    register int i;
    register int ybit, temp;
    register unsigned char *ptr;

    scale_x(x);
    scale_y(y);

    bm_active = Yes;

#ifdef DEBUG
    if (x < minx || x > maxx || y < miny || y > maxy)
    {
	fprintf(stderr, "point off map: (%d, %d)\n", x, y);
	return;
    }
#endif
    x -= minx;
    y  = maxy - y;	/* yes, it works */
    half_drawidth = drawidth >> 1;

    /* Remember the bitmap is built in increasing y */

    /* draw the "x" line vertically */
    mask = 0x80 >> (y & 007);
    ptr = (x - half_drawidth) * bm_width + (y >> 3) + bitmap;
    for (i = 0; i < drawidth; i++, ptr += bm_width)
    {
	*ptr |= mask;
    }

    /* draw the "y" line horizontally */
    y -= half_drawidth;
    ptr = (x * bm_width) + (y >> 3) + bitmap;
    ybit = y & 007;
    temp = ybit + drawidth;
    if (temp < 8)
    {
	/* special case -- less than one byte */
	*ptr |= (0xff >> ybit) ^ (0xff >> temp);
    }
    else
    {
	*ptr |= (0xff >> ybit);
	for (i = drawidth - 8 + ybit; i > 8; i -= 8)
	{
	    *++ptr |= 0xff;
	}
	*++ptr |= ~(0xff >> i);
    }
}

flush_bitmap()
{
	bm_active = No;
}

print_bitmap()

{
    int	bytesPerScanLine;
#ifdef DEBUG2
    int x;
    int y;
    int i;
    char *ptr;
#endif

    if (!bm_active)
    {
	/* don't bother */
	return;
    }

#ifdef DEBUG2
    /* debugging version for now */
    ptr = bitmap;
    for (x = minx; x <= maxx; x++)
    {
	for (y = miny; y <= maxy; y += 8, ptr++)
	{
	    for (i = 0x80; i != 0; i >>= 1)
	    {
		if (*ptr & i)
		{
		    putchar('*');
		}
		else
		{
		    putchar(' ');
		}
	    }
	}
	putchar('\n');
    }
#endif

    bytesPerScanLine = bm_width;

    /* inside a dosavesimplebody to preserve transform */
    AppendOp(OP_dosavesimplebody);
    AppendOp(OP_beginBody);

    /* set the transform to the right scale and position */
    /* transform must scale back to micas and position bitmap */
    AppendInteger((long) minx);
    AppendInteger((long)((int)(11 * INCH * drawscale) - maxy));
    AppendOp(OP_translate);
    AppendInteger(5L);
    AppendOp(OP_scale);
    AppendOp(OP_concat);
    AppendOp(OP_concatt);
  
    switch (IPDeviceType) {
	case Xerox8044_Services8:
	case Xerox8044_Services9:
	case Xerox8044_Services10:
	    {
	    unsigned char *bitmapP;
	    int	numberOfScanLines,
		pixelsPerScanLine,
		scanLinesPerStripe,
		bytesPerStripe,
		numberOfFullStripes,
		scanLinesRemaining,
		n;
	
	    numberOfScanLines = maxx - minx;
	    pixelsPerScanLine = bytesPerScanLine << 3;
	    scanLinesPerStripe = (64*1024 - 4 - 16)/bytesPerScanLine;
	    bytesPerStripe = scanLinesPerStripe * bytesPerScanLine;
	    numberOfFullStripes = numberOfScanLines / scanLinesPerStripe;
	    scanLinesRemaining = numberOfScanLines % scanLinesPerStripe;
	
	    for (n = 0, bitmapP = bitmap; n < numberOfFullStripes; n++, bitmapP += bytesPerStripe) {
	    	WritePixelArray(bitmapP, scanLinesPerStripe, pixelsPerScanLine);
		/*
		 * position the next stripe.  I tried going a setXRel followed
		 * by a trans but this cause strange things to happen on
		 * an 8044 running services 9.0
		 */
		AppendInteger((long)scanLinesPerStripe);
		AppendInteger(0L);
		AppendOp(OP_translate);
		AppendOp(OP_concatt);
	    }

    	    if (scanLinesRemaining != 0)
		WritePixelArray(bitmapP, scanLinesRemaining, pixelsPerScanLine);
    
	    }
	    break;

	case Xerox9700_V10:
	default:
	    WritePixelArray(bitmap, maxx - minx, bytesPerScanLine << 3);
    }

    AppendOp(OP_endBody);

    /* no longer active, now is it? */
    bm_active = No;
}

static
WritePixelArray(pixelArray, xPixels, yPixels)
unsigned char *pixelArray;
int xPixels, yPixels;
{
    int bytesPerScanLine,
	pixelArraySize;		/* in bytes */

    bytesPerScanLine = (yPixels + 7)/8;
    pixelArraySize = xPixels * bytesPerScanLine;

    /* build the pixel array */
    AppendInteger((long) xPixels);	/* xPixels */
    AppendInteger((long) yPixels);	/* yPixels */
    AppendInteger(1L);			/* samplesPerPixel */
    AppendInteger(1L);			/* maxSampleValue */
    AppendInteger(1L);			/* samplesInterleaved */
    Translate(0.0, 0.0);		/* (null) transform */

    AppendPPVector(pixelArraySize, 1, yPixels, pixelArray);

    /* make the pixel array */
    AppendOp(OP_makepixelarray);

    /* mask it */
    AppendOp(OP_maskpixel);
}

/*-----------------------------------------------------------------------------
 *	Gremlin additions:  This should be in a separate file.
 *---------------------------------------------------------------------------*/

/*-----------------------------------------------------------------------------
 *	drawPolygon(buffer, WantBorder)
 *---------------------------------------------------------------------------*/
#include <ctype.h>
#include <vfont.h>
#include <sys/types.h>
#include <sys/file.h>
#include <sys/stat.h>
#include <errno.h>

static StippleDesFD = -1;
static StippleChoice = -1;
static struct {
	int fileDes;
	int member;
	int maxSize;
	struct {
		char prelude[4];
		short bits[16];
	} ppv;		/* In Services <= 10  max sampled black is 
					at most 16 x 16 */
	struct header header;
	struct dispatch dispatch;
} curStipple;

iPdrawPolygon(s, cmd)
char *s;
char cmd;
{
	int x[maxPointsInPolygon],y[maxPointsInPolygon]; 
	int stippleMember, strokeWidth = 254;
	extern int hor_pos, ver_pos, lineThickness;
	int xi,yi,i,j,numPoints;
	float temp1,temp2,temp3,t,dis;
	float euclidDist();
	char more;

	/* skip all leading white space */
	while(white(*s)) s++;		
	if(!isdigit(*s)) return; 

	if(readNumber(&s, &stippleMember) == NULL)
		return;

	/* read in the x y pairs of points for the polygon */
	for(numPoints = 0; numPoints < maxPointsInPolygon;) {
		x[numPoints] = hor_pos;
		more = readNumber(&s, &xi);
		y[numPoints] = (11 * INCH) - ver_pos;
		more *= readNumber(&s, &yi);
		hor_pos += xi;
		ver_pos += yi;
		numPoints++;
		if (more == 0) break;
	}
	getStippleMember(stippleMember);
	/* Doit */
	if (numPoints < 2)
		return;
	Op(dosavesimplebody);
	Op(beginBody);

	/* First, draw outline, if desired */
	if (cmd == drawPolygon) {
		AppendRational((long) strokeWidth, 10);
		AppendInteger((long) I_strokeWidth);
		Op(iset);
		Moveto((double)x[0], (double)y[0]);
		for(j = 1; j < numPoints; j++)
			Lineto((double)x[j], (double)y[j]);
		Lineto((double)x[0], (double)y[0]);
		Op(maskstroke);
	}
	/* Make Sampled Color */
	AppendInteger(16L);			/* xPixels */
	AppendInteger(16L);			/* yPixels */
	AppendInteger(1L);			/* samplesPerPixel */
	AppendInteger(1L);			/* maxSampleValue */
	AppendInteger(1L);			/* samplesInterleaved */
	/*AppendRational((long) 2*strokeWidth, 10); fails in serv < 11 */
	AppendRational((long) strokeWidth, 30); /* 1 bit per 300th inch */
	Op(scale);				/* transform for color */

			    /* spew out the packed pixel vector */
	append_Sequence(sequencePackedPixelVector, 32 + 4,
					(char *) &curStipple.ppv);
	Op(makepixelarray); /* make the pixel array */
	AppendInteger(4L);
	Op(iget);	    /* current transformation */
	AppendInteger(1L);
	Op(makesampledblack);
	AppendInteger(13L);
	Op(iset);	    /* Set Color */


	/* Print Polygon */
	Moveto((double)x[0], (double)y[0]);
	for(j = 1; j < numPoints; j++)
		Lineto((double)x[j], (double)y[j]);
	Lineto((double)x[0], (double)y[0]);
	AppendInteger(1L);
	Op(makeoutline);
	Op(maskfill);
	AppendInteger(1L); Op(setgray); /* Restore normal black */
	Op(endBody);
}
newStippleFamily(new)
{
	char stippleFilename[80];

	if (new == stippleFamily)
		return;
	if (curStipple.fileDes > 0)
		close(curStipple.fileDes);
	stippleFamily = new;

	(void) sprintf(stippleFilename, "/usr/lib/vfont/%s.0",
				stipTypeName[new]);
	if ((curStipple.fileDes = open(stippleFilename, O_RDONLY, 0)) < 0) {
		(void) sprintf(stippleFilename, "%s/dev%s/%s.0",
				fontdirectory, devicename, stipTypeName[new]);
		if ((curStipple.fileDes
				= open(stippleFilename, O_RDONLY, 0)) < 0) {
			reportError(QUIT,
			  "can't open file %s for device characteristics (%s)",
			    stippleFilename, sys_errlist[errno]);
		}
	}
	read(curStipple.fileDes, (char *)&(curStipple.header),
					    sizeof (curStipple.header));
	curStipple.member = -1;
	getStippleMember(0);
			    /* build the packed pixel vector */
	curStipple.ppv.prelude[0] = 0;
	curStipple.ppv.prelude[1] = 1;
	curStipple.ppv.prelude[2] = (char)(0);		/* high order byte */ 
	curStipple.ppv.prelude[3] = (char) (16);	/* low  order byte */
}

int showStip = 0;
getStippleMember(member)
{
	register struct dispatch *dp = & curStipple.dispatch;
	register int i;
	long offset;
	short bits[32];

	if (curStipple.member == member)
		return;
	offset = sizeof(struct header) + (member*sizeof(*dp));
	lseek(curStipple.fileDes, offset, 0);
	read(curStipple.fileDes, (char *)dp, sizeof (*dp));
	if (dp->nbytes == 0) {
		if (member == 0)  return;
		reportError(CONTINUE,
			"Stipple Family %s doesn't have member %d",
			stipTypeName[stippleFamily], member);
		curStipple.member = 0;
		return;
	}
	if ((dp->up + dp->down) != 32 || ((dp->left + dp->right) != 32)) {
		if (member == 0)  return;
		reportError(CONTINUE,
			"Stipple Family %s member %d is not 32x32\n",
			stipTypeName[stippleFamily], member);
		curStipple.member = 0;
		return;
	}
	offset = sizeof(struct header) + (256*sizeof(*dp)) + dp->addr;
	lseek(curStipple.fileDes, offset, 0);
	read(curStipple.fileDes, (char *)bits, sizeof (bits));
	if (showStip)
		    fprintf(stderr, "Stipple Family %s, member %d\n",
					stipTypeName[stippleFamily], member);
	for (i = 0; i < 16; i++) {
		curStipple.ppv.bits[i] = bits[i+i];
		if (showStip) {
			register int j;
			register int mask = bits[i+i];
			for (j = 0; j < 16; j++) {
				if (mask & 1)
					putc('*', stderr);
				else
					putc(' ', stderr);
				mask >>= 1;
			}
			putc('\n', stderr);
		}
	}
}