

#include <stdio.h>
#include <conio.h>
#include <dos.h>
#include <process.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "hrprint.h"
#include "svgacc.h"

/* IBM ProPrinter Specific Printer Control Code Strings */
BYTE *OneDirection  = "\x1BU\x31";   /* ESC U 1 */
BYTE *TwoDirection  = "\x1BU\x30";   /* ESC U 1 */
BYTE *LowRes        = "\x1BK";       /* ESC K */
BYTE *MedRes        = "\x1BY";       /* ESC Y */
BYTE *HighRes       = "\x1BZ";       /* ESC Z */
BYTE *TextLineFeed  = "\x1B\x31";    /* ESC 1 - normal 7/72 text line feed */
BYTE *GraphicLineFeed="\x1B\x33\x18";/* ESC 3 24 - 24/216ths line feed */
BYTE *CrLf          = "\r\n";        /* graphics carriage ret line feed */
BYTE *DisAutoLf =     "\x1B\x35\x30";/* ESC 5 0 disable auto line feed */

int Negative;   /* flag for grey scale order */

extern PaletteData pcxpal;
PrinterModes PrtMode;


/* The following arrays define the half tone patterns used
  for the printout. 4x4 dither matrices are used in both
 cases.
*/

/* Bayer ordered dither matrix */

BYTE BayerMat[4][4] =
	{0, 8, 2, 10,
	12, 4, 14, 6,
	3, 11, 1, 9,
	15, 7, 13, 5};

/* Rylander recursive halftoning matrix */

struct DotPatterns RylanderMat[MAXPRTINTENSITIES] =

       {0x0F,0x0F,0x0F,0x0F,    /* 100.0X - all black */
	0x0F,0x0F,0x0F,0x0B,    /* 93.8% */
	0x0F,0x0E,0x0F,0x0B,    /* 87.5% */
	0x0F,0x0E,0x0F,0x0A,    /* 81.3% */
	0x0F,0x0A,0x0F,0x0A,    /* 75.0% */
	0x0F,0x0A,0x0B,0x0A,    /* 68.8% */
	0x0E,0x0A,0x0B,0x0A,    /* 62.5% */
	0x0E,0x0A,0x0A,0x0A,    /* 56.3% */
	0x0A,0x0A,0x0A,0x0A,    /* 50.0% */
	0x0A,0x0A,0x0A,0x02,    /* 43.8% */
	0x0A,0x08,0x0A,0x02,    /* 37.5% */
	0x0A,0x08,0x0A,0x00,    /* 31.3% */
	0x0A,0x00,0x0A,0x00,    /* 25.0% */
	0x0A,0x00,0x02,0x00,    /* 18. 8% */
	0x08,0x00,0x02,0x00,    /* 12 . 5% */
	0x08,0x00,0x00,0x00,    /* 6.3% */
	0x00,0x00,0x00,0x00};   /* 0.0% - all white */


void InitDensityTbl2( void )
{
unsigned ColorNum;
unsigned Intensity;


/*palget(0,255,pal);*/

/* this procedure builds the DensityTbl based upon the intensity of
the colors used in the palette to display the PCX image.
The intensity are calculated as described above. */

	     /* 256 color mode */
		   /* for each color register */
   for (ColorNum=0;ColorNum<256;ColorNum++)
     {

		/* calculate the intensity from the color values */
		Intensity = ((unsigned) pcxpal[ColorNum].r*30); /* calculate red contribution */
		Intensity += ((unsigned) pcxpal[ColorNum].g*59); /* calculate green contribution */
		Intensity += ((unsigned) pcxpal[ColorNum].b*11); /* calculate blue contribution */

	/* scale and store intensity result */
     if(Intensity>0){
	DensityTbl[ColorNum] =
	(unsigned)(((((double)Intensity*(double)16)/6300)+0.5));
	DensityTbl[ColorNum]=(int)((Intensity/420)+.5);
	if(DensityTbl[ColorNum]>15) DensityTbl[ColorNum]=15;
     }
     if(Intensity<=0) DensityTbl[ColorNum]=0;
     }
}


int format( double position )
{
int width = 6;
	if( position < 1000.0 ) width--;
	if( position < 100.0 ) width--;
	if( position < 10.0 ) width--;
return( width );
}



int Grey_Scale( int scanline, int palette_entry )
{
int grey = 0;
palette_entry=DensityTbl[palette_entry];

	switch(scanline)
	{
	case 0: {
		if( palette_entry & 4 ) grey |= 5;    /* sets bits .1.1*/
		if( palette_entry & 8 ) grey |= 10;   /* sets bits 1.1. */
		} break;
	case 1: {
		if( palette_entry & 1 ) grey |= 2;    /* sets hits    1. */
		if( palette_entry & 2 ) grey |= 8;    /* sets bits 1 */
		if( palette_entry & 8 ) grey |= 5;    /* sets bits .1.1 */
		} break;
	case 2: {
		if( palette_entry & 4 ) grey |= 5;    /* sets bits .1.1 */
		if( palette_entry & 8 ) grey |= 10;   /* sets bits 1.1. */
		} break;
	case 3: {
		if( palette_entry & 2 ) grey |= 2;    /* sets bits    1. */
	    /*	if( palette_entry & 2 ) grey |= 5;     sets bits    1. */
		if( palette_entry & 8 ) grey |= 5;    /* sets bits .1.1 */
		} break;

	}

    if(Negative) grey ^=0x0F;    /* inverts grey scale bitpatterns */
return(grey);
}



void LJ_Graphic(int MaxX, int MaxY)
{
int i, j, k, p;
double xprint, yprint, prstep, AspR;

char m, resolution[3];


AspR = 1;  /*set aspect ratio*/




		xprint = 1000.0; /* initial page print positions */
		yprint= 1000.0;

	      strcpy( resolution,"300"); /*select 150 DPI resolution */
		 prstep= 2.4* AspR;
	      /* prstep = 7.2 * AspR;  adjust to match screen image */

		fprintf(stdprn,"%s%sR",graph_init,resolution);
		for( j=0; j<=MaxX; j++ )
			for( p=0; p<4; p++ ){
				fprintf(stdprn,"\x1B&a%-*.1fh%-*.1fV",
					format(xprint),xprint,
					format(yprint),yprint);
				yprint+=prstep;
				fprintf(stdprn,"\x1B*r1A\x1B*b%dW",MaxY/2);
				for(i=0;i<=MaxY/2;i++)
				{
					m=0;
					for(k=0;k<=1;k++)
					{
					    m<<=4;/* shift m leftfour bits */
					    m|=Grey_Scale(p,
					      getpoint(MaxX-j,i*2+k));
					}
					fprintf(stdprn,"%c",m);
				}
				fprintf(stdprn,"%s",graph_ends);
			}


	fprintf(stdprn,"\x0C\x1B&l0O\x1B(8U\x1B(sp10h12vsb3T\x1B&l1H");

					/* close operations */
}


void Print_Pause(int Invert, int maxx, int maxy)
{

if( Invert ) Negative = 1;
else Negative = 0;

	InitDensityTbl2();
	LJ_Graphic(maxx, maxy);/*greyscale*/
}


void laser_print(int maxx, int maxy)
{
	Print_Pause(1,maxx,maxy);    /*1=normal white is white 0=white is black*/
}



/* Printer Interface Functions */

/* This function initializes the line printer for operation */
void PrtInit (unsigned PrtNum)
{
   regs.h.ah = INITPRTCODE;
   regs.x.dx = PrtNum;
   int86(PRINTERINT, &regs, &regs);
}

/* This function reads the status of the line printer */
BYTE PrtStatus (unsigned PrtNum)
{
regs.h.ah = GETPRTSTATUSCODE;
regs.x.dx = PrtNum;
int86(PRINTERINT, &regs, &regs);
return (regs.h.ah);
}

/* this function prints a character on the specified printer */
BYTE PrtChar(unsigned PrtNum, BYTE Character)
{
while(!(PrtStatus(PrtNum) & PRTBUSYBIT)); /* wait until not busy */

	regs.h.ah = PRTCHARCODE;          /* prt a character code */
	regs.h.al = Character;
	regs.x.dx = PrtNum;               /* select the printer */
	int86(PRINTERINT, &regs, &regs);
	return(regs.h.ah);                /* return operation status */
}

/* this function prints a null terminated string of characters
to the named printer */

BYTE PrtString(unsigned PrtNum, BYTE *String)
{
BYTE PrtError;

PrtError = FALSE; 
while ((*String != NULL) && (!PrtError)) /* do until the null or error */
	PrtError = ((PrtChar(PrtNum,*String++) & PRTTIMEOUT) == 1); 
	return(PrtError);
}


/* This function builds the DensityTbl which contain the index into the
DotDensities array that is to be used to represent the color of a given pixel
(in gray scale) when printed. The print dot density is calculated 
from the value of a color register. The intensity value for a
given color is computed from the formula:

	Intensity = Red Comp*30% + Green Comp*59% + BlueComp*11%

which corresponds to the sensitivity of the human eye to the various 
color components. This formula is taken from the IBM VGA technical
reference manual with VGA, the value of the color registers are settable.
This means the color register RGB components must be read from the
hardware before the intensity calculation can be performed. Each color
component has the range 0..63. With the maximum intensity VGA color (white)
the intensity value turns out to be 63. This value will be used to scale
all intensity values into the range 0..16 as required by the
DensityTbl array.
*/

void InitDensityTbl( void )
{
unsigned ColorNum;
unsigned Intensity;


/*palget(pal,0,255); */

/* this procedure builds the DensityTbl based upon the intensity of
the colors used in the palette to display the PCX image.
The intensity are calculated as described above. */



	     /* 256 color mode */
		   /* for each color register */
   for (ColorNum=0;ColorNum<256;ColorNum++)
     {

		/* calculate the intensity from the color values */
		Intensity = ((unsigned) pcxpal[ColorNum].r*30); /* calculate red contribution */
		Intensity += ((unsigned) pcxpal[ColorNum].g*59); /* calculate green contribution */
		Intensity += ((unsigned) pcxpal[ColorNum].b*11); /* calculate blue contribution */

	/* scale and store intensity result */
	DensityTbl[ColorNum] =
	(unsigned)(((((double)Intensity*(double)16)/6300)+0.5));
     }

}


/* This function returns a pixel from the screen. It works
differently for the 16 and the 256 color modes.
*/
unsigned GetAPixel(unsigned Col, unsigned Row)
{

	return(getpoint(Col,Row));

}

void DitherPrintCol (unsigned PrintMode,PrinterModes PrtMode,unsigned Col)
{
register unsigned MatrixRow;
register unsigned CurrentRow;
register BYTE Intensity, PrtByte;
int pch;
pch=0;
	/*PrtMode=1; ******ADDED THIS IN*****/
	switch (PrtMode)        /* send printer the graphic mode */
	{                       /* control code sequence */
	case HighResMode: {     pch=1;
				PrtString(LPT1,HighRes);
				break;
				}
	case MedResMode: {
				PrtString(LPT1,MedRes);
				break;
				}
	case LowResMode:
		default: {
				PrtString(LPT1,LowRes);
				break;
				}
	}
/* tell printer how many bytes to follow */

PrtChar(LPT1,N1);
PrtChar(LPT1,N2);


if(pch==0){
for (CurrentRow=0; CurrentRow < MaxScreenRow; CurrentRow++)
{

PrtByte = 0;
MatrixRow = CurrentRow % 4;
Intensity = DensityTbl[GetAPixel(Col,CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][3]) PrtByte |= 128;

Intensity = DensityTbl[GetAPixel(Col-1,CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][2]) PrtByte |= 64;

Intensity = DensityTbl[GetAPixel(Col-2, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][1]) PrtByte |= 32;

Intensity = DensityTbl[GetAPixel(Col-3, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][0]) PrtByte |= 16;

Intensity = DensityTbl[GetAPixel(Col-4, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][3]) PrtByte |= 8;

Intensity = DensityTbl[GetAPixel(Col-5, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][2]) PrtByte |= 4;

Intensity = DensityTbl[GetAPixel(Col-6, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][1]) PrtByte |= 2;

Intensity = DensityTbl[GetAPixel(Col-7, CurrentRow)]+Brightness;
if (Intensity>BayerMat[MatrixRow][0]) PrtByte |= 1;


/* The off and on pins are reversed at this point.
For example, PrtByte = 0 should print as black all pins on but
will instead print as white (all pins off).
To correct for this inversion, invert the sense of the PrintMode.
*/

if(PrintMode==POSPRINT) PrtByte ^= 0xFF;

	PrtChar(LPT1,PrtByte);  /* send two identical bytes */
	PrtChar(LPT1,PrtByte);  /* to the printer. */

	if (MaxScreenCol == 640)        /* if in 640 pixel mode */
	{
		PrtChar(LPT1,PrtByte);  /* send two more identical bytes */
		PrtChar(LPT1,PrtByte);  /* to the printer. */
	 }

 }
	PrtString(LPT1,CrLf);   /* output LfCr to printer */
} /*end if PCH==0*/
if(pch==1){
for (CurrentRow=0; CurrentRow < MaxScreenRow; CurrentRow++)
{
PrtByte = 0;
MatrixRow = CurrentRow % 4;
Intensity = DensityTbl[GetAPixel(Col,CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][3]) PrtByte |= 128;

Intensity = DensityTbl[GetAPixel(Col-1,CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][2]) PrtByte |= 64;

Intensity = DensityTbl[GetAPixel(Col-2, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][1]) PrtByte |= 32;

Intensity = DensityTbl[GetAPixel(Col-3, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][0]) PrtByte |= 16;

Intensity = DensityTbl[GetAPixel(Col-4, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][3]) PrtByte |= 8;

Intensity = DensityTbl[GetAPixel(Col-5, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][2]) PrtByte |= 4;

Intensity = DensityTbl[GetAPixel(Col-6, CurrentRow)]+Brightness;
if (Intensity > BayerMat[MatrixRow][1]) PrtByte |= 2;

Intensity = DensityTbl[GetAPixel(Col-7, CurrentRow)]+Brightness;
if (Intensity>BayerMat[MatrixRow][0]) PrtByte |= 1;
if(PrintMode==POSPRINT) PrtByte ^= 0xFF;

	PrtChar(LPT1,PrtByte);
	PrtChar(LPT1,PrtByte);

	if (MaxScreenCol == 640)
	{
		PrtChar(LPT1,PrtByte);
		PrtChar(LPT1,PrtByte);
	 }
   }
	PrtString(LPT1,CrLf);
  }/*end if pch==1*/
}  /*end and return function*/


void PatternPrintCol(unsigned PrintMode,PrinterModes PrtMode,unsigned Col)
{
register unsigned CurrentRow;
register int Density;
BYTE Row1Data, Row2Data, Row3Data, Row4Data;
	/*PrtMode=1;*/
	switch (PrtMode)        /* send printer the graphic mode */
	{                      /* control code sequence */
	case HighResMode: {
				PrtString(LPT1,HighRes);
				break;
				}
	case MedResMode:   {
				PrtString(LPT1,MedRes);
				break;
				}
	case LowResMode:
		default:    {
				PrtString(LPT1,LowRes);
				break;
				}
	}
/* tell printer how many bytes to follow */
PrtChar(LPT1,N1);
PrtChar(LPT1,N2);

for (CurrentRow=0;CurrentRow<MaxScreenRow;CurrentRow++)
  {
	/* calc the average density of a group of 4 horiz. pixels */

	Density = DensityTbl[GetAPixel(Col , CurrentRow)];
	Density += DensityTbl[GetAPixel(Col-1, CurrentRow)];
	Density += DensityTbl[GetAPixel(Col-2, CurrentRow)];
	Density += DensityTbl[GetAPixel(Col-3, CurrentRow)];
	Density /= 4;
	Density += Brightness; /* shift brightness level */
	Density = (Density < 0 ) ? 0:Density;
	Density = (Density > MAXDENSITYINDEX) ? MAXDENSITYINDEX:Density;

/* get dot pattern representing this average density */
/* shift by 4 because these dots will become the MS pin
date */

	Row1Data = RylanderMat[Density].Row1 << 4;
	Row2Data = RylanderMat[Density].Row2 << 4;
	Row3Data = RylanderMat[Density].Row3 << 4;
	Row4Data = RylanderMat[Density].Row4 << 4;

/* calc the average density of a group of 4 horiz. pixels */
Density = DensityTbl[GetAPixel(Col-4, CurrentRow)];
Density += DensityTbl[GetAPixel(Col-5, CurrentRow)];
Density += DensityTbl[GetAPixel(Col-6, CurrentRow)];
Density += DensityTbl[GetAPixel(Col-7, CurrentRow)];
Density /= 4;
Density += Brightness; /* shift brightness level */
Density = (Density < 0 ) ? 0:Density;
Density = (Density > MAXDENSITYINDEX) ? MAXDENSITYINDEX:Density;

/* get dot pattern representing this average density */
/* merge with MS pin data */
Row1Data |= RylanderMat[Density].Row1;
Row2Data |= RylanderMat[Density].Row2;
Row3Data |= RylanderMat[Density].Row3;
Row4Data |= RylanderMat[Density].Row4;

/* if a reverse image is requested compliment dot data */
if (PrintMode != POSPRINT)
  {
	Row1Data ^= 0xFF;
	Row2Data ^= 0xFF;
	Row3Data ^= 0xFF;
	Row4Data ^= 0xFF;
   }
 PrtChar(LPT1,Row1Data);        /* send 4 bytes of printer data */
 PrtChar(LPT1,Row2Data);        /* to the printer. This 32 bits of */
 PrtChar(LPT1,Row3Data);        /* data represent 8 bits of pixel */
 PrtChar(LPT1,Row4Data);        /* data */
 }
PrtString(LPT1,CrLf);           /* output LfCr to printer */
}


/* This is the main print screen function. It will print in gray scale
any picture displayed on a VGA graphic adapter. The parameter Rev
controls the interpretation on the data on the screen.
*/

CompletionCode PrtScreen (unsigned PrintMode,unsigned CurrentDisplayMode)
{
int ScreenCol;

switch(CurrentDisplayMode)
  {
	case 1:        { PrtMode = LowResMode;
			MaxScreenCol = 320;
			MaxScreenRow = 200;
			Is256Colors = 1;
			break;
			}
	case 2:         {PrtMode = MedResMode;
			MaxScreenCol = 640;
			MaxScreenRow = 200;
			Is256Colors = 1;
			break;
			}

	case 3:         {PrtMode = HighResMode;
			MaxScreenCol = 640;
			MaxScreenRow = 400;
			Is256Colors = 1;
			break;
			}
	default:        return(0); /* unsupported video mode */
  }

/*
Calculate densities to be used to display image
*/
InitDensityTbl();

/* Because we it be dumping the display in a vertical fashion starting
from the right most column, we must calculate the byte counts that will
be sent to the printer from the MaxScreenRow value. The number of screen
rows will be either 200 or 480. A 200 row screen will be dumped to the
printer while it is in the 960 dot mode. This will mean that each pixel
from the display will be printed two dots wide. A 480 row screen will be
dumped to the printer while it is in the 1920 dot mode. Each pixel will
be four dots wide.
*/

if ((MaxScreenCol == 320) && (Matrix == BayerMatrix))
   {
	N2 = (MaxScreenRow*2) >> 8;     /* calculate byte counts*/
	N1 = (MaxScreenRow*2) & 0xFF;   /* to be sent to printer*/
      /*	N2 = (MaxScreenRow*2) >> 8;     calculate byte counts*/
      /*	N1 = (MaxScreenRow*2) & 0xFF;   to be sent to printer*/
    }
   else
    {
	N2 = (MaxScreenRow*4) >> 8;     /* calculate byte counts */
	N1 = (MaxScreenRow*4) & 0xFF;   /* to be sent to printer */
     }
	PrtInit(LPT1);  /* initialize the printer */

	PrtString(LPT1,OneDirection);   /* set printer in one dir mode */
      /*	PrtString(LPT1,DisAutoLf); */     /* disable auto line feed */
	PrtString(LPT1,CrLf); /* output LfCr to printer REMOVE*/

	PrtString(LPT1,GraphicLineFeed);/* set 24/216 line feed as required */
					/* for 8 pin bit mapped printing */

/* move backward across displayed image */
/*for (ScreenCol=MaxScreenCol-1;ScreenCol>=0;ScreenCol -= 4) */
for (ScreenCol=MaxScreenCol-1;ScreenCol>=0;ScreenCol -= PIXELSPERPASS)
   {

	if (Matrix == BayerMatrix){
		DitherPrintCol(PrintMode, PrtMode, ScreenCol);

	    }
	else
		PatternPrintCol(PrintMode, PrtMode, ScreenCol);
  }

      PrtString(LPT1,TextLineFeed);   /* set text line feed */
      PrtString(LPT1,TwoDirection);   /* set printer to two dir mode */


    return(0);
}
