+ARCHIVE+ add.c         1012  3/15/1991 20:25:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		addimage		Add 2 images
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl twoimagefcts_(imgdes *,imgdes *,imgdes *,void (_cdecl *)());

/* Add 'count' bytes in sbuff to obuff and store result in dbuff */
static void _cdecl addtwo(UCHAR *sbuff, UCHAR *obuff, UCHAR *dbuff, int cols)
{
	int ch;
	while(cols--) {
		ch = *sbuff++ + *obuff++;
		*dbuff++ = (UCHAR)((ch>255) ? 255 : ch); /* Limit values to <= 255 */
		}
}

/* Add 2 images. Returns NO_ERROR, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl addimage(srcimg, oprimg, desimg)
imgdes *srcimg;			/* Image 1 */
imgdes *oprimg;			/* Image 2 */
imgdes *desimg;			/* Store result image here */
{
	return(twoimagefcts_(srcimg, oprimg, desimg,	addtwo));
}
+ARCHIVE+ and.c          930  3/16/1991  5:19:04
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		andimage		AND 2 images
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl twoimagefcts_(imgdes *,imgdes *,imgdes *,void (_cdecl *)());

/* AND 'count' bytes in sbuff with obuff and store result in dbuff */
static void _cdecl andtwo(UCHAR *sbuff, UCHAR *obuff, UCHAR *dbuff, int cols)
{
	while(cols--)
		*dbuff++ = *sbuff++ & *obuff++;
}

/* AND 2 images. Returns NO_ERROR, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl andimage(srcimg, oprimg, desimg)
imgdes *srcimg;			/* Image 1 */
imgdes *oprimg;			/* Image 2 */
imgdes *desimg;			/* Store result image here */
{
	return(twoimagefcts_(srcimg, oprimg, desimg, andtwo));
}
+ARCHIVE+ blur.c         827  3/16/1991  4:59:10
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		blur			Blur image by averaging 9 adjacent pixels
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern void _cdecl matrix_avg_(UCHAR huge *,char *,int,int,int *);
extern int _cdecl matrixall_(imgdes *,imgdes *,void (_cdecl *)(),int *);

/* Blur image by averaging 9 adjacent pixels. Returns NO_ERROR, BAD_RANGE,
	BAD_MEM (not enough convential memory), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR,
	or CM_ERR. Range error also if image area is less than 3x3 pixels.
*/
int _cdecl blur(imgdes *srcimg, imgdes *desimg)
{
	int dummy;

	return(matrixall_(srcimg, desimg, matrix_avg_, &dummy));
}

+ARCHIVE+ blurt.c        947  3/16/1991  4:59:10
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		blurthresh		Blur image by averaging 9 adjacent pixels WITH difference
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern void _cdecl matrix_dif_(UCHAR *,UCHAR *,int,int,int *);
extern int _cdecl matrixall_(imgdes *,imgdes *,void (_cdecl *)(),int *);

/* Blur image by averaging 9 adjacent pixels WITH difference. Returns
	NO_ERROR, BAD_RANGE, BAD_MEM (not enough convential memory), NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR. Range error also if image area
	is less than 3x3 pixels.
*/
int _cdecl blurthresh(int diff, imgdes *srcimg, imgdes *desimg)
/* EQUATION: *des = (abs(*scr - avg))>diff) ? *src : avg; */
{
	if(outrange(0, diff, 255))
		return(BAD_FAC);
	return(matrixall_(srcimg, desimg, matrix_dif_, &diff));
}
+ARCHIVE+ britmid.c     1660  3/15/1991 17:49:04
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		brightenmidrange		Raise brightness for printing
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Raise brightness of an image area for printing. Returns NO_ERROR,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl brightenmidrange(imgdes *srcimg, imgdes *desimg)
{
	static UCHAR BrtTab[] = {
		0,0,0,0,0,1,1,1,2,2,2,2,4,5,6,7,
		8,12,16,20,24,26,28,30,32,34,36,38,40,44,48,52,
		57,61,65,69,73,75,77,79,81,83,84,86,87,89,91,93,
		95,97,99,101,103,105,107,109,111,113,115,117,119,121,123,125,
		127,130,132,134,136,138,140,142,144,146,148,150,152,154,156,158,
		160,162,163,164,165,166,167,168,169,170,172,174,176,178,180,182,
		184,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,
		201,202,203,204,205,206,207,208,209,210,211,212,213,215,216,217,
		218,218,219,219,220,220,221,221,222,222,223,223,224,224,225,225,
		226,226,227,227,228,229,230,230,231,231,231,232,233,233,234,234,
		235,235,235,236,236,237,237,238,238,238,239,239,239,240,240,240,
		241,241,241,242,242,242,243,243,243,244,244,244,245,245,245,246,
		246,246,247,247,247,247,248,248,248,248,249,249,249,249,250,250,
		250,250,250,251,251,251,251,251,251,252,252,252,252,252,253,253,
		253,253,254,254,254,254,254,255,255,255,255,255,255,255,255,255,
		255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255
		};
	return(table_mod_(BrtTab, srcimg, desimg));
}
+ARCHIVE+ calcavg.c     1528  3/16/1991  5:21:30
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		calcavglevel	Return the average gray level of an area
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);

/* Return the average gray level of an area (0 - 255) or BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl calcavglevel(imgdes *srcimg)
{
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	long sum=0, pixels;
	int j, errcode=NO_ERROR, yctr, rows, cols, handle;

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	yctr = srcimg->sty;
	cols = srcimg->endx - srcimg->stx + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	pixels = rows * (long)cols;
	/* Assign handle, getrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if((errcode=getrow(Hbuff_, handle, srcimg->stx, yctr++, cols,
				srcimg->iwidth)) != NO_ERROR)
				break;
			for(j=0; j<cols; j++)
				sum += Hbuff_[j];
			}
		}
	cmclose_(srcimg, handle);		/* Close CM handle */
	return((errcode==NO_ERROR) ? ((int)(sum/pixels)) : errcode);
}
+ARCHIVE+ calchist.c    1605  3/16/1991  5:21:30
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		calchisto		Perform histogram on section of image
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);

/* Perform histogram on section of image. Fill table with values. Returns
	NO_ERROR, BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl calchisto(long *histab, imgdes *srcimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int errcode=NO_ERROR, j, rows, cols, yctr, handle;
	UCHAR *buff=&Hbuff_[4048];

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	yctr = srcimg->sty;
	cols = srcimg->endx - srcimg->stx + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	memset_(histab, 0, 4*256);	/* Zero bins array */
	/* Assign handle, getrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if((errcode=getrow(buff, handle, srcimg->stx, yctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			for(j=0; j<cols; j++)
				histab[buff[j]]++;
			}
		}
	cmclose_(srcimg, handle);	/* Close any CM handles */
	return(errcode);
}
+ARCHIVE+ change.c       821  3/15/1991 17:49:04
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		changebright		Change brightness -255 to 255
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Change brightness of an image area -255 to 255. Returns NO_ERROR,
	BAD_FAC, BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl changebright(int value, imgdes *srcimg, imgdes *desimg)
{
	int ch, j;
	UCHAR tab[256];

	if(outrange(-255, value, 255))
		return(BAD_FAC);
	for(ch=0; ch<256; ch++) {
		if((j=ch+value) < 0)
			j = 0;
		if(j > 255)
			j = 255;
		tab[ch] = (UCHAR)j;
		}
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ colproc.c    14528  5/24/1991 18:20:06
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		hsv2rgb				Convert an HSV palette to an RGB palette
		rgb2hsv				Convert an RGB palette to an HSV palette
		preprocessimage	Prepare a color image for image processing
		postprocessimage	Modify a color image based on the original palette
		matchimagepal
*/

#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>
#include <dos.h>
#include <fcntl.h>
#include <sys\stat.h>

static imgdes Colcopy;	/* Copy of original image */

extern UCHAR Hbuff_[];
void _cdecl hfree(void far *);
extern void _cdecl cmclose_(imgdes *,int);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);
static int near _pascal calchue(int,int,int,int);
static void near _pascal maxmin(int *,int *,int,int,int);
static void near _pascal hsv2rgbtrip(int,int,int,int *,int *,int *);
static int near _pascal make_copy(imgdes *,imgdes *);
extern int _pascal find_palno_(int,int,int,UCHAR *,int);

/* Convert an HSV palette to an RGB palette. Convert count bytes.
	Table values range 0 - 255.
*/
void _cdecl hsv2rgb(UCHAR *hsvpal, UCHAR *rgbpal, int count)
{
	int j, red, grn, blu, shue, sat, intens, min;

	count /= 3;
	for(j=0; j<count; j++) {
		shue   = *hsvpal++;
		sat    = *hsvpal++;
		intens = *hsvpal++;

		shue = (int)((360 * (long)shue) >> 8); /* Rescale hue to degrees 0-358 */
		if(sat == 0) {		/* No color => just grays */
			red = grn = blu = intens;
			}
		else {
			min = (int)((255 * (long)intens - (intens * (long)sat)) / 255);
			if(shue <= 120) {		/* shue between 0 and 120 => red to grn */
				blu = min;			/* => blu is min */
			 	if(shue <= 60) {	/* => red is max */
					red = intens;
					grn = min + shue * (intens - min) / (120 - shue);
					}
				else {	/* shue between 60 and 120 => grn is max */
					grn = intens;
					red = min + (120 - shue) * (intens - min) / shue;
					}
				}
			else if(shue <= 240) {	/* shue between 120 and 240 => grn to blu */
				red = min;			/* => red is min */
				if(shue <= 180) {	/* => grn is max */
					grn = intens;
					blu = min + (shue - 120) * (intens - min) / (240 - shue);
					}
				else {	/* shue between 180 and 240 => blu is max */
					blu = intens;
					grn = min + (240 - shue) * (intens - min) / (shue - 120);
					}
				}
			else {	/* shue between 240 and 360 => blu to red */
				grn = min;			/* => grn is min */
				if(shue <= 300) {	/* => blu is max */
					blu = intens;
					red = min + (shue - 240) * (intens - min) / (360 - shue);
					}
				else {	/* shue between 300 and 360 => red is max */
					red = intens;
					blu = min + (360 - shue) * (intens - min) / (shue - 240);
					}
				}
			}
		*rgbpal++ = (UCHAR)red;
		*rgbpal++ = (UCHAR)grn;
		*rgbpal++ = (UCHAR)blu;
		}
}

/* Convert an RGB palette to an HSV palette. Convert count bytes.
	Table values range 0 - 255.
*/
void _cdecl rgb2hsv(UCHAR *rgbpal, UCHAR *hsvpal, int count)
{
	int hue, sat, red, grn, blu, col1, col2, angle;
	int j, max, min;

	count /= 3;
	for(j=0; j<count; j++) {
		red = *rgbpal++;
		grn = *rgbpal++;
		blu = *rgbpal++;
		/* Find maximum and minimum values */
		maxmin(&max, &min, red, grn, blu);
		/* Calc hue and saturation */
		if(max == min) {	/* R, G, B equal => no color */
			hue = 0; sat = 0;
			}
		else {			/* R, G, B unequal => color */
			if(min == blu) {
				angle =   0; col1 = grn; col2 = red;
				}
			else if(min == red) {
				angle = 120; col1 = blu; col2 = grn;
				}
			else { /* min==grn */
				angle = 240; col1 = red; col2 = blu;
				}
			hue = calchue(angle, col1, col2, min);
			sat = (int)(255 * (long)(max - min) / max); /* Scale to 255 */
			}
		*hsvpal++ = (UCHAR)hue;		/* Scale to 256 divisions */
		*hsvpal++ = (UCHAR)sat;
		*hsvpal++ = (UCHAR)max;		/* Intensity = max */
		}
}

/* Calculate hue */
static int near _pascal calchue(int angle, int col1, int col2, int min)
{
	int rcode;
	rcode = (int)((((long)angle<<8) +
		(120*256 * (long)(col1 - min)/(col1 + col2 - (min<<1)))) / 36);
	if((rcode % 10) >= 5)
		rcode += 10;
	return(rcode /= 10);
}

/* Find the maximum and minimum values of val1 - val3 */
static void near _pascal maxmin(int *max, int *min,
	int val1, int val2, int val3)
{
	if(val1 >= val2) {
		/* max = val1 or val3, min = val3 or val2 */
		if(val1 >= val3) {
			*max = val1;	/* 1 > 2 and 1 > 3 */
			*min = (val2 <= val3) ? val2 : val3;
			}
		else {	/* 1 > 2 and 3 > 1 => 3 > 1 > 2 */
			*max = val3;
			*min = val2;
			}
		}
	else {	/* val2 > val1 */
		/* max = val2 or val3, min = val1 or val3 */
		if(val2 >= val3) {
			*max = val2;	/* 2 > 1 and 2 > 3 */
			*min = (val1 <= val3) ? val1 : val3;
			}
		else {	/* 2 > 1 and 3 > 2 => 3 > 2 > 1 */
			*max = val3;
			*min = val1;
			}
		}
}

/* Prepare a color image for image processing by:
	1) Create an HSV palette for the image.
	2) Save a copy of the original image.
	3) Replace the color pixel values with grayscale values
	Returns NO_ERROR, BAD_RANGE (normal range error, plus if source image
	has no palette), BAD_MEM (not enough memory for copy of image area),
	NO_EMM, EMM_ERR, EMM_VER, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl preprocessimage(imgdes *srcimg, imgdes *desimg)
{
	UCHAR *intensity, *hsvtab;
	int rcode, j, count=srcimg->palsize;

	/* Make sure RGB palette exists */
	if(count == 0)
		return(BAD_RANGE);
	/* Alloc space for hsv and intensity tables */
	if((hsvtab=(UCHAR *)malloc(count+256)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	intensity = &hsvtab[count];
	/* Make HSV palette */
	rgb2hsv(srcimg->palette, hsvtab, count);
	for(j=2; j<count; j+=3)
		*intensity++ = hsvtab[j];
	/* Save a copy of the original image */
	if((rcode=make_copy(srcimg, &Colcopy)) == NO_ERROR) {
		if((rcode=usetable(&hsvtab[count], srcimg, desimg)) != NO_ERROR)
			freeimage(&Colcopy); /* If error in usetab(), free memory */
		}
	free(hsvtab);
	return(rcode);
}

/* Find space for and copy an image. Call freeimage() to release memory
	later. Image may end up in extended, expanded, or conventional memory.
	Return NO_ERROR, BAD_RANGE, or BAD_MEM (not enough XM, EM, or CM).
*/
static int near _pascal make_copy(imgdes *srcimg, imgdes *desimg)
{
	int width, length;

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	/* Set up image descriptor of copied image */
	copyimgdes(srcimg, desimg);
	/* Set width and length to use */
	width = srcimg->endx - srcimg->stx + 1;
	length = srcimg->endy - srcimg->sty + 1;
	/* Try to allocate copy buffer in EM first */
	if(emallocimage(desimg, width, length) != NO_ERROR) {
		/* Try XM next */
		if(xmallocimage(desimg, width, length) != NO_ERROR) {
			/* Finally, try CM */
			if(cmallocimage(desimg, width, length) != NO_ERROR)
				return(BAD_MEM);
			}
		}
	/* Make the copy */
	if(copyimage(srcimg, desimg) != NO_ERROR)
		return(BAD_MEM);
	return(NO_ERROR);		/* If successful, return NO_ERROR */
}

/* Converts a processed image to a color image. Image must first be
	processed with preprocessimage(). Sequence is:
	1) Create an HSV palette for the image.
	2)	For each pixel, get original intensity from image copy
	3) Use original intensity value to get hue and sat values
	4)	Get processed intensity value from processed image
	5) Use hue, sat, intensity values to generate RGB triplet
	6) Find closest RGB match with original palette
	7) Insert palette number into the processed image
	Returns NO_ERROR, BAD_RANGE, BAD_MEM (not enough CM), NO_EMM, EMM_ERR,
	NO_XMM, XMM_ERR, or CM_ERR.
	Uses 64K histogram to create color image.
*/
int _cdecl postprocessimage(imgdes *desimg)
{
	int (_cdecl *cgetrow)(void huge *,int,int,int,int,int);
	int (_cdecl *cputrow)(void huge *,int,int,int,int,int);
	int (_cdecl *dgetrow)(void huge *,int,int,int,int,int);
	int (_cdecl *dputrow)(void huge *,int,int,int,int,int);
	UCHAR *hsvtab, *buff1=Hbuff_, *buff2=&Hbuff_[4048];
	int rcode=BAD_MEM, j, row, chandle, dhandle, dyctr;
	int hue, sat, ch, red, grn, blu, count=Colcopy.palsize;
	long lbin;
	UCHAR *histab;
/*	UCHAR huge *histab; */

	/* Check to make sure copy of image exists and
		Make sure RGB palette already exists.
	*/
	if(checkrange_(&Colcopy) || count == 0) {
		rcode = BAD_RANGE;
		goto xit1;		/* Return BAD_MEM if area not allocated */
		}
	/* Alloc space for histab table */
	if((histab=(UCHAR far *)halloc(0x8000L, 2)) == NULL)
		goto xit1;		/* Return BAD_MEM if area not allocated */
	/* Alloc space for hsv table */
	if((hsvtab=(UCHAR *)malloc(count)) == NULL)
		goto xit2;		/* Return BAD_MEM if area not allocated */
	/* Zero all bins */
	memset_(histab, 0, 0x8000U);
	memset_(&histab[0x8000U], 0, 0x8000U);
	/* Create an HSV palette for the image */
	rgb2hsv(Colcopy.palette, hsvtab, count);
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(&Colcopy, &chandle, &cgetrow, &cputrow)) == NO_ERROR &&
		(rcode=assign_gprow_(desimg, &dhandle, &dgetrow, &dputrow)) == NO_ERROR) {
		dyctr = desimg->sty;
		/* For each pixel... */
		for(row=0; row<Colcopy.ilength; row++) {
			/* Get a row of original intensity data from the image copy */
			if((rcode=cgetrow(buff1, chandle, 0, row,
				Colcopy.iwidth, Colcopy.iwidth)) != NO_ERROR)
				break;
			/* Get a row of processed intensity data from the processed image */
			if((rcode=dgetrow(buff2, dhandle, desimg->stx, dyctr++,
				Colcopy.iwidth, desimg->iwidth)) != NO_ERROR)
				break;
			/* Mark the bins that need to be matched. Marking is based on
				combining original color numbers with new intensities.
			*/
			for(j=0; j<Colcopy.iwidth; j++)
				histab[(unsigned)((buff2[j] << 8) + buff1[j])] = 0xff;
			}
		/* Go through histogram and an assign a color number from the original
			palette to every non-zero bin.
		*/
		for(lbin=0; lbin<65536L; lbin++) {
			if(histab[lbin]) {
				/* Break down bin number into original color number and
					processed color value
				*/
				hue = hsvtab[ch=3*((UCHAR)lbin & 0xff)];
				sat = hsvtab[ch+1];
				/* Convert hue, sat, and new val into RGB triplet */
				hsv2rgbtrip(hue, sat, (int)(lbin >> 8), &red, &grn, &blu);
				histab[lbin] = (UCHAR)find_palno_(red, grn, blu,
					Colcopy.palette, Colcopy.palsize);
				}
			}
		/* Go thru processed image and replace values with color values */
		dyctr = desimg->sty;
		/* For each pixel... */
		for(row=0; row<Colcopy.ilength; row++) {
			/* Get a row of original intensity data from the image copy */
			if((rcode=cgetrow(buff1, chandle, 0, row,
				Colcopy.iwidth, Colcopy.iwidth)) != NO_ERROR)
				break;
			/* Get a row of processed intensity data from the processed image */
			if((rcode=dgetrow(buff2, dhandle, desimg->stx, dyctr,
				Colcopy.iwidth, desimg->iwidth)) != NO_ERROR)
				break;
			/* Use original and new intensities to calc bin values */
			for(j=0; j<Colcopy.iwidth; j++)
				buff1[j] = histab[(unsigned)((buff2[j] << 8) + buff1[j])];
			/* Copy the palette values into the processed image */
			if((rcode=dputrow(buff1, dhandle, desimg->stx, dyctr++,
				Colcopy.iwidth, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	cmclose_(&Colcopy, chandle);
	cmclose_(desimg, dhandle);
	free(hsvtab);
xit2:
	hfree((UCHAR far *)histab);
xit1:
	freeimage(&Colcopy);		/* Release copy of original image */
	return(rcode);
}

/* Converts a single HSV triplet to an RGB triplet */
static void near _pascal hsv2rgbtrip(int hue, int sat, int val,
	int *red, int *grn, int *blu)
{
	int min;

	hue = (int)((360 * (long)hue) >> 8); /* Rescale hue to degrees 0-358 */
	if(sat==0) {
		*red = *grn = *blu = val;
		}
	else {
		min = (int)((255 * (long)val - (val * (long)sat)) / 255);
		if(hue <= 120) {
			*blu = min;
		 	if(hue <= 60) {
				*red = val;
				*grn = min + hue * (val - min) / (120 - hue);
				}
			else {
				*grn = val;
				*red = min + (120 - hue) * (val - min) / hue;
				}
			}
		else if(hue <= 240) {
			*red = min;
			if(hue <= 180) {
				*grn = val;
				*blu = min + (hue - 120) * (val - min) / (240 - hue);
				}
			else {
				*blu = val;
				*grn = min + (240 - hue) * (val - min) / (hue - 120);
				}
			}
		else {			/* hue <= 360 */
			*grn = min;
			if(hue <= 300) {
				*blu = val;
				*red = min + (hue - 240) * (val - min) / (360 - hue);
				}
			else {
				*red = val;
				*blu = min + (int)((360 - hue) * (long)(val - min) / (hue - 240));
				}
			}
		}
}

/* Force an image to use an existing palette. Returns NO_ERROR, BAD_RANGE,
	BAD_MEM, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl matchimagepal(UCHAR *newpal, imgdes *image)
{
	int rcode, j, red, grn, blu;
	UCHAR *tmptab, *oldpal=image->palette;
	int pals = 256*3, siz = image->palsize;

	/* Make sure RGB palette already exists. */
	if(siz == 0)
		return(BAD_RANGE);
	/* Alloc space for new level table table */
	if((tmptab=(UCHAR *)calloc(256, sizeof(UCHAR))) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	/* Use the intensity as an index into old palette to get RGB values */
	for(j=0; j<siz/3; j++) {
		red = *oldpal++;
		grn = *oldpal++;
		blu = *oldpal++;
		/* Find best match of old palette to the new palette */
		tmptab[j] = (UCHAR)find_palno_(red, grn, blu, newpal, pals);
		}
	/* Replace old intensity levels */
	rcode = usetable(tmptab, image, image);
	free(tmptab);
	return(rcode);
}

#if 0
/* Rewritten in assembler for speed */
/* Search thru rgbtab, find match, and return color number */
int _pascal find_palno_(int red, int grn, int blu, UCHAR *rgbtab, int pals)
{
	int k, min_k, rerr, gerr, berr, err, minerr=768;
	/* Find best palette entry */
	for(k=0; k<pals/3; k++) {
		/* Find minimum error */
		if((rerr = red - *rgbtab++) < 0)
			rerr = -rerr;
		if((gerr = grn - *rgbtab++) < 0)
			gerr = -gerr;
		if((berr = blu - *rgbtab++) < 0)
			berr = -berr;
		if((err = rerr + gerr + berr) == 0) {
			min_k = k;
			break;
			}
		if(err < minerr) {
			min_k = k;
			minerr = err;
			}
		}
	return(min_k);
}
#endif

+ARCHIVE+ copy.c        2196  3/16/1991  5:22:56
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		copyimage
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());

/* Copy an area from one image to another. Returns NO_ERROR, BAD_RANGE
	(if buffer coords are out of range or dstx + cols > ewidth), NO_EMM,
	EMM_ERR, (if EMM error), NO_XMM, XMM_ERR (if XMM error), or CM_ERR.
*/
int _cdecl copyimage(imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int errcode, cols, rows, shandle, dhandle;
	int srow, drow, increm, dendy;

	/* Check range of start, end positions */
	if(checkrange_(srcimg) || checkrange_(desimg))
		return(BAD_RANGE);
	cols = srcimg->endx - srcimg->stx + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	if(desimg->stx + cols > desimg->iwidth ||
		desimg->sty + rows > desimg->ilength)
		return(BAD_RANGE);
	dendy = desimg->sty + rows - 1;
	if(srcimg->sty > desimg->sty) { /* Start copy at top of box */
		srow = srcimg->sty;
		drow = desimg->sty;
		increm = 1;
		}
	else {				/* Start copy at bottom of box */
		srow = srcimg->endy;
		drow = dendy;
		increm = -1;
		}
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) == NO_ERROR &&
		(errcode=assign_gprow_(desimg, &dhandle, &dummy, &putrow)) == NO_ERROR) {
		while(rows--) { /* Hbuff_ is used here as a temporary buffer */
			if((errcode=getrow(Hbuff_, shandle, srcimg->stx, srow,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			if((errcode=putrow(Hbuff_, dhandle, desimg->stx, drow,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			srow += increm;
			drow += increm;
			}
		}
	cmclose_(srcimg, shandle);		/* Close any open CM handles */
	cmclose_(desimg, dhandle);
	return(errcode);
}
+ARCHIVE+ cover.c       1173  3/16/1991  4:59:10
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		cover		Cover SOURCE with OPERATOR
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

static int Threshold;
extern int _cdecl twoimagefcts_(imgdes *,imgdes *,imgdes *,void (_cdecl *)());

/* Cover 'count' bytes in sbuff with obuff and store result in sbuff */
static void _cdecl covertwo(UCHAR *sbuff, UCHAR *obuff, UCHAR *dbuff, int cols)
{
	while(cols--) {
		*dbuff = (*obuff > (UCHAR)Threshold) ? *obuff : *sbuff;
		sbuff++; obuff++; dbuff++;
		}
}

/* Cover SOURCE with OPERATOR image. Returns NO_ERROR, BAD_FAC, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl cover(thres, srcimg, oprimg, desimg)
int thres;					/* Threshold value */
imgdes *srcimg;			/* Image 1 */
imgdes *oprimg;			/* Image 2 */
imgdes *desimg;			/* Store result image here */
{
	if(outrange(0, thres, 255))
		return(BAD_FAC);
	Threshold = thres;
	return(twoimagefcts_(srcimg, oprimg, desimg, covertwo));
}
+ARCHIVE+ divpic.c       680  3/15/1991 17:54:10
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		divide		Divide by factor
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Divide by a factor. Returns NO_ERROR, BAD_RANGE, NO_EMM, EMM_ERR,
	NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl divide(int value, imgdes *srcimg, imgdes *desimg)
{
	int ch;
	UCHAR tab[256];

	if(value < 1)
		return(BAD_FAC);
	for(ch=0; ch<256; ch++)
		tab[ch] = (UCHAR)(ch / value);
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ emsc.c        3002  3/15/1991 17:54:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		emsaveimage		Save the image buffer area in expanded memory
		emgetimage		Retrieve the image buffer area from expanded memory
*/

#include <stdio.h>
#include <vicdefs.h>		/* Standard header files for library */
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl checkrange_(imgdes *);

/* Save the image buffer area in conventional memory in expanded memory.
	Returns EM handle and NO_ERROR, BAD_RANGE, NO_EMM, or EMM_ERR.
	Returns BAD_RANGE if source is not in CM!
*/
int _cdecl emsaveimage(int *handle, imgdes *srcimg)
{
	int rcode, cols, rows, yctr=0;
	int pages, ppowned;
	long saddr, pels; /* Pixels in an image area = cols*rows */
	UCHAR huge *src;	/* Pointer into image buffer */

	/* Check range of start, end positions and make sure source is CM */
	if(checkrange_(srcimg) || srcimg->ibuff == NULL)
		return(BAD_RANGE);
	/* Calc how much space we need */
	cols = srcimg->endx - srcimg->stx + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	pels = rows * (long)cols;		/* No. of pixels in the image area */
	pages = (int)(pels >> 14);
	if(pels&0x3fff)  pages++;
	/* If handle doesn't own enough EM, try to allocate it */
	if((ppowned=empagesowned(*handle)) < pages) {
		if(ppowned > 0)		/* If we own > 0, but < 'pages', free it */
			emfree(*handle);	/* and try to get more */
		/* Ignore errors from empagesowned(), emallocate() will catch it */
		if((rcode=emallocate(handle, pages)) != NO_ERROR)
			goto xit;
		}
	/* Calc starting addr in buffer */
	saddr = srcimg->stx + srcimg->sty * (long)srcimg->iwidth;
	src = &srcimg->ibuff[saddr];
	while(rows--) {
		if((rcode=emputrow(src, *handle, 0, yctr++, cols, cols)) != NO_ERROR) {
			emfree(*handle);	/* If there's an error, free EM */
			break;
			}
		src += srcimg->iwidth;
		}
xit:
	return(rcode);
}

/* Retrieve the image buffer area from extended memory. Returns NO_ERROR,
	BAD_RANGE, or EMM_ERR. Returns BAD_RANGE if dest is not in CM!
*/
int _cdecl emgetimage(int handle, imgdes *desimg)
{
	int rcode, cols, rows, pages, yctr=0;
	long daddr, pels; /* Pixels in an image area = cols*rows */
	UCHAR huge *des;	/* Pointer into image buffer */

	/* Check range of start, end positions and make sure dest is CM */
	if(checkrange_(desimg) || desimg->ibuff == NULL)
		return(BAD_RANGE);
	/* Calc how many bytes to retrieve */
	cols = desimg->endx - desimg->stx + 1;
	rows = desimg->endy - desimg->sty + 1;
	pels = rows * (long)cols;		/* No. of pixels in the image area */
	pages = (int)(pels >> 14);
	if(pels&0x3fff)  pages++;
	/* Calc starting addr in buffer */
	daddr = desimg->stx + desimg->sty * (long)desimg->iwidth;
	des = &desimg->ibuff[daddr];
	while(rows--) {
		if((rcode=emgetrow(des, handle, 0, yctr++, cols, cols)) != NO_ERROR)
			break;
		des += desimg->iwidth;
		}
	return(rcode);
}
+ARCHIVE+ equalize.c    3176  3/16/1991  5:22:58
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		histoequalize		Equalization of histogram
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#include <string.h>

extern UCHAR Hbuff_[];
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);
static int _cdecl check_equ(long *);

/* Equalization of histogram. Returns BAD_RANGE if range error, BAD_FAC if
	(iterations != 0-32767), NOT_EQU if ESC pressed or histo not equalized.
	Returns NO_ERROR if histo equalized. Returns NO_EMM, EMM_ERR, NO_XMM,
	XMM_ERR, or CM_ERR.
*/
int _cdecl histoequalize(int iters, int escape, imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	long *histab = (long *)Hbuff_; /* Use Hbuff_ array to save stack space */
	long havg;
	int rcode, ch, j, rows, yctr, dyctr, cols, time, shandle, dhandle;
	UCHAR *buff=&Hbuff_[4048];

	/* Check range of start, end positions */
	if(checkrange_(desimg)) /* NOTE: calchisto() below will check srcimg */
		return(BAD_RANGE);
	if(iters < 0)
		return(BAD_FAC);
	if(iters == 0)
		return(NOT_EQU);
	if((rcode=calchisto(histab, srcimg)) != NO_ERROR)
		return(rcode);
	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	havg = (long)((cols * (long)rows) >> 8);	/* maxpels/256 */
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) == NO_ERROR &&
		(rcode=assign_gprow_(desimg, &dhandle, &dummy, &putrow)) == NO_ERROR) {
		for(time=1; time<=iters; time++) { /* iters = number of iterations */
			for(yctr=srcimg->sty, dyctr=desimg->sty; yctr<=srcimg->endy; yctr++) {
				if((rcode=getrow(buff, shandle, srcimg->stx, yctr,
					cols, srcimg->iwidth)) != NO_ERROR)
					goto err;
				for(j=0; j<cols; j++) {
					ch = buff[j];
					if(histab[ch]>havg && ch<255) {
						histab[ch]--;
						ch++;
						histab[ch]++;
						buff[j] = (UCHAR)ch;
						}
					}
				if((rcode=putrow(buff, dhandle, desimg->stx, dyctr++,
					cols, desimg->iwidth)) != NO_ERROR)
					goto err;
				}
			/* Check if we're done */
			if((rcode=check_equ(histab)) == NO_ERROR)
				break;
			/* escape != 0 and ESC pressed? */
			if(escape && kbhit() && getkey()==ESC) {
				rcode = NOT_EQU;
				break;
				}
			}
		}
err:
	cmclose_(srcimg, shandle);		/* Close any open CM handles */
	cmclose_(desimg, dhandle);
	return(rcode);
}

/* Check if histogram is equalized (if bin0 = bin255 = bin80 = bin160)
	Return NO_ERROR or NOT_EQU.
*/
static int _cdecl check_equ(long *histab)
{
	int rcode = NOT_EQU;
	long hval=histab[0]>>3;

	if(hval == (histab[255]>>3) &&
		hval == (histab[80]>>3)  &&
		hval == (histab[160]>>3))
		rcode = NO_ERROR;
	return(rcode);
}
+ARCHIVE+ exchang.c      917  3/15/1991 17:54:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		exchangegray		Exchange gray levels
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Exchange gray levels. Returns NO_ERROR, BAD_FAC, BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl exchangegray(int min, int max, int newval,
	imgdes *srcimg, imgdes *desimg)
{
	int ch;
	UCHAR tab[256];

	if(min > max) {
		ch = max;
		max = min;
		min = ch;
		}
	if(outrange(0, newval, 255) || (max>255) || (min<0))
		return(BAD_FAC);
	ch = 0;
	while(ch < min)
		tab[ch++] = (UCHAR)ch;
	while(ch <= max)
		tab[ch++] = (UCHAR)newval;
	while(ch < 256)
		tab[ch++] = (UCHAR)ch;
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ expand.c       981  3/15/1991 17:54:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		expandcontrast		Expand gray levels
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Expand gray levels. Returns NO_ERROR, BAD_FAC, BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl expandcontrast(int min, int max, imgdes *srcimg, imgdes *desimg)
{
	int diff, ch=0;
	UCHAR tab[256];

	if(min > max) {	/* Swap values if min > max */
		diff = max;
		max = min;
		min = diff;
		}
	if(min<0 || max>255)
		return(BAD_FAC);
	diff = max - min;
	while(ch <= min)
		tab[ch++] = 0;
	while(ch < max)		/* Routine works for case max = min */
		tab[ch++] = (UCHAR)((255 * (unsigned)(ch - min)) / diff);
	while(ch < 256)
		tab[ch++] = 255;
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ flip.c        2416  3/16/1991  5:22:58
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		flipimage	Flip image by swapping rows top for bottom
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <string.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());

/* Flip image by swapping rows top for bottom. Returns NO_ERROR,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl flipimage(imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int rows, hrows, cols, errcode, shandle, dhandle;
	int syup, sydn, dyup, dydn;
	UCHAR *buff1=Hbuff_;
	UCHAR *buff2=&Hbuff_[4048];

	/* Use checkrange_ to reorder arguments if necessary */
	if(checkrange_(srcimg) || checkrange_(desimg))
		return(BAD_RANGE);
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) == NO_ERROR &&
		(errcode=assign_gprow_(desimg, &dhandle, &dummy, &putrow)) == NO_ERROR) {
		syup = srcimg->sty;
		sydn = srcimg->endy;
		dyup = desimg->sty;
		dydn = desimg->endy;
		rows = sydn - syup + 1;		/* Rows to move */
		hrows = rows / 2;		/* Rows to move */
		if(rows & 1)			/* If rows to do is odd, do one more */
			hrows++;
		cols  =  srcimg->endx - srcimg->stx + 1;
		while(hrows--) {
			/* Move upper src line -> buff1 */
			if((errcode=getrow(buff1, shandle, srcimg->stx, syup++,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			/* Move lower src line -> buff2 */
			if((errcode=getrow(buff2, shandle, srcimg->stx, sydn--,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			/* Move buff2 to des upper line */
			if((errcode=putrow(buff2, dhandle, desimg->stx, dyup++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			/* Move buff1 to des lower line */
			if((errcode=putrow(buff1, dhandle, desimg->stx, dydn--,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	cmclose_(srcimg, shandle);		/* Close any open CM handles */
	cmclose_(desimg, dhandle);
	return(errcode);
}
+ARCHIVE+ histbrit.c    2144  3/15/1991 17:54:14
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		histobrighten		Histogram brightening
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Histogram brightening. Area to brighten must contain >= 16 pixels.
	Wang et.al., Comp Vision, Graphics, Image Processing, p 373, 1983,
	new_gray = SQRT(prob(old_gray)). Returns NO_ERROR, BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl histobrighten(imgdes *srcimg, imgdes *desimg)
{
	int j, subt, sqrt=0;
	ULONG dfact, *histab, *prob; /* long histab[256]; long prob[256] */
	long number;
	UCHAR lookup[256];

	/* Use Hbuff_ array for histab and prob arrays to save stack space */
	histab = prob = (ULONG *)Hbuff_;

	j = calchisto((long *)histab, srcimg);
	/* Calc pixels in image area */
	number = (srcimg->endx - srcimg->stx + 1) *
		(long)(srcimg->endy - srcimg->sty + 1);
	/* If less than 16 pixels, division by zero */
	if(j==BAD_RANGE || number<16L)
		return(BAD_RANGE);
	prob[0] = histab[0] / 2;		/* prob[]=cumulative histogram */
	for(j=1; j<255; j++)
		prob[j] = prob[j-1] + histab[j];
	prob[255] = prob[255-1] + (histab[255] / 2);
	/* dfact = factor to produce 'number' = 255*255
		8192 used since with 16 pixels, prob[255] >= 8 and 8*8192 > 65025
	*/
	dfact = (prob[255] < 0x3ffffL) ? ((prob[255] * 8192L) / 65025L) :
												 (prob[255] / 65025L * 8192L);
	j=0;
	/* Assemble a lookup table */
	/*	Exit if j = 256, sqrt = 255 or prob[j] > 0xffffffffL/2000 */
	while(j<256 && sqrt<255 && prob[j]<=0x7ffffL) {
		/* Ensure values are between 0 and 255*255 */
		number = prob[j] * 8192 / dfact;
		sqrt = 0;				/* Calc square root of number -> sqrt */
		subt = 1;
		while((number-=subt) >= 0) {
			sqrt++;
			subt += 2;
			}
		lookup[j++] = (UCHAR)sqrt;
		}
	/* Fill remainder of table with 255's */
	while(j < 256)
		lookup[j++] = 255;
	return(table_mod_(lookup, srcimg, desimg));
}
+ARCHIVE+ kodalith.c     727  3/15/1991 17:59:30
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		kodalith			Kodalith high contrast
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Kodalith high contrast. Returns NO_ERROR, BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl kodalith(int thres, imgdes *srcimg, imgdes *desimg)
{
	int ch=0;
	UCHAR tab[256];

	if(outrange(0, thres, 255))
		return(BAD_FAC);
	while(ch < thres)
		tab[ch++] = 0;
	while(ch < 256)
		tab[ch++] = 255;
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ limit.c        714  3/15/1991 17:59:32
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		limitlevel
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Limit a pixels value. Returns NO_ERROR, BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl limitlevel(int max, imgdes *srcimg, imgdes *desimg)
{
	int ch=0;
	UCHAR tab[256];

	if(outrange(0, max, 255))
		return(BAD_FAC);
	while(ch <= max)
		tab[ch++] = (UCHAR)ch;
	while(ch < 256)
		tab[ch++] = (UCHAR)max;
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ linear.c      1152  3/15/1991 17:59:32
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		histolinearize		Linearization of histogram
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Linearization of histogram. Returns NO_ERROR, BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl histolinearize(imgdes *srcimg, imgdes *desimg)
{
	int j;
	long *histab, *prob;			/* long histab[256]; long prob[256] */
	UCHAR lookup[256];

	/* Use Hbuff_ array for histab and prob arrays to save stack space */
	histab = prob = (long *)Hbuff_;

	if(calchisto(histab, srcimg) == BAD_RANGE)
		return(BAD_RANGE);
	prob[0] = histab[0] / 2;		/* prob[]=cumulative histogram */
	for(j=1; j<255; j++)
		prob[j] = prob[j-1] + histab[j];
	prob[255] = prob[255-1] + (histab[255] / 2);
	for(j=0; j<(255+1); j++)		/* Assemble a lookup table */
		lookup[j] = (UCHAR)((255*prob[j]) / prob[255]);
	return(table_mod_(lookup, srcimg, desimg));
}
+ARCHIVE+ loadpbit.c    7126  4/05/1991 10:18:56
/* Victor Library, Copyright (c) 1990-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		loadpcxbitmap  Load bit mapped PCX file as an 8-bit image
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <stdlib.h>
#include <io.h>
#define DTASIZE  8192

static PcxData Pdat;        /* Reserve space for struct for loadpcx */
static int BytsPerPCXLine;  /* Bytes in a PCX line (BytesPerLine*Planes) */
static int Xwidth, Xlength; /* PCX width, height */

extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern int _cdecl assign_gprow_(imgdes *,int *,
	int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl unpackpcx_(UCHAR *,UCHAR *,int);
static int ReadBitPcx(imgdes *,int,int,int,int,int);
static int _cdecl check_bpcx(void);
static void _cdecl copy_erow(UCHAR *,UCHAR *,int,int);
extern UCHAR Hbuff_[];

/* Load bit mapped PCX file into image buffer. Returns NO_ERROR, BAD_RANGE,
	BAD_OPN, BAD_PCX, BAD_MEM, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl loadpcxbitmap(char *fname,
int filesx, int filesy,/* (x,y) coord of starting position within the file */
imgdes *desimg)		  /* Where to store 8-bit image data */
{
	int j, rcode, byts2wrt, xdist, ydist, rows, fhandle;

	/* Check range of start, end positions */
	if(checkrange_(desimg))
		return(BAD_RANGE);
	/* Get info on PCX file we're to load */
	if((rcode=pcxinfo(fname, &Pdat)) != NO_ERROR)	/* Fill structure */
		return(rcode);
	/* Check PCX hdr for validity, exit if error */
	if((rcode=check_bpcx()) != NO_ERROR)
		return(rcode);
	/* Check bytes available in a line and rows available in an image */
	if(((xdist=Xwidth-filesx) < 0) || ((ydist=Xlength-filesy) < 0))
		return(BAD_RANGE);
	if((fhandle=open(fname, O_BINARY|O_RDONLY)) < 3) /* Open fname.pcx file */
		return(BAD_OPN);
	/* Calculate byts2wrt and rows */
	if((byts2wrt=desimg->endx - desimg->stx + 1) > xdist) /* Use smaller value */
		byts2wrt = xdist;
	if((rows = desimg->endy - desimg->sty + 1) > ydist) /* Use smaller value */
		rows = ydist;
	/* Move file ptr to start of image */
	lseek(fhandle, 128L, SEEK_SET);
	/* Load the image data */
	rcode = ReadBitPcx(desimg, filesx, filesy, byts2wrt, rows, fhandle);
	close(fhandle);
	/* If image data was successfully loaded, load the palette data */
	if(rcode == NO_ERROR) {
		desimg->palsize = (desimg->palette) ?
			loadpcxpalette(fname, desimg->palette) : 0;
		/* Convert 48 byte palette to 768 byte palette */
		if(desimg->palsize == 48) {
			for(j=765; j>=0; j-=3)
				memcpy_(&desimg->palette[j], &desimg->palette[(j/48)*3], 3);
			desimg->palsize = 768; /* Reset palette size */
			}
		}
	return(rcode);
}

/* Load the 1 bit per pixel image data into 8 bit bytes. Returns NO_ERROR,
	BAD_MEM (not enough conventional memory for expansion buffer), NO_EMM,
	EMM_ERR, NO_XMM, or XMM_ERR.
*/
static int ReadBitPcx(imgdes *desimg, int filesx, int filesy,
	int byts2wrt, int rows, int fhandle)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	UCHAR *dta_addr=Hbuff_;  /* Address of our file buffer */
	int sctr=0;		 /* Byte counter in dta buffer */
	int dtalimit=0; /* Get more bytes from disk when dtalimit is exceeded */
	int valid_byts=0;
	int byts2mov, handle, yctr=desimg->sty, yy, rcode;
	UCHAR *pbuff, *expbuf;	/* Addr of memory for expansion buffer */

	/* Allocate memory for an expansion buffer and intermediate buffer */
	if((expbuf=(UCHAR *)malloc(BytsPerPCXLine + byts2wrt)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	pbuff = &expbuf[BytsPerPCXLine];	/* Our intermediate buffer */
	/* Assign handle, putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		/* Make rows = total rows to read, not just buffer rows to write */
		rows += filesy;
		for(yy=0; yy<rows; yy++) {
			if(sctr >= dtalimit) { /* Nearly out of valid bytes in the DTA */
				/* Move any valid bytes left to the front of the DTA */
				byts2mov = valid_byts - sctr;
				if(byts2mov < 0)  byts2mov = 0;		/* Play it safe */
				memcpy_(dta_addr, &dta_addr[sctr], byts2mov);
				/* Read in more data and calc valid bytes in the DTA */
				valid_byts = byts2mov +
					read(fhandle, &dta_addr[byts2mov], DTASIZE-byts2mov);
				/* No more bytes in the DTA => we're done */
				if(valid_byts == 0)
					break;
				/* Set dta_limit back from end of DTA to allow reading a
					line at a time without reading invalid data.
				*/
				if((dtalimit=valid_byts-2*BytsPerPCXLine) <= 0)
					dtalimit = valid_byts;
				sctr = 0;		/* Reinitialize sctr */
				}	/* Unpack a row into expbuf and update sctr */
			sctr += unpackpcx_(expbuf, &dta_addr[sctr], BytsPerPCXLine);
			if(yy >= filesy) { /* If we've reached the starting row */
				/* Move expanded bytes from expbuf to image buffer */
				copy_erow(pbuff, &expbuf[filesx>>3], filesx&7, byts2wrt);
				if((rcode=putrow(pbuff, handle, desimg->stx, yctr++,
					byts2wrt, desimg->iwidth)) != NO_ERROR)
					break;
				}
			}
		}
	cmclose_(desimg, handle);		/* Close CM handle */
	free(expbuf);
	return(rcode);
}

/* Move byts2mov bytes from the expansion buffer to the intermediate buffer
*/
static void _cdecl copy_erow(UCHAR *dbuff, /* Where to put bytes */
UCHAR *sbuff,		/* Where to get bytes */
int bitno,			/* Bit number to start at (0-7) */
int byts2mov)		/* Number of bytes to move */
{
	int ctr;		/* Amount to shift right (0-7) */
	int byt;		/* Char to write to dbuff */
	int pl;		/* Plane counter */
	int bmask;	/* Bit mask */
	int sval;	/* Amount to shift left (4-7) */
	int saddr;	/* Position in sbuff */

	sval = 8 - Pdat.Nplanes;	/* 1 plane => sval=7, 2 => 6, 3 => 5, 4 => 4 */
	bmask = 0x80 >> bitno;
	ctr = 7 - bitno;
	for(;;) {
		while(ctr >= 0) {
			if(byts2mov-- <= 0)
				return;
			saddr = 0;
			for(pl=0,byt=0; pl<Pdat.Nplanes; pl++) { /* Compensate for Nplanes */
				byt |= ((sbuff[saddr] & bmask) >> ctr) << pl;
				saddr += Pdat.BytesPerLine;
				}
			*dbuff++ = (UCHAR)(byt << sval); /* Make 0->15 to 0->240 (4 planes) */
			ctr--;
			bmask >>= 1;					 /* 0x80 -> 0x40 -> etc. */
			}
		ctr = 7;
		bmask = 0x80;
		sbuff++;
		}
}

#define  XLIMIT  4047		/* Limited by size of Hbuff_ in viccore.c */
#define  YLIMIT  32767
/* Check PCX header for valid settings before loading the file. Calc
	Xwidth and Xlength. Returns NO_ERROR or BAD_PCX.
*/
static int _cdecl check_bpcx(void)
{
	/* Note: PCX identity already checked by pcxinfo() */
	Xwidth = Pdat.Xmax - Pdat.Xmin + 1;
	Xlength= Pdat.Ymax - Pdat.Ymin + 1;
	if(Pdat.BPPixel == 1 && Pdat.Nplanes <= 4 &&
		inrange(0, Xwidth, XLIMIT) &&
		inrange(0, Xlength, YLIMIT) == 0)
			return(BAD_PCX);
	BytsPerPCXLine = Pdat.BytesPerLine * Pdat.Nplanes;
	return(NO_ERROR);
}
+ARCHIVE+ matrix.c      4047  3/16/1991  5:19:06
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		matrixconv		Modify image using matrix
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>
#include <string.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
int _cdecl matrixall_(imgdes *,imgdes *,
	void (_cdecl *)(UCHAR *,UCHAR *,int,int,int *),int *);
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);
/* matrix_sum_() processes a row of data using the matrix at
	tabaddr and stores the result in buff. It assumes 'src' points
	at the second row of three rows of data.
*/
extern void _cdecl matrix_sum_(UCHAR *,UCHAR *,int,int,int *);

/* Modify image using a [3x3] matrix. Returns NO_ERROR, BAD_RANGE,
	BAD_MEM (not enough convential memory), NO_EMM, EMM_ERR, NO_XMM,
	XMM_ERR, or CM_ERR.
*/
int _cdecl matrixall_(srcimg, desimg, matfct, varaddr)
imgdes *srcimg, *desimg;	/* Source, destination images */
/* Function that modifies the image */
void (_cdecl *matfct)(UCHAR *,UCHAR *,int,int,int *);
int *varaddr;					/* Address of optional variable */
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int errcode, rows, cols, bsiz, j, syctr, dyctr, handle;
	UCHAR *bptr, *buff1, *buff2, *buff3;

	if(checkrange_(srcimg) || checkrange_(desimg))
		return(BAD_RANGE);
	/* Do for points (sx,sy+1) -> (ex,ey-1) */
	rows = srcimg->endy - srcimg->sty - 1;
	cols = srcimg->endx - srcimg->stx + 1;
	if(rows<0 || cols<3)
		return(BAD_RANGE);
	/* Copy source area to destination area */
	if((errcode=copyimage(srcimg, desimg)) == NO_ERROR) {
		/* Use Hbuff_ or an allocated buffer, based on bsiz */
		if((bsiz=cols*3) < 8192)
			buff1 = Hbuff_;
		else {
			if((buff1=(UCHAR *)malloc(bsiz)) == NULL)
				return(BAD_MEM);	/* If area not allocated */
			}
		/* Since we process buff2, and store the result in buff1, buff1
			size must be cols + 1 (new data gets stored in buff1 at buff1[1]).
		*/
		buff2 = &buff1[cols+1];
		buff3 = &buff1[cols*2+1];
		/* Assign handles, getrow(), putrow(), and check for EM/XM */
		if((errcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) != NO_ERROR)
			goto err;
		syctr = desimg->sty;
		dyctr = desimg->sty + 1;
		/* Put first 2 rows from EM or XM into buff1 and buff2 */
		bptr = buff1 + 1;		/* Store data in buff1 at &buff[1] */
		for(j=0; j<2; j++) {	/*  and in buff2 at &buff2[0] */
			if((errcode=getrow(bptr, handle, desimg->stx,
				syctr++, cols, desimg->iwidth)) != NO_ERROR)
				goto err;
			bptr += cols;
			}
		/* syctr = desimg->sty + 2, dyctr = desimg->sty + 1 */
		while(rows--) {
			/* Get next row from buffer, store it in buff3 */
			if((errcode=getrow(buff3, handle, desimg->stx, syctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			/* Process row in buff2, store it in buff1 at &buff1[0] */
			matfct(buff2, buff1, cols, cols, varaddr);
			/* Put buff1 from &buff1[0] into buffer */
			if((errcode=putrow(buff1, handle, desimg->stx, dyctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			/* Copy buff 2-3 to buff 1-2 */
			memcpy_(buff1+1, buff2, cols*2);
			}
err:
		cmclose_(desimg, handle);		/* Close CM handle */
		if(bsiz >= 8192)	/* If true, we allocated a buffer, free it */
			free(buff1);
		}
	return(errcode);
}

/* Modify image using matrix. Returns NO_ERROR, BAD_RANGE, BAD_MEM (not
	enough convential memory), NO_EMM, EMM_ERR, NO_XMM, or XMM_ERR.
	NOTE: tabaddr[9] is used as divisor by matrix_sum_().
*/
int _cdecl matrixconv(char *tabaddr, imgdes *srcimg, imgdes *desimg)
{
	if(tabaddr[9] == 0)	/* Guard against division by zero */
		return(BAD_FAC);
	return(matrixall_(srcimg, desimg, matrix_sum_, (int *)tabaddr));
}
+ARCHIVE+ mirror.c      2023  3/16/1991  5:24:20
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		mirrorimage		Make mirror image by swapping pixels left for right
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <string.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());

/* Make mirror image by swapping pixels left for right. Returns NO_ERROR,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl mirrorimage(imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int errcode, rows, cols, j, syctr, shandle, dyctr, dhandle;
	UCHAR *sptr, *buff=&Hbuff_[4048];

	/* Use checkrange_ to reorder arguments if necessary */
	if(checkrange_(srcimg) || checkrange_(desimg))
		return(BAD_RANGE);
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) == NO_ERROR &&
		(errcode=assign_gprow_(desimg, &dhandle, &dummy, &putrow)) == NO_ERROR) {
		syctr = srcimg->sty;
		dyctr = desimg->sty;
		rows = srcimg->endy - srcimg->sty + 1;
		cols = srcimg->endx - srcimg->stx + 1;
		while(rows--) {
			if((errcode=getrow(Hbuff_, shandle, srcimg->stx, syctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			sptr = Hbuff_ + cols;	/* sptr points at end of row */
			/* Reverse the bytes in the row */
			for(j=0; j<cols; j++)
				buff[j] = *(--sptr);
			/* Put the row back */
			if((errcode=putrow(buff, dhandle, desimg->stx, dyctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	cmclose_(srcimg, shandle);		/* Close CM handles */
	cmclose_(desimg, dhandle);
	return(errcode);
}
+ARCHIVE+ mult.c         773  3/15/1991 17:59:34
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		multiply		Multiply by factor
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Multiply image area by a factor. Returns NO_ERROR, BAD_FAC,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl multiply(int value, imgdes *srcimg, imgdes *desimg)
{
	unsigned ch, j;
	UCHAR tab[256];

	if(outrange(0, value, 255))
		return(BAD_FAC);
	for(ch=0; ch<256; ch++)	{
		j = ch * (unsigned)value;
		tab[ch] = (UCHAR)((j<255) ? j : 255);
		}
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ negative.c     645  3/15/1991 17:59:34
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		negative		Make negative of image
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Make negative of image. Returns NO_ERROR, BAD_RANGE, NO_EMM, EMM_ERR,
	NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl negative(imgdes *srcimg, imgdes *desimg)
{
	int ch;
	UCHAR tab[256];

	for(ch=0; ch<256; ch++)
		tab[ch] = (UCHAR)(ch ^ 255);
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ or.c           923  3/16/1991  4:59:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		orimage		OR 2 images
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl twoimagefcts_(imgdes *,imgdes *,imgdes *,void (_cdecl *)());

/* OR 'count' bytes in sbuff with obuff and store result in dbuff */
static void _cdecl ortwo(UCHAR *sbuff, UCHAR *obuff, UCHAR *dbuff, int cols)
{
	while(cols--)
		*dbuff++ = *sbuff++ | *obuff++;
}

/* OR 2 images. Returns NO_ERROR, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl orimage(srcimg, oprimg, desimg)
imgdes *srcimg;			/* Image 1 */
imgdes *oprimg;			/* Image 2 */
imgdes *desimg;			/* Store result image here */
{
	return(twoimagefcts_(srcimg, oprimg, desimg, ortwo));
}
+ARCHIVE+ pack.c        4474  3/15/1991 18:08:10
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		packbits_		Pack a line of data using the PackBits scheme
		unpackbits_		Unpack a line of data using the PackBits scheme
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

#define MAXPBYTS 127		/* Limit compression run lengths to 127 */
		/* (Probably able to handle lengths of 128 bytes) */

static void _cdecl calc_freq(UCHAR huge *, UCHAR *,int);
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);

/* Pack a line of data using the PackBits scheme.
	Return number of compressed bytes.
	des = where to put the packed data, src = source of data to pack,
	byts2pack = number of data bytes to pack.
*/
int _cdecl packbits_(UCHAR huge *des, UCHAR huge *src, int byts2pack)
{
	UCHAR huge *dptr;
	UCHAR freq[130];		/* Frequency each char is repeated */
	int j, tval, mxchrs;	/* No. of mixed chars in a run */
	int numpack;			/* Bytes to pack */

	dptr = des;				/* Save des to calc no. of compressed bytes */
	while(byts2pack) {
		/* If more than 127 bytes to pack, do 127 at a time */
		numpack = (byts2pack<MAXPBYTS) ? byts2pack : MAXPBYTS;
		/* Fill frequency array */
		calc_freq(src, freq, numpack);
		mxchrs = 0;
		j = 0;
		while((tval=freq[j]) != 0) { /* NULL marks the end of valid data */
			if(tval == 1) {		/* Encountered a single char */
				mxchrs++;
				if(freq[j+1] == 1) {		/* Found 1 1 seq */
					mxchrs++;
					j += 2;
					}
				else if(freq[j+1] == 2 && freq[j+2] == 1) {
					/* Found 1 2 1 seq: handle as a literal run */
					mxchrs += 2;
					j += 2;
					}
				else {	/* freq[j+1] >= 2 or 0 */
					/* Found 1 n seq: write a mixed record */
					*des++ = (UCHAR)(mxchrs - 1);
					memcpy_(des, src, mxchrs);
					des += mxchrs;
					src += mxchrs;
					mxchrs = 0;
					j++;
					}
				}
			else {		/* Encountered a run of repeating chars */
				if(mxchrs) {	/* Write any mixed chars left */
					*des++ = (UCHAR)(mxchrs - 1);
					memcpy_(des, src, mxchrs);
					des += mxchrs;
					src += mxchrs;
					mxchrs = 0;
					}
				/* Then, write a repeat record */
				*des++ = (UCHAR)(257 - tval);		/* Store 257 - count */
				*des++ = *src;				/* Store char */
				src += tval;
				j++;
				}
			}
		if(mxchrs) {	/* Write any mixed chars left */
			*des++ = (UCHAR)(mxchrs - 1);
			memcpy_(des, src, mxchrs);
			des += mxchrs;
			src += mxchrs;
			}
		byts2pack -= numpack;
		}
	/* Return number of compressed bytes */
	return((int)(des - dptr));
}

/* Place frequency each char is repeated into freq array.
	Place NULL at end of array to mark end of valid data.
*/
static void _cdecl calc_freq(src, times, byts2pac)
UCHAR huge *src;		/* Data bytes to compress */
UCHAR *times;			/* Frequency each char is repeated */
int byts2pac;			/* Number of data bytes to compress */
{
	UCHAR oldbyte, newbyte;
	int freq = 1;		/* Number of times each char is repeated */

	oldbyte = *src++;
	while(--byts2pac) {
		newbyte = *src++;
		/* Continue until newbyte != oldbyte */
		if(newbyte == oldbyte)
			freq++;
		/* Bytes are different, store number of repeated chars */
		else {
			*times++ = (UCHAR)freq;
			oldbyte = newbyte;
			freq = 1;
			}
		}
	*(int *)times = freq;	/* Store last freq AND ADD NULL byte! */
}

/* Unpack a line of data compressed with the PackBits scheme.
	Return the number of compressed bytes read.
	des = where to put the unpacked data, src = source of data to unpack,
	des_byts = number of uncompressed bytes to write.
*/
int _cdecl unpackbits_(UCHAR huge *des, UCHAR huge *src, int des_byts)
{
	UCHAR huge *sptr;
	int count, ch;

	sptr = src;		/* Save src to calc no. of compressed bytes read */
	while(des_byts > 0) {
		ch = *src++;
		/* ch = 128 -> 255: write the following byte 257-ch times */
		if(ch & 0x80) {	/* If top bit set */
			count = 257 - ch;
			memset_(des, *src, count);
			src++;
			}
		/* ch = 0 -> 127: copy the following ch+1 bytes literally */
		else {
			count = ch + 1;
			memcpy_(des, src, count);
			src += count;
			}
		des_byts -= count;	/* Update bytes left to write */
		des += count;			/* and where to write them */
		}	/* Return the number of compressed bytes we read */
	return((int)(src - sptr));
}
+ARCHIVE+ pixelct.c     1136  3/15/1991 18:08:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		pixelcount		Return number of pixels between gray levels min and max
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];

/* Calculate number of pixels between gray levels min and max. Function
	uses Hbuff_ to save stack space. Return AS LONG INT! sum, BAD_FAC,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl pixelcount(int min_gray, int max_gray, long *pcount, imgdes *srcimg)
{
	long *histab=(long *)Hbuff_; /* Use Hbuff_ to save stack space */
	long sum=0;
	int rcode, j;

	if(min_gray > max_gray) { /* Swap min for max if necessary */
		j = max_gray;
		max_gray = min_gray;
		min_gray = j;
		}
	/* Check range of min and max */
	if(min_gray < 0 || max_gray > 255)
		return(BAD_FAC);
	/* Fill histo table */
	if((rcode=calchisto(histab, srcimg)) == NO_ERROR) {
		for(j=min_gray; j<=max_gray; j++)
			sum += histab[j];
		*pcount = sum;
		}
	return(rcode);
}
+ARCHIVE+ pixelize.c    2715  3/16/1991  5:26:30
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		pixellize
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());

/* Pixellation. Returns NO_ERROR,  BAD_RANGE if range error, BAD_FAC if
	pixellation factor is out of range (factor must be between 1 and del_x
	or del_y or 63), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl pixellize(int pixfac, imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	long sum;
	unsigned square;
	int errcode, small_dimen, xctr, yctr, xx, yy, handle;
	int rows, cols, nrows, ncols, k;

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	small_dimen = (cols<rows) ? cols : rows;	/* Get smallest dimension */
	if(small_dimen>63)	/* Value must be <= 63 */
		small_dimen = 63;
	/* pixfac must be <= smaller of cols or rows or 63 */
	if(outrange(2, pixfac, small_dimen))
		return(BAD_FAC);
	nrows = rows / pixfac;
	ncols = cols / pixfac;
	square = pixfac * pixfac;	/* square <= 63*63 */
	/* Copy source area to destination area */
	if((errcode=copyimage(srcimg, desimg)) == NO_ERROR) {
		/* Assign handles, getrow(), putrow(), and check for EM/XM */
		if((errcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) == NO_ERROR) {
			yctr = desimg->sty;
			while(nrows--) {
				xctr = desimg->stx;
				for(k=0; k<ncols; k++) {	/* Do 'ncols' blocks */
					/* Sum the pixels within the block */
					for(yy=0, sum=0; yy<pixfac; yy++) {
						if((errcode=getrow(Hbuff_, handle, xctr, yctr+yy,
							pixfac, desimg->iwidth)) != NO_ERROR)
							goto err;
						for(xx=0; xx<pixfac; xx++)
							sum += Hbuff_[xx];
						}
					/* Set the pixels in the block to the average value */
					memset_(Hbuff_, (int)(sum/square), pixfac); /* Set up Hbuff */
					for(yy=0; yy<pixfac; yy++) {
						if((errcode=putrow(Hbuff_, handle, xctr, yctr+yy,
							pixfac, desimg->iwidth)) != NO_ERROR)
							goto err;
						}
					xctr += pixfac;
					}
				/* Done with a row of ncols blocks, advance yctr */
				yctr += pixfac;
				}
			}
		}
err:
	cmclose_(desimg, handle);	/* Close CM handle */
	return(errcode);
}
+ARCHIVE+ prtimage.c   12501  3/16/1991  5:26:30
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		printimage
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>

#define PRTXMAX 2400		/* Maximum dots per page (at 300 DPI) */
#define PRTYMAX 3150
/* If mode = MINAVG, print using minavg method, else use dither method */
#define MINAVG   0
#define PRNHANDLE 4	/* Predifined stdprn handle */

static FILE *Stream;
static unsigned Rowctr;
static int Byts2send;
static int MaskVal;
static char PreLineStr[10];
/* If printing using the a dither matrix: Matrix to use */
static UCHAR Halftone64[] = {		/* 64-level halftone dither */
	112, 40, 72,104,144,176,208,136,
	 88,  8, 16, 48,192,232,240,168,
	 56, 24,  0, 80,160,224,248,200,
	 96, 64, 32,120,128,216,184,152,
	148,180,212,140,116, 44, 76,108,
	196,236,244,172, 92, 12, 20, 52,
	164,228,252,204, 60, 28,  4, 84,
	132,220,188,156,100, 68, 36,124
	};
/* If printing via minimum average: */
static int *BigE;

extern int _cdecl checkrange_(imgdes *);
extern void * _cdecl memmove_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl set_raw_(int,int);
extern UCHAR Hbuff_[];
static void _cdecl generate_ftable(unsigned,UCHAR *);
static void _cdecl prtbox(int,int,int,int,int);
static int _cdecl prtline(UCHAR *,int,int);
extern void _cdecl init_errindx_(int);					/* For minavg */
extern int _cdecl calc_pbyt_(int *,int,UCHAR *);		/* For minavg */
extern int _cdecl calc_dbyt_(UCHAR *,int,UCHAR *);	/* For dither */

/* Print a resized image area. Returns NO_ERROR, BAD_RANGE, PRT_ERR,
	BAD_MEM (not enough convential memory), or NO_EMM, EMM_ERR, NO_XMM,
	XMM_ERR, or CM_ERR.
*/
int _cdecl printimage(mode, dpi, srcimg, des_sx, des_sy, des_ex, des_ey, boxsiz)
int mode;			/* Print technique: dither or minavg */
int dpi;				/* Dots per inch printer resolution, 75, 100, 150, 300 */
imgdes *srcimg;	/* Source image */
int des_sx, des_sy;	/* Destination image area */
int des_ex, des_ey;
int boxsiz;				/* Thickness of box lines */
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	static UCHAR mask[] = {0x00, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01};
	int dxpixnum, dypixnum;	/* No. of pixels to plot in dest per source pixel */
	unsigned pcxinc, pcyinc;/* Factors representing % inc in size in x,y dir */
	int sxpix, sypix;			/* Width, ht, in pixels of source area */
	int dxpix, dypix;			/* Width, ht, in pixels of destn area */
	int xctr, yctr, j, handle;
	int sxindex, syindex, dxindex, dyindex, dyend, tint;
	int zx, zy;			/* Width, ht, in pixels to write in dest area */
	int syctr, rcode=NO_ERROR;
	long tmp;
	UCHAR *exbuff, *sptr, *xfactor, *yfactor;
	static int valid_dpis[] = {300, 150, 100, 75};

	for(j=0; j<sizeof(valid_dpis); j++) {
		if(dpi == valid_dpis[j])
			break;
		}
	/* Check range of start, end positions and dots per inch */	
	if(checkrange_(srcimg) || j >= sizeof(valid_dpis))
		return(BAD_RANGE);
	syctr = srcimg->sty;
	sxpix = srcimg->endx - srcimg->stx + 1;
	sypix = srcimg->endy - srcimg->sty + 1;
	/* Calc width, height of dest area */
 	dxpix = (des_ex - des_sx + 1) / (300/dpi);
	dypix = (des_ey - des_sy + 1) / (300/dpi);
	/* Number of pixels to write in dest, compensate for dot per inch */
	zx = (int)(((((long)dxpix << 8) / sxpix) * sxpix) >> 8);
	zy = (int)(((((long)dypix << 8) / sypix) * sypix) >> 8);
	/* If des has no width or height or box lines are too thick, exit */
	if(zx==0 || zy==0 || boxsiz>zx || boxsiz>zy ||
	/* Check that resized area to be printed fits on a page */
		(des_sx + zx > PRTXMAX) || (des_sy + zy > PRTYMAX))
		return(BAD_RANGE);
	Stream = stdprn;
	/* Set raw output mode for stdprn device to be able to output ctrl-z's */
	set_raw_(1, PRNHANDLE);
	Rowctr = 0;
	/* Make PreLineStr string */
	MaskVal = mask[j = zx & 7];	/* Calc remainder and mask value to use */
	Byts2send = zx / 8;
	if(j)  Byts2send++; /* If remainder, one more byte to send */
	sprintf(PreLineStr, "\033*b%dW", Byts2send);
	/* Set up printer */
	fprintf(Stream,"\033*t%dR"			/* Set dpi */
						"\033*p%dx%dY"	  	/* Set printer x,y position */
						"\033*r1A",			/* Begin graphics output */
						dpi, des_sx, des_sy);
	dxpixnum = zx / sxpix;		/* Multiplier, 200%->2, 414%->4, etc */
	dypixnum = zy / sypix;
	/* Increase factor in 256ths,
		pcxinc = ((zx % sxpix) * 256) / sxpix;
		pcxinc = 414% = 4+35.8/256->36, 231% = 2+79.4/256->79
	*/
	tmp = (long)(zx % sxpix) << 8; pcxinc = (unsigned)(tmp / sxpix);
	/* Round up if needed */
	if(tmp % sxpix > (sxpix >> 1))
		pcxinc++;
	/* Calc Y increase factor in 256ths */
	tmp = (long)(zy % sypix) << 8;
	pcyinc = (unsigned)(tmp / sypix);
	/* Round up if needed */
	if(tmp % sypix > (sypix >> 1))
		pcyinc++;
	dyend = des_sy + zy;		/* Calc end of block */
	syindex = 0;
	dyindex = des_sy;
	/* Assign handle, getrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) != NO_ERROR)
		goto xit2;
	j = sxpix;			/* Buffer size if using dither tech */
	if(mode == MINAVG) {		/* Buffer size if using minavg tech */
		j += zx * 3 * sizeof(int) + 16;
		init_errindx_(zx);	/* Setup errindx array */
		}
	/* Allocate exbuff for storage of a row of data to expand, factor
		tables, and possibly, the BigE array. Use calloc to zero BigE array.
	*/
	if((exbuff=(UCHAR *)calloc(j+512, sizeof(UCHAR))) == NULL) {
		rcode = BAD_MEM;	/* If area not allocated */
		goto xit2;
		}
	/* Generate xfactor, yfactor tables */
	generate_ftable(pcxinc, xfactor=&exbuff[sxpix]);
	generate_ftable(pcyinc, yfactor=&exbuff[sxpix+256]);
	/* Set up our big error array (we want 0's in front of the array).
		(BigE is not used if we're printing by the dither technique.)
	*/
	BigE = (int *)&exbuff[sxpix+512+8];
	for(;;) {
		/* Put the row of data to be printed into exbuff */
		if((rcode=getrow(exbuff, handle, srcimg->stx, syctr++,
			sxpix, srcimg->iwidth)) != NO_ERROR)
			goto prterr;
		sptr = exbuff;			/* Reset source ptr */
		yctr = dypixnum;		/* yctr is no. of lines to draw */
		if(yfactor[syindex & 0xff])	/* based on factor add a line */
			yctr++;
		if(yctr) {	/* Stretch or shrink in x direction */
			/* First time thru draw line */
			sxindex = 0;
			dxindex = 0;		/* Index into Hbuff_ */
			for(;;) {			/* Stretch or shrink one line */
				xctr = dxpixnum;	/* Set up xctr */
				/* Are extra points needed? */
				if(xfactor[sxindex & 0xff])	/* based on factor add a line */
					xctr++;
				tint = *sptr++;			/* Read source color */
				for(j=0; j<xctr; j++) {
					Hbuff_[dxindex++] = (UCHAR)tint;
					if(dxindex >= zx)		/* Write zx pixels */
						goto eol;
					}
				sxindex++;
				}
eol:		while(yctr--) {	/* Print the line in the buffer */
				if((rcode=prtline(Hbuff_, zx, mode)) == PRT_ERR)
					goto prterr;
				if(++dyindex >= dyend)	/* Don't draw line if out of block */
					goto xit;
				}
			}
		syindex++;
		}
xit:
	if(boxsiz) {	/* If boxsiz = 0, don't draw a frame around the image */
		j = 300/dpi;
		prtbox(des_sx, des_sy, des_sx+zx*j, des_sy+zy*j, boxsiz);
		}
	fputs("\033*rB", Stream); /* Exit graphics mode */
prterr:
	if(exbuff)			/* If we allocated a buffer, free it */
		free(exbuff);
xit2:
	cmclose_(srcimg, handle);		/* Close CM handle */
	set_raw_(0, PRNHANDLE);		/* Restore old output mode */
	return(rcode);
}

/* Print a line of Byts2send pixels using ordered dither matrix or
	minimum average technique. Return NO_ERROR or PRT_ERR if EOF.
*/
static int _cdecl prtline(src, imgwid, mode)
UCHAR *src;		/* Source of data bytes to print */
int imgwid;		/* Image width in pixels */
int mode;		/* Use dither matrix or minavg print method */
{
	int pbyt, j, rcode=NO_ERROR, byts2mov=Byts2send-1;
	int pos=2*imgwid;		/* Current position in BigE array */

	fputs(PreLineStr, Stream);
	for(j=0; j<=byts2mov; j++) {
		pbyt = (mode == MINAVG) ?
			calc_pbyt_(BigE, pos, src) :	/* Minavg routine to calc pbyt */
			calc_dbyt_(Halftone64, Rowctr, src); /* Dither rout to calc pbyt */
		pos += 8;		/* Minavg only: Update pos (we moved over 8 pixels) */
		src += 8;		/* Update src (we processed 8 bytes) */
		if(j == byts2mov)		/* If last byte in a row, we need to mask it */
			pbyt |= MaskVal;	/* Turn unused bits to 1, since ~1 = 0 */
		/* Finally, NOT and print the byte */
		if(fputc(~pbyt, Stream) == EOF) {
			rcode = PRT_ERR;
			break;
			}
		}
	if(mode == MINAVG) /* Move BigE down in picture: move row 1 & 2 -> row 0 & 1 */
		memmove_(BigE, &BigE[imgwid], imgwid*2*sizeof(int));
	Rowctr++;
	return(rcode);
}

/* Draw a box of line thickness boxsiz around printed image */
static void _cdecl prtbox(int stx, int sty, int endx, int endy, int boxsiz)
{
	fprintf(Stream,"\033*p%dx%dY"	  	/* Segment 1: set x,y position */
						"\033*c%da%db0P" 	/* Set horiz, vert rule size, prt it */
						"\033*p%dx%dY"	  	/* Segment 3: set x,y position */
						"\033*c0P"		 	/* Print it */
						"\033*p%dx%dY"	  	/* Segment 2: set x,y position */
						"\033*c%da%db0P" 	/* Set horiz, vert rule size, prt it */
						"\033*p%dx%dY"	  	/* Segment 4: set x,y position */
						"\033*c0P",			/* Print it */
						stx, sty, endx-stx, boxsiz,			/* Segment 1 */
						stx, endy-boxsiz,							/* Segment 3 */
						endx-boxsiz, sty, boxsiz, endy-sty, /* Segment 2 */
						stx, sty);									/* Segment 4 */
}

/* Generate X or Y increase factor table. Increm = increase factor, 0 - 255,
	i.e., no. of pixels out of 256 that should be set to 1.
*/
static void _cdecl generate_ftable(unsigned increm, UCHAR *ftable)
{
	unsigned j, indx, fact;
	long val;

	/* Zero table */
	memset_(ftable, 0, 256);
	if(increm) {		/* If increm = 0, table should consist of zeros */
		fact = 255*256 / increm;
		for(j=0; j<increm; j++) {
			val = j * (long)fact;
			indx = (unsigned)(val >> 8);
			if((val & 0xff) >= 128)
				indx++;
			ftable[indx] = 1;
			}
		}
}

#if 0
/* Rewritten in assembler for speed */
/* Calculate the byte to print */
int calc_dbyt_(UCHAR *matrix, int row, UCHAR *src)
{
	UCHAR *rowptr=&matrix[(rows & 7)<<3]; /* Assumes 8 elements per row */
	int pbyt, k;

	for(k=0; k<8; k++) {
		pbyt <<= 1;
		if(*src++ > *rptr++)
			pbyt |= 1;
		}
	return(pbyt);
}
#endif

/* Other possible matrices to use: */
#if 0
static UCHAR Classic[] = {		/* Janet's ordered dither matrix */
	  0,128, 32,160,  8,136, 40,168,
	192, 64,224, 96,200, 72,232,104,
	 48,176, 16,144, 56,184, 24,152,
	236,112,208, 80,244,120,216, 88,
	 12,140, 44,172,  4,132, 36,164,
	204, 76,232,108,196, 68,228,100,
	 60,188, 28,156, 52,180, 20,148,
	248,124,220, 92,240,116,212, 84,
	};
#endif
#if 0
static UCHAR CoarseFatting[] = {		/* 8x8 Coarse Fatting */
	 16, 56,208,232,224,180, 80, 24,
	 64,104,152,200,192,144,112, 72,
	172,140,124, 36, 44,100,132,164,
	244,184, 92,  4, 12, 52,220,240,
	228,188, 84, 28, 20, 60,212,236,
	196,148,116, 76, 68,108,156,204,
	 40, 96,128,160,168,136,120, 32,
	  8, 48,216,240,244,176, 88,  0,
	};
#endif
#if 0
static UCHAR VertLine[] = {			/* Vertical Line */
	  0, 64,124,188,  8, 72,132,192,
	 16, 80,140,200, 24, 88,148,204,
	 32, 96,156,212, 40,104,164,216,
	 48,112,172,220, 56,116,180,224,
	 12, 76,136,196,  4, 68,128,192,
	 28, 92,152,208, 20, 84,144,200,
	 44,108,168,216, 36,100,160,212,
	 60,120,184,224, 52,112,176,220,
	};
#endif
#if 0
static UCHAR FineFatting[] = {		/* Fine Fatting */
	  0, 32,148,160,  8, 40,144,156,
	 64, 96,172,184, 72,104,168,180,
	128,152, 16, 48,136,152, 24, 56,
	164,176, 80,112,164,176, 88,120,
	 12, 44,144,156,  4, 36,148,160,
	 76,108,168,180, 68,100,172,184,
	140,152, 28, 60,132,152, 20, 52,
	164,176, 92,124,164,176, 84,116,
	};
#endif
#if 0
static UCHAR BayerDither[] = {		/* 8x8 Bayer Dither */
	184, 64,128,176,220, 72,136,184,
	160,  0, 16, 80,168,  8, 24, 88,
	112, 48, 32,140,120, 56, 40,148,
	204,152, 96,192,212,156,104,200,
	220, 76,136,188,216, 68,132,180,
	172, 12, 28, 92,164,  4, 20, 84,
	124, 60, 44,148,116, 52, 36,144,
	212,156,108,208,152,144,100,196,
	};
#endif
+ARCHIVE+ resize.c      7719  3/16/1991  5:26:30
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		resize
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>
#include <string.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
static int _cdecl init_scratch(imgdes *,int,int);
static int _cdecl scratch2des(imgdes *,imgdes *,int,int);
static void _cdecl generate_ftable(unsigned,UCHAR *);

/* Resize an image area. Works in 1/256 increments. Source and result areas
	should not overlap unless sufficient extended, expanded, or conventional
	memory is available to hold the resized image.
	Returns NO_ERROR, BAD_RANGE, BAD_MEM, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR,
	or CM_ERR.
*/
int _cdecl resize(imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int dxpixnum, dypixnum;	/* no. of pixels to plot in dest per source pixel */
	unsigned pcxinc, pcyinc;/* factors representing % inc in size in x,y dir */
	int sxpix, sypix;			/* width, ht, in pixels of source area */
	int dxpix, dypix;			/* width, ht, in pixels of destn area */
	int xctr, yctr, j, dwidth, dxctr, dyctr, shandle, dhandle;
	int sxindex, syindex, dxindex, dyindex, dyend, tint;
	int zx, zy;			/* width, ht, in pixels to write in dest area */
	int syctr, rcode=NO_ERROR, tmpflag;	/* 1 if scratch buffer was allocated */
	UCHAR *exbuff, *sptr, *xfactor, *yfactor;
	long tmp;
	imgdes *image, scratch;	/* For temp storage of resized image */

	/* Check range of start, end positions */
	if(checkrange_(srcimg) || checkrange_(desimg))
		return(BAD_RANGE);
	syctr = srcimg->sty;
	sxpix = srcimg->endx - srcimg->stx + 1;
	sypix = srcimg->endy - srcimg->sty + 1;
	/* Calc width, height of dest area */
 	dxpix = desimg->endx - desimg->stx + 1;
	dypix = desimg->endy - desimg->sty + 1;
	/* Number of pixels to write in dest */
	zx = (int)(((((long)dxpix << 8) / sxpix) * sxpix) >> 8);
	zy = (int)(((((long)dypix << 8) / sypix) * sypix) >> 8);
	/* If dest area has no width or height, exit */
	if(!(zx && zy)) {
		rcode = BAD_RANGE;
		goto xit;
		}
	dxpixnum = zx / sxpix;		/* Multiplier, 200%->2, 414%->4, etc */
	dypixnum = zy / sypix;
	/* Increase factor in 256ths,
		pcxinc = ((zx % sxpix) * 256) / sxpix;
		pcxinc = 414% = 4+35.8/256->36, 231% = 2+79.4/256->79
	*/
	tmp = (long)(zx % sxpix) << 8; pcxinc = (unsigned)(tmp / sxpix);
	/* Round up if needed */
	if(tmp % sxpix > (sxpix >> 1))
		pcxinc++;
	/* Calc Y increase factor in 256ths */
	tmp = (long)(zy % sypix) << 8;
	pcyinc = (unsigned)(tmp / sypix);
	/* Round up if needed */
	if(tmp % sypix > (sypix >> 1))
		pcyinc++;
	dyend = desimg->sty + zy;		/* Calc end of block */
	syindex = 0;
	dyindex = desimg->sty;
	/* Allocate space for our source buffer and factor tables */
	if((exbuff=(UCHAR *)malloc(sxpix + 512)) == NULL) {
		rcode = BAD_MEM;	/* If area not allocated */
		goto xit;
		}
	/* Generate xfactor, yfactor tables */
	generate_ftable(pcxinc, xfactor=&exbuff[sxpix]);
	generate_ftable(pcyinc, yfactor=&exbuff[sxpix+256]);
	/* If possible, Set up a scratch buffer in extended, expanded, or
		conventional memory. Tmpflag != 0 if it worked.
	*/
	if((tmpflag=init_scratch(&scratch, zx, zy)) != 0) {
		image = &scratch;
		dxctr = 0;
		dyctr = 0;
		dwidth = zx;
		}
	else {
		image = desimg;
		dxctr = desimg->stx;
		dyctr = desimg->sty;
		dwidth = desimg->iwidth;
		}
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) != NO_ERROR ||
		(rcode=assign_gprow_(image, &dhandle, &dummy, &putrow)) != NO_ERROR)
		goto eob;
	for(;;) {
		/* Get a line of data to process */
		if((rcode=getrow(exbuff, shandle, srcimg->stx, syctr++,
			sxpix, srcimg->iwidth)) != NO_ERROR)
			goto eob;
		sptr = exbuff;		/* Reset source ptr */
		yctr = dypixnum;	/* yctr is no. of lines to draw */
		if(yfactor[syindex & 0xff])	/* based on factor add a line */
			yctr++;
		if(yctr) {	/* Stretch or shrink in x direction */
			/* First time thru draw line */
			sxindex = 0;
			dxindex = 0;		/* Index into Hbuff_ */
			for(;;) {			/* Stretch or shrink one line */
				xctr = dxpixnum;	/* Set up xctr */
				/* Are extra points needed? */
				if(xfactor[sxindex & 0xff])	/* based on factor add a line */
					xctr++;
				tint = *sptr++;	/* Read source color */
				for(j=0; j<xctr; j++) {
					Hbuff_[dxindex++] = (UCHAR)tint;
					if(dxindex >= zx)	/* Write zx pixels */
						goto eol;
					}
				sxindex++;
				}
eol:		while(yctr--) {
				/* Copy line from Hbuff_ to des or XM/EM/CM */
				if((rcode=putrow(Hbuff_, dhandle, dxctr, dyctr++, zx, dwidth)) != NO_ERROR ||
					(++dyindex >= dyend))	/* Don't draw line if out of block */
					goto eob;
				}
			}
		syindex++;
		}
eob:
	free(exbuff);
	cmclose_(srcimg, shandle);		/* Close CM handle */
	cmclose_(image, dhandle);
	/* Scratch buffer must now be emptied */
	if(tmpflag && rcode==NO_ERROR) /* Move resized data out of XM/EM/CM */
		rcode = scratch2des(&scratch, desimg, zx, zy);
	if(tmpflag)		/* Free any allocated EM/XM/CM */
		freeimage(&scratch);
xit:
	return(rcode);
}

/* Move resized image data out of XM/EM/CM into dest XM/EM/CM.
	Returns NO_ERROR, EMM_ERR, or XMM_ERR.
*/
static int _cdecl scratch2des(imgdes *srcimg, imgdes *desimg,
	int cols, int rows)
{
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int shandle, dhandle, rcode=NO_ERROR;
	int syctr=0, dyctr=desimg->sty;

	if((rcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) == NO_ERROR &&
		(rcode=assign_gprow_(desimg, &dhandle, &dummy, &putrow)) == NO_ERROR) {
		while(rows--) { /* Hbuff_ is used here as a temporary buffer */
			if((rcode=getrow(Hbuff_, shandle, 0, syctr++,
				cols, cols)) != NO_ERROR)
				break;
			/* Write data in Hbuff_ to des */
			if((rcode=putrow(Hbuff_, dhandle, desimg->stx, dyctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	cmclose_(srcimg, shandle);		/* Close CM handle */
	cmclose_(desimg, dhandle);
	return(rcode);
}

/* Try to allocate a scratch buffer in extended, expanded, or conventional
	memory. Return 1 if success, else 0.
*/
static int _cdecl init_scratch(imgdes *image, int width, int length)
{
	int rcode = 1;
	/* Try EM first */
	if(emallocimage(image, width, length)!=NO_ERROR) {
		/* Try XM next */
		if(xmallocimage(image, width, length) != NO_ERROR) {
			/* Finally, try CM */
			if(cmallocimage(image, width, length) != NO_ERROR)
				rcode = 0;	/* No scratch buffer, return 0 */
			}
		}
	return(rcode);
}

/* Generate X or Y increase factor table. Increm = increase factor, 0 - 255,
	i.e., no. of pixels out of 256 that should be set to 1.
*/
static void _cdecl generate_ftable(unsigned increm, UCHAR *ftable)
{
	unsigned j, indx, fact;
	long val;

	/* Zero table */
	memset_(ftable, 0, 256);
	if(increm) {		/* If increm = 0, table should consist of zeros */
		fact = 255*256 / increm;
		for(j=0; j<increm; j++) {
			val = j * (long)fact;
			indx = (unsigned)(val >> 8);
			if((val & 0xff) >= 128)
				indx++;
			ftable[indx] = 1;
			}
		}
}
+ARCHIVE+ savebif.c     5248  6/06/1991 11:56:54
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		savebif		Save image in system memory as a binary file
		loadbif		Load binary image file into system RAM
*/

#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#define  DTASIZE  8192

extern UCHAR Hbuff_[];
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);
static int Fhandle;
static int _cdecl ReadBifData(imgdes *);
static int _cdecl WriteBifData(imgdes *);
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);

/* Load binary image file. Returns NO_ERROR, BAD_OPN, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl loadbif(char *fname, imgdes *desimg)
{
	int errcode;

	/* Check range of start, end positions */
	if(checkrange_(desimg))
		return(BAD_RANGE);
	if((Fhandle=open(fname, O_BINARY|O_RDONLY)) < 3)
		return(BAD_OPN);
	/* Read in BIF file image data */
	errcode = ReadBifData(desimg);
	close(Fhandle);
	/* If image data was successfully loaded,
		indicate that there is no palette data
	*/
	if(errcode == NO_ERROR)
		desimg->palsize = 0;
	return(errcode);
}

/* Transfer image data stored as binary data on disk. Returns NO_ERROR,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
static int _cdecl ReadBifData(imgdes *desimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	UCHAR *dta_addr=Hbuff_;  /* Address of our file buffer */
	int sctr=0;		 /* Byte counter in dta buffer */
	int dtalimit=0; /* Get more bytes from disk when dtalimit is exceeded */
	int valid_byts=0;
	int handle, rcode=NO_ERROR, byts2mov, cols, rows, yctr=desimg->sty;

	rows = desimg->endy - desimg->sty + 1;
	cols = desimg->endx - desimg->stx + 1;
	/* Assign handle, putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if(sctr >= dtalimit) { /* Nearly out of valid bytes in the DTA */
				/* Move any valid bytes left to the front of the DTA */
				byts2mov = valid_byts - sctr;
				if(byts2mov < 0)  byts2mov = 0;		/* Play it safe */
				memcpy_(dta_addr, &dta_addr[sctr], byts2mov);
				/* Read in more data and calc valid bytes in the DTA */
				valid_byts = byts2mov +
					read(Fhandle, &dta_addr[byts2mov], DTASIZE-byts2mov);
				/* No more bytes in the DTA => we're done */
				if(valid_byts == 0)
					break;
				/* Set dta_limit back from end of DTA to allow reading a line at
					a time without reading invalid data.
				*/
				if((dtalimit=valid_byts-2*desimg->iwidth) <= 0)
					dtalimit = valid_byts;
				sctr = 0;			/* Reinitialize sctr */
				}
			/* Move data from DTA into buffer */
			if((rcode=putrow(&dta_addr[sctr], handle, desimg->stx, yctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			sctr += desimg->iwidth;	/* Add in cbyts to advance DTA index */
			}
		}
	cmclose_(desimg, handle);		/* Close CM handle */
	return(rcode);
}

/**** Write BIF functions ****/

/* Save image as a binary file. Returns NO_ERROR, BAD_DSK, BAD_CRT,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl savebif(char *fname, imgdes *srcimg)
{
	int errcode;

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	if((Fhandle=open(fname, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, S_IWRITE)) < 3)
		return(BAD_CRT);
	/* Write BIF file image data */
	errcode = WriteBifData(srcimg);
	close(Fhandle);
	if(errcode!=NO_ERROR)  remove(fname);	/* Error, erase file */
	return(errcode);
}

/* Write a binary image data (BIF) file. Returns NO_ERROR, BAD_DSK,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
static int _cdecl WriteBifData(imgdes *srcimg)
{
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	UCHAR *dta_addr=Hbuff_;	/* Address of our file buffer */
	int sctr=0;		/* Byte counter in dta buffer */
	int dtalimit;	/* Write the DTA when it gets this full */
	int rcode=NO_ERROR, cols, rows, yctr=srcimg->sty, handle;

	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	dtalimit = DTASIZE - (cols * 2);
	/* Assign handle, getrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if(sctr >= dtalimit) {	/* Write the DTA if it's full */
				if(write(Fhandle, dta_addr, sctr) != sctr) {
					rcode = BAD_DSK;
					goto err;
					}
				sctr = 0;			/* Reset DTA index */
				}
			if((rcode=getrow(&dta_addr[sctr], handle, srcimg->stx, yctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				goto err;
			sctr += cols;			/* Update sctr */
			}
		/* Done with "rows" rows. Write any valid bytes left in the DTA */
		if(write(Fhandle, Hbuff_, sctr) != sctr)
			rcode = BAD_DSK;
		}
err:
	cmclose_(srcimg, handle);		/* Close CM handle */
	return(rcode);
}
+ARCHIVE+ savegif.c    11626  3/27/1991 15:43:14
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		savegif					Save image in system memory as a GIF file
		  write_gif_header	Fix and write the GIF header
		loadgif					Load GIF image into system memory
		gifinfo					Get info on GIF file
		  find_image_descriptor Read file until we find first image descriptor
		loadgifpalette			Load GIF palette from colormap
*/

#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#define DTASIZE 8192

/* GIF header */
static UCHAR GifHdr[] = {
	'G','I','F','8','7','a',	/* "GIF87a" */
	0xff,0xff,						/* Screen width */
	0xff,0xff,						/* Screen height */
	0xf7,				/* 1 111 0 111, gbl col map, cr=7, bits/pixel=7 */
	0x00,				/* Screen backgnd color */
	0x00,				/* Reserved */
	};
/* Global color map (768 bytes of it) comes next (RGB bytes) */

static UCHAR Image1Hdr[] = {	/* Image descriptor starts at 781 */
	',',					/* Image separator char */
	0x00,0x00,			/*	Image left */
	0x00,0x00,			/*	Image top */
	0xff,0xff,			/*	Image width */
	0xff,0xff,			/*	Image height */
	0x00,					/* No local color map (map follows if 1), more */
	0x08					/* Code size is 8 bits per pixel */
/* Raster data starts at 792 (0x318) */
	};

static UCHAR GifFooter[] = {
	0x00,					/* Zero byte count -- terminates block */
	';'};					/* GIF terminator */

extern UCHAR Hbuff_[];
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern int _cdecl checkrange_(imgdes *);
int _cdecl WriteGif_(imgdes *,int,UCHAR *,UCHAR *);
int _cdecl ReadGif_(imgdes *,int,UCHAR *,UCHAR *,int,int,GifData *);
static int _cdecl check_em_xm(imgdes *);
static void _cdecl write_gif_header(imgdes *);
static long _cdecl find_image_descriptor(long);
static int Fhandle;
static int Cols, Rows;		/* Image columns, rows */
static long ColMapAddr;		/* Bytes from file start to colormap */
static long RastDataAddr;	/* Bytes from file start to start of raster data */
static int ColMapVals; 		/* Entries in colormap table (bytes) */

#define CODESIZE 8

/* Save image as a GIF file. Returns NO_ERROR, BAD_DSK (disk full),
	BAD_CRT, BAD_RANGE, BAD_MEM (not enough conventional memory), 
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl savegif(char *fname, imgdes *srcimg)
{
	UCHAR *strtab, *exbuff;
	int errcode;

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	if((Fhandle=open(fname, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, S_IWRITE)) < 3)
		return(BAD_CRT);
	/* Calculate no. of columns and rows to write */
	Cols = srcimg->endx - srcimg->stx + 1;
	Rows = srcimg->endy - srcimg->sty + 1;
	/* Allocate enough memory for the LZW string table and an
		expansion buffer
	*/
	if((strtab=(UCHAR *)malloc(5*4096+16 + Cols)) == NULL) {
		errcode = BAD_MEM;	/* If the area wasn't allocated */
		goto xit;
		}
	exbuff = &strtab[5*4096+16];	/* Assign part of it to exbuff */
	/* Write the GIF header (global color map, dimensions, etc.) */
	write_gif_header(srcimg); /* Ignore write errors for now */
	/* If we're using EM or XM, make sure that it exists */
	if((errcode=check_em_xm(srcimg)) == NO_ERROR) {
		if((errcode=WriteGif_(srcimg, Fhandle, exbuff, strtab)) == NO_ERROR) {
			/* Write the GIF footer */
			if(write(Fhandle, GifFooter, sizeof(GifFooter)) != sizeof(GifFooter))
				errcode = BAD_DSK;
			}
		}
	free(strtab);
xit:
	close(Fhandle);
	if(errcode!=NO_ERROR)  remove(fname);	/* Error, erase file */
	return(errcode);
}

/* Fix and write the GIF header (ignore write errors for now) */
static void _cdecl write_gif_header(imgdes *srcimg)
{
	int len, count;

	/* Assemble header in Hbuff_ */
	memcpy_(Hbuff_, GifHdr, len=sizeof(GifHdr));
	/* Copy the global color map into Hbuff_, but not more than 768 bytes */
	if((count=srcimg->palsize) > 768)
		count = 768;
	memcpy_(&Hbuff_[len], srcimg->palette, count);
	len += count;
	/* We want 768 entries -- zero any remaining bytes */
	memset_(&Hbuff_[len], 0, count=768-count);
	len += count;
	/*  and the rest of the header */
	memcpy_(&Hbuff_[len], Image1Hdr, sizeof(Image1Hdr));
	/* Fix screen width, length fields */
	*(int *)&Hbuff_[6] = *(int *)&Hbuff_[len+5] = Cols;
	*(int *)&Hbuff_[8] = *(int *)&Hbuff_[len+7] = Rows;
/* If we wish to use a different bits per pixel value:
	Hbuff_[10] = 0x80 | (color_res<<4) | (bitsperpixel-1);
*/
	Hbuff_[len+10] = CODESIZE;
	len += sizeof(Image1Hdr);
	write(Fhandle, Hbuff_, len);
}

/**** Load GIF routines ****/

/* Load GIF file into desimg. Returns NO_ERROR, BAD_OPN, BAD_GIF,
	BAD_RANGE, BAD_MEM (not enough conventional memory), NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl loadgif(char *fname, imgdes *desimg)
{
	GifData gdat;	/* Allocate space for struct for loadgif */
	int errcode;
	UCHAR *strtab, *exbuff;
	
	/* Check range of start, end positions */
	if(checkrange_(desimg))
		return(BAD_RANGE);
	/* Get info on GIF file we're to load */
	if((errcode=gifinfo(fname, &gdat)) != NO_ERROR)	/* Fill structure */
		return(errcode);
	if((Fhandle=open(fname, O_BINARY|O_RDONLY)) < 3)
		return(BAD_OPN);
	Rows = desimg->endy - desimg->sty + 1;
	if(Rows > gdat.Ilength)		/* Use the smaller no. of rows value */
		Rows = gdat.Ilength;
	Cols = desimg->endx - desimg->stx + 1;
	if(Cols > gdat.Iwidth)		/* Use the smaller no. of cols value */
		Cols = gdat.Iwidth;
	if(Cols == 0)			/* Exit if cols = 0 */
		return(NO_ERROR);
	/* Check GIF header for valid settings before loading the file */
	if(outrange(4, gdat.Codesize, 8))
		return(BAD_GIF);
	/* Allocate enough memory for the LZW string table and an
		expansion buffer
	*/
	if((strtab=(UCHAR *)malloc(3*4096+16 + gdat.Iwidth)) == NULL) {
		errcode = BAD_MEM;	/* If the area wasn't allocated */
		goto xit;
		}
	exbuff = &strtab[3*4096+16];	/* Assign part of it to exbuff */
	/* If we're using EM or XM, make sure that it exists */
	if((errcode=check_em_xm(desimg)) == NO_ERROR) {
		/* Move file pointer to start of Raster data */
		lseek(Fhandle, RastDataAddr, SEEK_SET);
		errcode = ReadGif_(desimg, Fhandle, exbuff, strtab, Cols, Rows, &gdat);
		}
	free(strtab);
xit:
	close(Fhandle);
	/* If image data was successfully loaded, load the palette data */
	if(errcode == NO_ERROR) {
		desimg->palsize = (desimg->palette) ?
			loadgifpalette(fname, desimg->palette) : 0;
		}
	return(errcode);
}

#ifdef USAGE
/* GIF file format info structure definition (used by gifinfo) */
GifData {			/* defined in vicdefs.h */
	int Iwidth, Ilength, BitsColRes, BitsPPixel, BckCol, Laceflag;
	} ginfo;
Caller must allocate space for GifData structure as follows:
	GifData ginfo;	/* Allocate space for struct */
	......
	errcode = gifinfo(filnam, &ginfo);	/* fill structure */
	......
	printf("Image width = %d",ginfo.Iwidth);
#endif

/* Get info on GIF file. Rets error codes: NO_ERROR - none,
	BAD_OPN - cannot find fname, BAD_GIF - not a GIF file
*/
int _cdecl gifinfo(char *fname, GifData *ginfo)
{
	int rcode=NO_ERROR;
	int global_color_map, local_color_map;
	long fpos;		/* Position from start of file in bytes */

	ColMapAddr = 0;
	ColMapVals = 0;	/* Open file */
	if((Fhandle=open(fname, O_BINARY|O_RDONLY)) < 3)
		return(BAD_OPN);
	memset_(ginfo, 0, sizeof(GifData));		/* Zero struct */
	/* Read in the image file header, get required info */
	read(Fhandle, Hbuff_, 256);
	/* Is it a GIF file? */
	if(memcmp(Hbuff_, "GIF87a", 6) != 0) {
		rcode = BAD_GIF;
		goto xit;
		}
	global_color_map = Hbuff_[10] & 0x80;
	ginfo->BitsColRes = ((Hbuff_[10]&0x70)>>4) + 1;
	ginfo->BitsPPixel = (Hbuff_[10] & 0x07) + 1;
	ginfo->BckCol = Hbuff_[11];	/* Background palette to use */
	/* Hbuff_[12] should be 0 */
	if(global_color_map) { /* If 0x80, Global color map exists => set addr */
		ColMapAddr = 13L;	  /* Addr of global color map */
		ColMapVals = (1<<ginfo->BitsPPixel)*3;
		}
	/* Move file pointer to end of Screen descriptor */
	lseek(Fhandle, fpos=ColMapVals+13L, SEEK_SET);
	/* Read file until we find the first image descriptor (marked by a ',')
		or EOF
	*/
	if((fpos=find_image_descriptor(fpos)) == -1L) {
		rcode = BAD_GIF;
		goto xit;
		}
	/* Move file pointer to start of Image descriptor and read it in */
	lseek(Fhandle, fpos, SEEK_SET);
	read(Fhandle, Hbuff_, 256);
	ginfo->Iwidth  = *(int *)&Hbuff_[5];
	ginfo->Ilength = *(int *)&Hbuff_[7];
	ginfo->Laceflag = (Hbuff_[9]&0x40)>>6;
	local_color_map = Hbuff_[9] & 0x80;
	if(local_color_map) { /* If 0x80, local color map exists, so set addr */
		/* If local color map, reset BitsPPixel */
		ginfo->BitsPPixel = (Hbuff_[9]&0x07) + 1;
		ColMapAddr = fpos + 10;
		ColMapVals = (1<<ginfo->BitsPPixel)*3;
		fpos += ColMapVals;		/* Adjust file pointer */
		}
	/* Move file pointer to start of Raster data */
	lseek(Fhandle, fpos += 10, SEEK_SET);
	read(Fhandle, Hbuff_, 1);	/* Get code size */
	ginfo->Codesize = Hbuff_[0];	/* Save start of raster data */
	RastDataAddr = fpos + 1;	/* (count byte beyond Codesize) */
xit:
	close(Fhandle);
	return(rcode);
}

/* Read file until we find the first image descriptor (marked by a ',')
	or EOF. Ret position of ',' or -1L.
*/
static long _cdecl find_image_descriptor(fpos)
long fpos;					/* Position from start of file in bytes */
{
	int byt_ct, j;

	while(read(Fhandle, Hbuff_, 256) > 0) { /* Read in some data */
		for(j=0; j<256; j++) {	/* Must find ',' or '!' within 256 bytes */
			if(Hbuff_[j] == ',')	/* Found an image separator */
				return(fpos + j);	/* Update fpos and return */
			if(Hbuff_[j] == '!') {	/* Found an extension block */
				/* Hbuff_[j] = '!', Hbuff_[j+1] = ext_code */
				fpos += j + 3;			/* Update fpos */
				byt_ct = Hbuff_[j+2];		/* Get no. of bytes in block */
				lseek(Fhandle, fpos, SEEK_SET);	/* and adjust the file ptr */
				while(byt_ct) {
					/* Keep reading data until we find 0, or run out of data */
					if(read(Fhandle, Hbuff_, byt_ct+1) != byt_ct+1)
						goto xit;	/* Error */
					fpos += byt_ct + 1;
					byt_ct = Hbuff_[byt_ct];
					}
				break;
				}
			}
		}
xit:
	return(-1L);	/* Ran out of data before finding a ',' */
}

/* Load GIF palette from colormap. Returns no. of color map entries,
	BAD_OPN, or BAD_GIF.
*/
int _cdecl loadgifpalette(char *fname, UCHAR *pal)
{
	GifData gdat;	/* Allocate space for struct for loadtif */
	int errcode;
	
	if((errcode=gifinfo(fname, &gdat)) != NO_ERROR)	/* Fill structure */
		return(errcode);
	/* Check GIF header for validity, exit if error */
	if(outrange(4, gdat.Codesize, 8))
		return(BAD_GIF);
	if((Fhandle=open(fname, O_BINARY|O_RDONLY)) < 3) /* Open file */
		return(BAD_OPN);
	/* No errors, return the palette data */
	/* Move file ptr to the colormap	*/
	lseek(Fhandle, ColMapAddr, SEEK_SET);
	read(Fhandle, pal, ColMapVals);		/* Put colormap into pal */
	close(Fhandle);
	return(ColMapVals);
}

/* If we're using EM or XM, make sure that it exists. Returns NO_ERROR,
	NO_EMM, EMM_ERR, NO_XMM, or XMM_ERR.
*/
static int _cdecl check_em_xm(imgdes *image)
{
	if(image->ibuff)			/* Image is in CM, return NO_ERROR */
		return(NO_ERROR);
	if(image->ehandle)		/* Image is in EM, make sure it exists */
		return(emdetect());
	return(xmdetect());		/* Image is in XM, make sure it exists */
}
+ARCHIVE+ savepcx.c    14370  4/05/1991  9:51:26
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		loadpcx			Load an 8-bit PCX file
		  ReadPcxData
		savepcx			Save an image buffer as an 8-bit PCX file
		  WritePcxData
		pcxinfo			Get info on PCX file
		loadpcxpalette	Load PCX palette
*/

#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <stdlib.h>
#include <io.h>
#define  XLIMIT   4047
#define  YLIMIT  32767
#define  DTASIZE  8192
/* If BPL_EVEN != 0, write PCX files with even bytes per line only
	Equate in writepcx.asm must match!
*/
#define  BPL_EVEN  0

extern UCHAR Hbuff_[];

extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl unpackpcx_(UCHAR *,UCHAR *,int);
extern int _cdecl packpcx_(UCHAR *,UCHAR *,int);
static int _cdecl ReadPcxData(int,imgdes *);
static int _cdecl WritePcxData(imgdes *);
static int Fhandle;
static int Xwidth, Xlength;	/* PCX width, height */

/* Load PCX file into desimg. Returns NO_ERROR, BAD_OPN, BAD_RANGE,
	BAD_PCX, BAD_MEM (not enough conventional memory), NO_EMM, EMM_ERR,
	NO_XMM, or XMM_ERR.
*/
int _cdecl loadpcx(char *fname, imgdes *desimg)
{
	PcxData pdat;	/* Allocate space for struct */
	int errcode;
	
	/* Check range of start, end positions */
	if(checkrange_(desimg))
		return(BAD_RANGE);
	/* Get info on PCX file we're to load */
	if((errcode=pcxinfo(fname, &pdat)) != NO_ERROR)	/* Fill structure */
		return(errcode);
	if((Fhandle=open(fname, O_BINARY|O_RDONLY)) < 3) /* Open fname.pcx file */
		return(BAD_OPN);
	/* Check PCX header for valid settings before loading the file
		Note: PCX identity already checked
	*/
	Xwidth = pdat.Xmax - pdat.Xmin + 1;
	Xlength= pdat.Ymax - pdat.Ymin + 1;
	if(pdat.BPPixel==8 && pdat.Nplanes==1 &&
		/* Also, calculate Xwidth and Xlength */
		inrange(0, Xwidth, XLIMIT) &&
		inrange(0, Xlength, YLIMIT)) {
			/* Move file ptr to start of image data */
			lseek(Fhandle, 128L, SEEK_SET);
			/* Read in the image data */
			errcode = ReadPcxData(pdat.BytesPerLine, desimg);
		}
	else  errcode = BAD_PCX;
	close(Fhandle);
	/* If image data was successfully loaded, load the palette data */
	if(errcode == NO_ERROR) {
		desimg->palsize = (desimg->palette) ?
			loadpcxpalette(fname, desimg->palette) : 0;
		}
	return(errcode);
}

/* Load PCX file into desimg. Returns NO_ERROR, BAD_MEM (not enough
	conventional memory for expansion buffer), NO_EMM, EMM_ERR, NO_XMM,
	or XMM_ERR.
*/
static int _cdecl ReadPcxData(int bpline, imgdes *desimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	UCHAR *dta_addr=Hbuff_;  /* Address of our file buffer */
	int sctr=0;		 /* Byte counter in dta buffer */
	int dtalimit=0; /* Get more bytes from disk when dtalimit is exceeded */
	int valid_byts=0;
	int rcode=NO_ERROR, byts2mov, cols, rows, yctr=desimg->sty, handle;
	UCHAR *exbuff;

	/* Use the smaller number of rows value */
	rows = desimg->endy - desimg->sty + 1;
	if(rows > Xlength)	/* Xlength = rows available based on PCX header */
		rows = Xlength;
	/* Use the smaller number of cols value */
	cols = desimg->endx - desimg->stx + 1;
	if(cols > Xwidth)
		cols = Xwidth;
	/* Allocate space for expansion buffer */
	if((exbuff=(UCHAR *)malloc(bpline)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	/* Assign handle, putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if(sctr >= dtalimit) { /* Nearly out of valid bytes in the DTA */
				/* Move any valid bytes left to the front of the DTA */
				byts2mov = valid_byts - sctr;
				if(byts2mov < 0)  byts2mov = 0;		/* Play it safe */
				memcpy_(dta_addr, &dta_addr[sctr], byts2mov);
				/* Read in more data and calc valid bytes in the DTA */
				valid_byts = byts2mov +
					read(Fhandle, &dta_addr[byts2mov], DTASIZE-byts2mov);
				/* No more bytes in the DTA => we're done */
				if(valid_byts == 0)
					break;
				/* Set dta_limit back from end of DTA to allow reading a
					line at a time without reading invalid data.
				*/
				if((dtalimit=valid_byts-2*bpline) <= 0)
					dtalimit = valid_byts;
				sctr = 0;		/* Reinitialize sctr */
				}	/* Unpack a row into exbuff and update sctr */
			sctr += unpackpcx_(exbuff, &dta_addr[sctr], bpline);
			if((rcode=putrow(exbuff, handle, desimg->stx, yctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	free(exbuff);		/* Free the allocated buffer */
	cmclose_(desimg, handle);		/* Close CM handle */
	return(rcode);
}

/**** Write PCX functions ****/

/* PCX header used for saving images as 8-bit PCX files */
static UCHAR PcxHdr[] = { 		 			/* byte offset */
	10, 5, 1,	/* PCX file, version info, RLE mode */
	8,				/* BitsPerPixel */
	0,0, 0,0,					/* Window - Xmin,Ymin */
	0x3f,0x01, 0xf3,0x00,	/* Window - Xmax,Ymax */
	0x40,0x01, 0xc8,0x00,	/* Hres, Vres */
	/* ColorMap - not used for saving VGA PCX images */
	0x00,0x00,0x00, 0x10,0x10,0x10, 0x20,0x20,0x20, 0x30,0x30,0x30,
	0x40,0x40,0x40, 0x50,0x50,0x50, 0x60,0x60,0x60, 0x70,0x70,0x70,
	0x80,0x80,0x80, 0x90,0x90,0x90, 0xa0,0xa0,0xa0, 0xb0,0xb0,0xb0,
	0xc0,0xc0,0xc0, 0xd0,0xd0,0xd0, 0xe0,0xe0,0xe0, 0xf0,0xf0,0xf0,
	0, 1,			/* Reserved, NumPlanes */
	0x40, 0x01,	/* BytesPerLine 320 */
	2, 0			/* Palette interpretation: 1 = color, 2 = gray scale */
	};

/* Save image as a PCX file. If Paltab == NULL we're not saving the palette
	info. Paltab otherwise must be 768 bytes of palette info (red, blue, and
	green bytes). Returns NO_ERROR, BAD_DSK (disk full), BAD_CRT, BAD_RANGE,
	BAD_MEM (not enough conventional memory), NO_EMM, EMM_ERR, NO_XMM,
	or XMM_ERR.
*/
int _cdecl savepcx(char *fname, imgdes *srcimg)
{
	int *ip, errcode, bpline;

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	if((Fhandle=open(fname, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, S_IWRITE)) < 3)
		return(BAD_CRT);
	/* Fix and write the PCX header */
	PcxHdr[1] = (UCHAR)((srcimg->palsize == 0) ? 3 : 5); /* PCX version no. */
	ip = (int *)PcxHdr;
	ip[4/2]  = srcimg->stx; ip[6/2] = srcimg->sty; /* Xmin, Ymin */
	ip[8/2]  = srcimg->endx; ip[10/2] = srcimg->endy; /* Xmax, Ymax */
	ip[12/2] = srcimg->iwidth;	 		/* Hres */
	ip[14/2] = srcimg->endy - srcimg->sty + 1; /* Vres = rows */
	bpline = srcimg->endx - srcimg->stx + 1;
#if BPL_EVEN
	if(bpline & 1)  bpline++;	/* Make sure bpline is even */
#endif
	ip[66/2] = bpline; /* Bytes per line */
	ip[68/2] = 1;			 		/* Pal info interp, 1=color, 2=gray */
	/* Write the header (ignore errors for now) */
	write(Fhandle, PcxHdr, 128);

	/* Write PCX file image data */
	if((errcode=WritePcxData(srcimg)) == NO_ERROR &&
		srcimg->palsize != 0) {
		/* Insert the header byte and copy over the palette info at EOF */
		Hbuff_[0] = 12;
		memcpy_(&Hbuff_[1], srcimg->palette, 768);
		/* Write the palette info */
		if(write(Fhandle, Hbuff_, 769) != 769)
			errcode = BAD_DSK;		/* Disk full, couldn't write it */
		}
	close(Fhandle);
	if(errcode!=NO_ERROR)  remove(fname);	/* Error, erase file */
	return(errcode);
}

/* Write a PCX compressed file. Returns NO_ERROR, BAD_DSK (disk full),
	BAD_MEM (not enough conventional memory for compression buffer),
	NO_EMM, EMM_ERR, NO_XMM, or XMM_ERR.
*/
static int _cdecl WritePcxData(imgdes *srcimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	UCHAR *exbuff, *dta_addr=Hbuff_;	/* Address of our file buffer */
	int sctr=0;		/* Byte counter in dta buffer */
	int rcode=NO_ERROR, cols, rows, yctr=srcimg->sty, handle;
	int dtalimit;				/* Write the DTA when it gets this full */

	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	dtalimit = DTASIZE - 2 - (cols * 2);
	/* Allocate space for compression buffer. One row of PCX data is
		compressed into exbuff. Worst case behavior is 1 -> 2 bytes.
	*/
	if((exbuff=(UCHAR *)malloc(2*cols)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	/* Assign handle, getrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if(sctr >= dtalimit) {	/* Write the DTA if it's full */
				if(write(Fhandle, dta_addr, sctr) != sctr) {
					rcode = BAD_DSK;
					goto err;
					}
				sctr = 0;		/* Reset DTA index */
				}
			if((rcode=getrow(exbuff, handle, srcimg->stx, yctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				goto err;
			/* Pack a line and update sctr */
			sctr += packpcx_(&dta_addr[sctr], exbuff, cols);
			}
		/* Write any valid bytes left in the DTA */
		if(write(Fhandle, dta_addr, sctr) != sctr)
			rcode = BAD_DSK;
		}
err:
	free(exbuff);		/* Free the allocated buffer */
	cmclose_(srcimg, handle);		/* Close CM handle */
	return(rcode);
}

#ifdef USAGE
/* PCX file format info structure definition (used by pcxinfo) */
typedef struct {		/* defined in vicdefs.h */
int PCXvers,		/* 5 = palette info, 3 no pal info */
	 BPPixel,		/* Bits per pixel */
	 Xmin, Ymin,	/* Min X, Min Y */
	 Xmax, Ymax,	/* Max X, Max Y */
	 Nplanes,		/* Number of planes */
	 BytesPerLine,	/* Bytes per line */
	 PalInt;		/* Palette info interpretation: 1 = color, 2 = gray scale */
	 } PcxData;
Caller must allocate space for TiffData structure as follows:
	PcxData pinfo;	/* Allocate space for struct */
	......
	errcode = pcxinfo(filnam, &pinfo);	/* fill structure */
	......
	printf("Version no. = %d",pinfo.PCXvers);
#endif

/* Get info on PCX file. Returns error codes: NO_ERROR - none,
	BAD_OPN - cannot find filename, BAD_PCX - not a PCX file
*/
int _cdecl pcxinfo(char *fname, PcxData *pinfo)
{
	int fhr;

	if((fhr=open(fname, O_BINARY|O_RDONLY)) < 3)
		return(BAD_OPN);
	memset_(pinfo, 0, sizeof(PcxData));	/* zero struct */
	/* Read image file header into Hbuff_ */
	read(fhr, Hbuff_, 128);
	/* Byte 0 must be 10 and byte 2 must be 1 */
	if(Hbuff_[0] != 10 || Hbuff_[2] != 1)
		return(BAD_PCX);
	pinfo->PCXvers = Hbuff_[1];
	pinfo->BPPixel = Hbuff_[3];
	pinfo->Xmin = *(int *)&Hbuff_[4];
	pinfo->Ymin = *(int *)&Hbuff_[6];
	pinfo->Xmax = *(int *)&Hbuff_[8];
	pinfo->Ymax = *(int *)&Hbuff_[10];
	pinfo->Nplanes = Hbuff_[65];
	pinfo->BytesPerLine = *(int *)&Hbuff_[66];
	pinfo->PalInt = *(int *)&Hbuff_[68];
	close(fhr);
	return(NO_ERROR);
}

/* Load PCX palette. Returns number of bytes of palette info, BAD_OPN
	or BAD_PCX.
*/
int _cdecl loadpcxpalette(char *fname, UCHAR *paltbl)
{
	PcxData pdat;	/* Allocate space for struct */
	int errcode, count;
	
	if((errcode=pcxinfo(fname, &pdat)) != NO_ERROR)	/* Fill structure */
		return(errcode);
	if((Fhandle=open(fname, O_BINARY|O_RDONLY)) < 3)
		return(BAD_OPN);
	/* Note: PCX identity already checked */
	/* Version MUST be 5 for palette info to be present */
	if(pdat.PCXvers == 5 || pdat.PCXvers == 2) {
		/* If it's a Gray scale image, check at the end of the file */
		if(pdat.BPPixel == 8 && pdat.Nplanes == 1) {
			/* Move file ptr to end of file - 769 bytes	*/
			lseek(Fhandle, -769L, SEEK_END);
			read(Fhandle, Hbuff_, 769); /* Read "palette info" into Hbuff_ */
			if(Hbuff_[0] == 12)	/* If valid palette data, first byte = 12 */
				memcpy_(paltbl, &Hbuff_[1], count=768);	/* Copy over pal info */
			}
		else {	/* Else palette info is in the header */
			/* Move file ptr to palette info in the PCX header */
			lseek(Fhandle, 16L, SEEK_SET);
			read(Fhandle, paltbl, count=48);		/* Read palette info into pal */
			}
		}
	else
		count = 0;		/* No palette info available */
	close(Fhandle);
	return(count);		/* Ret bytes of palette info (0, 48, or 768) */
}

#if 0
/* Rewritten in Assembler for speed */
/* Unpack a line of data compressed with the PCX scheme.
	Return the number of compressed bytes read.
*/
int _cdecl unpackpcx_(des, src, des_byts)
UCHAR *des;			/* Where to put the unpacked data */
UCHAR *src;			/* Source of data to unpack */
int des_byts;		/* Uncompressed bytes to write */
{
	UCHAR *sptr=src; /* Save src to calc no. of compressed bytes read */
	int count, ch;

	while(des_byts > 0) {
		count = 1;
		/* If ch = 192 -> 255, write the following byte (63 & ch) times */
		if((ch = *src++) >= 0xc0) {
			count = ch & 0x3f;
			ch = *src++;
			}
		/* Store count bytes if there's room */
		while(count--) {
			if(des_byts-- == 0)
				goto xit; /* Exit if we've written as many bytes as requested */
			*des++ = ch;	/* Update dest */
			}
		}	/* Return the number of compressed bytes we read */
xit:
	return(src - sptr);
}
#endif

#if 0
/* Rewritten in Assembler for speed */
/* Pack a line of data using the PCX scheme.
	Return number of compressed bytes.
*/
int _cdecl packpcx_(des, src, byts2pack)
UCHAR *des;			/* Where to put the packed data */
UCHAR *src;			/* Source of data to pack */
int byts2pack;		/* Data bytes to pack */
{
	UCHAR *dptr=des; /* Save des to calc no. of compressed bytes */
	int count, last_byt, ch;

#if 0
	/* Make sure byts2pack is even */
	if(byts2pack & 1)
		byts2pack++;
#endif
	/* Init last_byte, count, and counter */
	last_byt = *src++;
	byts2pack--;
	count = 1;
	while(byts2pack--) {
		if((ch = *src++) == last_byt) {	/* Current byte = last byte => run */
			/* Bump run counter and test if run is done */
			if(++count >= 63) {	/* If yes, write count/byte */
				des += enc_pcx_(last_byt, count, des);	/*  and advance des */
				count = 0;		/* Reset run counter */
				}
			}
		else { 		/* Current byte != last byte, write count/byte */
			des += enc_pcx_(last_byt, count, des);	/*  and advance des */
			last_byt = ch;
			count = 1;		/* Reset run counter */
			}
		}
	/* Write last run fragment */
	des += enc_pcx_(last_byt, count, des);
	/* Return number of compressed bytes */
	return(des - dptr);
}
#endif

+ARCHIVE+ savepiw.c    10666  3/16/1991  5:29:10
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		savepiw			Save an image buffer as an ImageWise PIW file
		loadpiw			Load an ImageWise PIW/PIC/IMW file into an image buffer
*/

#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <fcntl.h>
#include <stdlib.h>
#include <sys\stat.h>
#include <io.h>
#define  DTASIZE  8192
#define  SOP   0x40
#define  SOL   0x41
#define  EOP   0x42
#define  REP1  0x80
#define  REP16 0x90
#define  PIWWIDE  256
#define  PIWLONG  244

extern UCHAR Hbuff_[];
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl enc_piw_(int,int,UCHAR *);
static int _cdecl ReadPiwData(imgdes *);
static int _cdecl unpackpiw(UCHAR *,UCHAR *,int);
static int _cdecl WritePiwData(imgdes *, int);
static int _cdecl packpiw1(UCHAR *,UCHAR *,int);
static int _cdecl packpiw2(UCHAR *,UCHAR *,int);

static int Fhandle;

/* Load a PIW format file into desimg. By definition a PIW file expands
	to a block of 6-bit image data 256 by 244. Since a PIW file has an
	image width = 256, desimg->iwidth must be >= 256. Returns NO_ERROR,
	BAD_OPN, BAD_RANGE, BAD_PIW, BAD_MEM (not enough conventional memory),
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl loadpiw(char *fname, imgdes *desimg)
{
	int errcode, piwhdr;

	/* Check range of start, end positions */
	if(checkrange_(desimg) || desimg->iwidth < 256)
		return(BAD_RANGE);
	if((Fhandle=open(fname, O_BINARY|O_RDONLY)) < 3)
		return(BAD_OPN);
	/* Check PIW "header" for 0x4140, exit if error */
	read(Fhandle, (char *)&piwhdr, 2);
	if(piwhdr == 0x4140) {
		/* "Header" OK, reset file ptr to first SOL (0x41) */
		lseek(Fhandle, 1L, SEEK_SET);
		errcode = ReadPiwData(desimg);
		}
	else  errcode = BAD_PIW;
	close(Fhandle);
	/* If image data was successfully loaded,
		indicate that there is no palette data
	*/
	if(errcode == NO_ERROR)
		desimg->palsize = 0;
	return(errcode);
}

/* Load PIW file into desimg. Returns NO_ERROR, BAD_MEM (not enough
	conventional memory for expansion buffer), NO_EMM, EMM_ERR, NO_XMM,
	or XMM_ERR.
*/
static int _cdecl ReadPiwData(imgdes *desimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	UCHAR *exbuff, *dta_addr=Hbuff_;  /* Address of our file buffer */
	int sctr=0;		 /* Byte counter in dta buffer */
	int dtalimit=0; /* Get more bytes from disk when dtalimit is exceeded */
	int byts_rd, valid_byts=0;
	int rcode=NO_ERROR, byts2mov, cols, rows, yctr=desimg->sty, handle;

	rows = desimg->endy - desimg->sty + 1;
	cols = desimg->endx - desimg->stx + 1;
	/* Allocate space for expansion buffer. One row of PIW data is
		expanded into exbuff. Worst case behavior is 258 -> 256 bytes.
	*/
	if((exbuff=(UCHAR *)malloc(256)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	/* Assign handle, putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if(sctr >= dtalimit) { /* Nearly out of valid bytes in the DTA */
				/* Move any valid bytes left to the front of the DTA */
				byts2mov = valid_byts - sctr;
				if(byts2mov < 0)  byts2mov = 0;		/* Play it safe */
				memcpy_(dta_addr, &dta_addr[sctr], byts2mov);
				/* Read in more data and calc valid bytes in the DTA */
				valid_byts = byts2mov +
					read(Fhandle, &dta_addr[byts2mov], DTASIZE-byts2mov);
				/* No more bytes in the DTA => we're done */
				if(valid_byts == 0)
					break;
				/* Set dta_limit back from end of DTA to allow reading a
					line at a time without reading invalid data.
				*/
				if((dtalimit=valid_byts-320) <= 0)
					dtalimit = valid_byts;
				sctr = 0;		/* Reinitialize sctr */
				}	/* Unpack a row into exbuff and update sctr */
			if((byts_rd=unpackpiw(exbuff, &dta_addr[sctr], 256)) == EOF)
				break;
			sctr += byts_rd;
			if((rcode=putrow(exbuff, handle, desimg->stx, yctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	free(exbuff);		/* Free the allocated buffer */
	cmclose_(desimg, handle);		/* Close CM handle */
	return(rcode);
}

/* Unpack a line of data compressed with the PIW scheme.
	Return the number of compressed bytes read or EOF if EOP (0x42) found.
	des = where to put the unpacked data, src = source of data to unpack,
	des_byts = number of uncompressed bytes to write.
*/
static int _cdecl unpackpiw(UCHAR *des, UCHAR *src, int des_byts)
{
	UCHAR *sptr=src; /* Save src to calc no. of compressed bytes read */
	int last_byt, count, ch;

	while(des_byts > 0) {
		/* If not a special char, save and store the byte */
		if((ch=*src++) < SOP) {
			last_byt = ch << 2; /* Store value in last_byt, convert to 0->252 */
			*des++ = (UCHAR)last_byt;  /* Update dest */
			des_byts--;
			}
		/* Byte repeated 1-16 times? */
		else if((ch & 0xf0) == 0x80) {
			count = ch & 0x0f;
			if(!count) count = 16;
rep_byts:	/* Store count bytes if there's room */
			while(count--) {
				if(des_byts-- == 0)
					goto xit; /* Exit if we've written as many bytes as requested */
				*des++ = (UCHAR)last_byt;		/* Update dest */
				}
			}
		/* Byte repeated 16-256 times? */
		else if((ch & 0xf0) == 0x90) {
			count = ch & 0x0f;
			if(!count) count = 16;
			count <<= 4;
			goto rep_byts;
			}
		else if(ch == EOP)		/* EOP => we're done */
			return(EOF);
		}	/* Return the number of compressed bytes we read */
xit:
	return((int)(src - sptr));
}

/**** Save PIW routines ****/

/* Save image as an ImageWise PIW file. Since a PIW file has an image
	width = 256, desimg->iwidth must be >= 256. Returns NO_ERROR, BAD_DSK
	(disk full), BAD_CRT, BAD_RANGE, BAD_MEM (not enough conventional
	memory), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl savepiw(char *fname, imgdes *srcimg, int comp)
/* If comp = 1, use compression when saving,
	if comp = 0, just add SOP, SOL, and EOP codes.
*/
{
	int errcode;

	/* Check range of start, end positions */
	if(checkrange_(srcimg) || srcimg->iwidth < 256)
		return(BAD_RANGE);
	if((Fhandle=open(fname, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, S_IWRITE)) < 3)
		return(BAD_CRT);
	/* Write PIW file image data */
	errcode = WritePiwData(srcimg, comp);
	close(Fhandle);
	if(errcode!=NO_ERROR)  remove(fname);	/* Error, erase file */
	return(errcode);
}

/* Write a PIW format file. Returns NO_ERROR, BAD_DSK (disk full),
	BAD_MEM (not enough conventional memory for expansion buffer),
	NO_EMM, EMM_ERR, NO_XMM, or XMM_ERR.
*/
static int _cdecl WritePiwData(imgdes *srcimg, int comp)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *packfct)(UCHAR *,UCHAR *,int);
	UCHAR *exbuff, *dta_addr=Hbuff_;	/* Address of our file buffer */
	int sctr=1;			/* Byte counter in dta buffer */
	int rcode=NO_ERROR, cols, rows, yctr=srcimg->sty, handle;
	int dtalimit = DTASIZE - 264; /* Write the DTA when it gets this full */

	/* A PIW image is limited to 256x244 lines */
	if((rows=srcimg->endy - srcimg->sty + 1) > PIWLONG)
		rows = PIWLONG;
	if((cols=srcimg->endx - srcimg->stx + 1) > PIWWIDE)
		cols = PIWWIDE;
	packfct = (comp)	? packpiw1 : packpiw2;
	/* Allocate space for compression buffer. Worst case is cols + 2 */
	if((exbuff=(UCHAR *)malloc(cols+4)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	/* Assign handle, getrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		dta_addr[0] = SOP;	/* Insert header byte */
		while(rows--) {
			if(sctr >= dtalimit) {	/* Write the DTA if it's full */
				if(write(Fhandle, dta_addr, sctr) != sctr) {
					rcode = BAD_DSK;
					goto err;
					}
				sctr = 0;		/* Reset DTA index */
				}
			if((rcode=getrow(exbuff, handle, srcimg->stx, yctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				goto err;
			/* Pack a line and update sctr */
			sctr += packfct(&dta_addr[sctr], exbuff, cols);
			}
		dta_addr[sctr++] = EOP;	/* Insert footer byte */
		/* Write any valid bytes left in the DTA */
		if(write(Fhandle, dta_addr, sctr) != sctr)
			rcode = BAD_DSK;
		}
err:
	free(exbuff);		/* Free the allocated buffer */
	cmclose_(srcimg, handle);		/* Close CM handle */
	return(rcode);
}

/* Pack a line of data using the PIW scheme. For comp = 0, just add SOP,
	SOL, and EOP codes. Return number of bytes written.
	des = where to put the packed data, src = source of data to pack,
	byts2pack = data bytes to pack.
*/
static int _cdecl packpiw2(UCHAR *des, UCHAR *src, int byts2pack)
{
	UCHAR *dptr=des; /* Save des to calc no. of bytes written */
	int j, count;

	*des++ = SOL;
	for(j=0; j<byts2pack; j++)	/* Move the required bytes */
		*des++ = (UCHAR)(*src++ >> 2); /* Reduce image data 0-255 -> 0-63 */
	/* Calc the bytes left to write to fill out the line */
	memset_(des, 0, count=256-byts2pack);	/* Zero the rest */
	des += count;						/* Update des */
	/* Return number of bytes written */
	return((int)(des - dptr));
}

/* Pack a line of data using the PIW scheme. For comp = 1, compress the
	data and add SOP, SOL, and EOP codes. Return number of compressed bytes.
	des = where to put the packed data, src = source of data to pack,
	byts2pack = data bytes to pack.
*/
static int _cdecl packpiw1(UCHAR *des, UCHAR *src, int byts2pack)
{
	UCHAR *dptr=des; /* Save des to calc no. of compressed bytes */
	int count, last_byt, ch;
	int bytsleft = 256-byts2pack;

	*des++ = SOL;		/* Insert SOL char */
	/* Init last_byte and run counter */
	last_byt = *src++;
	count = 0;
	byts2pack--;		/* Already placed one byte */
	while(byts2pack--) {
		if((ch = *src++) == last_byt) /* Current byte = last byte => run */
			count++;				/* Bump run counter */
		else { 		/* Current byte != last byte, write count/byte */
			des += enc_piw_(last_byt, count, des);	/*  and advance des */
			last_byt = ch;
			count = 0;		/* Reset run counter */
			}
		}
	/* Write last run fragment */
	des += enc_piw_(last_byt, count, des);
	/* Fill out the rest of the row with 0's */
	if(bytsleft)
		des += enc_piw_(0, bytsleft, des);
	/* Return number of compressed bytes */
	return((int)(des - dptr));
}
+ARCHIVE+ savergb.c    14545  6/05/1991  9:30:58
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		loadtifrgb			Load TIFF RGB image
		savetifrgb			Save TIFF RGB image
*/

#include <stdio.h>
#include <vicdefs.h>		/* Standard header files for VICTOR.LIB */
#include <vicfcts.h>
#include <vicerror.h>
#include <keydefs.h>
#include <stdlib.h>
#include <stdarg.h>
#include <tiff.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <io.h>
#include <dos.h>

/* We need a bigger strip size here, because 3 images of width XLIMIT (4047)
	would exceed Hbuff_, which is 8192 bytes.
*/
#define BIGDTASIZE 3*4096	/* Maximum strip size */
#define BIGSTRIPSIZE 3*4096	/* Maximum strip size */

extern unsigned TiffHdr_[];

static unsigned Rows, Cols;
static int RowsPStrip;		/* Rows in a strip */

/* TIFF header variables */
extern int Strips_;			/* Number of strips in image */
extern int Thandle_;
extern int PlanarCfg_;		 /* Planar configuration */
extern long *StripCounts_;	 /* Ptr to area used to store strip counts */
extern long *StripStarts_;
extern long BitsPSample_[]; /* Bits per sample, up to 3 values for TIFF RGB */
extern int _cdecl GetStripOffCts_(void);
extern int _cdecl AllocStrips_(void);
extern unsigned _cdecl ReadMoData_(long *,int *,int,UCHAR *);
extern int _cdecl GetTiffHeaderSize_(void);
extern UCHAR Hbuff_[];
extern unsigned TiffHdr_[];
static int _cdecl ReadRGBTif(imgdes *,imgdes *,imgdes *,TiffData *);
static int _cdecl WriteRGBTif(imgdes *,imgdes *,imgdes *);
static void _cdecl write_tifrgb_hdr(int);
static void _cdecl WrtFilePos(int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);

/* Load and dissect a TIFF RGB image. Returns NO_ERROR, BAD_OPN - can't find
	fname, BAD_RANGE, BAD_TIFF, BAD_MEM, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR,
	or CM_ERR. Use tiffinfo() to determine amount of memory needed for
	allocating red, green, and blue image buffers.
*/
int _cdecl loadtifrgb(char *fname, imgdes *red, imgdes *green, imgdes *blue)
{
	TiffData tdat;
	int errcode;

	/* Check range of start, end positions */
	if(checkrange_(red) || checkrange_(green) || checkrange_(blue))
		return(BAD_RANGE);
	/* Get info on TIFF file we're to load */
	if((errcode=tiffinfo(fname, &tdat)) != NO_ERROR)	/* Fill structure */
		return(errcode);
	if((Thandle_=open(fname, O_BINARY|O_RDONLY)) < 3)	/* open fname.TIF file */
		return(BAD_OPN);
	Rows = red->endy - red->sty + 1;
	/* Use the smaller number of rows value */
	if(Rows > tdat.Ilength)
		Rows = tdat.Ilength;
	Cols = red->endx - red->stx + 1;
	/* Use the smaller number of cols value */
	if(Cols > tdat.Iwidth)
		Cols = tdat.Iwidth;
	/* Allocate memory for StripStarts, StripCounts and
		fill StripStarts and StripCounts arrays
	*/
	if((errcode=GetStripOffCts_()) == NO_ERROR) {
		/* Check that file is a valid TIFF RGB file */
		if(tdat.Comp<=1 && tdat.SamplesPPixel==3 && tdat.PhotoInt==2 &&
			PlanarCfg_==1 && BitsPSample_[0]==8 &&
			BitsPSample_[1]==8 && BitsPSample_[2]==8)
			/* File to load is a valid TIFF RGB image. Data is organized as
				RGBRGB, etc. bytes.
			*/
			errcode = ReadRGBTif(red, green, blue, &tdat);
		else
			errcode = BAD_TIFF;
		free(StripCounts_);
		}
	close(Thandle_);
	return(errcode);
}

/* Read 8-bit TIFF RGB file with no compression. Only reads RGB files
	with planar confg = 1 (bytes arranged RGBRGBRGB, etc.).
	Returns NO_ERROR, BAD_MEM, EMM_ERR, XMM_ERR, CM_ERR.
*/
static int _cdecl ReadRGBTif(imgdes *red, imgdes *green,
	imgdes *blue, TiffData *tinfo)
{
	int strip_ctr=0;		/* Strip counter */
	long bp_strip=0;		/* Bytes per strip */
	int sctr=0;				/* Byte counter in dta buffer */
	int dtalimit=0; /* Get more bytes from disk when dtalimit is exceeded */
	int valid_byts=0;
	int rcode=NO_ERROR, byts2mov, cbyts=3*tinfo->Iwidth;
	unsigned j;
	UCHAR *redbuff=Hbuff_, *grnbuff=&Hbuff_[4072];
	/* Need a DTA size > 3*XLIMIT = 3*(8192/2) */
	UCHAR *dta_addr, *blubuff, *bptr;
	int redhandle, grnhandle, bluhandle;
	int redyctr=red->sty, grnyctr=green->sty, bluyctr=blue->sty;
	int (_cdecl *putrowred)(void huge *,int,int,int,int,int);
	int (_cdecl *putrowgrn)(void huge *,int,int,int,int,int);
	int (_cdecl *putrowblu)(void huge *,int,int,int,int,int);
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);

	/* Allocate DTA buffer and 1 line buffer */
	if((dta_addr=(UCHAR *)malloc(BIGDTASIZE+Cols)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	blubuff = &dta_addr[BIGDTASIZE];
	/* Assign handles, getrow(), putrow(), open cmhandle, check for EM/XM */
	if((rcode=assign_gprow_(red, &redhandle, &dummy, &putrowred)) != NO_ERROR ||
		(rcode=assign_gprow_(green, &grnhandle, &dummy, &putrowgrn)) != NO_ERROR ||
		(rcode=assign_gprow_(blue, &bluhandle, &dummy, &putrowblu)) != NO_ERROR)
		goto xit;
	while(Rows--) {
		if(sctr >= dtalimit) { /* Nearly out of valid bytes in the DTA */
			/* Move any valid bytes left to the front of the DTA */
			byts2mov = valid_byts - sctr;
			if(byts2mov < 0)  byts2mov = 0;		/* Play it safe */
			memcpy_(dta_addr, &dta_addr[sctr], byts2mov);
			/* Don't read in more data if bytes per strip = 0 and there are
				bytes left in the DTA to process
			*/
			valid_byts = byts2mov;
			if(!(bp_strip==0 && byts2mov)) {
				/* Read in more data and calc valid bytes in the DTA */
				valid_byts += ReadMoData_(&bp_strip, &strip_ctr,
					BIGDTASIZE-byts2mov, &dta_addr[byts2mov]);
				}
			/* No more bytes in DTA => we're done */
			if(valid_byts == 0)
				break;
			/* Set dta_limit back from end of DTA to allow reading a line at
				a time without reading invalid data.
			*/
			if((dtalimit=valid_byts-cbyts) <= 0)
				dtalimit = valid_byts;
			sctr = 0;	/* Reinitialize sctr */
			}
		bptr = &dta_addr[sctr];
		sctr += cbyts;		/* Add in 3*Cols to advance DTA index */
		/* Move the data into red, green, and blue line buffers */
		for(j=0; j<Cols; j++) {
			redbuff[j] = *bptr++;
			grnbuff[j] = *bptr++;
			blubuff[j] = *bptr++;
			}
		/* Move line buffers into image buffers */
		if((rcode=putrowred(redbuff, redhandle, red->stx, redyctr++,
			Cols, red->iwidth)) != NO_ERROR)
			goto xit;
		if((rcode=putrowgrn(grnbuff, grnhandle, green->stx, grnyctr++,
			Cols, green->iwidth)) != NO_ERROR)
			goto xit;
		if((rcode=putrowblu(blubuff, bluhandle, blue->stx, bluyctr++,
			Cols, blue->iwidth)) != NO_ERROR)
			goto xit;
		}
xit:
	cmclose_(red, redhandle);		/* Close CM handle, if open */
	cmclose_(green, grnhandle);
	cmclose_(blue, bluhandle);
	free(dta_addr);
	return(rcode);
}

/***** Save Functions *****/

/* Save image as a TIFF RGB file. Returns NO_ERROR, BAD_RANGE (range error),
	BAD_CRT (cannot create fname), BAD_DSK (disk full, fname not written),
	BAD_MEM (not enough conventional memory), NO_EMM, EMM_ERR, NO_XMM,
	XMM_ERR, or CM_ERR. Uses red image data to set image width, length, etc.
*/
int _cdecl savetifrgb(char *fname, imgdes *red, imgdes *green, imgdes *blue)
{
	int tifhdrsize, icols, errcode;
	long Pels;			/* Pixels in an image area = cols*rows */
	int StripSize;		/* Strip size = (BIGSTRIPSIZE/cols)*cols so it's
								evenly divisible by cols */

	/* Check range of start, end positions */
	if(checkrange_(red) || checkrange_(green) || checkrange_(blue))
		return(BAD_RANGE);
	if((Thandle_=open(fname, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, S_IWRITE)) < 3)
		return(BAD_CRT);
	/* Calculate no. of columns and rows to write based on red image */
	Cols = red->endx - red->stx + 1;
	icols = 3 * Cols;
	Rows = red->endy - red->sty + 1;
	/* Calc number of pixels in the image area */
	Pels = Rows * (long)icols;
	if(Pels <= BIGSTRIPSIZE) {
		StripSize = (int)Pels;
		RowsPStrip = StripSize / icols;	/* Rows per strip */
		Strips_ = 1;
		}
	else {
	/* Best strip byte count = (BIGSTRIPSIZE/Cols)*Cols = RowsPStrip*Cols
		= BIGSTRIPSIZE-(BIGSTRIPSIZE % Cols)
	*/
		RowsPStrip = BIGSTRIPSIZE / icols;	/* Rows per strip */
		StripSize = RowsPStrip * icols;
		Strips_ = (int)(Pels / StripSize);
	/* If the no. of pixels in the image area is not evenly divisible by
		the no. of bytes in a strip, add another strip.
	*/
		if(Pels % StripSize)  Strips_++;
		}
	/* Allocate memory for StripStarts, StripCounts */
	if((errcode=AllocStrips_()) == NO_ERROR) {
		/* Move file ptr to skip the header. StripCounts and StripStarts
			are written last.
		*/
		lseek(Thandle_, (long)((tifhdrsize=GetTiffHeaderSize_()) + Strips_*8),
			SEEK_SET);
		/* Write an uncompressed file */
		if((errcode=WriteRGBTif(red, green, blue)) == NO_ERROR) {
			/* Move file ptr to start of file to write the header */
			lseek(Thandle_, (long)0, SEEK_SET);
			/* Fix and write the TIFF header */
			write_tifrgb_hdr(tifhdrsize);
			}
		free(StripCounts_);	/* Free memory allocated by AllocStrips_() */
		}
	close(Thandle_);
	if(errcode!=NO_ERROR)  remove(fname);	/* Disk full */
	return(errcode);
}

#define IFDSIZ 6	/* IFD size in ints */
#define IFDST  5	/* Offset of 0th IFD in ints */
#define CNT    2	/* Offset of count field in an IFD */
#define VAL    4	/* Offset of value field in an IFD */

/* Fix and write the TIFF header (ignore any write errors for now) */
static void _cdecl write_tifrgb_hdr(int tifhdrsize)
{
	static unsigned BtsPSm[] = {TGBITSPERSAMPLE, TIFFSHORT, 3,00, 0xf6,00};
	static int Eights[] = {8, 8, 8};	/* Bits per sample in an RGB TIF image */
	unsigned j, counts, starts;

	for(j=0; j<(unsigned)Strips_; j++)	/* Calc strip byte counts */
		StripCounts_[j] = StripStarts_[j+1] - StripStarts_[j];
	/* Fill in the necessary header values */
	TiffHdr_[ 2*IFDSIZ+IFDST+VAL] = Cols;			/* Image width  */
	TiffHdr_[ 3*IFDSIZ+IFDST+VAL] = Rows;			/* Image length */
	/* Bits per sample = 8, 8, 8 */
	memcpy_(&TiffHdr_[4*IFDSIZ+IFDST], BtsPSm, sizeof(BtsPSm));
	memcpy_(&TiffHdr_[0xf6/2], Eights, sizeof(Eights));
	TiffHdr_[ 5*IFDSIZ+IFDST+VAL] = 1;				/* Compression */
	TiffHdr_[ 6*IFDSIZ+IFDST+VAL] = 2;	/* PhotoInt=2 for RGB images */
	TiffHdr_[ 8*IFDSIZ+IFDST+CNT] = Strips_;		/* No. of StripOffsets */
	TiffHdr_[11*IFDSIZ+IFDST+CNT] = Strips_;		/* No. of StripByteCounts */
	TiffHdr_[ 9*IFDSIZ+IFDST+VAL] = 3;	/* Samples per pixel for RGB image */
	TiffHdr_[10*IFDSIZ+IFDST+VAL] = RowsPStrip;	/* Rows per strip */
	TiffHdr_[4] = 17;			/* IFD entries */
	*(long *)&TiffHdr_[17*IFDSIZ+IFDST] = 0L;	/* Next IFD address = 0 */
	/* Put the strip offsets and strip byte counts into the header.
		If only 1 strip, put StripByteCt and StripOffset in TiffHdr.
	*/
	counts = tifhdrsize;						/* StrCounts */
	starts = tifhdrsize + (Strips_<<2);	/* StrStarts */
	if(Strips_ == 1) {
		counts = (unsigned)StripCounts_[0];
		starts = (unsigned)StripStarts_[0];
		}
	/* Insert byte offset of StripCounts/StripStarts */
	TiffHdr_[11*IFDSIZ+IFDST+VAL] = counts;
	TiffHdr_[8*IFDSIZ+IFDST+VAL] = starts;
	write(Thandle_, (char *)TiffHdr_, tifhdrsize);/* Write the header */
	j = Strips_ << 2;
	write(Thandle_, (char *)StripCounts_, j);	/* Write the StripByteCts */
	write(Thandle_, (char *)StripStarts_, j);	/* Write the StripOffsets */
}

/* Write an uncompressed file */
static int _cdecl WriteRGBTif(imgdes *red, imgdes *green, imgdes *blue)
{
	int redhandle, grnhandle, bluhandle;
	int redyctr=red->sty, grnyctr=green->sty, bluyctr=blue->sty;
	int (_cdecl *getrowred)(void huge *,int,int,int,int,int);
	int (_cdecl *getrowgrn)(void huge *,int,int,int,int,int);
	int (_cdecl *getrowblu)(void huge *,int,int,int,int,int);
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int rcode=NO_ERROR;	/* Assume no errors */
	int str_ctr=0;	/* Strip counter */
	unsigned j, yy;
	UCHAR *redbuff=Hbuff_, *grnbuff=&Hbuff_[4072];
	/* Need a DTA size > 3*XLIMIT = 3*(8192/2) */
	UCHAR *dta_addr, *blubuff, *bptr;
	/* Write the DTA when it gets this full */
	int dtalimit = BIGSTRIPSIZE - (Cols*3);
	int sctr=0, cbyts=3*Cols;

	/* Allocate 2 line buffers and our DTA */
	if((dta_addr=(UCHAR *)malloc(BIGSTRIPSIZE + Cols)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	blubuff = &dta_addr[BIGSTRIPSIZE];
	/* Assign handles, getrow(), and check for EM/XM */
	if((rcode=assign_gprow_(red, &redhandle, &getrowred, &dummy)) == NO_ERROR &&
		(rcode=assign_gprow_(green, &grnhandle, &getrowgrn, &dummy)) == NO_ERROR &&
		(rcode=assign_gprow_(blue, &bluhandle, &getrowblu, &dummy)) == NO_ERROR) {
		/* Write image data using no compression */
		for(yy=0; yy<Rows; yy++) {
			/* Flush the buffer if we've written RowsPStrip rows
				or the DTA is about full
			*/
			if(yy % RowsPStrip == 0 || sctr >= dtalimit) {
				/* Write the bytes to disk */
				if(write(Thandle_, dta_addr, sctr) != sctr) {
					rcode = BAD_DSK;
					goto xit;
					}
				if(yy % RowsPStrip == 0)
					/* Update StrStart[i] array with file ptr position */
					WrtFilePos(str_ctr++);
				sctr = 0;			/* Reset DTA index */
				}
			/* Move data from images into line buffers */
			if((rcode=getrowred(redbuff, redhandle, red->stx, redyctr++,
				Cols, red->iwidth)) != NO_ERROR)
				goto xit;
			if((rcode=getrowgrn(grnbuff, grnhandle, green->stx, grnyctr++,
				Cols, green->iwidth)) != NO_ERROR)
				goto xit;
			if((rcode=getrowblu(blubuff, bluhandle, blue->stx, bluyctr++,
				Cols, blue->iwidth)) != NO_ERROR)
				goto xit;
			bptr = &dta_addr[sctr];
			sctr += cbyts;		/* Add in 3*Cols to advance DTA index */
			/* Move the data into the DTA */
			for(j=0; j<Cols; j++) {
				*bptr++ = redbuff[j];
				*bptr++ = grnbuff[j];
				*bptr++ = blubuff[j];
				}
			}
		/* Done with "rows" rows. If bytes are left in the buffer that need
			to be written, write them and update StrStart[StripCtr].
		*/
		if(sctr) {	/* If sctr = 0, no bytes to write */
			if(write(Thandle_, dta_addr, sctr) != sctr) {
				rcode = BAD_DSK;
				goto xit;
				}
			WrtFilePos(str_ctr++); /* Set StrStart[last] */
			}
		}
xit:
	cmclose_(red, redhandle);		/* Close CM handle, if open */
	cmclose_(green, grnhandle);
	cmclose_(blue, bluhandle);
	free(dta_addr);	/* Free the allocated buffer */
	return(rcode);
}

/* Set StripStarts[StripCtr] = current file ptr position */
static void _cdecl WrtFilePos(int strctr)
{
	StripStarts_[strctr] = lseek(Thandle_, 0L, SEEK_CUR);
}
+ARCHIVE+ savetif.c    35054  6/05/1991  9:30:58
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		savetif					Save image in system memory as a TIFF file
		  Write8Tif				Write an uncompressed or PackBits file
		  write_tif_header	Fix and write the TIFF header
		  WrtFilePos			Get current file ptr position
		loadtif					Load TIF image into system memory
		  GetStripOffCts_		Allocate, fill StripStarts and StripCounts
		  Read48Tif				Read 4 to 8-bit TIFF with comp = none or PackBits
		  ReadMoData_			Fill DTA buffer with image data
		  SetFilePtr			Get bytes per strip and set file ptr to strip start
		tiffinfo					Get info on TIF file
		  setoffcts_			Copy over strip offsets or strip counts
		  GetDataAddr_			Extract data address from the image file dir entry
		  GetStrAddr_			Extract string address from image file dir entry
		  GetValue_				Extract value from image file dir entry
		  ReadHeader			Read in TIFF file header
		  AllocStrips_
		loadtifpalette			Load TIFF colormap into memory
		GetTiffHeaderSize_	Return size of TIFF header
		check_em_xm_			Make sure EM or XM exists
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <fcntl.h>
#include <sys\stat.h>
#include <stdlib.h>
#include <tiff.h>
#include <io.h>
#define MAXSTRIPSIZE 8192	/* Maximum strip size */
#define DTASIZE 8192
#define PACBITSID 0x8005	/* (32773), comp value for PackBits scheme */

#define IFDSIZ 6	/* IFD size in ints */
#define IFDST  5	/* Offset of 0th IFD in ints */
#define CNT    2	/* Offset of count field in an IFD */
#define VAL    4	/* Offset of value field in an IFD */

unsigned TiffHdr_[] = { 		 			/* byte offset */
	INTELTIFF,TFVERSION,8,00,				  	/* tiff header   0 */
/* start of IFD */
	18,					/* # of IFD entries						  8 */
/* Entries:	2				 2				4				 4
 *	Tag 					Data type   Length(ct)	Value */
	TGNEWSUBFILETYPE,	TIFFLONG,	 1,00,		  0,00,	/* 0x0a */
	TGSUBFILETYPE,		TIFFSHORT,	 1,00,		  1,00,	/* 0x16 */
	TGIMAGEWIDTH,		TIFFSHORT,	 1,00,		512,00,	/* 0x22 */
	TGIMAGELENGTH,		TIFFSHORT,	 1,00,		488,00,	/* 0x2e */
	TGBITSPERSAMPLE,	TIFFSHORT,	-1,00,		 -1,00,	/* 0x3a */
	TGCOMPRESSION,		TIFFSHORT,	 1,00,	 	  1,00,	/* 0x46 */
	TGPHOTOMETRICINT,	TIFFSHORT,	 1,00,		 -1,00,	/* 0x52 */
	TGDOCUMENTNAME,	TIFFASCII,	16,00,	  0xe6,00,	/* 0x5e */
	TGSTRIPOFFSETS,	TIFFLONG,	-1,00,	    -1,00,	/* 0x6a */
	TGSAMPLESPERPIXEL,TIFFSHORT,	 1,00,		  1,00,	/* 0x76 */
	TGROWSPERSTRIP,	TIFFLONG,	 1,00,		 -1,00,	/* 0x82 */
	TGSTRIPBYTECOUNTS,TIFFLONG,	-1,00,	    -1,00,  /* 0x8e */
	TGXRESOLUTION,		TIFFRATNL,	 1,00,	 0x106,00,  /* 0x9a */ 
	TGYRESOLUTION,		TIFFRATNL,	 1,00,	 0x10e,00,	/* 0xa6 */
	TGPLANARCONFIG,   TIFFSHORT,   1,00,        1,00,	/* 0xb2 */
	TGRESOLUTIONUNIT,	TIFFSHORT,	 1,00,		  2,00,	/* 0xbe */
	TGPREDICTOR,		TIFFSHORT,	 1,00,		  1,00,  /* 0xca */
	TGCOLORMAP,			TIFFSHORT,	-1,00,		 -1,00,	/* 0xd6 */
	0,0,											/* Next IFD addr  0xe2 */
	0,0,0,0,0,0,0,0,							/* Document name	0xe6 */
	0,0,0,0,0,0,0,0,				  /* Bits per sample, etc. 0xf6 */
	75,0,1,0,				/* XResolution = 75dpi = 3.41in  0x106 */
	75,0,1,0,										/* YResolution 0x10e */
	};
	/* StripByteCts start at byte offset 0x116, StripOffsets start
		at 0x116 + Strips*4, and Colormap at 0x116 + Strips*8
	*/
int Strips_;					/* Number of strips in image */
long *StripStarts_;			/* Ptr to area used to store strip starts */
long *StripCounts_;			/* Ptr to area used to store strip counts */
long BitsPSample_[3];		/* Bits per sample, up to 3 values for TIFF RGB */
int PlanarCfg_;				/* Planar configuration */
int Thandle_;					/* File handle */
static unsigned Comp;		/* Compression: only 1, 5, or 32773 is valid */
static long StripOffAddrs;	/* Bytes from file start to strip offsets */
static long StripCtAddrs; 	/* Bytes from file start to strip counts */
static long DocStrAddr;		/* Bytes from file start to doc name string */
static long ColMapAddr;		/* Bytes from file start to colormap */
static int ColMapVals;		/* Entries in colormap table (ints) */
static int RowsPStrip;		/* Rows in a strip */
static unsigned Sotype;		/* Strip offset data type: SHORT (3) or LONG (4) */
static unsigned Sctype;		/* Strip count data type: SHORT (3) or LONG (4) */
static int MotType;		/* TIFF type: Motorola (0x4d4d) or Intel (0x4949) */
static int LZWPredicator;
static unsigned Cols, Rows;/* Columns, rows of image buffer to write */
extern UCHAR Hbuff_[];

extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl packbits_(UCHAR huge *,UCHAR huge *,int);
extern int _cdecl expand_(UCHAR *,UCHAR *,int,int);
extern int _cdecl unpackbits_(UCHAR *,UCHAR *,int,int);
int _cdecl WriteTif_(imgdes *,int,UCHAR *,UCHAR *,long *,int);
int _cdecl ReadTif_(imgdes *,int,UCHAR *,UCHAR *,unsigned,unsigned,
	long *,long *,int,TiffData *);
unsigned _cdecl ReadMoData_(long *,int *,int,UCHAR *);
int _cdecl check_em_xm_(imgdes *);
static void _cdecl write_tif_header(imgdes *);
static int _cdecl Write8Tif(imgdes *);
static void _cdecl WrtFilePos(int);
static int _cdecl Read48Tif(imgdes *,int,int,unsigned);
static int _cdecl SetFilePtr(long *,int *);
static int _cdecl ReadHeader(TiffData *);
static void _cdecl fix_pal(int,UCHAR *);
void _cdecl setoffcts_(long,unsigned,long *,int);
void _cdecl GetDataAddr_(UCHAR *,unsigned *,unsigned *,long *,long);
int _cdecl GetStrAddr_(UCHAR *,long *,long);
int _cdecl GetValue_(UCHAR *,unsigned *);
extern void _cdecl swapwords_(void *,int);
extern void _cdecl swapbytes_(void *,int);
int _cdecl AllocStrips_(void);
int _cdecl GetStripOffCts_(void);
int _cdecl loadtifpalette(char *,UCHAR *);

/* Save image as a TIFF file. Returns NO_ERROR, BAD_RANGE (range error),
	BAD_CRT (cannot create fname), BAD_DSK (disk full, fname not written),
	BAD_MEM (not enough conventional memory), BAD_CMP (invalid compression
	type), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl savetif(char *fname, imgdes *srcimg, int cmprsn)
{
	/* 0 => No comp, 1 => LZW, 2 => packbits */
	static unsigned comp_list[] = {1, 5, PACBITSID};
	int errcode;
	UCHAR *exbuff, *strtab; /* Expansion buffer and LZW string table */
	long Pels;			/* Pixels in an image area = cols*rows */
	int StripSize;		/* Strip size = (MAXSTRIPSIZE/cols)*cols so it's
								evenly divisible by cols */

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	if(inrange(0, cmprsn, 2))		/* Valid range is 0 -> 2 */
		Comp = comp_list[cmprsn];
	else
		return(BAD_CMP);
	/* If we're saving data in EM or XM, check that it exists */
	if((errcode=check_em_xm_(srcimg)) != NO_ERROR)
		return(errcode);
	if((Thandle_=open(fname, O_BINARY|O_RDWR|O_CREAT|O_TRUNC, S_IWRITE)) < 3)
		return(BAD_CRT);
	/* Calculate no. of columns and rows to write */
	Cols = srcimg->endx - srcimg->stx + 1;
	Rows = srcimg->endy - srcimg->sty + 1;
	/* Calc number of pixels in the image area */
	Pels = Rows * (long)Cols;
	if(Pels <= MAXSTRIPSIZE) {
		StripSize = (int)Pels;
		RowsPStrip = StripSize / Cols;	/* Rows per strip */
		Strips_ = 1;
		}
	else {
	/* Best strip byte count = (MAXSTRIPSIZE/Cols)*Cols = RowsPStrip*Cols
		= MAXSTRIPSIZE-(MAXSTRIPSIZE % Cols)
	*/
		RowsPStrip = MAXSTRIPSIZE / Cols;			/* Rows per strip */
		StripSize = RowsPStrip * Cols;
		Strips_ = (int)(Pels / StripSize);
	/* If the no. of pixels in the image area is not evenly divisible by
		the no. of bytes in a strip, add another strip.
	*/
		if(Pels % StripSize)  Strips_++;
		}
	/* Allocate memory for StripStarts, StripCounts */
	if((errcode=AllocStrips_()) == NO_ERROR) {
		/* Move file ptr to skip the header. StripCounts, StripStarts, and
			the colormap (if present) are written last.
		*/
		ColMapVals = (srcimg->palette) ? srcimg->palsize : 0;	/* Entries in colormap */
		lseek(Thandle_, (long)(sizeof(TiffHdr_) + Strips_*8 + ColMapVals*2), SEEK_SET);
		if(Comp==5) {		/* Use LZW compression */
			/* Allocate enough memory for the LZW string table and an
				expansion buffer
			*/
			if((strtab=(UCHAR *)malloc(5*4096+16 + Cols)) != NULL) {
				exbuff = &strtab[5*4096+16];	/* Assign part of it to exbuff */
				/* Write an LZW compressed file */
				errcode = WriteTif_(srcimg, Thandle_, exbuff, strtab,
					StripStarts_, StripSize);
				free(strtab);
				}
			else
				errcode = BAD_MEM;	/* If area not allocated */
			}
		else		/* Write an uncompressed or PackBits file */
			errcode = Write8Tif(srcimg);
		if(errcode == NO_ERROR) {
			/* Move file ptr to start of file to write the header */
			lseek(Thandle_, (long)0, SEEK_SET);
			/* Fix and write the TIFF header */
			write_tif_header(srcimg);
			}
		free(StripCounts_);	/* Free memory allocated by AllocStrips_() */
		}
	close(Thandle_);
	if(errcode!=NO_ERROR)  remove(fname);	/* Disk full */
	return(errcode);
}

/* Fix and write the TIFF header (ignore any write errors for now) */
static void _cdecl write_tif_header(imgdes *srcimg)
{
	unsigned j, counts, starts;

	for(j=0; j<(unsigned)Strips_; j++)	/* Calc strip byte counts */
		StripCounts_[j] = StripStarts_[j+1] - StripStarts_[j];
	/* Fill in the necessary header values */
	TiffHdr_[ 2*IFDSIZ+IFDST+VAL] = Cols;			/* Image width  */
	TiffHdr_[ 3*IFDSIZ+IFDST+VAL] = Rows;			/* Image length */
	TiffHdr_[ 4*IFDSIZ+IFDST+CNT] = 1;	/* No. of bits per sample entries */
	TiffHdr_[ 4*IFDSIZ+IFDST+VAL] = 8;				/* Bits per sample */
	TiffHdr_[ 5*IFDSIZ+IFDST+VAL] = Comp;			/* Compression */
	TiffHdr_[ 8*IFDSIZ+IFDST+CNT] = Strips_;		/* No. of StripOffsets */
	TiffHdr_[11*IFDSIZ+IFDST+CNT] = Strips_;		/* No. of StripByteCounts */
	TiffHdr_[ 9*IFDSIZ+IFDST+VAL] = 1;	/* Samples per pixel for non RGB image */
	TiffHdr_[10*IFDSIZ+IFDST+VAL] = RowsPStrip;	/* Rows per strip */
	if(ColMapVals == 0) {	/* If it's not a palette color TIFF */
		TiffHdr_[4] = 17;			/* IFD entries */
		TiffHdr_[6*IFDSIZ+IFDST+VAL] = 1; /* PhotoInt = 1 */
		*(long *)&TiffHdr_[17*IFDSIZ+IFDST] = 0L;	/* Next IFD address = 0 */
		}
	else {	/* If it's a palette color TIFF: */
		TiffHdr_[4] = 18;			/* IFD entries */
		TiffHdr_[6*IFDSIZ+IFDST+VAL] = 3; /* PhotoInt = 3 for palette color */
		TiffHdr_[17*IFDSIZ+IFDST] = TGCOLORMAP;
		TiffHdr_[17*IFDSIZ+IFDST+1] = TIFFSHORT;
		/* Insert byte offset of Colormap */
		TiffHdr_[17*IFDSIZ+IFDST+VAL] = sizeof(TiffHdr_) + (Strips_<<3);
		TiffHdr_[17*IFDSIZ+IFDST+CNT] = ColMapVals; /* No. of Colormap entries */
		}
	/* Put the strip offsets and strip byte counts into the header.
		If only 1 strip, put StripByteCt and StripOffset in TiffHdr.
	*/
	counts = sizeof(TiffHdr_);						/* StrCounts */
	starts = sizeof(TiffHdr_) + (Strips_<<2);	/* StrStarts */
	if(Strips_ == 1) {
		counts = (unsigned)StripCounts_[0];
		starts = (unsigned)StripStarts_[0];
		}
	/* Insert byte offset of StripCounts/StripStarts */
	TiffHdr_[11*IFDSIZ+IFDST+VAL] = counts;
	TiffHdr_[8*IFDSIZ+IFDST+VAL] = starts;
	write(Thandle_, (char *)TiffHdr_, sizeof(TiffHdr_));/* Write the header */
	write(Thandle_, (char *)StripCounts_, j=Strips_<<2);/* Write StripByteCts */
	write(Thandle_, (char *)StripStarts_, j);	/* Write the StripOffsets */
	if(ColMapVals)
		fix_pal(1, srcimg->palette);	/* Write palette info */
}

/* Write an uncompressed or PackBits file */
static int _cdecl Write8Tif(imgdes *srcimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int yctr=srcimg->sty, handle;
	int rcode=NO_ERROR;	/* Assume no errors */
	int str_ctr=0;	/* Strip counter */
	unsigned yy;
	/* Write the DTA when it gets this full */
	int dtalimit = MAXSTRIPSIZE - (Cols*2);
	int cbyts=Cols, k=0;
	UCHAR *exbuff;

	/* Allocate space for an expansion buffer */
	if((exbuff=(UCHAR *)malloc(Cols)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	/* Assign handle, getrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		/* Write image data using PackBits or no compression */
		for(yy=0; yy<Rows; yy++) {
			/* Flush the buffer if we've written RowsPStrip rows
				or the DTA is about full
			*/
			if(yy % RowsPStrip == 0 || k >= dtalimit) {
				/* Write the bytes to disk */
				if(write(Thandle_, Hbuff_, k) != k) {
					rcode = BAD_DSK;
					goto xit;
					}
				if(yy % RowsPStrip == 0)
					/* Update StrStart[i] array with file ptr position */
					WrtFilePos(str_ctr++);
				k = 0;			/* Reset DTA index */
				}
			if((rcode=getrow(exbuff, handle, srcimg->stx, yctr++,
				Cols, srcimg->iwidth)) != NO_ERROR)
				goto xit;
			if(Comp == PACBITSID)
				cbyts = packbits_(&Hbuff_[k], exbuff, Cols);	/* Pack a line */
			else
				memcpy_(&Hbuff_[k], exbuff, Cols);				/* Copy a line */
			k += cbyts;		/* Update k */
			}
		/* Done with "rows" rows. If bytes are left in the buffer that need
			to be written, write them and update StrStart[StripCtr].
		*/
		if(k) {	/* If k = 0, no bytes to write */
			if(write(Thandle_, Hbuff_, k) != k) {
				rcode = BAD_DSK;
				goto xit;
				}
			WrtFilePos(str_ctr++); /* Set StrStart[last] */
			}
		}
xit:
	free(exbuff);		/* Free the allocated buffer */
	cmclose_(srcimg, handle);		/* Close CM handle */
	return(rcode);
}

/* Set StripStarts[StripCtr] = current file ptr position */
static void _cdecl WrtFilePos(int strctr)
{
	StripStarts_[strctr] = lseek(Thandle_, 0L, SEEK_CUR);
}

/* Load TIF image into system memory. Returns NO_ERROR, BAD_RANGE, BAD_OPN,
	BAD_TIFF, BAD_IFD, BAD_BPS, BAD_CMP, BAD_MEM (not enough conventional
	memory),	or NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl loadtif(char *fname, imgdes *desimg)
{
	TiffData tdat;		/* Allocate space for struct */
	UCHAR *exbuff, *strtab;	/* Expansion buffer, LZW string table */
	int cbyts, errcode;
	unsigned adj_twidth;		/* No. of bytes in an expanded row */

	/* Check range of start, end positions */
	if(checkrange_(desimg))
		return(BAD_RANGE);
	/* Get info on TIFF file we're to load */
	if((errcode=tiffinfo(fname, &tdat)) != NO_ERROR)	/* Fill structure */
		return(errcode);
	/* If we're loading data into EM or XM, check that it exists */
	if((errcode=check_em_xm_(desimg)) != NO_ERROR)
		return(errcode);
	if((Thandle_=open(fname, O_BINARY|O_RDONLY)) < 3)	/* open fname.TIF file */
		return(BAD_OPN);
	Rows = desimg->endy - desimg->sty + 1;
	/* Use the smaller number of rows value */
	if(Rows > tdat.Ilength)
		Rows = tdat.Ilength;
	Cols = desimg->endx - desimg->stx + 1;
	/* Use the smaller number of cols value */
	if(Cols > tdat.Iwidth)
		Cols = tdat.Iwidth;
	if(Cols == 0)			/* Exit if cols = 0 */
		return(NO_ERROR);
	/* Allocate memory for StripStarts, StripCounts and
		fill StripStarts and StripCounts arrays
	*/
	if((errcode=GetStripOffCts_()) != NO_ERROR)
		goto xit;
	/* Calculate the adjusted image width: adj_twidth =
		no. of bytes in an expanded row = ((tdat.Iwidth * BPS + 7)/8) * 8/BPS
	*/
	adj_twidth = (unsigned)((((long)tdat.Iwidth * tdat.BitsPSample + 7L) &
		0xfffffff8L) / tdat.BitsPSample);
	/* Check TIF header for valid settings before loading the file */
	/* Note: TIFF version no. already checked */
	if(StripOffAddrs==0 || tdat.SamplesPPixel==3)
		errcode = BAD_TIFF;
	/* No comp and 8-, 6-, or 4-bps OR PackBits comp and 8-bps => Read48Tif */
	else if((tdat.Comp<=1 && inrange(4, tdat.BitsPSample, 8)) ||
		(tdat.Comp==PACBITSID && tdat.BitsPSample==8)) {
		errcode = Read48Tif(desimg, adj_twidth, tdat.BitsPSample, tdat.Comp);
		}
	/* LZW comp, 8-bps, and Pred=1 => ReadTif_ */
	else if(tdat.Comp==5 && tdat.BitsPSample==8 && LZWPredicator==1) {
		/* Allocate enough memory for the LZW string table and an
			expansion buffer
		*/
		if((strtab=(UCHAR *)malloc(3*4096+16 + tdat.Iwidth)) != NULL) {
			exbuff = &strtab[3*4096+16];	/* Assign part of it to exbuff */
			errcode = ReadTif_(desimg, Thandle_, exbuff, strtab, Cols, Rows,
				StripStarts_, StripCounts_, Strips_, &tdat);
			free(strtab);
			}
		else
			errcode=BAD_MEM;
		}
	else
		errcode=BAD_CMP;
	free(StripCounts_);
xit:
	close(Thandle_);
	/* If image data was successfully loaded, load the palette data */
	if(errcode == NO_ERROR  && desimg->palette) {
		cbyts = loadtifpalette(fname, desimg->palette);
		desimg->palsize = (cbyts > 0) ? cbyts : 0;
		}
	return(errcode);
}

/* Allocate memory for StripStarts, StripCounts and fill StripStarts and
	StripCounts arrays. Return NO_ERROR or BAD_MEM.
*/
int _cdecl GetStripOffCts_(void)
{
	int j, rcode;

	if((rcode=AllocStrips_()) == NO_ERROR) {
		/* Copy over strip offsets */
		setoffcts_(StripOffAddrs, Sotype, StripStarts_, Strips_);
		/* Copy over strip byte counts if more than one strip and
			a strip byte counts tag was specified
		*/
		if(Strips_>1 && StripCtAddrs)
			setoffcts_(StripCtAddrs, Sctype, StripCounts_, Strips_);
		else {	/* No strip byte counts specified, so calculate them */
			for(j=0; j<Strips_-1; j++)
				StripCounts_[j] = StripStarts_[j+1] - StripStarts_[j];
			/* Set last StripByteCounts to some high value */
			StripCounts_[j] = filelength(Thandle_) - StripStarts_[j];
			}
		}
	return(rcode);
}

/* Read 4 to 8-bit TIFF file with no compression or an 8-bit file with
	PackBits compression.
*/
static int _cdecl Read48Tif(desimg, atwidth, bits_psam, comp)
imgdes *desimg;	/* Store image here */
int atwidth;		/* Adjusted image width from TIFF header */
int bits_psam;		/* Bits per sample - 4, 6, or 8 */
unsigned comp;		/* Compression: 0, 1, or 32773 (packbits) */
{
	/* PackBits decompression routine (packbits actually takes 3 args,
		4th added to satisfy compiler.
	*/
	/* Pointer to expansion function */
	int (_cdecl *expfct)(UCHAR *,UCHAR *,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	UCHAR *exbuff;			/* Intermediate buffer */
	int strip_ctr=0;		/* Strip counter */
	long bp_strip=0;		/* Bytes per strip */
	int sctr=0;				/* Byte counter in dta buffer */
	UCHAR *dta_addr=Hbuff_;  /* Address of our file buffer */
	int dtalimit=0; /* Get more bytes from disk when dtalimit is exceeded */
	int cbyts=atwidth;	/* No. of compressed bytes expanded */
	int valid_byts=0;
	int nocomp8=0;	  		/* Flag for 8-bit uncompressed type file */
	int rcode=NO_ERROR, byts2mov;
	int yctr=desimg->sty, handle;

	/* Need an expansion buffer of 2*atwidth (for 4 bit TIFF) */
	if((exbuff=(UCHAR *)malloc(2*atwidth)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	if(bits_psam==8 && comp!=PACBITSID)
		nocomp8 = 1;	/* Read an 8-bit uncompressed image */
	else {
		nocomp8 = 0;  	/* Read a PackBits or non 8-bit uncompressed image */
		expfct = (comp==PACBITSID)	? unpackbits_ : expand_;
		}
	/* Assign handle, putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(Rows--) {
			if(sctr >= dtalimit) { /* Nearly out of valid bytes in the DTA */
				/* Move any valid bytes left to the front of the DTA */
				byts2mov = valid_byts - sctr;
				if(byts2mov < 0)  byts2mov = 0;		/* Play it safe */
				memcpy_(dta_addr, &dta_addr[sctr], byts2mov);
				/* Don't read in more data if bytes per strip = 0 and there are
					bytes left in the DTA to process
				*/
				valid_byts = byts2mov;
				if(!(bp_strip==0 && byts2mov)) {
					/* Read in more data and calc valid bytes in the DTA */
					valid_byts += ReadMoData_(&bp_strip, &strip_ctr,
						DTASIZE-byts2mov, &dta_addr[byts2mov]);
					}
				/* No more bytes in DTA => we're done */
				if(valid_byts == 0)
					break;
				/* Set dta_limit back from end of DTA to allow reading a line at
					a time without reading invalid data.
				*/
				if((dtalimit=valid_byts-2*atwidth) <= 0)
					dtalimit = valid_byts;
				sctr = 0;	/* Reinitialize sctr */
				}
			if(nocomp8)
				/* If uncompressed 8-bit data, store data in exbuff */
				memcpy_(exbuff, &dta_addr[sctr], Cols);
			else
				/* If 8-bit PackBits or uncompressed non 8-bit data,
					unpack/expand data into exbuff
				*/
				cbyts = expfct(exbuff, &dta_addr[sctr], atwidth, bits_psam);
				/* NOTE: for unpackbits, only 3 of 4 args are used! */
			sctr += cbyts;		/* Add in cbyts to advance DTA index */
			if((rcode=putrow(exbuff, handle, desimg->stx, yctr++,
				Cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	free(exbuff);		/* Free the buffer if it was allocated */
	cmclose_(desimg, handle);		/* Close CM handle */
	return(rcode);
}

/* Fill DTA buffer with image data. Returns number of bytes read. */
unsigned _cdecl ReadMoData_(bp_straddr, str_ctraddr, dtasiz, dta_addr)
long *bp_straddr;		/* Bytes per strip */
int *str_ctraddr;		/* Strip counter */
int dtasiz;				/* Size of DTA buffer */
UCHAR *dta_addr;		/* Where to write the bytes */
{
	int count;

	/* If there are aren't any bytes left in a strip, start a new strip */
	if(*bp_straddr == 0) {
		if(SetFilePtr(bp_straddr, str_ctraddr) == -1)
			return(0);		/* => no more strips to process */
		}
	if(*bp_straddr-dtasiz >= 0) {	/* If strip doesn't end in our DTA */
		count = dtasiz;				/*  read dtasiz bytes */
		*bp_straddr -= dtasiz;		/*  and dec bytes per strip counter */
		}
	else {
		count = (int)(*bp_straddr); /* More bytes in DTA than in strip */
		*bp_straddr = 0;				 /*  read bytes to finish strip */
		}
	return(read(Thandle_, dta_addr, count));
}

/* Get bytes per strip from StripCounts[] and position file pointer to
	start of next strip. Returns NO_ERROR or -1 if we run out of
	strips to read.
*/
static int _cdecl SetFilePtr(bp_straddr, str_ctraddr)
long *bp_straddr;		/* Bytes per strip */
int *str_ctraddr;		/* Strip counter */
{
	if(*str_ctraddr < Strips_) {	/* More strips to read? */
		*bp_straddr = StripCounts_[*str_ctraddr];	/* Set bytes per strip */
		/* Move file pointer */
		if(lseek(Thandle_, StripStarts_[*str_ctraddr], SEEK_SET) != -1L) {
			(*str_ctraddr)++;				/* Bump strip counter */
			return(NO_ERROR);
			}
		}
	return(-1);
}

#ifdef USAGE
TiffData {			/* Declared in vicdefs.h */
	unsigned ByteOrder,Iwidth,Ilength,BitsPSample,Comp,SamplesPPixel,PhotoInt;
	} tinfo;
Caller must allocate space for TiffData structure as follows:
	TiffData tinfo;	/* Allocate space for struct */
	......
	errcode = tiffinfo(filnam, &tinfo);	/* fill structure */
	......
#endif

/* Get info on TIF file. Rets error codes: NO_ERROR - none,
	BAD_OPN - cannot find fname, BAD_TIFF - not a TIF file
*/
int _cdecl tiffinfo(char *fname, TiffData *tinfo)
{
	static TiffData defvals={0, 0, 0, 1, 1, 1, 1};
	int ifd_entries, ifd_bytes, j, rcode;
	long bps_addr, ifdstart; /* Bytes from file start to 1st IFD tag */
	unsigned tag, length, value, type;
	UCHAR *tpos;

	LZWPredicator = 1;	/* If LZWPredicator not given or 1, proceed */
	PlanarCfg_ = 1;		/* Assume RGB images are coded RGBRGB, etc. */
	StripOffAddrs = 0;
	StripCtAddrs = 0;
	DocStrAddr = 0;
	ColMapAddr = 0;
	ColMapVals = 0;
	if((Thandle_=open(fname, O_BINARY|O_RDONLY)) <3)
		return(BAD_OPN);								/* Open file */
	memcpy_(tinfo, &defvals, sizeof(TiffData)); /* Set default values */
	memset_(BitsPSample_, 1, 3*sizeof(long));	/* Use default of 1 */

/* Read image file header, check byte order, version number,
	and move file pointer to head of IFD.
*/
	if((rcode=ReadHeader(tinfo)) != 0)
		goto xit;
/* Hbuff_[0] contains number of entries in IFD */
	if(MotType)  swapbytes_(Hbuff_, 2); /* Mot type, swap bytes for IFDEntries */
	ifd_entries = *(int *)Hbuff_;				/* Number of TAG fields */
	/* ifd_bytes = size in bytes of IFD */
	ifd_bytes = ifd_entries*12;
	ifdstart = tell(Thandle_);	/* Record offset to start of first IFD */
	/* Don't overflow Hbuff_ and read in first IFD */
	if((ifd_bytes>8192) || (read(Thandle_, Hbuff_, ifd_bytes) != ifd_bytes)) {
		rcode = BAD_IFD;
		goto xit;
		}
	/* Hbuff_ -> tag of first entry */
	for(j=0; j<ifd_bytes; j+=12) {
		tpos = &Hbuff_[j];
		if(MotType)  swapbytes_(tpos, 2); /* If Motorola, swap tag bytes */
		tag = *(int *)tpos;
		if(tag == TGIMAGEWIDTH) {
			if((rcode=GetValue_(tpos, &value)) != 0)
				goto xit;
			tinfo->Iwidth = value;
			continue;
			}
		if(tag == TGIMAGELENGTH) {
			if((rcode=GetValue_(tpos, &value)) != 0)
				goto xit;
			tinfo->Ilength = value;
			continue;
			}
		if(tag == TGBITSPERSAMPLE) {
			GetDataAddr_(tpos, &type, &length, &bps_addr, ifdstart+(long)j);
			/* Copy over bits per sample */
			if(length <= 3) {
				setoffcts_(bps_addr, type, BitsPSample_, length);
				/* Just put the first value in the TIFF structure */
				tinfo->BitsPSample = (unsigned)(*BitsPSample_);
				continue;
				}
			rcode = BAD_TIFF;	/* If length > 3 */
			goto xit;
			}
		if(tag == TGCOMPRESSION) {
			if((rcode=GetValue_(tpos, &value)) != 0)
				goto xit;
			tinfo->Comp = value;
			continue;
			}
		if(tag == TGDOCUMENTNAME) {
			/* Get address of string */
			if((rcode=GetStrAddr_(tpos, &DocStrAddr,
				ifdstart+(long)j)) != 0)
				goto xit;
			continue;
			}
		if(tag == TGSTRIPOFFSETS) {		/* loc of first strip offset */
			GetDataAddr_(tpos, &Sotype, (unsigned *)&Strips_,
				&StripOffAddrs, ifdstart+(long)j);
			continue;
			}
		if(tag == TGSAMPLESPERPIXEL) {
			if((rcode=GetValue_(tpos, &value)) != 0)
				goto xit;
			tinfo->SamplesPPixel = value;		/* Samples per pixel */
			continue;
			}
		if(tag == TGSTRIPBYTECOUNTS) {	/* loc of first strip byte count */
			GetDataAddr_(tpos, &Sctype, &length,
				&StripCtAddrs, ifdstart+(long)j);
			continue;
			}
		if(tag == TGPREDICTOR) {
			if((rcode=GetValue_(tpos, &value)) != 0)
				goto xit;
			LZWPredicator = value;
			continue;
			}
		if(tag == TGPHOTOMETRICINT) {
			if((rcode=GetValue_(tpos, &value)) != 0)
				goto xit;
			tinfo->PhotoInt = value;
			continue;
			}
		if(tag == TGPLANARCONFIG) {
			if((rcode=GetValue_(tpos, &value)) != 0)
				goto xit;
			PlanarCfg_ = value;
			continue;
			}
		if(tag == TGCOLORMAP) {		/* loc of first strip offset */
			GetDataAddr_(tpos, &length, (unsigned *)&ColMapVals,
				&ColMapAddr, ifdstart+(long)j);
			continue;
			}
		}
xit:
	close(Thandle_);
	return(rcode);
}

/* Copy over TIFF header data values.
	Used for strip offsets, strip counts, and bits per sample.
*/
void _cdecl setoffcts_(lptr, type, saddr, count)
long lptr;		/* Where to set file ptr */
unsigned type;	/* Data type, 3 (short) or 4 (long) */
long *saddr;	/* Where to store values */
int count;		/* How many values to store */
{
	int j, bytes2read;

	/* Copy over strip offsets or strip counts: Move file ptr to field */
	if(lseek(Thandle_, lptr, SEEK_SET) == lptr) {
		/* type = 4 (TIFFLONG) or 3 (TIFFSHORT) */
		bytes2read = (type == 4) ? count<<2 : count<<1;
		if(read(Thandle_, Hbuff_, bytes2read) == bytes2read) {
			if(type == 4) {	/* If values are stored as longs: */
				for(j=0; j<count; j++) {
					if(MotType)  swapwords_(&Hbuff_[j<<2], 4);/* Swap offset words */
					saddr[j] = *(long *)&Hbuff_[j<<2]; /* Store values */
					}
				}
			else {	/* If values are stored as ints: */
				for(j=0; j<count; j++) {
					if(MotType)  swapbytes_(&Hbuff_[j<<1], 2);/* Swap offset bytes */
					saddr[j] = (long)(*(unsigned *)&Hbuff_[j<<1]); /* Store values */
					}
				}
			}
		}
}

/* Extract data address from the image file dir entry for tag
	with data type = LONG or SHORT.
*/
void _cdecl GetDataAddr_(pos, dtype, dlength, data_addr, tagloc)
UCHAR *pos; /* Abs addr within buffer holding all of first image file dir */
unsigned *dtype;				/* Data type: TIFFSHORT or TIFFLONG */
unsigned *dlength;			/* Number of elements to get */
long *data_addr;				/* Where to put addr we're to get */
long tagloc;					/* Bytes from file start to start of IFD entry */
{
	long bytes2read;		/* tsize = dtype*dlength */

	/* Dir entry is 12 bytes long */
	if(MotType) {	/* Motorola type TIFF: */
		swapbytes_(pos+2, 2);		/* Swap dtype bytes */
		swapwords_(pos+4, 4);		/*  and dlength words */
		}
	*dtype = *(unsigned *)&pos[2];  /* Data type: TIFFSHORT or TIFFLONG */
	*dlength = (unsigned)(*(long *)&pos[4]);
	bytes2read = (*dtype)*(*dlength);
	/* Get address of the data */
	if(bytes2read <= 4)		/* If <= 4 bytes, data is in TiffHdr */
		*data_addr = tagloc + 8L;
	else {	/* If > 4 bytes, TiffHdr contains ptr to data */
		if(MotType)  swapwords_(pos+8, 4);	/* Swap pointer words */
		*data_addr = *(long *)(pos + 8);
		}
}

/* Extract string address from image file dir entry for tag with data
	type = ASCII. Ret BAD_TIFF if error.
*/
int _cdecl GetStrAddr_(pos, string, tagloc)
UCHAR *pos; /* Abs addr within buffer holding all of first image file dir */
long *string;	/* Where to put addr we're to get */
long tagloc;	/* Bytes from file start to start of IFD entry */
{
	unsigned dtype;				/* Data type */
	long dlength;		/* No. of elements of data type */
	
	/* Dir entry is 12 bytes long */
	if(MotType) {	/* Motorola type TIFF: */
		swapbytes_(pos+2, 2);		/* Swap dtype bytes */
		swapwords_(pos+4, 4);		/*  and dlength words */
		}
	dtype = *(unsigned *)&pos[2];	/* data type: TIFFASCII is valid */
	/* dtype must be 2 to be valid */
	if(dtype != TIFFASCII)
		return(BAD_TIFF);
	/* Since dtype=ASCII, dlength=no. of bytes to read in string */
	dlength = *(long *)&pos[4];
	/* If dlength <= 4, string addr = tagloc + 8, else
		pos + 8 points to the string's addr
	*/
	if(dlength <= 4)
		*string = tagloc + 8L;
	else {
		if(MotType)  swapwords_(pos+8, 4);	/* Swap pointer words */
		*string = *(long *)(pos + 8);
		}
	return(NO_ERROR);
}

/* Extract value from image file dir entry for tag with data type = short
	or long and no. of elements = 1. Ret BAD_TIFF if error.
*/
int _cdecl GetValue_(pos, value)
UCHAR *pos; /* Abs addr within buffer holding all of first image file dir */
unsigned *value;	/* Where to put value we're to get */
{
	unsigned dtype;			/* Data type */
	long dlength;				/* No. of elements */
	
	/* Dir entry is 12 bytes long */
	if(MotType) {	/* Motorola type TIFF: */
		swapbytes_(pos+2, 2);		/* Swap dtype bytes */
		swapwords_(pos+4, 4);		/*  and dlength words */
		}
	dtype = *(int *)&pos[2];	/* data type: TIFFSHORT or TIFFLONG are valid */
	/* dtype must be 3 or 4 to be valid */
	if(outrange(TIFFSHORT, dtype, TIFFLONG))
		return(BAD_TIFF);
	dlength = *(long *)&pos[4];
	/* dlength must be 1 to be valid */
	if(dlength != 1L)
		return(BAD_TIFF);
	/* Data is at start of field + 8 */
	if(dtype == TIFFSHORT) {
		if(MotType)  swapbytes_(pos+8, 2);	/* Swap bytes */
		*value = *(unsigned *)(pos+8);
		}
	else {
		if(dtype == TIFFLONG) {
			if(MotType)  swapwords_(pos+8, 4);	/* Swap words */
			*value = (unsigned)(*(long *)(pos+8));
			}
		else  return(BAD_TIFF);
		}
	return(NO_ERROR);
}

/* Read in TIFF file header, check version number, set/clear MotType */
static int _cdecl ReadHeader(TiffData *tinfo)		/* Where to put info */
{
	long ifd_addr;
	unsigned *ip;
	
	read(Thandle_, Hbuff_, 8);	/* read in image file header (8 bytes) */
	ip = (unsigned *)Hbuff_;
	/* Set MotType if Motorola type TIFF */
	if(ip[0] == 0x4d4d) {			/* "II" or "MM"? */
		MotType = 1;
		swapbytes_(ip, 4);		/* Motorola type, swap bytes in header */
		swapwords_(&ip[2], 4);		/* and swap words for IFD Addr */
		}
	else {	/* Clear MotType if Intel type TIFF */
		if(ip[0] == 0x4949)  MotType = 0;
		else  return(BAD_TIFF);	/* Not "II" or "MM" => not a TIFF file */
		}
	tinfo->ByteOrder = ip[0];				/* Set ByteOrder */
	if(ip[1] != 42)	/* "version" no. MUST be 42 */
		return(BAD_TIFF);
	ifd_addr = *(long *)&ip[2]; /* offset of first IFD */
/* Move file ptr to first IFD */
	if(lseek(Thandle_, ifd_addr, SEEK_SET) != ifd_addr)
		return(BAD_TIFF);
/* Read in number of entries in IFD */
	if(read(Thandle_, Hbuff_, 2) != 2)
		return(BAD_TIFF);
	return(NO_ERROR);
}

/* Allocate an area to be used to store StripCounts and StripStarts.
	Leave room for one extra StripStart.
*/
int _cdecl AllocStrips_(void)
{
	int errcode = BAD_MEM;	/* If area not allocated... */
	if((StripCounts_=(long *)calloc(2*Strips_+1, sizeof(long))) != NULL) {
		/* Assign half of buffer to StripStarts */
		StripStarts_ = &StripCounts_[Strips_];
		errcode = NO_ERROR;
		}
	return(errcode);
}

/* Load TIF palette from colormap. Returns number of color map entries,
	BAD_OPN, or BAD_TIFF.
*/
int _cdecl loadtifpalette(char *fname, UCHAR *pal)
{
	TiffData tdat;		/* Allocate space for struct */
	int errcode;
	
	if((errcode=tiffinfo(fname, &tdat)) != NO_ERROR)	/* Fill structure */
		return(errcode);
	/* Check TIFF header for a valid palette color image, exit if error */
	if((tdat.PhotoInt==3 && tdat.SamplesPPixel==1 &&
		ColMapVals>0 && ColMapVals<=768) == 0)
		return(0);	/* No valid colormap bytes */
	if((Thandle_=open(fname, O_BINARY|O_RDONLY)) < 3) /* Open file */
		return(BAD_OPN);
	/* No errors, return the palette data */
	/* Move file ptr to the colormap	*/
	lseek(Thandle_, ColMapAddr, SEEK_SET);
	read(Thandle_, Hbuff_, ColMapVals<<1);	/* Read colormap into Hbuff_ */
	fix_pal(0, pal);		/* Reorder and copy over the palette info */
	close(Thandle_);
	return(ColMapVals);
}

/* Reorder and load (0) or save (1) the palette info */
static void _cdecl fix_pal(int mode, UCHAR *pal)
{
	int j, k, ct, colvals;
	unsigned *uptr;

	uptr = (unsigned *)Hbuff_;
	colvals = ColMapVals / 3;
	for(k=0; k<3; k++) {
		j = k;
		if(mode) {		/* Save the palette info */
			/* Reorder the colormap data so it's in planes and 0 - 65535 */
			for(ct=0; ct<colvals; ct++) {
				*uptr = pal[j] << 8;
				j += 3;
				uptr++;
				}
			}
		else {			/* Load the palette info */
			/* Values are stored in red, green, and blue PLANES */
			for(ct=0; ct<colvals; ct++) {
				pal[j] = (UCHAR)(MotType ? *uptr : (*uptr >> 8));
				j += 3;
				uptr++;
				}
			}
		}
	if(mode)				/* Write the colormap */
		write(Thandle_, Hbuff_, ColMapVals<<1);
}

#pragma check_stack(off)
int _cdecl GetTiffHeaderSize_(void)
{
	return(sizeof(TiffHdr_));
}

/* If we're using EM or XM, make sure that it exists. Returns NO_ERROR,
	NO_EMM, EMM_ERR, NO_XMM, or XMM_ERR.
*/
int _cdecl check_em_xm_(imgdes *image)
{
	if(image->ibuff)			/* Image is in CM, return NO_ERROR */
		return(NO_ERROR);
	if(image->ehandle)		/* Image is in EM, make sure it exists */
		return(emdetect());
	return(xmdetect());		/* Image is in XM, make sure it exists */
}
+ARCHIVE+ scanjet.c    11008  3/27/1991 15:46:24
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:

		SJdetect		Make sure scanner driver is present and hardware is OK
		SJerrno		Return last Scanjet error code
		SJgetcols	Determine bytes per scanline
		SJgetdwidth	Determine output data width
		SJgetodata	Determine output data type
		SJgetrows	Determine scanlines in the window
		SJmodel		Determine ScanJet model
		SJscanimage	Scan the window and transfer data to image
		SJscanwin	Scan the window
		SJsetdwidth	Set output data width
		SJsetodata	Set output data type and invert image
		SJxyres		Set X,Y resolution
		SJwinsize	Set scan window size
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>
#include <string.h>
#include <dos.h>
#include <stdarg.h>
#include <io.h>
#include <fcntl.h>
#define DEBUG 0
#define WHITE 1				/* Image type */
#define BLACK 2
#define DITH  3
#define GRAY  4

static int _cdecl SJgetval(int,char *);
static int _cdecl SJsetval(int,char *,...);
static void _cdecl swap(int *,int *);
extern unsigned _cdecl SJiofct(int,UCHAR);
extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void _cdecl cmclose_(imgdes *,int);
extern void _cdecl set_raw_(int,int);
extern int _cdecl check_ioctl_(int);
#if DEBUG == 1
static void sdisp_err(int,int);
#endif

/* Make sure scanner driver is present, hardware is operational, and return
	a device handle. Returns NO_ERROR if everything is OK, BAD_OPN if driver
	was not detected, and SCAN_ERR if there's a hardware problem.
	For SJ, SJPlus.
*/
int _cdecl SJdetect(int *sjhandle)
{
	int model, rcode=SCAN_ERR;

	/* Check that the scanner driver is installed */
	if((*sjhandle=open("HPSCAN", O_RDWR | O_BINARY)) < 3)
		return(BAD_OPN);
	/* Make sure "HPSCAN" is a device name and not a filename */
	if(check_ioctl_(*sjhandle) == 0)
		rcode = BAD_OPN;
	else {
		/* Check for a scanner hardware error (may simply be turned off) */
		if(SJgeterrstat(*sjhandle) == NO_ERROR) {
			/* If scanner returns an error, don't continue */
			model = SJmodel(*sjhandle);
			if(inrange(0, model, 1))
				return(NO_ERROR);
			}
		}
	close(*sjhandle);		/* Done with device */
	return(rcode);
}

/* Return error number. Returns last Scanjet error code or SCAN_ERR if write
	error. For SJ, SJPlus.
*/
int _cdecl SJerrno(int handle)
{
	int errno=0xff;
	if(write(handle, "\033*s259E", 6) == 6) {	/* Get errno */
		read(handle, (char *)&errno, 2);			/* Get value */
		write(handle, "\033*oE", 4);		/* Clear last error */
		return(errno); 		/* Return value */
		}
	return(SCAN_ERR);
}

/* Determine bytes per scanline. Return bytes or SCAN_ERR if error.
	For SJ, SJPlus.
*/
int _cdecl SJgetcols(int handle)
{
	return(SJgetval(handle, "\033*s1025E"));
}

/* Determine output data width. Return 1, 4, 8, or SCAN_ERR if error.
	For SJ, SJPlus.
*/
int _cdecl SJgetdwidth(int handle)
{
	int model, dtype, dwidth=1;

	dtype = SJgetodata(handle);
	if(outrange(0, dtype, 4))
		return(SCAN_ERR);
	if(dtype == GRAY) {
		if((model=SJmodel(handle)) == 0)
			dwidth = 4;			/* HP ScanJet, 16 grays */
      else if(model == 1)	/* HP ScanJet Plus, 256 grays */
			dwidth = SJgetval(handle, "\033*s10312R");
		}
	return(dwidth);
}

/* Determine output data type. Return 0 - 4 or SCAN_ERR if error.
	For SJ, SJPlus.
*/
int _cdecl SJgetodata(int handle)
{
	return(SJgetval(handle, "\033*s10325R"));
}

/* Determine scanlines in the window. Return rows or SCAN_ERR if error.
	For SJ, SJPlus.
*/
int _cdecl SJgetrows(int handle)
{
	return(SJgetval(handle, "\033*s1026E"));
}

/* Determine ScanJet model. Return 0 if SJ, 1 if SJPlus, SCAN_ERR if error.
	For SJ, SJPlus.
*/
int _cdecl SJmodel(int handle)
{
	static char *sj_strs[] = {"\033*s3d5W9190A","\033*s3d5W9195A"};
	char buff[16];
	int j;

	if(write(handle, "\033*s3E", 5) == 5) {
		if(read(handle, buff, 12) == 12) {
			for(j=0; j<2; j++) {
				if(memcmp(buff, sj_strs[j], 12) == 0)
					return(j);	/* Match, it's a ScanJet or SJ plus */
				}
			}
		}
	return(SCAN_ERR);	/* Write/read error or unidentified string */
}

/* Scan the window into desimg. Works for 4- and 8-bit data widths.
	Returns NO_ERROR, SCAN_ERR, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl SJscanimage(int sjhandle, imgdes *desimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int errcode=NO_ERROR, xsrows, scols, srows, cols, rows, bcols, yctr;
	int j, excols, mhandle, dwidth;
	UCHAR *sptr, *dptr=Hbuff_;

	/* Check range of start, end positions */
	if(checkrange_(desimg))
		return(BAD_RANGE);
	yctr = desimg->sty;
	/* Set raw output mode to be able to input ctrl-z's */
	set_raw_(1, sjhandle);
	/* Get the number of cols, rows to do according to the scanner */
	if((scols=SJgetcols(sjhandle)) == SCAN_ERR)
		return(SCAN_ERR);	/* Catch invalid handle error */
	srows = SJgetrows(sjhandle);
	/* Use data width to set buffer cols */
	bcols = scols;
	if((dwidth=SJgetdwidth(sjhandle)) == 4) /* Data width = 1, 4, or 8 */
		bcols = scols * 2;
	/* Use the smaller number of rows value */
	rows = desimg->endy - desimg->sty + 1;
	if(rows > srows)
		rows = srows;
	/* Use the smaller number of cols value */
	cols = desimg->endx - desimg->stx + 1;
	if(cols > bcols)
		cols = bcols;
	excols = cols / 2;	/* Used if we're receiving 4-bit data */
	/* Assign handle, putrow(), and check for EM/XM */
	if((errcode=assign_gprow_(desimg, &mhandle, &getrow, &putrow)) == NO_ERROR) {
		SJscanwin(sjhandle);	/* Scan the window */
		xsrows = srows - rows;	/* Rows that won't be copied */
		/* Transfer the data */
		while(srows--) {
			if(read(sjhandle, Hbuff_, scols) != scols) {
				errcode = SCAN_ERR;
				break;
				}
			if(srows >= xsrows) {	/* Copy the data over if it's in range */
				if(dwidth == 4) {		/* Scanning 4-bit data */
					sptr = Hbuff_;
					dptr = &Hbuff_[4048];
					/* Convert a nibble to a byte and mult value by 16 */
					for(j=0; j<excols; j++) {
						*dptr++ = (UCHAR)(*sptr & 0xf0); /* yyyyxxxx -> yyyy0000 */
						*dptr++ = (UCHAR)(*sptr++ << 4); /* yyyyxxxx -> xxxx0000 */
						}
					dptr = &Hbuff_[4048];
					}
				if((errcode=putrow(dptr, mhandle, desimg->stx, yctr++,
					cols, desimg->iwidth)) != NO_ERROR)
					break;
				}
			}
		}
	set_raw_(0, sjhandle);		/* Restore old output mode */
	cmclose_(desimg, mhandle);		/* Close CM handle */
#if DEBUG == 1
	sdisp_err(errcode, sjhandle);	/* Display any EM/XM/scanner error codes */
#endif
	/* If scan data was successfully loaded, set the palette size */
	if(errcode == NO_ERROR)
		desimg->palsize = 0;
	return(errcode);
}

#if DEBUG == 1
/* Display any EM or XM error codes */
static void _cdecl sdisp_err(int errcode, int handle)
{
	if(errcode != NO_ERROR) {
		printf("\nError: %d", errcode);
		if(errcode == EMM_ERR)
			printf(", EMM error: %x", emerror());
		else if(errcode == XMM_ERR)
			printf(", XMM error: %x", xmerror());
		else if(errcode == SCAN_ERR)
			printf(", scanner error: %x", SJerrno(handle));
		}
}
#endif

/* Scan the window. Returns NO_ERROR or SCAN_ERR if write error.
	For SJ, SJPlus.
*/
int _cdecl SJscanwin(int handle)
{
	return(SJsetval(handle, "\033*f0S"));
}

/* Set output data width. Returns NO_ERROR or SCAN_ERR if write error.
	For SJPlus.
*/
int _cdecl SJsetdwidth(int handle, int dwidth)
{
	return(SJsetval(handle, "\033*a%dG", dwidth));
}

/* Set output data type and invert image.	Returns NO_ERROR or SCAN_ERR
	if write error. For SJ, SJPlus.
*/
int _cdecl SJsetodata(int handle, int type)
{
	return(SJsetval(handle, "\033*a%dT\033*a1I", type));
}

/* Set X,Y resolution. Returns NO_ERROR or SCAN_ERR if write error.
	For SJ, SJPlus.
*/
int _cdecl SJxyres(int handle, int xval, int yval)
{
	return(SJsetval(handle, "\033*a%dR\033*a%dS", xval, yval));
}

/* Set scan window size. Returns NO_ERROR or SCAN_ERR if write error.
	For SJ, SJPlus.
*/
int _cdecl SJwinsize(int handle, int sx, int sy, int ex, int ey)
{
	int cols, rows;
	swap(&sx, &ex);
	cols = ex - sx + 1;
	swap(&sy, &ey);
	rows = ey - sy + 1;
	return(SJsetval(handle, "\033*f%dX\033*f%dY\033*f%dP\033*f%dQ",
		sx, sy, cols, rows));
}

static void _cdecl swap(int *sx, int *ey)
{
	int tmp;
	if(*sx > *ey) {
		tmp = *sx; *sx = *ey; *ey = tmp;
		}
}

/* Internal functions */
/* Convert SJ reply to an int. Return vals or SCAN_ERR if error.
	For SJ, SJPlus.
*/
static int _cdecl SJgetval(int handle, char *askstr)
{
	char buff[64];
	int len;

	len = strlen(askstr);
	if(write(handle, askstr, len) == len) {	/* Send string to SJ */
		read(handle, buff, 18);						/* Get reply */
		if(memcmp(buff, askstr, len-1) == 0)	/* Check prefix */
			return(atoi(&buff[len]));			/* Return value if valid */
		}
	return(SCAN_ERR);	/* Write/read error or unidentified string */
}

/* Set value. Returns NO_ERROR or SCAN_ERR if write error.
	For SJ, SJPlus.
*/
static int _cdecl SJsetval(int handle, char *askstr, ...)
{
	va_list arg_ptr;
	char buff[64];
	int len;

	va_start(arg_ptr, askstr);	/* "arg_ptr" points to format string */
	vsprintf(buff, askstr, arg_ptr);
	va_end(arg_ptr);
	len = strlen(buff);
	if(write(handle, buff, len) == len)
		return(NO_ERROR);
	return(SCAN_ERR);
}

#if 0
/*** Rewritten in assembler ***/
/* Data format used by IOCTL call */
typedef struct {
	UCHAR cmnd;	/* 1: Read error line status, 2: Read swing buff size, */
					/* 3: Read swing buff seg, 4: Read I/O base addr */
	UCHAR err_stat; /* Ret status, bit 0=1 => scanner error, bit 7=1 => invalid cmd */
	unsigned io_data;	/* Requested data for commands 2 - 4 */
	} io_packet;
/* Access scanner control functions. Return value, NO_ERROR, SCAN_ERR
	or BAD_RANGE. For SJ, SJPlus.
*/
unsigned _cdecl SJiofct_(handle, cmd)
int handle;	/* ScanJet handle */
UCHAR cmd;	/* 0 reset, 1 read error line stat, 2 read swing buff size,
					3 read swing buff seg, 4 read i/o base addr  */
{
	union REGS inregs, outregs;
	struct SREGS segregs;
	io_packet iodata;
	io_packet *cmdstr;
	unsigned rcode = NO_ERROR;

	if(cmd > 4)  return(BAD_RANGE);
	iodata.cmnd = cmd;
	inregs.x.ax = 0x4403;	/* IOCTL send control strings function */
	inregs.x.cx = 4;			/* Command is 4 bytes long */
	inregs.x.bx = handle;	/* Device handle */
	cmdstr = &iodata;
	segregs.ds  = FP_SEG(cmdstr);
	inregs.x.dx = FP_OFF(cmdstr);
	intdosx(&inregs, &outregs, &segregs);
	if(iodata.err_stat & 1)	/* Bit 0=1 => scanner error, */
		rcode = SCAN_ERR;		/* bit 7=1 => invalid command */
	else if(cmd > 1)			/* Commands 0 and 1 return nothing */
		rcode = iodata.io_data;
	return(rcode);
}
#endif
+ARCHIVE+ showhist.c    3412  3/16/1991  4:59:16
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		showhisto		Produce framed histo on HGC/CGA/EGA/VGA
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <string.h>
#define CGA_   6			/* PC video modes */
#define MDA_   7
#define EGA_  16
#define EEGA_ 18

extern void * _cdecl strcpyn_(void huge *,void huge *,unsigned);
static void _cdecl writCGA_(int,int,int,char *);
/* 6 routines are in egahisto.asm */
extern void _cdecl EGAhisto_(UCHAR *,int,int);
extern void _cdecl CGAhisto_(UCHAR *,int,int);
extern void _cdecl HGChisto_(UCHAR *,int,int);
extern void _cdecl writEGA_(int,int,int,char *);
extern void _cdecl writHGC_(int,int,int,char *);
extern void _cdecl set_ega_window_(int,int,int,int,int);
extern void _cdecl crt_src_(int,int);

/* Produce framed histo on HGC/CGA/EGA/VGA
	TitleStr and LegendStr are centered. Color values bar_col,txt_col,
	and bck_col apply to EGA and VGA only. Valid vmodes are 6 (CGA),
	7 (HGC), 16 (EGA), and 18 (EEGA). Returns NO_ERROR, BAD_RANGE
	(No pixels!), or VMODE_ERR (invalid video mode).
*/
int _cdecl showhisto(int vmode, long *his_table, char *titlestr,
	char *legendstr, int bar_col, int txt_col, int bck_col)
{
	void (_cdecl *showfct)(UCHAR *,int,int);
	void (_cdecl *writstr)(int,int,int,char *);
	char sstr[80];
	UCHAR tab[256];
	int sp, flag=0;
	long *lp;
	long maxpop;
	static char *dotstr = ".    .    .    .    .    .    .    .    .    .    .    .    .";
	static char *numstr = "0   20   40   60   80   100  120  140  160  180  200  220  240";
	int titlerow=0, axisrow=20, legendrow=23;

	if(vmode==EEGA_ || vmode==EGA_) {
			showfct = EGAhisto_;
			writstr = writEGA_;
			}
	else if(vmode == CGA_) {
			showfct = CGAhisto_;
			writstr = writCGA_;
			}
	else if(vmode == MDA_) {
			showfct = HGChisto_;
			writstr = writHGC_;
			}
	else
		return(VMODE_ERR);		/* Invalid video mode */

	/* Find most populated bin = maxpop */
	lp = his_table;
	maxpop = *lp++;		/* Initialize maxpop and point lp at bin 1*/
	sp = 255;
	while(sp--) {			/* Do next 255 bins */
		if(maxpop < *lp)
			maxpop = *lp;
		lp++;
		}
	if(maxpop == 0)
		return(BAD_RANGE);		/* No pixels! */
/* Normalize to population = 128 if maxpop >= 128 */
	lp = his_table;
	if(maxpop >= 128) {
		flag = 1;
		maxpop >>= 7;
		}
	for(sp=0; sp<256; sp++) {
		/* val = bin/(maxpop/128) or bin*128/maxpop */
		tab[sp] = (UCHAR)((flag ? (*lp) : (*lp * 128)) / maxpop);
		lp++;
		}
	/* Write title str */
	strcpyn_(sstr, titlestr, 74);
	sp = 40 - (strlen(sstr) / 2);

	if(vmode >= EGA_)		/* Set fore col for a window, move cursor */
		set_ega_window_(0, 0, 79, 349, bck_col);
	writstr(titlerow, sp, txt_col, sstr);

	writstr(axisrow, 8, txt_col, dotstr);
	writstr(axisrow+1, 8, txt_col, numstr);
	/* For writ EGA, mul row by 14 and col by 8 */

	/* Write legend str */
	strcpyn_(sstr, legendstr, 74);
	sp = 40 - (strlen(sstr) / 2);
	writstr(legendrow, sp, txt_col, sstr);
	showfct(tab, bar_col, 0);
	return(NO_ERROR);
}

/* Display string on CGA adapter (doesn't use color arg) */
static void _cdecl writCGA_(int row, int col, int color, char *str)
{
	crt_src_(row, col);	/* Adjust cursor position */
	puts(str);				/* Just use std C function */
}

+ARCHIVE+ smatrix.c     1647  3/16/1991  4:59:16
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		sharpen				Sharpen image using convolution
		outline				Outline image using convolution
		sharpengentle		Gently sharpen image using convolution
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
extern int _cdecl matrixall_(imgdes *,imgdes *,void (_cdecl *)(),int *);
extern void _cdecl matrix_sharp_(UCHAR *,UCHAR *,int,int,int *);
extern void _cdecl matrix_gsharp_(UCHAR *,UCHAR *,int,int,int *);

/* Normal sharpen image using convolution.
	Uses kernal[9] = -1,-1,-1,-1,9,-1,-1,-1,-1.
	Returns NO_ERROR, BAD_RANGE, BAD_MEM (not enough convential
	memory), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl sharpen(imgdes *srcimg, imgdes *desimg)
{
	int multr = 9;

	return(matrixall_(srcimg, desimg, matrix_sharp_, &multr));
}

/* Outline image using convolution.
	Uses kernal[9] = -1,-1,-1,-1,8,-1,-1,-1,-1.
	Returns NO_ERROR, BAD_RANGE, BAD_MEM (not enough convential
	memory), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl outline(imgdes *srcimg, imgdes *desimg)
{
	int multr=8;

	return(matrixall_(srcimg, desimg, matrix_sharp_, &multr));
}

/* Gently sharpen image using convolution
	Uses kernal[9] = 0,0,0,-1,3,-1,0,0,0.
	Returns NO_ERROR, BAD_RANGE, BAD_MEM (not enough convential
	memory), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl sharpengentle(imgdes *srcimg, imgdes *desimg)
{
	int dummy;

	return(matrixall_(srcimg, desimg, matrix_gsharp_, &dummy));
}
+ARCHIVE+ sqaspect.c    3507  3/16/1991  5:30:54
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		squareaspect	Square the aspect ratio of an image
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <string.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void * _cdecl memset_(void huge *,int,unsigned);
static void _cdecl avg2rows(UCHAR *,int,int);

/* Square the aspect ratio of an image by adjusting to 80% - lines 0-2 of
	src become lines 0-2 of des, lines 3 & 4 of src are averaged and become
	line 4 of des. Return number of next line to process, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl squareaspect(imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int ln, rcode, rows, cols, srow, drow;
	int syctr, dyctr, shandle, dhandle;
	UCHAR *bptr;

	/* Check range of start, end positions */
	if(checkrange_(srcimg) || checkrange_(desimg))
		return(BAD_RANGE);
	syctr = srcimg->sty;
	dyctr = desimg->sty;
	cols = srcimg->endx - srcimg->stx + 1;
	drow = srow = rows = srcimg->endy - srcimg->sty + 1;
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) == NO_ERROR &&
		(rcode=assign_gprow_(desimg, &dhandle, &dummy, &putrow)) == NO_ERROR) {
		for(;;) {
			if(srow - 3 <= 0) /* Do while there are source rows to move */
				break;
			/* Move rows 0-2 to result */
			for(ln=3; ln>0; ln--) {
				/* Move data from row into Hbuff_ */
				if((rcode=getrow(Hbuff_, shandle, srcimg->stx, syctr++,
					cols, srcimg->iwidth)) != NO_ERROR)
					goto err;
				/* Move data in Hbuff_ to des image */
				if((rcode=putrow(Hbuff_, dhandle, desimg->stx, dyctr++,
					cols, desimg->iwidth)) != NO_ERROR)
					goto err;	/* NOTE: this is des image width! */
				}
			srow -= 3;
			drow -= 3;
			if(srow - 2 <= 0)
				break;
			/* Move rows 3-4 to Hbuff_ */
			bptr = Hbuff_;
			for(ln=2; ln>0; ln--) {
				/* Move data from row into Hbuff_ */
				if((rcode=getrow(bptr, shandle, srcimg->stx, syctr++,
					cols, srcimg->iwidth)) != NO_ERROR)
					goto err;
				bptr += srcimg->iwidth;		/* NOTE: this is src image width! */
				}
			/* Average the 2 rows */
			avg2rows(Hbuff_, cols, srcimg->iwidth);
			if((rcode=putrow(Hbuff_, dhandle, desimg->stx, dyctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				goto err;	/* NOTE: this is des image width! */
			srow -= 2;
			drow--;
			}
		/* Return error code or number of next line to process */
		rcode = desimg->sty + rows - drow;
#ifdef ZERO_REST
		while(drow--) {		/* Zero rest of dest pic */
			memset_(des, 0, cols); des += desimg->iwidth;
			}
#endif
		}
err:
	cmclose_(srcimg, shandle);		/* Close CM handle */
	cmclose_(desimg, dhandle);
	return(rcode);
}

/* Average the 2 rows in src and store the result back into src. Organization
	of src is row1row2. Row1 starts at src[0], row2 at src[width].
*/
static void _cdecl avg2rows(UCHAR *src, int byts2avg, int width)
{
	while(byts2avg--) {
		*src = (UCHAR)(((int)*src + (int)*(src+width)) >> 1);
		src++;
		}
}
+ARCHIVE+ sub.c          997  3/16/1991  4:59:16
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		subimage		Subtract 2 images
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl twoimagefcts_(imgdes *,imgdes *,imgdes *,void (_cdecl *)());

/* Subtract 'count' bytes in obuff from sbuff and store result in dbuff */
static void _cdecl subtwo(UCHAR *sbuff, UCHAR *obuff, UCHAR *dbuff, int cols)
{
	int ch;

	while(cols--) {
		ch = *sbuff++ - *obuff++;
		*dbuff++ = (UCHAR)((ch<0) ? 0 : ch);
		}
}

/* Subtract 2 images. Returns NO_ERROR, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl subimage(srcimg, oprimg, desimg)
imgdes *srcimg;			/* Image 1 */
imgdes *oprimg;			/* Image 2 */
imgdes *desimg;			/* Store result image here */
{
	return(twoimagefcts_(srcimg, oprimg, desimg, subtwo));
}
+ARCHIVE+ tablemod.c    1993  3/27/1991 15:35:44
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		table_mod_
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#define DEBUG 0

extern UCHAR Hbuff_[];
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);

/* Modify image using a lookup table. Returns NO_ERROR, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
	tabaddr = address of table to use, srcimg = source image location,
	desimg = destination image location.
*/
int _cdecl table_mod_(UCHAR *tabaddr, imgdes *srcimg, imgdes *desimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int errcode, j, cols, rows, shandle, dhandle, syctr, dyctr;
   UCHAR *buff=&Hbuff_[4048];

	/* Use checkrange_ to reorder arguments if necessary */
	if(checkrange_(srcimg) || checkrange_(desimg))
		return(BAD_RANGE);
	syctr = srcimg->sty;
	dyctr = desimg->sty;
	/* Cols and rows to do is based on source image */
	cols = srcimg->endx - srcimg->stx + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &shandle, &getrow, &dummy)) == NO_ERROR &&
		(errcode=assign_gprow_(desimg, &dhandle, &dummy, &putrow)) == NO_ERROR) {
		while(rows--) {
			if((errcode=getrow(buff, shandle, srcimg->stx, syctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			for(j=0; j<cols; j++)
				buff[j] = tabaddr[buff[j]];
			if((errcode=putrow(buff, dhandle, desimg->stx, dyctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	cmclose_(srcimg, shandle);		/* Close CM handle */
	cmclose_(desimg, dhandle);
	return(errcode);
}
+ARCHIVE+ thresh.c       705  3/15/1991 18:25:06
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		threshold
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Threshold. Returns NO_ERROR, BAD_FAC, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl threshold(int thres, imgdes *srcimg, imgdes *desimg)
{
	int ch=0;
	UCHAR tab[256];

	if(outrange(0, thres, 255))
		return(BAD_FAC);
	while(ch < thres)
		tab[ch++] = 0;
	while(ch < 256)
		tab[ch++] = (UCHAR)ch;
	return(table_mod_(tab, srcimg, desimg));
}
+ARCHIVE+ twoimage.c    2486  3/17/1991  9:41:24
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		twoimagefcts_	Combine 2 images
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
extern int _cdecl checkrange_(imgdes *);
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());

/* Modify 2 images. Returns NO_ERROR, BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM,
	or XMM_ERR.
	srcimg = Image 1, oprimg = Image 2, desimg = where to store result image,
	(*twofct)() = function to combine the two images.
*/
int _cdecl twoimagefcts_(imgdes *srcimg, imgdes *oprimg, imgdes *desimg,
	int (_cdecl *twofct)(UCHAR *,UCHAR *,UCHAR *,int))
{
	int (_cdecl *sgetrow)(void huge *,int,int,int,int,int);
	int (_cdecl *ogetrow)(void huge *,int,int,int,int,int);
	int (_cdecl *dputrow)(void huge *,int,int,int,int,int);
	int (_cdecl *dummy)(void huge *,int,int,int,int,int);
	int rows, cols, errcode, shandle, ohandle, dhandle, syctr, oyctr, dyctr;
	UCHAR *sbuff=Hbuff_, *dbuff=&Hbuff_[4048];

	/* Check range of start, end positions */
	if(checkrange_(srcimg) || checkrange_(oprimg) || checkrange_(desimg))
		return(BAD_RANGE);
	syctr = srcimg->sty;
	oyctr = oprimg->sty;
	dyctr = desimg->sty;
	/* Cols and rows to do should be based on source image */
	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	/* Assign handles, getrow(), putrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &shandle, &sgetrow, &dummy)) == NO_ERROR &&
		(errcode=assign_gprow_(oprimg, &ohandle, &ogetrow, &dummy)) == NO_ERROR &&
		(errcode=assign_gprow_(desimg, &dhandle, &dummy, &dputrow)) == NO_ERROR) {
		while(rows--) {
			if((errcode=sgetrow(sbuff, shandle, srcimg->stx, syctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			if((errcode=ogetrow(dbuff, ohandle, oprimg->stx, oyctr++,
				cols, oprimg->iwidth)) != NO_ERROR)
				break;
			twofct(sbuff, dbuff, dbuff, cols);
			if((errcode=dputrow(dbuff, dhandle, desimg->stx, dyctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	cmclose_(srcimg, shandle);		/* Close CM handle */
	cmclose_(oprimg, ohandle);
	cmclose_(desimg, dhandle);
	return(errcode);
}
+ARCHIVE+ usertab.c      576  3/15/1991 18:25:08
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		usetable		Modify pic using table
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl table_mod_(UCHAR *,imgdes *,imgdes *);

/* Modify pic using table. Returns NO_ERROR, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl usetable(UCHAR *tabaddr, imgdes *srcimg, imgdes *desimg)
{
	return(table_mod_(tabaddr, srcimg, desimg));
}
+ARCHIVE+ viccore.c     2051  3/15/1991 18:25:10
/*	Victor Library core routines
	Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		checkrange_			Check range of arguments
		setimagearea		Set image area fields of an image descriptor
*/

#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

/*-------Global Variables------*/
/* Multi purpose buffer used by library routines */
UCHAR Hbuff_[8192] = {0};
static char *ID="Victor Library - Copyright (c) 1989-1991, Catenary Systems";
/*-----------------------------*/

#define  XLIMIT  4047		/* Limited by size of Hbuff_ */
#define  YLIMIT  32767

/* Check range of startx, starty, endx, endy, iwidth. Swap values if needed.
	** Standard range checking routine called by image processing functions **
	Range error is returned if a valid image location wasn't specified,
	endx>=iwidth, stx<0, endx>XLIMIT, endy>=ilength, sty<0, or endy>YLIMIT.
*/
int _cdecl checkrange_(imgdes *image)
{
	int temp, rcode=NO_ERROR;

	/* Make sure there's a valid image location */
	if((image->ibuff || image->ehandle || image->xhandle) == 0)
		return(BAD_RANGE);
	/* Swap end x with start x and end y with start y, if necessary - image
		processing routines require that endx >= startx and endy >= starty
	*/
	if(image->stx > image->endx) {
		temp = image->endx;
		image->endx = image->stx;
		image->stx = temp;
		}
	if(image->sty > image->endy) {
		temp = image->endy;
		image->endy = image->sty;
		image->sty = temp;
		}
	/* Range error if endx is greater than image width, etc. */
	if(image->endx >= image->iwidth  || image->stx < 0 ||
		image->endx > XLIMIT || image->endy >= image->ilength ||
		image->sty < 0 || image->endy > YLIMIT)
		rcode = BAD_RANGE;
	return(rcode);
}

/* Set image area fields of an image descriptor */
void _cdecl setimagearea(imgdes *image, int stx, int sty, int endx, int endy)
{
	image->stx = stx;
	image->sty = sty;
	image->endx = endx;
	image->endy = endy;
}
+ARCHIVE+ viewati.c     2399  3/28/1991  8:20:10
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewatievga		Display image at 640x480x256 resolution on the VGA
							screen using an ATI VGA Wonder video display adapter
		SetAtiPage_		ATI select video page
		SetUpAti_		ATI setup/reset

	Supported modes:
		Mode	Resolution		Xmax	Ymax	RAM
		0x61	640x400x256		639	399	256k
		0x62	640x480x256		639	479	512k
		0x63	800x600x256		799	599	512k
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <conio.h>
#include <dos.h>
#define  PLANE_MASK    0xe1
#define  PLANE_SELECT  0xb2
#define  DATA_I  0xbb
#define  LOMODE  0x61
#define  HIMODE  0x63

static unsigned ATI_reg;

extern int _cdecl viewevga_(int,int,imgdes *,int,int,unsigned,unsigned,
	void (_cdecl *)(),void (_cdecl *)());
void _cdecl SetUpAti_(int);
void _cdecl SetAtiPage_(int);

/* Display contents of image buffer at greater than 320x200x256 resolution
	using a ATI VGA Wonder video display adapter. Call pcvideoinfo() and
	then check that EVGAflag = ATI before calling this function to ensure
	that an ATI VGA Wonder video adapter is installed and that it has the
	necessary 512K RAM for the 800x600x256 mode. Returns NO_ERROR, VMODE_ERR
	(unsupported video mode was requested), BAD_RANGE, NO_EMM, EMM_ERR,
	NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewatievga(vmode, scr_x, scr_y, srcimg)
int vmode;				/* Video mode we're using */
int scr_x, scr_y;		/* (x,y) position on VGA screen to start display */
imgdes *srcimg;		/* Image */
{
	static int xmaxvals[] = {639, 639, 799};	/* modes 0x61->0x63 */
	static int ymaxvals[] = {399, 479, 599};
	int xmax, ymax;

	/* Make sure that the video mode is correct */
	if(outrange(LOMODE, vmode, HIMODE))
		return(VMODE_ERR);
	/* Convert vmode to index and set xmax,ymax */
	xmax = xmaxvals[vmode-=LOMODE];
	ymax = ymaxvals[vmode];
	return(viewevga_(scr_x, scr_y, srcimg, xmax, ymax, 0xa000, 0x40,
		SetUpAti_, SetAtiPage_));
}

void _cdecl SetAtiPage_(int page)
{
	unsigned ch;
	outp(ATI_reg, PLANE_SELECT);
	ch = (inp(ATI_reg+1) & PLANE_MASK);
	outpw(ATI_reg, ((ch|(page<<1))<<8) | PLANE_SELECT);
}

#pragma check_stack(off)
void _cdecl SetUpAti_(int mode)
{
	if(mode)
		ATI_reg = *(unsigned *)MAKE_FPTR(0xc000, 0x10);
}
+ARCHIVE+ viewdith.c    4046  4/12/1991  9:20:14
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewdither		Display image on EGA, VGA screen as a dither
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#define EGA_  16	/* PC video mode */
#define XMAX 639	/* Screen dimensions */
#define YMAX 479
#define XCOLS ((XMAX+1)/8)
#define BKGND 0

extern UCHAR Hbuff_[];
extern void _cdecl set_vid_regs_(int);
extern void _cdecl restore_vregs_(void);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl calc_dbyt_(UCHAR *,int,UCHAR *);
extern int _cdecl erase_1row_(UCHAR far *,int,int);

static UCHAR Classic[]= {		/* Ordered dither matrix */
    0,128, 32,160,  8,136, 40,168,
  192, 64,224, 96,200, 72,232,104,
   48,176, 16,144, 56,184, 24,152,
  240,112,208, 80,248,120,216, 88,
   12,140, 44,172,  4,132, 36,164,
  204, 76,232,108,196, 68,228,100,
   60,188, 28,156, 52,180, 20,148,
  252,124,220, 92,244,116,212, 84};

/* Display contents of Pic on EGA/EEGA screen as an ordered dither.
	Returns NO_ERROR, BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
	See p 600 Foley & van Dam.
*/
int _cdecl viewdither(int vmode, int pic_color, int scr_x, int scr_y,
	imgdes *srcimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int j, rows, cols, scols, srows, yctr, xctr, handle;
	int errcode=NO_ERROR;
	int ylimit=480;	/* Assume non-EGA display */
	UCHAR far *addr, far *scraddr;	/* Starting screen address */
	UCHAR *bptr;

	/* Check range of start, end positions in buffer */
	if(checkrange_(srcimg) ||
		/* Check screen start, end positions */
		outrange(0, scr_x, XMAX) || outrange(0, scr_y, YMAX))
		return(BAD_RANGE);
	if(vmode == EGA_)
		ylimit = 350;
	/* Calc starting screen address. Since X must start on a byte boundary
		on the screen, convert x coord to cols.
	*/
	addr = MAKE_FPTR(EGASEG, (unsigned)scr_y * XCOLS + (scr_x >>= 3));
	/* Image buffer rows, cols */
	cols = (srcimg->endx>>3) - (srcimg->stx>>3) + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	/* Screen rows, cols */
	scols = XCOLS - scr_x;
	srows = ylimit - scr_y;
	/* Rows, cols to display */
	if(srows < rows)
		rows = srows;
	if(scols < cols)
		cols = scols;
	outp(0x3ce, 1); outp(0x3cf, 0x0f); /* Enable 4 planes */
	scols = cols << 3;	/* Bytes in the buffer to read */
	/* X,Y starting position within the buffer */
	yctr = srcimg->sty;
	xctr = srcimg->stx & 0xfff8;		/* Calc X to use */
	/* Assign handle, getrow(), amd check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows) {
			if((errcode=getrow(Hbuff_, handle, xctr, yctr++,
				scols, srcimg->iwidth)) != NO_ERROR)
				break;
			bptr = Hbuff_;				/* bptr -> start of Hbuff_ */
			/* scraddr -> start of screen line */
			erase_1row_(scraddr=addr, cols, BKGND); /* Erase a row */
			/* Set Set/Reset reg to pic color */
			outp(0x3ce, 0); outp(0x3cf, pic_color);
			outp(0x3ce, 8);		/* Point to bit mask reg */
			for(j=0; j<cols; j++) {
				outp(0x3cf, calc_dbyt_(Classic, rows, bptr));
				*(scraddr++) &= 1;	/* Read byte/write byte */
				bptr += 8;				/* Update bptr (we processed 8 bytes) */
				}
			addr += XCOLS;			/* Advance to next screen line */
			rows--;
			}
		}
	cmclose_(srcimg, handle);		/* Close CM handle */
	restore_vregs_();
	return(errcode);
}

#if 0
/* Rewritten in assembler for speed */
/* Calculate the byte to display */
int _cdecl calc_dbyt_(UCHAR *matrix, int row, UCHAR *src)
{
	UCHAR *rowptr=&matrix[(rows & 7)<<3]; /* Assumes 8 elements per row */
	int pbyt, k;

	for(k=0; k<8; k++) {
		pbyt <<= 1;
		if(*src++ > *rptr++)
			pbyt |= 1;
		}
	return(pbyt);
}
#endif

+ARCHIVE+ viewega.c     2575  3/16/1991  5:32:48
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewega		Display image on 640x350(480)x16 EGA(VGA) screen
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#define EEGA_ 18		/* PC video mode */
#define XMAX 639
#define YMAX 479
#define XCOLS (XMAX+1)

extern UCHAR Hbuff_[];
extern void _cdecl wrtegapixel_(int, int, int);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);
extern void _cdecl wrt1egarow_(int,int,UCHAR *,int);
extern void _cdecl wrtegainit_(void);
extern void _cdecl wrtegareset_(void);

/* Display contents of srcimg on VGA/EGA screen. Returns NO_ERROR,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewega(int vmode, int scr_x, int scr_y, imgdes *srcimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int yctr, rows, cols, srows, scols, handle;
	int errcode=NO_ERROR, ylimit=350;

	/* Check range of start, end positions */
	if(checkrange_(srcimg) ||
		/* Check screen start, end positions */
		outrange(0, scr_x, XMAX) || outrange(0, scr_y, YMAX))
		return(BAD_RANGE);
	yctr = srcimg->sty;
	/* Set image length */
	if(vmode == EEGA_)
		ylimit = 480;
	/* Image buffer rows, cols */
	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	/* Maximum screen rows, cols */
	scols = XCOLS - scr_x;
	srows = ylimit - scr_y;
	/* Rows, cols to display */
	if(srows < rows)
		rows = srows;
	if(scols < cols)
		cols = scols;
	wrtegainit_();		/* Setup EGA regs for wrt1egarow_() */
	/* Assign handle, getrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if((errcode=getrow(Hbuff_, handle, srcimg->stx, yctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			wrt1egarow_(scr_x, scr_y, Hbuff_, cols);
			scr_y++;
			}
		}
	wrtegareset_();		/* Restore default EGA regs */
	cmclose_(srcimg, handle);		/* Close CM handle */
	return(errcode);
}

#if 0
/* Rewritten in assembler for speed */
/* Write a row of "cols" pixels in EGA/EEGA mode starting at stx,sty */
void _cdecl wrt1egarow_(int stx, int sty, UCHAR *buff, int cols)
{
	int col;

	for(j=0; j<cols; j++)
		wrtegapixel_(stx, sty, *buff>>4);
		buff++;
		}
}
#endif
+ARCHIVE+ viewevga.c    4406  3/17/1991  9:36:26
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewevga_	Display an image at greater than 320x200x256 resolution on
						the VGA screen using a super VGA display adapter
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>

extern UCHAR Hbuff_[];
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern int _cdecl checkrange_(imgdes *);

/* Display contents of image buffer at greater than 320x200x256 resolution
	on the VGA screen using a super VGA display adapter. Returns NO_ERROR,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
	scr_x, scr_y = (x,y) position on VGA screen to start display
	srcimg       = Image buffer
	xmax, ymax   = Maximum x, y value (based on video mode
	vid_seg      = Video segment to use, 0xa000 or 0xb000
	win_siz      = Window size in Kb
	(*setup_chipset)() = Init/reset routine for chipset
	(*set_page)()		 = Set page routine for chipset
*/
int _cdecl viewevga_(int scr_x, int scr_y, imgdes *srcimg,
	int xmax, int ymax, unsigned vid_seg, unsigned win_siz,
	void (_cdecl *setup_chipset)(int), void (_cdecl *set_page)(int))
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int yctr, rows, cols, srows, scols, page, handle;
	unsigned winofs;				/* Current position in screen window */
	long saddr, safebyts;
	UCHAR far *vid_addr;
	int errcode=NO_ERROR, bytsleft, scrwidth=xmax+1;	/* Screen width */
	long winsize=(long)win_siz * 1024;	/* Window size in bytes */

	/* Check range of start, end positions in buffer and screen start
		positions on the VGA screen
	*/
	if(checkrange_(srcimg) || outrange(0, scr_x, xmax) ||
		outrange(0, scr_y, ymax))
		return(BAD_RANGE);
	setup_chipset(1);		/* Initialize specific chipset */
	yctr = srcimg->sty;
	/* Calc image rows and cols */
	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	/* Calc screen rows and cols */
	srows = (ymax+1) - scr_y;
	scols = scrwidth - scr_x;
	/* Rows, cols to display */
	if(srows<rows)
		rows = srows;
	if(scols<cols)
		cols = scols;
	/* Set up for first pixel */
	saddr = scr_x + (long)scr_y * scrwidth; /* Screen starting address */
	/* Calculate and set the video page we'll start on */
	page = (int)(saddr / winsize);
	set_page(page++);
	/* Calc starting screen address */
	winofs = (unsigned)(saddr % winsize);
	vid_addr = (UCHAR far *)MAKE_FPTR(vid_seg, winofs);
	/* Calc bytes that can be written without crossing a segment boundary */
	safebyts = winsize - winofs;
	/* Assign handle, getrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {				/* If there's enough room to write a */
			if(safebyts >= cols) {	/* row without crossing a segment, do it */
				if((errcode=getrow(vid_addr, handle, srcimg->stx, yctr++,
					cols, srcimg->iwidth)) != NO_ERROR)
					break;
				vid_addr += scrwidth;	/* Update screen address */
				safebyts -= scrwidth;	/* Update safebyts */
				}
			else { /* Must select a new video page to write a row */
				/* If safebyts <= 0, just set the next page and update safebyts */
				if(safebyts <= 0)
					set_page(page++);		/* Select the next page */
				else {	/* If safebyts > 0, write row in sections */
					/* Get the next row to write */
					if((errcode=getrow(Hbuff_, handle, srcimg->stx, yctr++,
						cols, srcimg->iwidth)) != NO_ERROR)
						break;
					/* Write what we can on the current page */
					memcpy_(vid_addr, Hbuff_, bytsleft=(unsigned)safebyts);
					/* Select the next page */
					set_page(page++);
					/* Write what's left on the new page */
					memcpy_(MAKE_FPTR(vid_seg,0), Hbuff_+bytsleft, cols-bytsleft);
					vid_addr += scrwidth;	/* Update screen address */
					}
				winofs = (unsigned)(FP_OFF(vid_addr) % winsize);
				vid_addr = (UCHAR far *)MAKE_FPTR(vid_seg, winofs);
				safebyts = winsize - winofs;
				}
			}
		}
	cmclose_(srcimg, handle);		/* Close CM handle */
	setup_chipset(0);			/* Restore specific chipset */
	return(errcode);
}
+ARCHIVE+ viewhalf.c    3941  4/12/1991  9:20:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewhalftone		Display image on EGA, VGA screen as a 9 level halftone
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#define EGA_ 16			/* PC video mode */
#define XMAX 639
#define YMAX 479
#define XCOLS ((XMAX+1)/8)
#define BKGND 0

extern UCHAR Hbuff_[];
extern void _cdecl set_vid_regs_(int);
extern void _cdecl restore_vregs_(void);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl erase_1row_(UCHAR far *,int,int);

/* Display contents of Pic on EGA/EEGA screen as a 9 level halftone.
	Returns NO_ERROR, BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewhalftone(int vmode, int pic_color, int scr_x, int scr_y,
	imgdes *srcimg)
{
	static char ltabl[]={0,0, 2,0, 2,1, 3,1, 3,3, 3,3, 3,3, 3,3, 3,3};
	static char rtabl[]={0,0, 0,0, 0,0, 0,0, 0,0, 2,0, 3,0, 3,1, 3,3};
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int j, k, rows, cols, scols, srows, yctr, xctr, handle;
	int ch, errcode=NO_ERROR;
	int ylimit=480;
	int ctr=0;	/* For alternating between rtabl or ltabl */
	/* Calc starting screen address */
	UCHAR far *addr, far *scraddr;	/* Screen position to write */
	UCHAR pbyt1, pbyt2, *bptr;

	/* Check range of start, end positions in buffer */
	if(checkrange_(srcimg) ||
		/* Check screen start, end positions */
		outrange(0, scr_x, XMAX) || outrange(0, scr_y, YMAX))
		return(BAD_RANGE);
	if(vmode == EGA_)
		ylimit = 350;
	/* Calc starting screen address. Since X must start on a byte boundary
		on the screen, convert x coord to cols.
	*/
	addr = MAKE_FPTR(EGASEG, (unsigned)scr_y * XCOLS + (scr_x >>= 3));
	/* Image rows, cols */
	cols = (srcimg->endx>>2) - (srcimg->stx>>2) + 1;
	rows = (srcimg->endy<<1) - (srcimg->sty<<1) + 1;
	/* Screen rows, cols */
	scols = XCOLS - scr_x;
	srows = ylimit - scr_y;
	/* Rows, cols to display */
	if(srows < rows)
		rows = srows;
	if(scols < cols)
		cols = scols;
	outp(0x3ce, 1); outp(0x3cf, 0x0f); /* Enable 4 planes */
	scols = cols << 2;	/* Bytes in the buffer to read */
	/* X,Y starting position within the buffer */
	yctr = srcimg->sty;
	xctr = srcimg->stx & 0xfff8;	/* Calc X to use */
	/* Assign handle, getrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows > 0) {
			if((errcode=getrow(Hbuff_, handle, xctr, yctr++,
				scols, srcimg->iwidth)) != NO_ERROR)
				break;
			bptr = Hbuff_;				/* bptr -> start of Hbuff_ */
			/* scraddr -> start of screen line */
			erase_1row_(scraddr=addr, cols, BKGND); /* Erase a row */
			erase_1row_(scraddr+XCOLS, cols, BKGND);
			/* Set Set/Reset reg to pic color */
			outp(0x3ce, 0); outp(0x3cf, pic_color);
			outp(0x3ce, 8);		/* Point to bit mask reg */
			for(j=0; j<cols; j++) {
				for(k=0; k<4; k++) {
					ch = *bptr++;
					ch = (ch/29) << 1;	/* Levels 0->8 */
					pbyt1 <<= 2;
					pbyt2 <<= 2;
					if(ctr) {
						pbyt1 |= rtabl[ch];
						pbyt2 |= rtabl[ch+1];
						}
					else {
						pbyt1 |= ltabl[ch];
						pbyt2 |= ltabl[ch+1];
						}
					ctr ^= 1;	/* Change state of ctr */
					}
				outp(0x3cf, pbyt1);
				*(scraddr) &= 1;			/* Read byte/write byte */
				outp(0x3cf, pbyt2);
				*(scraddr+XCOLS) &= 1;
				scraddr++;
				}
			/* Advance to next screen line (we write 2 rows at a time) */
			addr += 2*XCOLS;
			ctr ^= 1;
			rows -= 2;				/* We write 2 rows at a time */
			}
		}
	cmclose_(srcimg, handle);		/* Close CM handle */
	restore_vregs_();
	return(errcode);
}
+ARCHIVE+ viewmin.c     5663  4/12/1991  9:20:16
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewminavg		Display image on EGA/VGA screen as a minimum average pic
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#include <stdlib.h>
#include <string.h>
#define EGA_  16		/* PC video mode */
#define XMAX 639
#define YMAX 479
#define XCOLS ((XMAX+1)/8)
#define BKGND 0

extern UCHAR Hbuff_[];
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memmove_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern void _cdecl set_vid_regs_(int);
extern void _cdecl restore_vregs_(void);
extern void _cdecl init_errindx_(int);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern int _cdecl calc_pbyt_(int *,int,UCHAR *);
extern int _cdecl checkrange_(imgdes *);
extern int _cdecl erase_1row_(UCHAR far *,int,int);

/* Display contents of image on EGA/VGA screen. Return NO_ERROR, BAD_RANGE,
	BAD_MEM, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewminavg(int vmode, int pic_color, int scr_x, int scr_y, imgdes *srcimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int *bigE;	/* Big error array */
	UCHAR far *addr, far *scraddr;	/* Starting screen address */
	int j, rows, cols, scols, srows, yctr, xctr, handle;
	int pos, errcode=NO_ERROR, ylimit=480;
	UCHAR *bptr, *exbuff;

	/* Check range of start, end positions */
	if(checkrange_(srcimg) ||
		/* Check screen start, end positions */
		outrange(0, scr_x, XMAX) || outrange(0, scr_y, YMAX))
		return(BAD_RANGE);
	/* Set image length */
	if(vmode == EGA_)
		ylimit = 350;
	/* Calc starting screen address. Since X must start on a byte boundary
		on the screen, convert x coord to cols.
	*/
	addr = MAKE_FPTR(EGASEG, (unsigned)scr_y * XCOLS + (scr_x >>= 3));
	/* Image buffer rows, cols */
	cols = (srcimg->endx>>3) - (srcimg->stx>>3) + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	/* Screen rows, cols */
	scols = XCOLS - scr_x;
	srows = ylimit - scr_y;
	/* Rows, cols to display */
	if(srows < rows)
		rows = srows;
	if(scols < cols)
		cols = scols;
	/* Use Hbuff_ for bigE to save stack space -- need col*3*sizeof(int) bytes
		Since Hbuff_ is 8192 bytes, xmax must be <= 1365
	*/
	memset_(Hbuff_, 0, 8192);		/* zero bigE array */
	bigE = (int *)&Hbuff_[8];		/* Move in from edge to put 0 to left */
	scols = cols << 3;	/* Bytes in the buffer to read */
	/* Allocate space for source buffer. Scols bytes of CM or EM data is
		copied into exbuff.
	*/
	if((exbuff=(UCHAR *)malloc(scols)) == NULL)
		return(BAD_MEM);	/* If area not allocated */
	yctr = srcimg->sty;
	xctr = srcimg->stx & 0xfff8;		/* Calc X to use */
	/* Assign handle, getrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		init_errindx_(scols);	/* Setup errindx array */
		outp(0x3ce, 1); outp(0x3cf, 0x0f); /* Enable 4 planes */
		while(rows--) {
			if((errcode=getrow(exbuff, handle, xctr, yctr++,
				scols, srcimg->iwidth)) != NO_ERROR)
				break;
			pos = 2 * scols;			/* Current position in BigE array */
			bptr = exbuff;				/* bptr -> start of exbuff */
			/* scraddr -> start of screen line */
			erase_1row_(scraddr=addr, cols, BKGND); /* Erase a row */
			/* Set Set/Reset reg to pic color */
			outp(0x3ce, 0); outp(0x3cf, pic_color);
			outp(0x3ce, 8);		/* Point to bit mask reg */
			for(j=0; j<cols; j++) {
				/* Calculate and display the byte */
				outp(0x3cf, calc_pbyt_(bigE, pos, bptr)); /* -> Bit Mask reg */
				*(scraddr++) &= 1;	/* Read byte/write byte */
				bptr += 8;				/* Update bptr (we processed 8 bytes) */
				pos += 8;				/*  and pos (we moved over 8 pixels) */
				}
			/* Move bigE down 1 row in picture, bigE[scols] -> bigE[0] */
			memmove_(bigE, &bigE[scols], scols*2*sizeof(int));
			addr += XCOLS;			/* Advance to next screen line */
			/* if(keystat()) {if(getkey()==ESC)  break;} */
			}
		}
	free(exbuff);		/* Free allocated memory */
	restore_vregs_();
	cmclose_(srcimg, handle);		/* Close CM handle */
	return(errcode);
}

#if 0
/* Rewritten in Assembler for speed */
/* Calculate the byte to display */
int _cdecl calc_pbyt_(bigE, pos, src)
int *bigE;			/* Address of big error array */
int pos;				/* Current position in big error array */
UCHAR *src;			/* Where the data will come from */
{
	int j, pbyt, iprime, kk=8;
	long sumerr;	/* sumerr can probably be an int */
	static char alpha[] = {	/* Multiplied by error array */
		1, 3, 5, 3, 1,
		3, 5, 7, 5, 3,
		5, 7, 0, 0, 0};
#define  SUMALPHA  (1+3+5+3+1+3+5+7+5+3+5+7+0+0+0)		/* 48 */

	while(kk--) {
		sumerr = 0;
		pbyt <<= 1;
		for(j=0; j<12; j++)		/* Calc sumerr */
			sumerr +=  bigE[Errindx[j] + pos]  * (int)alpha[j];
		iprime = (int)(*src) + (int)(sumerr/SUMALPHA);
		if(iprime > 128) {
			iprime -= 255;
			pbyt |= 1;		/* Set least significant bit */
			}
		bigE[pos] = iprime; 	/* Update BigE array */
		src++;
		pos++;			/* Move over one pixel */
		}
	return(pbyt);
}

static int Errindx[15];	/* Used to store positions of ints to fetch */
/* Calc 15 indices to use in BigE array */
void _cdecl init_errindx_(int iwidth)
{
	int j=0, xx, yy;
	for(yy=-2; yy<=0; yy++) {
		for(xx=-2; xx<=2; xx++)
			Errindx[j++] = yy*iwidth + xx;
		}
}
#endif
+ARCHIVE+ viewpara.c    2888  3/28/1991  8:21:14
/* Victor Library, Copyright (c) 1990-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		viewparaevga	Display image at 640x480x256 resolution on the VGA
							using a Paradise VGA Professional video display adapter
		SetParaPage_	Paradise select video page
		SetUpPara_		Paradise setup/reset

	Supported modes:
		Mode	Resolution		Xmax	Ymax	RAM
		0x5e	640x400x256		639	399	256k
		0x5f	640x480x256		639	479	512k
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#define  LOMODE      0x5e
#define  HIMODE      0x5f
#define  GDC_INDEX  0x3ce	/* GDC index reg */
#define  GDC_DATA   0x3cf	/* GDC data reg */
#define  UNLOCK      0x05	/* Value to unlock PR regs PR0 - PR4 */
#define  PR5         0x0f	/* PR reg for unlocking PR0 - PR4 regs */
#define  PR1         0x0b
#define  PR0A        0x09	/* Address offset A reg */

extern int _cdecl viewevga_(int,int,imgdes *,int,int,unsigned,unsigned,
	void (_cdecl *)(),void (_cdecl *)());
void _cdecl SetUpPara_(int);
void _cdecl SetParaPage_(int);

/* Display contents of image buffer at greater than 320x200x256 resolution
	using a Paradise VGA Professional display adapter. Call pcvideoinfo()
	and then check that EVGAflag = PARADISE before calling this function
	to ensure that a Paradise video adapter is installed and that it has
	the necessary 512K RAM for the 640x480x256 mode. Returns NO_ERROR,
	VMODE_ERR (unsupported video mode was requested), BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewparaevga(vmode, scr_x, scr_y, srcimg)
int vmode;				/* Video mode we're using */
int scr_x, scr_y;		/* (x,y) position on VGA screen to start display */
imgdes *srcimg;		/* Image */
{
	static int xmaxvals[] = {639, 639};	/* modes 0x5e->0x5f */
	static int ymaxvals[] = {399, 479};
	int xmax, ymax;

	/* Make sure that the video mode is valid */
	if(outrange(LOMODE, vmode, HIMODE))
		return(VMODE_ERR);
	/* Convert vmode to index and set xmax,ymax */
	xmax = xmaxvals[vmode-=LOMODE];
	ymax = ymaxvals[vmode];
	return(viewevga_(scr_x, scr_y, srcimg, xmax, ymax, 0xa000, 0x40,
		SetUpPara_, SetParaPage_));
}

void _cdecl SetUpPara_(int mode)
{
	static int lock_stat;

	if(mode) {
		/* Check if special regs are unlocked (bits 0-2 = 5) */
		outp(GDC_INDEX, PR5);			/* Access special reg */
		if((lock_stat=inp(GDC_DATA)&7) != UNLOCK)
			outpw(GDC_INDEX, (UNLOCK<<8) | PR5);	/* Unlock special regs */
		}
	else {
		outpw(GDC_INDEX, PR0A);				/* Zero PR0A */
		if(lock_stat != UNLOCK)				/* If they were unlocked */
			outpw(GDC_INDEX, 0x00ff & PR5);	/* lock special regs */
		}
}

#pragma check_stack(off)
void _cdecl SetParaPage_(int page)
{
	outpw(GDC_INDEX, (page<<12)|PR0A);	/* Set PR0A reg */
}
+ARCHIVE+ viewtrid.c    4359  3/28/1991  8:22:06
/* Victor Library, Copyright (c) 1990-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		viewtridevga	Display image at 640x480x256 resolution on the VGA
							using a Trident 8900/8800CS-based video display adapter
		SetTridPage_	Trident select video page
		SetUpTrid_		Trident setup/reset

	Supported modes:
		Mode	Resolution		Xmax	Ymax	RAM
		0x5c	640x400x256		639	399	256Kb
		0x5d	640x480x256		639	479	512Kb
		0x5e	800x600x256		799	599	512Kb
		0x62 1024x768x256	  1023	767  1024Kb		8900 only
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#define  LOMODE      0x5c
#define  HIMODE      0x5e
#define  HIMODE89    0x62
#define  MISC_READ  0x3cc	/* Miscellaneous output READ reg */
#define  MISC_WRITE 0x3c2	/* Miscellaneous output WRITE reg */
#define  GDC_INDEX  0x3ce	/* GDC index reg */
#define  GDC_DATA   0x3cf	/* GDC data reg */
#define  GDC_MISC       6	/* Bits 2-3 select a 64K or 128K video buffer */
#define  TS_INDEX   0x3c4	/* TS index reg */
#define  TS_DATA    0x3c5	/* TS data reg */
#define  TRI_VERS    0x0b	/* Chip version reg, bits 0-3 */
#define  TRI_MODE1   0x0e	/* Segment select reg, bits 0-3 */
#define  BR_VERS        1	/* 8800BR version chipset (rectangular) */
#define  CS_VERS        2	/* 8800CS version chipset (square) */

extern int _cdecl viewevga_(int,int,imgdes *,int,int,unsigned,unsigned,
	void (_cdecl *)(),void (_cdecl *)());
extern int _cdecl TridType_(void); /* Determine chipset version: 1=BR, 2=CS, 3=8900 */
extern int _cdecl TridMemory_(void);	/* Gets banks of 256Kb RAM installed */
void _cdecl SetUpTrid_(int);
void _cdecl SetTridPage_(int);

/* Display contents of image buffer at greater than 320x200x256 resolution
	using a 8800CS or 8900 Trident CS-based display adapter. Call
	pcvideoinfo() and then check that EVGAflag = TRIDENT before calling this
	function to ensure that a Trident based video adapter is installed and
	that it has the necessary 512K RAM for the 640x480x256 mode. For 8800CS
	and 8900 version chip: uses 64K page mode. Returns NO_ERROR, VMODE_ERR
	(unsupported video mode was requested), BAD_RANGE, NO_EMM, EMM_ERR,
	NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewtridevga(vmode, scr_x, scr_y, srcimg)
int vmode;				/* Video mode we're using */
int scr_x, scr_y;		/* (x,y) position on VGA screen to start display */
imgdes *srcimg;		/* Image */
{
	static int xmaxvals[] = {639, 639, 799};	/* Modes 0x5c->0x5e */
	static int ymaxvals[] = {399, 479, 599};
	int xmax, ymax;
	int tri_vers;		/* Trident chipset version, 8800BR, 8800CS, or 8900 */

	/* Determine chipset (BR, CS, or 8900) */
	tri_vers = TridType_();
	/* Make sure that the video mode is correct */
	if(vmode==HIMODE89 && tri_vers==3) {	/* Handle mode 0x62 */
		if(TridMemory_() < 4)				/* Check for 1024Kb RAM */
			return(VMODE_ERR);
		}
	else if(outrange(LOMODE, vmode, HIMODE)) /* 5c -> 5e for CS/8900 */
		return(VMODE_ERR);
	/* Convert vmode to index and set xmax,ymax */
	if(vmode == HIMODE89) {	/* Handle special conditions: mode 0x62 */
		xmax = 1023; ymax =  767;
		}
	else {
		xmax = xmaxvals[vmode-=LOMODE];
		ymax = ymaxvals[vmode];
		}
	return(viewevga_(scr_x, scr_y, srcimg, xmax, ymax, 0xa000, 0x40,
		SetUpTrid_, SetTridPage_));
}

/* Initialize/restore 8800CS/8900 Trident chipset for 64K page mode.
	If mode != 0, initialize chipset, else reset it.
*/
void _cdecl SetUpTrid_(int mode)
{
	static int old_page_mode;

	if(mode) {		/* Initialize Trident chipset */
		/* Read current page mode and save the value */
		outp(GDC_INDEX, GDC_MISC);
		old_page_mode = inp(GDC_DATA);
		/* Set 64K page mode */
		outp(GDC_DATA, (old_page_mode & 0xf3) | 4);
		/* Set mode control 1 reg for 64K mode by reading the version reg */
		outp(TS_INDEX, TRI_VERS);
		inp(TS_DATA);
		}
	else {	/* Restore Trident chipset configuration */
		outpw(GDC_INDEX, (old_page_mode<<8)|GDC_MISC);
		/* If old page mode was 128K, set mode control 1 reg for 128K mode */
		if((old_page_mode & 0xf3) == 0)	/*  by writing the version reg */
			outpw(TS_INDEX, TRI_VERS);
		}
}

#pragma check_stack(off)
void _cdecl SetTridPage_(int page)
{
	outpw(TS_INDEX, ((page^2) << 8) | TRI_MODE1);
}
+ARCHIVE+ viewtsen.c    3568  3/28/1991  8:23:58
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewtsengevga		Display image at 640x480x256 resolution on the VGA
								screen using a Tseng video display adapter
		SetTseng3000_		Tseng ET3000 select video page
		SetTseng4000_		Tseng ET4000 select video page
		SetUpTseng_			Tseng setup/reset

	Supported modes:
		Mode	Resolution		Xmax	Ymax	RAM
		0x2d	640x350x256		639	349	256Kb
		0x2e	640x480x256		639	479	512Kb
		0x2f	720x512x256		719	511	512Kb		3000 chipset
		0x2f	640x480x256		639	479	512Kb		4000 chipset
		0x30  800x600x256		799	599	512Kb
		0x38  1024x768x256  1024	768  1024Kb		4000 chipset only
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#define  GDCSS  0x3cd	/* GDC Segment Select reg (Tseng only) */
#define  LOMODE  0x2d
#define  HIMODE  0x30
#define  HIMOD4  0x38	/* Valid mode for 4000 chipset */

extern int _cdecl viewevga_(int,int,imgdes *,int,int,unsigned,unsigned,
	void (_cdecl *)(),void (_cdecl *)());
extern int _cdecl TsengType_(void);
extern int _cdecl Tseng4Memory_(void);
void _cdecl SetUpTseng_(int);
void _cdecl SetTseng3000_(int);
void _cdecl SetTseng4000_(int);

/* Display contents of image buffer at 640x480x256 or higher resolution
	on the VGA screen using a Tseng video display adapter. Call pcvideoinfo()
	and then check that EVGAflag = TSENG or TSENG4 before calling this
	function to ensure that a Tseng-based video adapter is installed and
	that it has enough memory for the 800x600x256 mode. Returns NO_ERROR,
	VMODE_ERR (unsupported video mode was requested), BAD_RANGE, NO_EMM,
	EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewtsengevga(vmode, scr_x, scr_y, srcimg)
int vmode;				/* Video mode we're using */
int scr_x, scr_y;		/* (x,y) position on VGA screen to start display */
imgdes *srcimg;		/* Image */
{
	/* Tseng 3000 allows modes 0x2d->0x30. Tseng 4000 allows modes
		0x2d->0x30, and 0x38. For 4000, mode 0x2f resolution is 640x400
	*/
	static int xmaxvals[] = {639, 639, 719, 799};	/* Modes 0x2d->0x30 */
	static int ymaxvals[] = {349, 479, 511, 599};	/* For 3000 chipset */
	int xmax, ymax, tsentyp;

	/* Determine chipset (3000 or 4000) */
	tsentyp = TsengType_();
	/* Make sure that the video mode is correct */
	if(vmode==HIMOD4 && tsentyp==4000) {	/* Handle mode 0x38 */
		if(Tseng4Memory_() < 4)					/* Check for 1024Kb RAM */
			return(VMODE_ERR);
		}
	else if(outrange(LOMODE, vmode, HIMODE)) /* 2d -> 30 for 3000/4000 */
		return(VMODE_ERR);
	/* Convert vmode to index and set xmax,ymax */
	if(vmode == 0x38) {	/* Handle special conditions: mode 38 */
		xmax = 1023; ymax =  767;
		}
	else if(vmode==0x2f && tsentyp==4000) {	/* Mode 2f has either 640x400 */
		xmax = 639; ymax = 399;						/* or 720x512 resolution */
		}
	else {
		xmax = xmaxvals[vmode-=LOMODE];
		ymax = ymaxvals[vmode];
		}
	return(viewevga_(scr_x, scr_y, srcimg, xmax, ymax, 0xa000, 0x40,
		SetUpTseng_, (tsentyp==3000) ? SetTseng3000_ : SetTseng4000_));
}

#pragma check_stack(off)
/* Nothing to do here since TsengType_() was recently called */
void _cdecl SetUpTseng_(int mode)
{
}

/* Set video page routine for Tseng 3000 chipset */
void _cdecl SetTseng3000_(int page)
{
	outp(GDCSS,	(page << 3) | page | 0x40);
}

/* Set video page routine for Tseng 4000 chipset */
void _cdecl SetTseng4000_(int page)
{
	outp(GDCSS,	(page << 4) | page);
}
+ARCHIVE+ viewvega.c    4468  4/11/1991  9:56:28
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		viewvegaevga	Display image at 640x480x256 resolution on the VGA
							screen using a Vega V7 video display adapter
		SetVegaPage_	Vega select video page
		SetUpVega_		Vega setup/reset

	Supported modes:
		Mode	Resolution		Xmax	Ymax	RAM
		0x66	640x400x256		639	399	256k
		0x67	640x480x256		639	479	512k
		0x68	720x540x256		719	539	512k
		0x69	800x600x256		799	599	512k

	To set the Vega 640x480x256 video mode use:
		mov ax,06f05h	;Extended mode set
		mov bl,67h		;Mode number is 0x67
		int 10h
	or:
		regs.x.ax = 0x06f05;		Extended mode set
		regs.h.bl = 0x67;			Mode number is 0x67
		int86(0x10, &regs, &regs);

	NOTE: The normal setvideomode() function can be used with
	non-standard mode numbers.
		Std modes:     0x66, 0x67, 0x68, 0x69
		Non-std modes:	0x1a, 0x1b, 0x1c, 0x1d
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#include <conio.h>
#define  LOMODE	   0x66		/* 0x1a */
#define  HIMODE	   0x69		/* 0x1d */
#define  TS_INDEX    0x3c4		/* Sequencer/ extensions index */
#define  TS_DATA		0x3c5
#define  EX_PAGE_SEL 0x0f9		/* Extended page select */
#define  EX_BANK_SEL 0x0f6		/* Extended bank select */
#define  MISC_INPUT  0x3cc
#define  MISC_OUTPUT 0x3c2
#define  EXTENS_ON	0xea06	/* Enable extensions */
#define  EXTENS_OFF	0xae06	/* Disable extensions */
#define  SR6			0x006		/* Index reg for enabling/disabling extns */

extern int _cdecl viewevga_(int,int,imgdes *,int,int,unsigned,unsigned,
	void (_cdecl *)(),void (_cdecl *)());
void _cdecl SetUpVega_(int);
void _cdecl SetVegaPage_(int);

/* Display contents of image buffer at greater than 320x200x256 resolution
	using a Vega V7 VGA video display adapter. Call pcvideoinfo() and then
	check that EVGAflag = VEGA before calling this function to ensure that
	a Vega V7 video adapter is installed and that it has the necessary 512K
	RAM for the 800x600x256 mode. Returns NO_ERROR, VMODE_ERR (unsupported
	video mode was requested), BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR,
	or CM_ERR.
*/
int _cdecl viewvegaevga(vmode, scr_x, scr_y, srcimg)
int vmode;				/* Video mode we're using */
int scr_x, scr_y;		/* (x,y) position on VGA screen to start display */
imgdes *srcimg;		/* Image buffer */
{
	static int xmaxvals[] = {639, 639, 719, 799};	/* Modes 0x66->0x69 */
	static int ymaxvals[] = {399, 479, 539, 599};
	int xmax, ymax;

	/* Allow non-standard alternate mode numbers */
	if(inrange(LOMODE-0x4c, vmode, HIMODE-0x4c))
		vmode += 0x4c;		/* 0x1b -> 0x67 */
	/* Make sure that the video mode is valid */
	if(outrange(LOMODE, vmode, HIMODE))
		return(VMODE_ERR);
	/* Convert vmode to index and set xmax,ymax */
	xmax = xmaxvals[vmode-=LOMODE];
	ymax = ymaxvals[vmode];
	return(viewevga_(scr_x, scr_y, srcimg, xmax, ymax, 0xa000, 0x40,
		SetUpVega_, SetVegaPage_));
}

void _cdecl SetUpVega_(int mode)
{
	static int extn_stat, OldMiscOutput, OldExPageSel, OldExBankSel;

	if(mode) {
		/* Check if Vega extensions are already enabled */
		outp(TS_INDEX, SR6);
		if((extn_stat=inp(TS_DATA)) == 0) {
			/* Enable Vega extensions */
			outpw(TS_INDEX, EXTENS_ON);	/* Enable extensions */
			outp(TS_INDEX, EX_PAGE_SEL);	/* Save the 3 regs we modify */
			OldExPageSel = inp(TS_DATA);
			outp(TS_INDEX, EX_BANK_SEL);
			OldExBankSel = inp(TS_DATA);
			OldMiscOutput= inp(MISC_INPUT);
			}
		}
	/* If extensions were turned off on entry to routine, disable them here */
	else if(extn_stat == 0) {
		outp(MISC_OUTPUT, OldMiscOutput);
		outpw(TS_INDEX, (OldExPageSel<<8) | EX_PAGE_SEL);
		outpw(TS_INDEX, (OldExBankSel<<8) | EX_BANK_SEL);
		outpw(TS_INDEX, EXTENS_OFF);	/* Disable extensions */
		}
}

/* Set video page */
void _cdecl SetVegaPage_(int page)
{
	unsigned ch, pg_sel_bit, bk_sel_bit;

	pg_sel_bit = ((page & 2)<<4);
	bk_sel_bit = (page & 0x0c) | ((page & 0x0c)>>2);
	/* Set or clear Page Select bit */
	ch = (inp(MISC_INPUT) & 0xdf);	/* Clear page select bit */
	outp(MISC_OUTPUT, ch | pg_sel_bit);
	/* Set or clear Extended Page Select bit */
	outpw(TS_INDEX, ((page&1)<<8) | EX_PAGE_SEL);
	/* Set or clear Bank Select bits */
	outp(TS_INDEX, EX_BANK_SEL);
	ch = (inp(TS_DATA) & 0xf0);	/* Clear bank select bits */
	outp(TS_DATA, ch|bk_sel_bit);
}
+ARCHIVE+ viewvesa.c    3187  3/28/1991  8:26:52
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewvesaevga	Display image in an 8-bit mode using a video display
							adapter that supports VESA BIOS extensions
		SetVesaPage_	VESA select video page
		SetUpVesa_		VESA setup/reset

	Potential 256-color modes:						 64Kb blocks
	Mode	 Resolution		Xmax	Ymax	 RAM	 required
	100h	 640x 400x256	 639	 399	 256Kb    4
	101h	 640x 480x256	 639	 479	 512Kb    5
	103h	 800x 600x256	 799	 599	 512Kb    8
	105h	1024x 768x256	1023	 767	1024Kb   12
	107h	1280x1024x256	1279	1023	2048Kb   20
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <dos.h>
#define  LOMODE  0x100
#define  HIMODE  0x107

extern UCHAR Hbuff_[];

static int MemWin;		 		/* Memory window to use, 0 or 1 */
static unsigned GranFactor;	/* Compensate for granularity */

extern int _cdecl viewevga_(int,int,imgdes *,int,int,unsigned,unsigned,
		void (_cdecl *)(int),void (_cdecl *)(int));
void _cdecl SetUpVesa_(int);
void _cdecl SetVesaPage_(int);

/* Display an image buffer in an 8-bit mode using a video display adapter
	that supports the VESA BIOS extensions. Call pcvideoinfo() and then
	check that VESAflag != 0 before calling this function to ensure
	that a VESA supported video adapter is installed. Returns NO_ERROR,
	VMODE_ERR (unsupported video mode was requested or VESA BIOS extensions
	not present), BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewvesaevga(vmode, scr_x, scr_y, srcimg)
int vmode;				/* Video mode we're using */
int scr_x, scr_y;		/* (x,y) position on VGA screen to start display */
imgdes *srcimg;		/* Image buffer */
{
	/* For VESA modes 0x100 -> 0x107 */
	static int ymaxvals[] = {399, 479, 599, 599, 767, 767,1023,1023};
	/* vesamodeinfo() copies mode info into Hbuff_ */
	ModeInfo *minfo=(ModeInfo *)Hbuff_;
	unsigned vidseg;		/* Video segment, 0xa000 */

	/* Make sure that VESA BIOS extensions are present and that the
		video mode is valid. Also, get video mode info.
	*/
	if(outrange(LOMODE, vmode, HIMODE) || vesamodeinfo(vmode) != NO_ERROR)
		return(VMODE_ERR);
	/* Set vidseg and MemWin */
	/* Check window A attributes: 5 => window is supported & writeable */	
	if((minfo->WinAAttr & 5) == 5) {
		vidseg = minfo->WinASeg;
		MemWin = 0;				/* Use memory window 0 */
		}
	else if((minfo->WinBAttr & 5) == 5) {
		vidseg = minfo->WinBSeg;
		MemWin = 1;				/* Use memory window 1 */
		}
	else
		return(VMODE_ERR);	/* No writeable window was found */
	GranFactor = minfo->WinSize / minfo->WinGran;
	return(viewevga_(scr_x, scr_y, srcimg, minfo->BPScanLine-1,
		ymaxvals[vmode-LOMODE], vidseg, minfo->WinSize, SetUpVesa_,	SetVesaPage_));
}

#pragma check_stack(off)
/* Set the video page using VESA BIOS function */
void _cdecl SetVesaPage_(int page)
{
	union REGS regs;
	regs.x.ax = 0x4f05;		/* VESA Set bank function */
	regs.x.bx = MemWin;		/* BH = 0, BL = window */
	regs.x.dx = page * GranFactor;
	int86(0x10, &regs, &regs);
}

void _cdecl SetUpVesa_(int mode)
{
}
+ARCHIVE+ viewvga.c     2019  3/27/1991 19:04:12
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		viewvga		Display image on 320x200x256 VGA screen
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#define XMAX 319	/* Screen dimensions */
#define YMAX 199

extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern int _cdecl checkrange_(imgdes *);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());

/* Display contents of image on VGA screen. Returns NO_ERROR,
	BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl viewvga(int scr_x, int scr_y, imgdes *srcimg)
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int yctr, rows, cols, srows, scols, handle, errcode=NO_ERROR;
	UCHAR far *scraddr;

	/* Check range of start, end positions */
	if(checkrange_(srcimg) ||
	/* Check screen start, end positions */
		outrange(0, scr_x, XMAX) || outrange(0, scr_y, YMAX))
		return(BAD_RANGE);
	yctr = srcimg->sty;
	/* Calculate starting position on screen */
	scraddr = MAKE_FPTR(EGASEG, (XMAX+1)*(unsigned)scr_y + scr_x);
	/* Image rows, cols */
	rows = srcimg->endy - srcimg->sty + 1;
	cols = srcimg->endx - srcimg->stx + 1;
	/* Screen rows, cols */
	srows = YMAX + 1 - scr_y;
	scols = XMAX + 1 - scr_x;
	/* Rows, cols to display */
	if(srows < rows)
		rows = srows;
	if(scols < cols)
		cols = scols;
	/* Assign handle, getrow(), and check for EM/XM */
	if((errcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			/* Get a row of data to process */
			if((errcode=getrow(scraddr, handle, srcimg->stx, yctr++,
				cols, srcimg->iwidth)) != NO_ERROR)
				break;
			scraddr += XMAX + 1;
			}
		}
	cmclose_(srcimg, handle);		/* Close CM handle */
	return(errcode);
}
+ARCHIVE+ vresize.c     6252  3/16/1991  5:34:00
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314)962-7833
	Contents:
		vgaresize	Resize image area in buffer and display on VGA screen
*/
#include <stdio.h>			/* Resolution is 1 part in 16, 6.25% */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>
#include <string.h>
#define  SWIDTH  320			/* Screen dimensions */
#define  SLENGTH 200

extern int _cdecl checkrange_(imgdes *);
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
static int _cdecl checkscrrange(int *,int *,int *,int *,int,int);
extern void _cdecl cmclose_(imgdes *,int);
extern int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
static void _cdecl generate_ftable(unsigned,UCHAR *);
extern UCHAR Hbuff_[];

/* Resize an area of an image buffer and display on VGA. Works in 6.25%
	increments. Returns NO_ERROR, BAD_RANGE, BAD_MEM (insufficient
	conventional memory), NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl vgaresize(imgdes *srcimg, int des_sx,
	int des_sy, int des_ex, int des_ey)		/* Destination on screen */
{
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int dxpixnum, dypixnum;	/* no. of pixels to plot in dest per source pixel */
	unsigned pcxinc, pcyinc;/* factors representing % inc in size in x,y dir */
	int sxpix, sypix;			/* width, ht, in pixels of source area */
	int dxpix, dypix;			/* width, ht, in pixels of destn area */
	int xctr, yctr, j, handle, syctr;
	int sxindex, syindex, dxindex, dyend, tint;
	int zx, zy;				/* width, ht, in pixels to write in dest area */
	UCHAR *exbuff, *sptr, *xfactor, *yfactor;
	long tmp;
	/* Calc starting position on screen */
	UCHAR far *des = MAKE_FPTR(0xa000, des_sx + (unsigned)des_sy * SWIDTH);
	int rcode = NO_ERROR;

	/* Check range of start, end positions in buffer and on screen */
	if(checkrange_(srcimg) || checkscrrange(&des_sx, &des_sy,
		&des_ex, &des_ey, SWIDTH, SLENGTH))
		return(BAD_RANGE);
	syctr = srcimg->sty;
	sxpix = srcimg->endx - srcimg->stx + 1;
	sypix = srcimg->endy - srcimg->sty + 1;
	/* Calc width, height of dest area */
	dxpix = des_ex - des_sx + 1;
	dypix = des_ey - des_sy + 1;
	/* Number of pixels to write in dest */
	zx = (int)(((((long)dxpix << 8) / sxpix) * sxpix) >> 8);
	zy = (int)(((((long)dypix << 8) / sypix) * sypix) >> 8);
	/* If des area has no width or height, exit */
	if(!(zx && zy)) {
		rcode = BAD_RANGE;
		goto xit;
		}
	dxpixnum = zx / sxpix;		/* Multiplier, 200%->2, 414%->4, etc */
	dypixnum = zy / sypix;
	/* Increase factor in 256ths,
		pcxinc = ((zx % sxpix) * 256) / sxpix;
		pcxinc = 414% = 4+35.8/256->36, 231% = 2+79.4/256->79
	*/
	tmp = (long)(zx % sxpix) << 8; pcxinc = (unsigned)(tmp / sxpix);
	/* Round up if needed */
	if((tmp % sxpix) > (sxpix >> 1))
		pcxinc++;
	/* Calc Y increase factor in 256ths */
	tmp = (long)(zy % sypix) << 8;
	pcyinc = (unsigned)(tmp / sypix);
	/* Round up if needed */
	if(tmp % sypix > (sypix >> 1))
		pcyinc++;
	dyend = des_sy + zy;		/* calc end of block */
	syindex = 0;
	/* Allocate space for our source buffer and factor tables */
	if((exbuff=(UCHAR *)malloc(sxpix + 512)) == NULL) {
		rcode = BAD_MEM;	/* If area not allocated */
		goto xit;
		}
	/* Generate xfactor, yfactor tables */
	generate_ftable(pcxinc, xfactor=&exbuff[sxpix]);
	generate_ftable(pcyinc, yfactor=&exbuff[sxpix+256]);
	/* Assign handle, getrow(), and check for EM/XM */
	if((rcode=assign_gprow_(srcimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		for(;;) {
			/* Get a line of data to process */
			if((rcode=getrow(exbuff, handle, srcimg->stx, syctr++,
				sxpix, srcimg->iwidth)) != NO_ERROR)
				goto eob;
			sptr = exbuff;		/* Reset source ptr */
			yctr = dypixnum; /* yctr is no. of lines to draw */
			if(yfactor[syindex & 0xff])	/* based on factor add a line */
				yctr++;
			if(yctr) {	/* Stretch or shrink in x direction */
				/* First time thru draw line */
				sxindex = 0;
				dxindex = 0;		/* Index into Hbuff_ */
				for(;;) { /* stretch or shrink one line */
					xctr = dxpixnum;	/* set up xctr */
					/* Are extra points needed? */
					if(xfactor[sxindex & 0xff])	/* based on factor add a line */
						xctr++;
					tint = *sptr++;			/* read source color */
					for(j=0; j<xctr; j++) {
						Hbuff_[dxindex++] = (UCHAR)tint;
						if(dxindex >= zx)	/* write zx pixels */
							goto eol;
						}
					sxindex++;
					}
eol:			while(yctr--) {
					/* Copy line from Hbuff_ to the screen */
					memcpy_(des, Hbuff_, zx);
					des += SWIDTH;
					if(++des_sy >= dyend)	/* Don't draw line if out of block */
						goto eob;
					}
				}
			syindex++;
			}
		}
eob:
	free(exbuff);		/* Free the scratch buffer */
	cmclose_(srcimg, handle);		/* Close CM handle */
xit:
	return(rcode);
}

/* Check range of stx, sty, endx, endy. Swap values if needed.
	Range error if stx<0, endx>SCRXLIM, sty<0, or endy>SCRYLIM.
*/
static int _cdecl checkscrrange(int *stx, int *sty, int *endx, int *endy,
	int xmax, int ymax)
{
	int temp, rcode = NO_ERROR;

	/* Swap end_x with start_x if necessary - image processing routines
		require that endx >= startx and endy >= starty
	*/
	if(*stx > *endx) {
		temp = *endx;
		*endx = *stx;
		*stx = temp;
		}
	if(*sty > *endy) {	/* Swap end_y, start_y ? */
		temp = *endy;
		*endy = *sty;
		*sty = temp;
		}
	if(*stx<0 || *endx>xmax || *sty<0 || *endy>ymax)
		rcode = BAD_RANGE;
	return(rcode);
}

/* Generate X or Y increase factor table. Increm = increase factor, 0 - 255,
	i.e., no. of pixels out of 256 that should be set to 1.
*/
static void _cdecl generate_ftable(unsigned increm, UCHAR *ftable)
{
	unsigned j, indx, fact;
	long val;

	/* Zero table */
	memset_(ftable, 0, 256);
	if(increm) {		/* If increm = 0, table should consist of zeros */
		fact = 255*256 / increm;
		for(j=0; j<increm; j++) {
			val = j * (long)fact;
			indx = (unsigned)(val >> 8);
			if((val & 0xff) >= 128)
				indx++;
			ftable[indx] = 1;
			}
		}
}
+ARCHIVE+ wtavg.c       1270  3/16/1991  4:59:20
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		wtaverage	Weighted average: (SOURCE*weight + OPERATOR*(100-weight))/100
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

static int Weight;
static int Diff;
extern int _cdecl twoimagefcts_(imgdes *,imgdes *,imgdes *,void (_cdecl *)());

/* Weighted average: (SOURCE*weight + OPERATOR*(100-weight))/100 */
static void _cdecl wtavgtwo(UCHAR *sbuff, UCHAR *obuff, UCHAR *dbuff, int cols)
{
	while(cols--) {
		*dbuff = (UCHAR)((*sbuff * Weight + *obuff * Diff) / 100);
		sbuff++; obuff++; dbuff++;
		}
}

/* Weighted average: (SOURCE*weight + OPERATOR*(100-weight))/100. Returns
	NO_ERROR, BAD_FAC, BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl wtaverage(weight, srcimg, oprimg, desimg)
int weight;					/* Weight to use */
imgdes *srcimg;			/* Image 1 */
imgdes *oprimg;			/* Image 2 */
imgdes *desimg;			/* Store result image here */
{
	if(outrange(0, weight, 100))
		return(BAD_FAC);
	Diff = 100 - (Weight=weight);
	return(twoimagefcts_(srcimg, oprimg, desimg, wtavgtwo));
}
+ARCHIVE+ xchgxy.c      1667  3/15/1991 18:36:16
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		xchgxyaxis	Exchange X and Y axis data

						abcdefg		 ahov3
						hijklmn  ->  bipw4
						opqrstu		 cjqx5
						vwxyz12		 dkry6
						3456789		 elsz7
*/

#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>
#include <string.h>

extern int _cdecl checkrange_(imgdes *);

/* Exchange X and Y axes of image. Returns NO_ERROR, BAD_RANGE,
	NO_EMM, EMM_ERR, NO_XMM, or XMM_ERR.
*/
int _cdecl xchgxyaxis(imgdes *srcimg, imgdes *desimg)
{
	int nrows, ncols, col1, col2, j, k, byts2mov;
	int sx, sy, dx, dy;
	int rcode=NO_ERROR;

	/* Check range of start, end positions */
	if(checkrange_(srcimg))
		return(BAD_RANGE);
	nrows = srcimg->endy - srcimg->sty;
	ncols = srcimg->endx - srcimg->stx;
	/* Use the smaller of the 2 dimensions */
	byts2mov = (nrows<ncols) ? nrows : ncols;
	sx = srcimg->stx; sy = srcimg->sty;
	dx = desimg->stx;	dy = desimg->sty;
	for(k=0; k<byts2mov; k++) {
		for(j=0; j<byts2mov-k; j++) {
			if((col1=getpixelgray(srcimg, sx+k+j, sy+k)) < 0) {
				/* Error if value is outside the range 0 - 255 */
				rcode = col1;
				goto gerr;
				}
			if((col2=getpixelgray(srcimg, sx+k, sy+k+j)) < 0) {
				/* Error if value is outside the range 0 - 255 */
				rcode = col2;
				goto gerr;
				}
			if((rcode=setpixelgray(desimg, dx+k+j, dy+k, col2)) != NO_ERROR ||
			   (rcode=setpixelgray(desimg, dx+k, dy+k+j, col1)) != NO_ERROR)
				goto gerr;	/* Error if rcode != NO_ERROR */
			}
		}
gerr:
	return(rcode);
}
+ARCHIVE+ xmsc.c        3039  3/15/1991 18:36:18
/* Victor Library, Copyright (c) 1990-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		xmsaveimage		Save the image buffer area in expanded memory
		xmgetimage		Retrieve the image buffer area from expanded memory
*/

#include <stdio.h>
#include <vicdefs.h>		/* Standard header files for library */
#include <vicfcts.h>
#include <vicerror.h>
#include <stdlib.h>

extern int _cdecl checkrange_(imgdes *);

/* Save the image buffer area in conventional memory in extended memory.
	Returns XM handle and NO_ERROR, BAD_RANGE, NO_XMM, or XMM_ERR.
	Returns BAD_RANGE if source is not in CM!
*/
int _cdecl xmsaveimage(int *handle, imgdes *srcimg)
{
	int rcode, cols, rows, yctr=0;
	int kbyts, kbowned;
	long saddr, pels; /* Pixels in an image area = cols*rows */
	UCHAR huge *src;	/* Pointer into image buffer */

	/* Check range of start, end positions and make sure source is CM */
	if(checkrange_(srcimg) || srcimg->ibuff == NULL)
		return(BAD_RANGE);
	/* Calc how much space we need */
	cols = srcimg->endx - srcimg->stx + 1;
	rows = srcimg->endy - srcimg->sty + 1;
	pels = rows * (long)cols;		/* No. of pixels in the image area */
	kbyts = (int)(pels >> 10);
	if(pels&0x3ff)  kbyts++;
	/* If handle doesn't own enough XM, try to allocate it */
	if((kbowned=xmkbytesowned(*handle)) < kbyts) {
		if(kbowned > 0)		/* If we own > 0, but < 'kbyts', free it */
			xmfree(*handle);	/* and try to get more */
		/* If xmbytesowned() returns an error (value < 0), ignore it for now */
		if((rcode=xmallocate(handle, kbyts)) != NO_ERROR)
			goto xit;
		}
	/* Calc starting addr in buffer */
	saddr = srcimg->stx + srcimg->sty * (long)srcimg->iwidth;
	src = &srcimg->ibuff[saddr];
	while(rows--) {
		if((rcode=xmputrow(src, *handle, 0, yctr++, cols, cols)) != NO_ERROR) {
			xmfree(*handle);	/* If there's an error, free XM */
			break;
			}
		src += srcimg->iwidth;
		}
xit:
	return(rcode);
}

/* Retrieve the image buffer area from extended memory.
	Returns NO_ERROR, BAD_RANGE, or XMM_ERR.
	Returns BAD_RANGE if dest is not in CM!
*/
int _cdecl xmgetimage(int handle, imgdes *desimg)
{
	int rcode, cols, rows, yctr=0;
	unsigned kbyts;
	long daddr, pels; /* Pixels in an image area = cols*rows */
	UCHAR huge *des;	/* Pointer into image buffer */

	/* Check range of start, end positions and make sure dest is CM */
	if(checkrange_(desimg) || desimg->ibuff == NULL)
		return(BAD_RANGE);
	/* Calc how many bytes to retrieve */
	cols = desimg->endx - desimg->stx + 1;
	rows = desimg->endy - desimg->sty + 1;
	pels = rows * (long)cols;		/* No. of pixels in the image area */
	kbyts = (int)(pels >> 10);
	if(pels&0x3ff)  kbyts++;
	/* Calc starting addr in buffer */
	daddr = desimg->stx + desimg->sty * (long)desimg->iwidth;
	des = &desimg->ibuff[daddr];
	while(rows--) {
		if((rcode=xmgetrow(des, handle, 0, yctr++, cols, cols)) != NO_ERROR)
			break;
		des += desimg->iwidth;
		}
	return(rcode);
}
+ARCHIVE+ xor.c          932  3/16/1991  4:59:22
/* Victor Library, Copyright (c) 1989-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		xorimage		XOR 2 images
*/
#include <stdio.h>		/* Standard header files for VIC.LIB */
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern int _cdecl twoimagefcts_(imgdes *,imgdes *,imgdes *,void (_cdecl *)());

/* XOR 'count' bytes in obuff with sbuff and store result in dbuff */
static void _cdecl xortwo(UCHAR *sbuff, UCHAR *obuff, UCHAR *dbuff, int cols)
{
	while(cols--)
		*dbuff++ = *sbuff++ ^ *obuff++;
}

/* XOR 2 images. Returns NO_ERROR, BAD_RANGE, NO_EMM, EMM_ERR, NO_XMM,
	XMM_ERR, or CM_ERR.
*/
int _cdecl xorimage(srcimg, oprimg, desimg)
imgdes *srcimg;			/* Image 1 */
imgdes *oprimg;			/* Image 2 */
imgdes *desimg;			/* Store result image here */
{
	return(twoimagefcts_(srcimg, oprimg, desimg, xortwo));
}

+ARCHIVE+ zerobuff.c    5893  3/17/1991  7:06:38
/* Victor Library, Copyright (c) 1990-1991, ALL RIGHTS RESERVED
			Catenary Systems
			470 Belleview
			St Louis, MO 63119
			(314) 962-7833
	Contents:
		assign_gprow_
		cmallocimage
		copyimgdes
		emallocimage
		freeimage
		xmallocimage
		zeroimage
		zeroimgdes
*/
#include <stdio.h>
#include <vicdefs.h>
#include <vicfcts.h>
#include <vicerror.h>

extern UCHAR Hbuff_[];
void _cdecl hfree(void far *);
static void _cdecl setup_imgdes(imgdes *,int,int);
extern int _cdecl cmopen_(int *,UCHAR huge *);
int _cdecl assign_gprow_(imgdes *,int *,int (_cdecl **)(),int (_cdecl **)());
extern void * _cdecl memcpy_(void huge *,void huge *,unsigned);
extern void * _cdecl memset_(void huge *,int,unsigned);
extern int _cdecl cmputrow_(UCHAR huge *,int,int,int,int,int);
extern int _cdecl cmgetrow_(UCHAR huge *,int,int,int,int,int);
extern void _cdecl cmclose_(imgdes *,int);

/* Assign correct values for handle, getrow(), putrow(), and check for EM/XM.
	Returns NO_ERROR, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR if
	we're to use CM and there's no room in the handle/buffer address table.
*/
int _cdecl assign_gprow_(imgdes *image, int *handle,
	int (_cdecl **getaddr)(), int (_cdecl **putaddr)())
{
	int rcode=NO_ERROR;

	if(image->ibuff) {			/* Buffer is in CM */
		if((rcode=cmopen_(handle, image->ibuff)) == NO_ERROR)
			*getaddr = cmgetrow_;
			*putaddr = cmputrow_;
		}
	else if(image->ehandle) {	/* Buffer is in EM */
		if((rcode=emdetect()) == NO_ERROR) {
			*handle = image->ehandle;
			*getaddr = emgetrow;
			*putaddr = emputrow;
			}
		}
	else if(image->xhandle) {	/* Buffer is in XM */
		if((rcode=xmdetect()) == NO_ERROR) {
			*handle = image->xhandle;
			*getaddr = xmgetrow;
			*putaddr = xmputrow;
			}
		}
	return(rcode);
}

/* Allocate conventional memory. Fills in image descriptor location fields,
	and image area fields if successful. Returns NO_ERROR or BAD_MEM.
*/
int _cdecl cmallocimage(imgdes *image, int iwidth, int ilength)
{
	UCHAR huge *pic;

	if((pic=(UCHAR huge *)halloc(iwidth * (long)ilength, 1)) != NULL) {
		/* Success! Zero image descriptor location fields and fill in
			image area fields.
		*/
		setup_imgdes(image, iwidth, ilength);
		image->ibuff = pic;		/* Set image descriptor buffer address */
		return(NO_ERROR);
		}
	return(BAD_MEM);
}

/* Copy all elements of an image descriptor */
imgdes * _cdecl copyimgdes(imgdes *srcimg, imgdes *desimg)
{
	return(memcpy_(desimg, srcimg, sizeof(imgdes)));
}

/* Allocate expanded memory. Fills in image descriptor location fields,
	image->iwidth, and image->ilength if successful.
	Returns NO_ERROR, NO_EMM, or EMM_ERR.
*/
int _cdecl emallocimage(imgdes *image, int iwidth, int ilength)
{
	int errcode, pages, handle;
	long pels=iwidth*(long)ilength;

	/* Calc how much space we need in 16Kb pages */
	pages = (int)(pels / 16384);
	if(pels % 16384)  pages++;		/* Round up if necessary */
	/* Try to allocate the space */
	if((errcode=emallocate(&handle, pages)) == NO_ERROR) {
		/* Success! Zero image descriptor location fields and fill in
			image area fields.
		*/
		setup_imgdes(image, iwidth, ilength);
		image->ehandle = handle;
		}
	return(errcode);
}

/* Free an image buffer. Fills in image descriptor location fields,
	image->iwidth, and image->ilength if successful.
	Returns NO_ERROR or BAD_MEM.
*/
void _cdecl freeimage(imgdes *image)
{
	if(image->ibuff)
		hfree((UCHAR far *)image->ibuff);
	else if(image->ehandle)
		emfree(image->ehandle);
	else if(image->xhandle)
		xmfree(image->xhandle);
	/* Zero image descriptor location fields */
	memset_(image, 0, ofssetof(imgdes, stx));
}

/* Allocate extended memory. Fills in image descriptor location fields,
	image->iwidth, and image->ilength if successful.
	Returns NO_ERROR, NO_XMM, or XMM_ERR.
*/
int _cdecl xmallocimage(imgdes *image, int iwidth, int ilength)
{
	int errcode, kbyts, handle;
	long pels=iwidth*(long)ilength;

	/* Calc how much space we need in kilobytes */
	kbyts = (int)(pels / 1024);
	if(pels % 1024)  kbyts++;		/* Round up if necessary */
	/* Try to allocate the space */
	if((errcode=xmallocate(&handle, kbyts)) == NO_ERROR) {
		/* Success! Zero image descriptor location fields and fill in
			image area fields.
		*/
		setup_imgdes(image, iwidth, ilength);
		image->xhandle = handle;
		}
	return(errcode);
}

/* Set all elements of an image area to a value. Returns NO_ERROR, BAD_RANGE,
	BAD_FAC, NO_EMM, EMM_ERR, NO_XMM, XMM_ERR, or CM_ERR.
*/
int _cdecl zeroimage(int value, imgdes *desimg)
{
	int (_cdecl *putrow)(void huge *,int,int,int,int,int);
	int (_cdecl *getrow)(void huge *,int,int,int,int,int);
	int errcode=NO_ERROR, rows, cols, yctr, handle;

	if(checkrange_(desimg))
		return(BAD_RANGE);
	if(outrange(0, value, 255))
		return(BAD_FAC);
	yctr = desimg->sty;
	rows = desimg->endy - desimg->sty + 1;
	cols = desimg->endx - desimg->stx + 1;
	/* Set bytes in Hbuff_ to value */
	memset_(Hbuff_, value, cols);
	/* Assign handle, putrow(), and check for EM/XM */
	if((errcode=assign_gprow_(desimg, &handle, &getrow, &putrow)) == NO_ERROR) {
		while(rows--) {
			if((errcode=putrow(Hbuff_, handle, desimg->stx, yctr++,
				cols, desimg->iwidth)) != NO_ERROR)
				break;
			}
		}
	cmclose_(desimg, handle);		/* Close CM handle */
	return(errcode);
}

/* Zero all elements of an image descriptor */
imgdes * _cdecl zeroimgdes(imgdes *image)
{
	return(memset_(image, 0, sizeof(imgdes)));
}

/* Zero image descriptor location fields and fill in image area fields */
static void _cdecl setup_imgdes(imgdes *image, int width, int length)
{
	memset_(image, 0, ofssetof(imgdes, iwidth));
	image->endx = width - 1;	/* Set remaining image area fields */
	image->iwidth = width;
	image->endy = length - 1;
	image->ilength = length;
}
