home *** CD-ROM | disk | FTP | other *** search
/ Piper's Pit BBS/FTP: ibm 0040 - 0049 / ibm0040-0049 / ibm0040.tar / ibm0040 / IMGPROC.ZIP / C7.ZIP / PRINT.C next >
Encoding:
C/C++ Source or Header  |  1990-04-06  |  21.6 KB  |  633 lines

  1. /*  
  2. Copyright 1990 by John Wiley & Sons, Inc.
  3.           All Rights Reserved.
  4. */
  5. /****************************************************/
  6. /*                     print.c                      */
  7. /*                                                  */
  8. /*          Display and Print .PCX files            */
  9. /*      Prints images displayed on VGA adapter        */
  10. /*  on an IBM ProPrinter using halftone techniques  */
  11. /*            written in Turbo C 2.0                */
  12. /*                                                  */
  13. /* Usage: print [-v -mB/R -b(+/- 0-9) -n] filename  */
  14. /*    -v displays info about the .PCX file          */
  15. /*    -m selects the dither matrix to use:          */
  16. /*       B = Bayer ordered dither                   */
  17. /*       R = Rylander recursive halftoning          */
  18. /*     -b alters briteness                          */
  19. /*     -n prints negative image                     */
  20. /*                                                  */
  21. /*          written by Craig A. Lindley             */
  22. /*        Vers: 1.0  Last Update: 11/29/89          */
  23. /****************************************************/
  24.  
  25. #include <stdio.h>
  26. #include <conio.h>
  27. #include <dos.h>
  28. #include <process.h>
  29. #include <stdlib.h>
  30. #include <string.h>
  31. #include <graphics.h>
  32. #include "misc.h"
  33. #include "pcx.h"
  34. #include "vga.h"
  35. #include "printer.h"
  36.  
  37. #define MAXVGAINTVAL 6300.0       /* Max VGA intensity x 100 */
  38. #define MAXPRTINTENSITIES 17      /* 17 possible densities in 4x4 matrix */
  39. #define MAXDENSITYINDEX (MAXPRTINTENSITIES-1)
  40.  
  41. /* Version information */
  42. static short ver = 1;
  43. static short rel = 0;
  44.  
  45. /* print function variables */
  46. static unsigned Verbose, PrintMode;
  47. static int      Brightness;
  48. static unsigned MaxScreenRow, MaxScreenCol, Is256Colors;
  49. static unsigned DensityTbl[MAX256PALETTECOLORS];
  50. static unsigned N1,N2;
  51. static union    REGS regs;
  52. static enum     MatrixType Matrix;
  53.  
  54. /*
  55. The following arrays define the half tone patterns used
  56. for the printout. 4x4 dither matrices are used in
  57. both cases.
  58. */
  59.  
  60. /* Bayer ordered dither matrix */
  61. BYTE BayerMat[4][4] =
  62. { 0,  8,  2, 10,
  63.  12,  4, 14,  6,
  64.   3, 11,  1,  9,
  65.  15,  7, 13,  5};
  66.  
  67.  
  68. /* Rylander recursive halftoning matrix */
  69. struct   DotPatterns RylanderMat[MAXPRTINTENSITIES] =
  70.          {0x0F,0x0F,0x0F,0x0F,   /* 100.0% - all black */
  71.           0x0F,0x0F,0x0F,0x0B,   /*  93.8% */
  72.           0x0F,0x0E,0x0F,0x0B,   /*  87.5% */
  73.       0x0F,0x0E,0x0F,0x0A,   /*  81.3% */
  74.           0x0F,0x0A,0x0F,0x0A,   /*  75.0% */
  75.           0x0F,0x0A,0x0B,0x0A,   /*  68.8% */
  76.           0x0E,0x0A,0x0B,0x0A,   /*  62.5% */
  77.           0x0E,0x0A,0x0A,0x0A,   /*  56.3% */
  78.           0x0A,0x0A,0x0A,0x0A,   /*  50.0% */
  79.           0x0A,0x0A,0x0A,0x02,   /*  43.8% */
  80.           0x0A,0x08,0x0A,0x02,   /*  37.5% */
  81.           0x0A,0x08,0x0A,0x00,   /*  31.3% */
  82.           0x0A,0x00,0x0A,0x00,   /*  25.0% */
  83.           0x0A,0x00,0x02,0x00,   /*  18.8% */
  84.           0x08,0x00,0x02,0x00,   /*  12.5% */
  85.           0x08,0x00,0x00,0x00,   /*   6.3% */
  86.           0x00,0x00,0x00,0x00};  /*   0.0% - all white */
  87.  
  88. /* IBM ProPrinter Specific Printer Control Code Strings */
  89. BYTE *OneDirection   = "\x1BU\x31";    /* ESC U 1 */
  90. BYTE *TwoDirection   = "\x1BU\x30";    /* ESC U 1 */
  91. BYTE *LowRes         = "\x1BK";        /* ESC K */
  92. BYTE *MedRes         = "\x1BY";        /* ESC Y */
  93. BYTE *HighRes        = "\x1BZ";        /* ESC Z */
  94. BYTE *TextLineFeed   = "\x1B\x31";     /* ESC 1 - normal 7/72 text line feed */
  95. BYTE *GraphicLineFeed= "\x1B\x33\x18"; /* ESC 3 24 -  24/216ths line feed */
  96. BYTE *CrLf           = "\r\n";         /* graphics carrage ret line feed */
  97. BYTE *DisAutoLf      = "\x1B\x35\x30"; /* ESC 5 0 disable auto line feed */
  98.  
  99.  
  100. /* Printer Interface Functions */
  101.  
  102. /* This function initializes the line printer for operation */
  103. void PrtInit (unsigned PrtNum)
  104. {
  105.    regs.h.ah = INITPRTCODE;
  106.    regs.x.dx = PrtNum;
  107.    int86(PRINTERINT, ®s, ®s);
  108. }
  109.  
  110. /* This function reads the status of the line printer */
  111. BYTE PrtStatus (unsigned PrtNum)
  112. {
  113.    regs.h.ah = GETPRTSTATUSCODE;
  114.    regs.x.dx = PrtNum;
  115.    int86(PRINTERINT, ®s, ®s);
  116.    return (regs.h.ah);
  117. }
  118.  
  119.  
  120. /* this function prints a character on the specified printer */
  121. BYTE PrtChar(unsigned PrtNum, BYTE Character)
  122. {
  123.  
  124.    while(!(PrtStatus(PrtNum) & PRTBUSYBIT)); /* wait until not busy */
  125.    regs.h.ah = PRTCHARCODE;            /* prt a character code */
  126.    regs.h.al = Character;
  127.    regs.x.dx = PrtNum;                 /* select the printer */
  128.    int86(PRINTERINT, ®s, ®s);
  129.    return(regs.h.ah);                  /* return operation status */
  130. }
  131.  
  132. /* this function prints a null terminated string of characters
  133.    to the named printer */
  134.  
  135. BYTE PrtString(unsigned PrtNum, BYTE *String)
  136. {
  137.    BYTE PrtError;
  138.  
  139.    PrtError = FALSE;
  140.    while ((*String != NULL) && (!PrtError)) /* do until the null or error */
  141.       PrtError = ((PrtChar(PrtNum,*String++) & PRTTIMEOUT) == 1);
  142.    return(PrtError);
  143. }
  144.  
  145. /*
  146. This function builds the DensityTbl which contain the index into the
  147. DotDensities array that is to be used to represent the color of a given pixel
  148. (in gray scale) when printed. The print dot density is calculated
  149. from the value of a color register.  The intensity value for a
  150. given color is computed from the formula:
  151.  
  152.       Intensity = Red Comp*30% + Green Comp*59% + BlueComp*11%
  153.  
  154. which corresponds to the sensitivity of the human eye to the various
  155. color components. This formula is taken from the IBM VGA technical reference
  156. manual.
  157.  
  158. With VGA, the value of the color registers are settable. This means the
  159. color register RGB components must be read from the hardware before the
  160. intensity calculation can be performed. Each color component has the
  161. range 0..63. With the maximum intensity VGA color (white) the intensity
  162. value turns out to be 63. This value will be used to scale all intensity
  163. values into the range 0..16 as required by the DensityTbl array.
  164. */
  165.  
  166. void InitDensityTbl( void )
  167. {
  168.    unsigned ColorEntry, ColorNum;
  169.    unsigned Intensity;
  170.    struct palettetype palette;
  171.  
  172.    /* this procedure builds the DensityTbl based upon the intensity of
  173.       the colors used in the palette to display the PCX image. The intensity
  174.       are calculated as described above. */
  175.  
  176.    getpalette(&palette);               /* get the current palette */
  177.  
  178.    if (!Is256Colors)                   /* 16 color modes only */
  179.    {
  180.       /* for each entry in the palette */
  181.       for (ColorEntry=0; ColorEntry < palette.size; ColorEntry++)
  182.       {
  183.          ColorNum = palette.colors[ColorEntry]; /* get a palette entry */
  184.          /*
  185.          because the color register values can change for VGA, the
  186.          color components of each palette entry must be read before the
  187.          Intensity can be calculated
  188.          */
  189.          regs.h.ah = 0x10;             /* get the color components of a */
  190.          regs.h.al = 0x15;             /* color register. */
  191.          regs.x.bx = ColorNum;
  192.          int86(VIDEO,®s,®s);
  193.  
  194.          /*
  195.      If the palette is a gray scale already, its intensity is
  196.          just a single component. In this case Red. The intensity
  197.      value must be scaled by 100 because it will be divided
  198.      later when scaled.
  199.          */
  200.  
  201.          if ((regs.h.dh == regs.h.ch) && (regs.h.ch == regs.h.cl))
  202.         Intensity = regs.h.dh*100;
  203.           else
  204.          {
  205.             /* calculate the intensity from the color values */
  206.             Intensity =  ((unsigned) regs.h.dh*30);  /* calculate red   contribution */
  207.             Intensity += ((unsigned) regs.h.ch*59);  /* calculate green contribution */
  208.             Intensity += ((unsigned) regs.h.cl*11);  /* calculate blue  contribution */
  209.          }
  210.          /* scale and store intensity result */
  211.      DensityTbl[ColorEntry] = (unsigned) (((((double) Intensity *
  212.                          (double) MAXDENSITYINDEX)
  213.                          / MAXVGAINTVAL)+0.5));
  214.       }
  215.    }
  216.    else                      /* 256 color mode */
  217.    {
  218.       /* for each color register */
  219.       for (ColorNum=0; ColorNum < MAX256PALETTECOLORS; ColorNum++)
  220.       {
  221.          /* no palette is used in 256 color mode */
  222.          regs.h.ah = 0x10;             /* get the color components of a */
  223.          regs.h.al = 0x15;             /* color register. */
  224.          regs.x.bx = ColorNum;
  225.          int86(VIDEO,®s,®s);
  226.  
  227.          /*
  228.      If the palette is a gray scale already, its intensity is
  229.      just a single component. In this case Red. The intensity
  230.      value must be scaled by 100 because it will be divided
  231.      later when scaled.
  232.          */
  233.  
  234.          if ((regs.h.dh == regs.h.ch) && (regs.h.ch == regs.h.cl))
  235.         Intensity = regs.h.dh*100;
  236.           else
  237.          {
  238.             /* calculate the intensity from the color values */
  239.             Intensity =  ((unsigned) regs.h.dh*30);  /* calculate red   contribution */
  240.             Intensity += ((unsigned) regs.h.ch*59);  /* calculate green contribution */
  241.             Intensity += ((unsigned) regs.h.cl*11);  /* calculate blue  contribution */
  242.          }
  243.          /* scale and store intensity result */
  244.      DensityTbl[ColorNum] = (unsigned) (((((double) Intensity *
  245.                            (double) MAXDENSITYINDEX)
  246.                            / MAXVGAINTVAL)+0.5));
  247.       }
  248.    }
  249. }
  250.  
  251. /*
  252. This function returns a pixel from the screen. It works
  253. differently for the 16 and the 256 color modes.
  254. */
  255. unsigned GetAPixel(unsigned Col, unsigned Row)
  256. {
  257.  
  258.    if (Is256Colors)
  259.      return(GetPixel256(Col,Row));
  260.    else /* is 16 color mode */
  261.      return(getpixel(Col,Row));
  262. }
  263.  
  264.  
  265. void DitherPrintCol (unsigned PrintMode, PrinterModes PrtMode, unsigned Col)
  266. {
  267.    register unsigned CurrentRow, MatrixRow;
  268.    register BYTE     Intensity, PrtByte;
  269.  
  270.    switch (PrtMode)                    /* send printer the graphic mode */
  271.    {                                   /* control code sequence */
  272.      case HighResMode: {
  273.              PrtString(LPT1,HighRes);
  274.              break;
  275.                }
  276.      case MedResMode:  {
  277.              PrtString(LPT1,MedRes);
  278.              break;
  279.                }
  280.      case LowResMode:
  281.          default:  {
  282.              PrtString(LPT1,LowRes);
  283.              break;
  284.                }
  285.    }
  286.  
  287.    /* tell printer how many bytes to follow */
  288.  
  289.    PrtChar(LPT1,N1);
  290.    PrtChar(LPT1,N2);
  291.  
  292.    for (CurrentRow=0; CurrentRow < MaxScreenRow; CurrentRow++)
  293.    {
  294.       PrtByte = 0;
  295.       MatrixRow = CurrentRow % 4;
  296.  
  297.       Intensity  = DensityTbl[GetAPixel(Col, CurrentRow)]+Brightness;
  298.       if (Intensity > BayerMat[MatrixRow][3])
  299.     PrtByte |= 128;
  300.  
  301.       Intensity  = DensityTbl[GetAPixel(Col-1, CurrentRow)]+Brightness;
  302.       if (Intensity > BayerMat[MatrixRow][2])
  303.     PrtByte |= 64;
  304.  
  305.       Intensity  = DensityTbl[GetAPixel(Col-2, CurrentRow)]+Brightness;
  306.       if (Intensity > BayerMat[MatrixRow][1])
  307.     PrtByte |= 32;
  308.  
  309.       Intensity  = DensityTbl[GetAPixel(Col-3, CurrentRow)]+Brightness;
  310.       if (Intensity > BayerMat[MatrixRow][0])
  311.     PrtByte |= 16;
  312.  
  313.       Intensity  = DensityTbl[GetAPixel(Col-4, CurrentRow)]+Brightness;
  314.       if (Intensity > BayerMat[MatrixRow][3])
  315.     PrtByte |= 8;
  316.  
  317.       Intensity  = DensityTbl[GetAPixel(Col-5, CurrentRow)]+Brightness;
  318.       if (Intensity > BayerMat[MatrixRow][2])
  319.     PrtByte |= 4;
  320.  
  321.       Intensity  = DensityTbl[GetAPixel(Col-6, CurrentRow)]+Brightness;
  322.       if (Intensity > BayerMat[MatrixRow][1])
  323.     PrtByte |= 2;
  324.  
  325.       Intensity  = DensityTbl[GetAPixel(Col-7, CurrentRow)]+Brightness;
  326.       if (Intensity > BayerMat[MatrixRow][0])
  327.     PrtByte |= 1;
  328.  
  329.       /*
  330.       The off and on pins are reversed at this point. For example,
  331.       PrtByte = 0 should print as black all pins on but will instead
  332.       print as white (all pins off). To correct for this inversion,
  333.       invert the since of the PrintMode.
  334.       */
  335.       if (PrintMode == POSPRINT)
  336.      PrtByte ^= 0xFF;
  337.  
  338.       PrtChar(LPT1,PrtByte);           /* send two identical bytes */
  339.       PrtChar(LPT1,PrtByte);           /* to the printer. */
  340.  
  341.       if (MaxScreenCol == 640)         /* if in 640 pixel mode */
  342.       {
  343.      PrtChar(LPT1,PrtByte);        /* send two more identical bytes */
  344.      PrtChar(LPT1,PrtByte);        /* to the printer. */
  345.       }
  346.    }
  347.    PrtString(LPT1,CrLf);               /* output LfCr to printer */
  348. }
  349.  
  350.  
  351. void PatternPrintCol (unsigned PrintMode, PrinterModes PrtMode, unsigned Col)
  352. {
  353.    register unsigned CurrentRow;
  354.    register int Density;
  355.    BYTE     Row1Data, Row2Data, Row3Data, Row4Data;
  356.  
  357.    switch (PrtMode)                    /* send printer the graphic mode */
  358.    {                                   /* control code sequence */
  359.      case HighResMode: {
  360.              PrtString(LPT1,HighRes);
  361.              break;
  362.                }
  363.      case MedResMode:  {
  364.              PrtString(LPT1,MedRes);
  365.              break;
  366.                }
  367.      case LowResMode:
  368.          default:  {
  369.              PrtString(LPT1,LowRes);
  370.              break;
  371.                }
  372.    }
  373.  
  374.    /* tell printer how many bytes to follow */
  375.    PrtChar(LPT1,N1);
  376.    PrtChar(LPT1,N2);
  377.  
  378.    for (CurrentRow=0; CurrentRow < MaxScreenRow; CurrentRow++)
  379.    {
  380.       /* calc the average density of a group of 4 horiz. pixels */
  381.       Density  = DensityTbl[GetAPixel(Col  , CurrentRow)];
  382.       Density += DensityTbl[GetAPixel(Col-1, CurrentRow)];
  383.       Density += DensityTbl[GetAPixel(Col-2, CurrentRow)];
  384.       Density += DensityTbl[GetAPixel(Col-3, CurrentRow)];
  385.       Density /= 4;
  386.       Density += Brightness;            /* shift briteness level */
  387.       Density = (Density < 0 ) ? 0:Density;
  388.       Density = (Density > MAXDENSITYINDEX) ? MAXDENSITYINDEX:Density;
  389.  
  390.       /* get dot pattern representing this average density */
  391.       /* shift by 4 because these dots will become the MS pin date */
  392.       Row1Data = RylanderMat[Density].Row1 << 4;
  393.       Row2Data = RylanderMat[Density].Row2 << 4;
  394.       Row3Data = RylanderMat[Density].Row3 << 4;
  395.       Row4Data = RylanderMat[Density].Row4 << 4;
  396.  
  397.       /* calc the average density of a group of 4 horiz. pixels */
  398.       Density  = DensityTbl[GetAPixel(Col-4, CurrentRow)];
  399.       Density += DensityTbl[GetAPixel(Col-5, CurrentRow)];
  400.       Density += DensityTbl[GetAPixel(Col-6, CurrentRow)];
  401.       Density += DensityTbl[GetAPixel(Col-7, CurrentRow)];
  402.       Density /= 4;
  403.       Density += Brightness;            /* shift briteness level */
  404.       Density = (Density < 0 ) ? 0:Density;
  405.       Density = (Density > MAXDENSITYINDEX) ? MAXDENSITYINDEX:Density;
  406.  
  407.       /* get dot pattern representing this average density */
  408.       /* merge with MS pin data */
  409.       Row1Data |= RylanderMat[Density].Row1;
  410.       Row2Data |= RylanderMat[Density].Row2;
  411.       Row3Data |= RylanderMat[Density].Row3;
  412.       Row4Data |= RylanderMat[Density].Row4;
  413.  
  414.       /* if a reverse image is requested compliment dot data */
  415.       if (PrintMode != POSPRINT)
  416.       {
  417.          Row1Data ^= 0xFF;
  418.          Row2Data ^= 0xFF;
  419.          Row3Data ^= 0xFF;
  420.          Row4Data ^= 0xFF;
  421.       }
  422.       PrtChar(LPT1,Row1Data);          /* send 4 bytes of printer data */
  423.       PrtChar(LPT1,Row2Data);          /* to the printer. This 32 bits of */
  424.       PrtChar(LPT1,Row3Data);          /* data represent 8 bits of pixel */
  425.       PrtChar(LPT1,Row4Data);          /* data */
  426.    }
  427.    PrtString(LPT1,CrLf);               /* output LfCr to printer */
  428. }
  429.  
  430.  
  431.  
  432. /*
  433. This is the main print screen function. It will print in gray scale any
  434. picture displayed on a VGA graphic adapter. The parameter Rev
  435. controls the interpretation on the data on the screen.
  436. */
  437.  
  438. CompletionCode PrtScreen (unsigned PrintMode)
  439. {
  440.    int          ScreenCol;
  441.    PrinterModes PrtMode;
  442.    unsigned     CurrentDisplayMode;
  443.  
  444.  
  445.    CurrentDisplayMode = GetVideoMode(); /* get the current mode */
  446.    switch(CurrentDisplayMode)
  447.    {
  448.       case LRVIDEOMODE:
  449.          PrtMode = MedResMode;
  450.          MaxScreenCol = 320;
  451.          MaxScreenRow = 200;
  452.          Is256Colors = TRUE;
  453.          break;
  454.       case MRVIDEOMODE:
  455.          PrtMode = MedResMode;
  456.          MaxScreenCol = 640;
  457.          MaxScreenRow = 200;
  458.          Is256Colors = FALSE;
  459.          break;
  460.       case HRVIDEOMODE:
  461.          PrtMode = HighResMode;
  462.          MaxScreenCol = 640;
  463.          MaxScreenRow = 480;
  464.          Is256Colors = FALSE;
  465.          break;
  466.       default:
  467.          return(FALSE);  /* unsupported video mode */
  468.    }
  469.  
  470.    /*
  471.    Calculate densitys to be used to display image
  472.    */
  473.    InitDensityTbl();
  474.  
  475.    /*
  476.    Because we'll be dumping the display in a vertical fashion starting from
  477.    the right most column, we must calculate the byte counts that will be
  478.    sent to the printer from the MaxScreenRow value. The number of screen
  479.    rows will be either 200 or 480. A 200 row screen will be dumped to the
  480.    printer while it is in the 960 dot mode. This will mean that each pixel
  481.    from the display will be printed two dots wide. A 480 row screen will be
  482.    dumped to the printer while it is in the 1920 dot mode. Each pixel
  483.    will be four dots wide.
  484.    */
  485.  
  486.    if ((MaxScreenCol == 320) && (Matrix == BayerMatrix))
  487.    {
  488.       N2 = (MaxScreenRow*2) >> 8;         /* calculate byte counts */
  489.       N1 = (MaxScreenRow*2) & 0xFF;       /* to be sent to printer */
  490.    }
  491.    else
  492.    {
  493.       N2 = (MaxScreenRow*4) >> 8;         /* calculate byte counts */
  494.       N1 = (MaxScreenRow*4) & 0xFF;       /* to be sent to printer */
  495.    }
  496.  
  497.    PrtInit(LPT1);                      /* initialize the printer */
  498.    PrtString(LPT1,OneDirection);       /* set printer in one dir mode */
  499.    PrtString(LPT1,DisAutoLf);          /* disable auto line feed */
  500.    PrtString(LPT1,GraphicLineFeed);    /* set 24/216 line feed as required */
  501.                                        /* for 8 pin bit mapped printing */
  502.  
  503.    /* move backward across displayed image */
  504.    for (ScreenCol=MaxScreenCol-1; ScreenCol >= 0; ScreenCol -= PIXELSPERPASS)
  505.    {
  506.       if (kbhit())                     /* check for abort */
  507.       {                                /* if key hit */
  508.          getch();                      /* consume it */
  509.          break;                        /* and quit */
  510.       }
  511.       if (Matrix == BayerMatrix)
  512.      DitherPrintCol(PrintMode, PrtMode, ScreenCol);
  513.       else
  514.      PatternPrintCol(PrintMode, PrtMode, ScreenCol);
  515.  
  516.    }
  517.    PrtString(LPT1,TextLineFeed);       /* set text line feed */
  518.    PrtChar(LPT1,'\f');                 /* do form feed when finished */
  519.    PrtString(LPT1,TwoDirection);       /* set printer to two dir mode */
  520.    return(NoError);
  521. }
  522.  
  523. /*
  524. This function provides help in the advent of operator error. Program
  525. terminates after help is given
  526. */
  527.  
  528. void ShowHelp( void )
  529. {
  530.    printf("\nThis program displays and prints a .PCX file. Image\n");
  531.    printf("must be 320x200 in 256 colors, 640x200 in 16 colors or\n");
  532.    printf("640x480 in 16 colors.\n\n");
  533.    printf("Program is envoked as follows:\n\n");
  534.    printf("Usage: print [-v -mB/R -b(+/- 0-9) -n] filename <cr>\n");
  535.    printf("    -v displays info about the .PCX file\n");
  536.    printf("    -m selects the dither matrix to use:\n");
  537.    printf("       B = Bayer ordered dither\n");
  538.    printf("       R = Rylander recursive halftoning\n");
  539.    printf("    -b alters briteness\n");
  540.    printf("    -n prints negative image\n");
  541.    printf("    filename is the name of a .PCX image file\n\n");
  542.    exit(1);
  543. }
  544.  
  545.  
  546.  
  547. void main(argc,argv)
  548.  
  549. short argc;
  550. char *argv[];
  551.  
  552. {
  553.    unsigned FileNameCounter, ArgIndex;
  554.    char    *InFileName;
  555.  
  556.    InitGraphics();
  557.  
  558.    printf("Print Program -- Displays and Prints a .PCX Image\n");
  559.    printf("  Ver: %d.%d by Craig A. Lindley\n\n\n",ver,rel);
  560.    delay(1000);
  561.  
  562.    /* install defaults */
  563.    Verbose = FALSE;                    /* not verbose */
  564.    Brightness = 0;                     /* use calculated briteness */
  565.    PrintMode = POSPRINT;               /* print whites as white */
  566.    Matrix = BayerMatrix;               /* use Bayer matrix */
  567.  
  568.    FileNameCounter = 0;                /* count of user specified filenames */
  569.    for (ArgIndex=1; ArgIndex < argc; ArgIndex++)
  570.    {
  571.       if (*argv[ArgIndex] != '-')      /* if not a cmd line switch */
  572.       {                                /* must be a filename */
  573.          if (FileNameCounter > 1)      /* only one filename allowed */
  574.             ShowHelp();                /* if more then error exit */
  575.          InFileName = argv[ArgIndex];  /* save PCX filename */
  576.          FileNameCounter++;            /* inc count for error check */
  577.       }
  578.       else                             /* its a cmd line switch */
  579.       {
  580.          switch (*(argv[ArgIndex]+1))     /* parse the cmd line */
  581.          {
  582.             case 'v':
  583.             case 'V':
  584.               Verbose = TRUE;
  585.               break;
  586.             case 'm':
  587.             case 'M':
  588.               if ((*(argv[ArgIndex]+2) == 'r') || (*(argv[ArgIndex]+2) == 'R'))
  589.                  Matrix = RylanderMatrix; /* use Rylander matrix */
  590.               else
  591.                  Matrix = BayerMatrix;    /* use Bayer matrix */
  592.               break;
  593.             case 'b':
  594.             case 'B':
  595.               sscanf(argv[ArgIndex]+2,"%d",&Brightness);
  596.               if (abs(Brightness) > 9)
  597.               {
  598.                  printf("Error - invalid briteness specified\n");
  599.                  ShowHelp();
  600.               }
  601.               break;
  602.           case 'n':
  603.           case 'N':
  604.               PrintMode = NEGPRINT;
  605.               break;
  606.           default:
  607.             printf("Error - invalid cmd line switch encountered\n");
  608.             ShowHelp();
  609.          }
  610.       }
  611.    }
  612.    if (FileNameCounter != 1)
  613.    {
  614.       printf("Error - a PCX filename is required\n");
  615.       ShowHelp();
  616.    }
  617.  
  618.    /* Display the specified PCX file */
  619.    DisplayPCXFile(InFileName,Verbose);
  620.  
  621.    /* Print the image displayed on the screen */
  622.    if (PrtScreen(PrintMode) != NoError)
  623.    {
  624.      restorecrtmode();
  625.      closegraph();
  626.      printf("Unsupported video mode being utilized\n\n");
  627.      exit(FALSE);
  628.    }
  629.    restorecrtmode();
  630.    closegraph();
  631. }
  632.  
  633.