home *** CD-ROM | disk | FTP | other *** search
/ Shareware Overload / ShartewareOverload.cdr / progm / pcgraphc.zip / DGRAPH.C < prev    next >
C/C++ Source or Header  |  1989-01-02  |  12KB  |  357 lines

  1. /* dgraph.c
  2.  
  3. graphics dump for the RX/FX-80/100 printers
  4.  
  5. This program is a graphics dump utility for the Epson RX/FX-80/100
  6. printer.  It is very similar to the program graphics.com which is used
  7. to dump graphics to the Epson RX/FX-80/100 printers.  
  8.  
  9.     graphics dump for the RX/FX-80/100 printers
  10.     Includes CGA, EGA, and AT&T hi-res dump modes.
  11.     (c) Lantern Systems 1986, 1988, 1989
  12.  
  13. calling convention:
  14.  
  15.     dgraph ( row_min, col_min, row_max, col_max )
  16.  
  17. where row_min, row_max, col_min, col_max are integers describing the
  18. screen co-ordinates to use as a window.  If max values are set to 0, 
  19. the values default to the full screen size.
  20.  
  21. Returns 0 for normal, EOF for error, 1 for object locked or printer not ready
  22. */
  23.  
  24. #include    <stdio.h>
  25. #include    <stdlib.h>
  26. #include    <dos.h>
  27.  
  28. #define        CR        0x0D
  29. #define        LF        0x0A
  30. #define        VIDEO_INT    0x10
  31. #define        ESC        0x1B
  32. #define        GET_VIDEO    0x0F        /* fn. code for read video */
  33. #define        READ_PIX    0x0D        /* fn. code for read pixel */
  34. #define        MAX_COL_H    639        /* max # of high-res col.s */
  35. #define        MAX_ROW_H    399        /* max # of high-res rows */
  36. #define        MAX_ROW_M    199        /* max # of med-res rows */
  37. #define        MAX_COL_M    639        /* max # of med-res col.s */
  38. #define        MAX_ROW_L    199        /* max # of low-res rows */
  39. #define        MAX_COL_L    319        /* max # of low res col.s */
  40. #define        EGA_ROWMAX    349        /* max # of EGA rows */
  41. #define        PRINTER        0x17        /* interrupt for printer i/o */
  42.  
  43. #define        MAX(x,y)    ( (x) < (y) ) ? (y) : (x)
  44. #define        MIN(x,y)    ( (x) < (y) ) ? (x) : (y)
  45.  
  46. static unsigned far *mon_lock;
  47. static int raster_rows, bits, err;
  48. static unsigned char top, mid;
  49. static union REGS regs;
  50. static int row_min, row_max, col_min, col_max;
  51.  
  52. /*    top is the top of a pixel triplet, mid is the top of a
  53.     merged pixel triplet. This code is very sensitive to the size of
  54.     long int's and the allocation off char's.  In this program, the
  55.     union of long and char is such that pixels [3] is the MSB of the
  56.     long and pixels [0] is the LSB.  In this way it is possible to 
  57.     rotate bits into the entire dword with a single instruction. */
  58.  
  59. int dgraph ( row_mn, col_mn, row_mx, col_mx )
  60.     int col_mn, col_mx, row_mn, row_mx;
  61.     {
  62.  
  63.     int col_last, row_idx, col_idx, mode;
  64.  
  65.  
  66.     /*    raster_rows defines the number of rows that make up a
  67.         printhead raster scan and col_last holds the pointer 
  68.         to the last active pixel of the current printhead raster. */
  69.  
  70.  
  71.     mon_lock = (unsigned far *) 0x5000000;    /* point to seg. 50, adr. 0 for monitor lock byte */
  72.  
  73.     if ( *mon_lock == 1) return (1);    /* monitor is already locked */
  74.     regs.h.ah = GET_VIDEO;            /* return current video mode */
  75.     int86 (VIDEO_INT, ®s, ®s);
  76.     mode = regs.h.al;            /* returned video mode */
  77.     if ((mode == 7) || (mode < 4)) return (EOF);
  78.     *mon_lock = 1;                /* assert monitor lock */
  79.  
  80.  
  81. /*---------------------------------------------------------
  82.     This block of code tests for valid graphics modes to dump graphics.
  83.     The ranges of the graphics dump window are also tested here.  No 
  84.     attempt was made to check for min values > max values.  */
  85.  
  86.     set_lpi();        /* set-up new printer linefeed size */
  87.     row_min = MAX (0, row_mn);
  88.     col_min = MAX (0, col_mn);
  89.     switch (mode)
  90.         {
  91.         case 4:                /* CGA low-res mode 320x200 */
  92.         case 5:
  93.             row_max = MIN (row_mx, MAX_ROW_L);
  94.             col_max = MIN (col_mx, MAX_COL_L);
  95.             if (row_max == 0) row_max = MAX_ROW_L;
  96.             if (col_max == 0) col_max = MAX_COL_L;
  97.             err = low_res ();
  98.             *mon_lock = 0;        /* release monitor lock */
  99.             return (err);
  100.             break;
  101.         case 6:                /* CGA med-res mode 640x200 */
  102.             row_max = MIN (row_mx, MAX_ROW_M);
  103.             col_max = MIN (col_mx, MAX_COL_H);
  104.             if (row_max == 0) row_max = MAX_ROW_M;
  105.             if (col_max == 0) col_max = MAX_COL_H;
  106.             raster_rows = 4;
  107.             bits = 2;
  108.             err = mh_res ();
  109.             *mon_lock = 0;        /* release monitor lock */
  110.             return (err);
  111.             break;
  112.         case 0x0d:            /* EGA 320x200 */
  113.             row_max = MIN (row_mx, MAX_ROW_L);
  114.             col_max = MIN (col_mx, MAX_COL_L);
  115.             if (row_max == 0) row_max = MAX_ROW_L;
  116.             if (col_max == 0) col_max = MAX_COL_L;
  117.             err = low_res ();
  118.             *mon_lock = 0;        /* release monitor lock */
  119.             return (err);
  120.             break;
  121.         case 0x0e:            /* EGA 640x200 */
  122.             row_max = MIN (row_mx, MAX_ROW_M);
  123.             col_max = MIN (col_mx, MAX_COL_H);
  124.             if (row_max == 0) row_max = MAX_ROW_M;
  125.             if (col_max == 0) col_max = MAX_COL_H;
  126.             raster_rows = 4;
  127.             bits = 2;
  128.             err = mh_res ();
  129.             *mon_lock = 0;        /* release monitor lock */
  130.             return (err);
  131.             break;
  132.         case 0x10:            /* EGA 640x350 */
  133.             row_max = MIN (row_mx, EGA_ROWMAX);
  134.             col_max = MIN (col_mx, MAX_COL_H);
  135.             if (row_max == 0) row_max = EGA_ROWMAX;
  136.             if (col_max == 0) col_max = MAX_COL_H;
  137.             raster_rows = 8;
  138.             bits = 1;
  139.             err = mh_res ();
  140.             *mon_lock = 0;        /* release monitor lock */
  141.             return (err);
  142.             break;
  143.         case 0x40:            /* ATT high-res mode 640x400 */
  144.         case 0x48:
  145.             row_max = MIN (row_mx, MAX_ROW_H);
  146.             col_max = MIN (col_mx, MAX_COL_H);
  147.             if (row_max == 0) row_max = MAX_ROW_H;
  148.             if (col_max == 0) col_max = MAX_COL_H;
  149.             raster_rows = 8;
  150.             bits = 1;
  151.             err = mh_res ();
  152.             *mon_lock = 0;        /* release monitor lock */
  153.             return (err);
  154.             break;
  155.         default:
  156.             *mon_lock = 0;        /* release monitor lock */
  157.             return (EOF);
  158.             break;
  159.         }
  160.     }                    /* end of main part of dump routine */
  161. /*---------------------------------------------------------
  162.     This routine scans the low-res (320x200) graphics screen for active
  163.     pixels.  If no active pixels are found, only a <cr><lf> sequence
  164.     is sent to the printer.  This saves printhead motion and time. */
  165.  
  166. static int low_res ()
  167.     {
  168.     int row, last_col;
  169.     raster_rows = 4;                    /* screen rows per printer raster */
  170.     for (row = row_min; row <= row_max; row +=raster_rows)    /*starting row for printer dump */
  171.         {
  172.         if ((last_col = scan (row) ) >= col_min)
  173.             err = xmit_low (row, last_col);
  174.         if (err == EOF) return (EOF);
  175.         }
  176.     return (0);
  177.     }
  178. /*---------------------------------------------------------
  179.     This routine transmits 4 rows of data per printhead raster.  It sends 
  180.     3 bytes per column.  Color contrast is acheived by controling vertical
  181.     and horizontal dot density. Each pixel is 3 printer pixels wide and two
  182.     pixels tall to provide the correct aspect ratio for RX/FX-80/100 printers
  183.     and color representation in grey scale. */
  184.  
  185. static int xmit_low (row, last_col)
  186.     int row, last_col;
  187.     {
  188.     int row_idx, col, row_stop;
  189.     set_bit_image ( (last_col - col_min + 1) * 3);        /* set byte count */
  190.     row_stop = MIN ( row_max, row + raster_rows - 1);
  191.     for (col = col_min; col <= last_col; ++col)        /* start at col_min and stop at last col. */
  192.         {
  193.         top = 0;    /* zero pixel data buffers */
  194.         mid = 0;
  195.         for (row_idx = row_stop; row_idx >= row; --row_idx)
  196.             {
  197.             top = (char) _rotr ((unsigned int) top, 2);
  198.             mid = (char) _rotr ((unsigned int) mid, 2);
  199.             regs.x.dx = row_idx;    /* setup row # */
  200.             regs.x.cx = col;        /* setup column # */
  201.             regs.h.ah = READ_PIX;
  202.             int86 (VIDEO_INT, ®s, ®s);    /* read pixel */
  203.             switch (regs.h.al & 3)            /* only low byte used */
  204.                 {
  205.                 case 0:            /* background color */
  206.                     break;        /* do nothing */
  207.                 case 1:            /* color 1 */
  208.                     top |= 0x0c0; 
  209.                     break;
  210.                 case 2:            /* color 2 */
  211.                     mid |= 0x0c0;
  212.                     break;
  213.                 case 3:            /* color 3 */
  214.                     top |= 0x0c0;
  215.                     mid |= 0x0c0;
  216.                     break;
  217.                 }
  218.             }
  219.         if (fputc ( top, stdprn ) == EOF) return (EOF);
  220.         if (fputc ( mid, stdprn ) == EOF) return (EOF);
  221.         if (fputc ( top, stdprn ) == EOF) return (EOF);
  222.         }
  223.     if (fputc('\n', stdprn) == EOF) return (EOF);
  224.     return (0);
  225.     }
  226. /*--------------------------------------------------------
  227.     This routine scans the med-res (640x200) graphics screen and the
  228.     high-res (640x400) graphics screen for active pixels.  If no active
  229.     pixels are found, only a <cr><lf> sequence is sent to the printer.
  230.     This saves printhead motion and time. raster_rows = 4 for med-res, and
  231.     8 for high-res.  Similarly, bits = 6 for med-res, and 3 for high-res */
  232.  
  233. static int mh_res ()
  234.     {
  235.     int last_col, row, err;
  236.     for (row = row_min; row <= row_max; row +=raster_rows)    /*starting row for printer dump */
  237.         {
  238.         if ((last_col = scan (row) ) >= col_min)
  239.             err = xmit_mh (row, last_col);
  240.         if (err == EOF) return (EOF);
  241.          }
  242.     return (0);
  243.      }
  244. /*--------------------------------------------------------
  245.     This routine transmits 4 rows of data per printhead raster.  It 
  246.     sends 3 bytes/2 columns. The 2nd byte is transmitted as the 
  247.     logical OR of the columns on either side of it.  In this way, the 
  248.     aspect ratio is corrected without biasing the drawing in favor of 
  249.     even or odd columns. */
  250.  
  251. static int xmit_mh (row, last_col)
  252.     int row, last_col;
  253.     {
  254.     register int row_idx, row_stop, col;
  255.     int idx, err;
  256.     unsigned char pixel;
  257.     idx = last_col - col_min + 1;                /* true column count */
  258.     set_bit_image ( idx  + (idx >> 1) + (idx & 1) );    /* set byte count */
  259.     row_stop = MIN ( row_max, row + raster_rows - 1);
  260.     mid = 0;
  261.     for (col = col_min; col <= last_col; ++col)        /* start at col_min and stop at last col. */
  262.         {
  263.         top = 0;
  264.         for (row_idx = row_stop; row_idx >= row; --row_idx)
  265.             {
  266.             regs.x.dx = row_idx;
  267.             regs.x.cx = col;        /* pixel at (row,col) = (dx,cx) */
  268.             regs.h.ah = READ_PIX;
  269.             int86 (VIDEO_INT, ®s, ®s);
  270.             /* value returned in al reg. */
  271.             pixel = 0;
  272.             if (regs.h.al != 0) pixel = 0x80;    /* set top pixel: only 1 bit for BW modes */
  273.             for (idx = 0; idx < bits; ++idx)    /* shift in the pixel data */
  274.                 {
  275.  
  276.                 top = (unsigned char) _rotr ((unsigned int) top, 1);
  277.                 top |= pixel;
  278.  
  279.                 }
  280.  
  281.             }
  282.         mid |= top;    /* merge the column data */
  283.         if (fputc ( top, stdprn ) == EOF) return (EOF);
  284.         if (col & 1)
  285.             {
  286.             if (fputc ( mid, stdprn ) == EOF) return (EOF);
  287.             mid = 0;
  288.             }
  289.         }
  290.     if (col & 1)    /* need to print merged byte if last */
  291.         {
  292.         if (fputc ( mid, stdprn ) == EOF) return (EOF);
  293.         }
  294.     if (fputc ( '\n', stdprn ) == EOF) return (EOF);
  295.     return (err);                        /* column was an odd col. number */
  296.     }
  297.  
  298. /*--------------------------------------------------------*/
  299. static int pdump ( data ) union  { unsigned char pix[4]; unsigned long p;} data;
  300.     {
  301.     register int idx;
  302.     /* send bytes of raster data to printer */
  303.  
  304.     for (idx = 3; idx > 0; --idx)
  305.         {
  306.         if (fputc ( data.pix[idx], stdprn ) == EOF) return (EOF);
  307.         }
  308.     return (0);
  309.     }
  310. /*---------------------------------------------------------
  311.     This routine scans the columns and finds the last column where an active
  312.     pixel exists, if any.  When it returns, (dx,cx) contain the (row,col)
  313.     of the last location scanned.  If (dx,cx) >= (row_min,col_min) then there
  314.     is an active pixel to transmit to the printer.
  315.     */
  316. static int scan (row)
  317.     int row;
  318.     {
  319.     register int col_idx, row_idx, row_stop;
  320.     row_stop = MIN ( row_max + 1, row + raster_rows);
  321.     for (col_idx = col_max; col_idx >= col_min; --col_idx)
  322.         {
  323.         for (row_idx = row; row_idx < row_stop; ++row_idx)
  324.             {
  325.             regs.h.ah = READ_PIX;
  326.             regs.x.dx = row_idx;
  327.             regs.x.cx = col_idx;
  328.             int86 (VIDEO_INT, ®s, ®s);
  329.             if (regs.h.al != 0) return (col_idx);
  330.             }
  331.         }
  332.     return (col_idx);
  333.     }
  334. /*---------------------------------------------------------*/
  335. static int set_lpi()
  336.     {
  337.     if (fputs ( "\015\012\033\063\030", stdprn ) == EOF) return (EOF);
  338.     return (0);    /* <cr><lf><esc>'3 '<24> :  set printer to 24/2160 inch vert line spacing */
  339.     }
  340. /*---------------------------------------------------------*/
  341. static int reset_lpi()
  342.     {
  343.     if (fputs ("\033\062", stdprn ) == EOF ) return (EOF);
  344.     return (0);    /* <esc> '2' : set printer to 6 lpi vert spacing */
  345.     }
  346. /*---------------------------------------------------------*/
  347. static int set_bit_image (count) int count;
  348.     {
  349.     /* set printer for bit image mode.
  350.     and send the byte count */
  351.     if (fputs ("\033L", stdprn)  == EOF) return (EOF);    /* <esc> L set double density graphics */
  352.     if (fputc ( (char) count, stdprn) == EOF) return (EOF);
  353.     if (fputc ( (char) (count >> 8), stdprn) == EOF) return (EOF);
  354.     return (0);
  355.                 /* <esc>*<39h> <count % 256> <count/256> */
  356.     }
  357.