home *** CD-ROM | disk | FTP | other *** search
- /*
- Copyright 1990 by John Wiley & Sons, Inc.
- All Rights Reserved.
- */
- /****************************************************/
- /* print.c */
- /* */
- /* Display and Print .PCX files */
- /* Prints images displayed on VGA adapter */
- /* on an IBM ProPrinter using halftone techniques */
- /* written in Turbo C 2.0 */
- /* */
- /* Usage: print [-v -mB/R -b(+/- 0-9) -n] filename */
- /* -v displays info about the .PCX file */
- /* -m selects the dither matrix to use: */
- /* B = Bayer ordered dither */
- /* R = Rylander recursive halftoning */
- /* -b alters briteness */
- /* -n prints negative image */
- /* */
- /* written by Craig A. Lindley */
- /* Vers: 1.0 Last Update: 11/29/89 */
- /****************************************************/
-
- #include <stdio.h>
- #include <conio.h>
- #include <dos.h>
- #include <process.h>
- #include <stdlib.h>
- #include <string.h>
- #include <graphics.h>
- #include "misc.h"
- #include "pcx.h"
- #include "vga.h"
- #include "printer.h"
-
- #define MAXVGAINTVAL 6300.0 /* Max VGA intensity x 100 */
- #define MAXPRTINTENSITIES 17 /* 17 possible densities in 4x4 matrix */
- #define MAXDENSITYINDEX (MAXPRTINTENSITIES-1)
-
- /* Version information */
- static short ver = 1;
- static short rel = 0;
-
- /* print function variables */
- static unsigned Verbose, PrintMode;
- static int Brightness;
- static unsigned MaxScreenRow, MaxScreenCol, Is256Colors;
- static unsigned DensityTbl[MAX256PALETTECOLORS];
- static unsigned N1,N2;
- static union REGS regs;
- static enum MatrixType Matrix;
-
- /*
- 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.0% - 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 */
-
- /* 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 carrage ret line feed */
- BYTE *DisAutoLf = "\x1B\x35\x30"; /* ESC 5 0 disable auto line feed */
-
-
- /* 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, ®s, ®s);
- }
-
- /* This function reads the status of the line printer */
- BYTE PrtStatus (unsigned PrtNum)
- {
- regs.h.ah = GETPRTSTATUSCODE;
- regs.x.dx = PrtNum;
- int86(PRINTERINT, ®s, ®s);
- 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, ®s, ®s);
- 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 ColorEntry, ColorNum;
- unsigned Intensity;
- struct palettetype palette;
-
- /* 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. */
-
- getpalette(&palette); /* get the current palette */
-
- if (!Is256Colors) /* 16 color modes only */
- {
- /* for each entry in the palette */
- for (ColorEntry=0; ColorEntry < palette.size; ColorEntry++)
- {
- ColorNum = palette.colors[ColorEntry]; /* get a palette entry */
- /*
- because the color register values can change for VGA, the
- color components of each palette entry must be read before the
- Intensity can be calculated
- */
- regs.h.ah = 0x10; /* get the color components of a */
- regs.h.al = 0x15; /* color register. */
- regs.x.bx = ColorNum;
- int86(VIDEO,®s,®s);
-
- /*
- If the palette is a gray scale already, its intensity is
- just a single component. In this case Red. The intensity
- value must be scaled by 100 because it will be divided
- later when scaled.
- */
-
- if ((regs.h.dh == regs.h.ch) && (regs.h.ch == regs.h.cl))
- Intensity = regs.h.dh*100;
- else
- {
- /* calculate the intensity from the color values */
- Intensity = ((unsigned) regs.h.dh*30); /* calculate red contribution */
- Intensity += ((unsigned) regs.h.ch*59); /* calculate green contribution */
- Intensity += ((unsigned) regs.h.cl*11); /* calculate blue contribution */
- }
- /* scale and store intensity result */
- DensityTbl[ColorEntry] = (unsigned) (((((double) Intensity *
- (double) MAXDENSITYINDEX)
- / MAXVGAINTVAL)+0.5));
- }
- }
- else /* 256 color mode */
- {
- /* for each color register */
- for (ColorNum=0; ColorNum < MAX256PALETTECOLORS; ColorNum++)
- {
- /* no palette is used in 256 color mode */
- regs.h.ah = 0x10; /* get the color components of a */
- regs.h.al = 0x15; /* color register. */
- regs.x.bx = ColorNum;
- int86(VIDEO,®s,®s);
-
- /*
- If the palette is a gray scale already, its intensity is
- just a single component. In this case Red. The intensity
- value must be scaled by 100 because it will be divided
- later when scaled.
- */
-
- if ((regs.h.dh == regs.h.ch) && (regs.h.ch == regs.h.cl))
- Intensity = regs.h.dh*100;
- else
- {
- /* calculate the intensity from the color values */
- Intensity = ((unsigned) regs.h.dh*30); /* calculate red contribution */
- Intensity += ((unsigned) regs.h.ch*59); /* calculate green contribution */
- Intensity += ((unsigned) regs.h.cl*11); /* calculate blue contribution */
- }
- /* scale and store intensity result */
- DensityTbl[ColorNum] = (unsigned) (((((double) Intensity *
- (double) MAXDENSITYINDEX)
- / MAXVGAINTVAL)+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)
- {
-
- if (Is256Colors)
- return(GetPixel256(Col,Row));
- else /* is 16 color mode */
- return(getpixel(Col,Row));
- }
-
-
- void DitherPrintCol (unsigned PrintMode, PrinterModes PrtMode, unsigned Col)
- {
- register unsigned CurrentRow, MatrixRow;
- register BYTE Intensity, PrtByte;
-
- 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++)
- {
- 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 since 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 */
- }
-
-
- void PatternPrintCol (unsigned PrintMode, PrinterModes PrtMode, unsigned Col)
- {
- register unsigned CurrentRow;
- register int Density;
- BYTE Row1Data, Row2Data, Row3Data, Row4Data;
-
- 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 briteness 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 briteness 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)
- {
- int ScreenCol;
- PrinterModes PrtMode;
- unsigned CurrentDisplayMode;
-
-
- CurrentDisplayMode = GetVideoMode(); /* get the current mode */
- switch(CurrentDisplayMode)
- {
- case LRVIDEOMODE:
- PrtMode = MedResMode;
- MaxScreenCol = 320;
- MaxScreenRow = 200;
- Is256Colors = TRUE;
- break;
- case MRVIDEOMODE:
- PrtMode = MedResMode;
- MaxScreenCol = 640;
- MaxScreenRow = 200;
- Is256Colors = FALSE;
- break;
- case HRVIDEOMODE:
- PrtMode = HighResMode;
- MaxScreenCol = 640;
- MaxScreenRow = 480;
- Is256Colors = FALSE;
- break;
- default:
- return(FALSE); /* unsupported video mode */
- }
-
- /*
- Calculate densitys to be used to display image
- */
- InitDensityTbl();
-
- /*
- Because we'll 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 */
- }
- 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,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 -= PIXELSPERPASS)
- {
- if (kbhit()) /* check for abort */
- { /* if key hit */
- getch(); /* consume it */
- break; /* and quit */
- }
- if (Matrix == BayerMatrix)
- DitherPrintCol(PrintMode, PrtMode, ScreenCol);
- else
- PatternPrintCol(PrintMode, PrtMode, ScreenCol);
-
- }
- PrtString(LPT1,TextLineFeed); /* set text line feed */
- PrtChar(LPT1,'\f'); /* do form feed when finished */
- PrtString(LPT1,TwoDirection); /* set printer to two dir mode */
- return(NoError);
- }
-
- /*
- This function provides help in the advent of operator error. Program
- terminates after help is given
- */
-
- void ShowHelp( void )
- {
- printf("\nThis program displays and prints a .PCX file. Image\n");
- printf("must be 320x200 in 256 colors, 640x200 in 16 colors or\n");
- printf("640x480 in 16 colors.\n\n");
- printf("Program is envoked as follows:\n\n");
- printf("Usage: print [-v -mB/R -b(+/- 0-9) -n] filename <cr>\n");
- printf(" -v displays info about the .PCX file\n");
- printf(" -m selects the dither matrix to use:\n");
- printf(" B = Bayer ordered dither\n");
- printf(" R = Rylander recursive halftoning\n");
- printf(" -b alters briteness\n");
- printf(" -n prints negative image\n");
- printf(" filename is the name of a .PCX image file\n\n");
- exit(1);
- }
-
-
-
- void main(argc,argv)
-
- short argc;
- char *argv[];
-
- {
- unsigned FileNameCounter, ArgIndex;
- char *InFileName;
-
- InitGraphics();
-
- printf("Print Program -- Displays and Prints a .PCX Image\n");
- printf(" Ver: %d.%d by Craig A. Lindley\n\n\n",ver,rel);
- delay(1000);
-
- /* install defaults */
- Verbose = FALSE; /* not verbose */
- Brightness = 0; /* use calculated briteness */
- PrintMode = POSPRINT; /* print whites as white */
- Matrix = BayerMatrix; /* use Bayer matrix */
-
- FileNameCounter = 0; /* count of user specified filenames */
- for (ArgIndex=1; ArgIndex < argc; ArgIndex++)
- {
- if (*argv[ArgIndex] != '-') /* if not a cmd line switch */
- { /* must be a filename */
- if (FileNameCounter > 1) /* only one filename allowed */
- ShowHelp(); /* if more then error exit */
- InFileName = argv[ArgIndex]; /* save PCX filename */
- FileNameCounter++; /* inc count for error check */
- }
- else /* its a cmd line switch */
- {
- switch (*(argv[ArgIndex]+1)) /* parse the cmd line */
- {
- case 'v':
- case 'V':
- Verbose = TRUE;
- break;
- case 'm':
- case 'M':
- if ((*(argv[ArgIndex]+2) == 'r') || (*(argv[ArgIndex]+2) == 'R'))
- Matrix = RylanderMatrix; /* use Rylander matrix */
- else
- Matrix = BayerMatrix; /* use Bayer matrix */
- break;
- case 'b':
- case 'B':
- sscanf(argv[ArgIndex]+2,"%d",&Brightness);
- if (abs(Brightness) > 9)
- {
- printf("Error - invalid briteness specified\n");
- ShowHelp();
- }
- break;
- case 'n':
- case 'N':
- PrintMode = NEGPRINT;
- break;
- default:
- printf("Error - invalid cmd line switch encountered\n");
- ShowHelp();
- }
- }
- }
- if (FileNameCounter != 1)
- {
- printf("Error - a PCX filename is required\n");
- ShowHelp();
- }
-
- /* Display the specified PCX file */
- DisplayPCXFile(InFileName,Verbose);
-
- /* Print the image displayed on the screen */
- if (PrtScreen(PrintMode) != NoError)
- {
- restorecrtmode();
- closegraph();
- printf("Unsupported video mode being utilized\n\n");
- exit(FALSE);
- }
- restorecrtmode();
- closegraph();
- }
-