static char copyr[] = "Copyright 1990 by Dr. R. Brooks Van Horn, Jr."; /* This version of the Print Screen routine is for the Epson LQ 2500 series printer and a VGA or EGA video adaptor with the higher resolution video modes, including super VGA. These C-routines were written using Mix's Power C. */ #include #include #include #include #include #include #include #define DITHER 7 /* dimension of dithering matrix */ #define dpi 180 /* printer resolution in dots per inch */ #define pmode 39 /* 24 pin mode for the dpi resolution */ #define esc 27 /* functions needed in program */ void interrupt (far * int05)(void); void interrupt PrtScrn (void); int Print ( int, char * ); int Graphics ( char, char, char ); void PinSet ( char *, char *, char *, int, int ); char Read_Pixel (int, int); /* static global data needed */ static int Max_Rows; static int Max_Cols; static int number; static int phase; static char Video_Mode; static long Columns; int h_ratio, h_fract, v_ratio, v_fract; char far * dds = 0x00000000; /* DOS Data Segment */ int far * dkb = 0x0000041a; /* DOS Keyboard Area */ char far * vds = 0x00000500; /* Video Data Segment */ char far * Regen = 0xa0000000; /* Video Screen Address */ struct PINS { int first [12]; int last [12]; char value [12]; } head; /*----------------------------------------------------------------------*/ main () { unsigned int pgm_size; char far * ptr = 0x00000467; /* use cassette data area */ number = 0; *vds = 0; if (*ptr == 'b' && *(ptr+1) == 'v' && *(ptr+2) == 'h') { puts ("Epson24.Exe TSR is already resident."); exit (1); } int05 = getvect (0x05); *(ptr ) = 'b'; *(ptr+1) = 'v'; *(ptr+2) = 'h'; setvect (0x05, PrtScrn); pgm_size = farsetsize(0); puts ("Epson LQ-2500 Graphics Print Screen TSR"); puts ( copyr ); puts ("has now been installed."); keep (0, pgm_size); } /*----------------------------------------------------------------------*/ void interrupt PrtScrn (void) { int row, col, index, height, cbit, error, tsum, kb_head, kb_tail; int col_to_do, total, pin, i, j, k, rtot, extra, tcheck, kntr; char pat, pat1, pat2, pat3, zero = 0x00; char init_prn[] = { esc, '@' }; /* inititialize printer */ char graph[] = { esc, '*', pmode, 0, 0 }; /* 24 pin graphics 180 dpi */ char set_lf_180[] = { esc, '3', 24 }; /* set line feed to 24/180" */ char crlf[] = { 0x0d, 0x0a }; /* do cr/lf cmd */ char eop[] = { 0x0c, esc, '@' }; /* reset & eject page */ char ahp[] = { esc, '$', 60, 0 }; /* move 1" from left margin */ union REGS regs; /* if user pushed called us twice with no result then do it now */ if (++number > 1) *vds = 0; if (*vds != 0) { /* if printing is active then exit */ sound (1500,5); sound (1000,5); sound (1500,5); return; } number = 0; Video_Mode = *(dds + 0x0449); if ((Video_Mode < 4) || (Video_Mode == 7)) {/* if not a graphics mode */ int05(); *vds = 0; return; } /* we are now in a position to do a print screen */ *vds = 0xff; /* mark print screen status flag for others */ enable(); /* enable further interrupts */ kb_head = *(dkb); kb_tail = *(dkb+1); Max_Rows = (int) *(dds + 0x0484) + 1; Max_Cols = ((int) *(dds + 0x044a)) + (((int) *(dds + 0x0000044b)) << 8); height = (int) *(dds + 0x0485); Max_Rows *= height; /* convert text chars to pixels */ Columns = (long) Max_Cols; Max_Cols *= 8; /* The dimensions of the screen were obtained from the bios data area. The next step is to determine the size of the picture based on reserving a one inch margin on all sides and trying to use a 5 x 5 dithering matrix. We use the term vertical to represent the direction along the 8.5" side of the printer paper and horizontal along the 11" side. ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ 1" ³ ³ ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿ ³ ³ ³ Top ³ ³ ³ ³ ³ ³ ³ ³ ³ ³ <------- ³ 1"³ Picture ³1" ³ 8.5"(v) Paper ³ ³ ³ ³ Feed ³ ³Left ³ ³ ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ ³ ³ 1" ³ ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ 11" (h) */ v_ratio = (13 * dpi) >> 1; /* setup for 6.5" along vertical side */ /* but adjust if it is too big for dithering matrix */ v_ratio = v_ratio > (DITHER * Max_Rows) ? (DITHER * Max_Rows) : v_ratio; h_ratio = (4 * v_ratio + 1) / 3; /* 4:3 ratio adj for length */ /* get the fraction part of the ratio for vertical and horizontal */ v_fract = v_ratio % Max_Rows; v_fract = (10 * v_fract + (Max_Rows>>1)) / Max_Rows; /* in [0,9] */ h_fract = h_ratio % Max_Cols; h_fract = (10 * h_fract + (Max_Cols>>1)) / Max_Cols; /* in [0,9] */ /* then get the integer part of the ratios */ v_ratio = v_ratio / Max_Rows; h_ratio = h_ratio / Max_Cols; /* now check for overflows in rounding too high */ if (v_fract >= 10) { v_ratio++; v_fract -= 10; } if (h_fract >= 10) { h_ratio++; h_fract -= 10; } /* define the number of bytes to send printer per line of graphics */ tcheck = ((10 * v_ratio + v_fract) * Max_Rows) / 10; graph[3] = tcheck & 0x00ff; graph[4] = tcheck >> 8; /* initialize the printer */ regs.byte.ah = 1; regs.word.dx = 0; int86 ( 23, ®s, ®s ); /* initialize port LPT0 */ if ( Print ( 2, init_prn ) ) /* reset the printer */ goto GET_OUT; for (k = 0; k < 5; ++k) /* make a 1" top margin */ if ( Print ( 2, crlf ) ) goto GET_OUT; if ( Print ( 3, set_lf_180 ) ) goto GET_OUT; /* for the 24 pin printer, get the number of column pixels/pass */ col_to_do = 240 / (10 * h_ratio + h_fract); kntr = 0; for ( col = 0; col < Max_Cols; col += col_to_do ) { /* move print head 1" from the left margin */ if ( Print ( 4, ahp ) ) /* advance to horizontal position */ goto GET_OUT; /* check for key pressed */ if ((*dkb != kb_head) || (*(dkb+1) != kb_tail)) { *dkb = kb_head; /* restore head of kbd */ *(dkb+1) = kb_tail; /* restore tail of kbd */ Print ( 3, eop ); goto GET_OUT; } /* declare number of items to send to printer */ tsum = 0; if ( Print ( 5, graph ) ) goto GET_OUT; rtot = 0; extra = 0; for (row = Max_Rows-1; row >= 0; --row ) { total = 0; pin = 0; k = 0; /* for this row, get the next col_to_do column values */ for ( cbit = 0; cbit < col_to_do ; ++cbit ) { /* read a pixel's color */ pat = Read_Pixel ( row, (col+cbit) ); /* replicate that color at h_ratio pins */ pin += h_ratio; /* add fraction in to the sum */ total += h_fract; if (total >= 10) { /* adjust for fractionals */ total -= 10; ++pin; } head.first [cbit] = k; /* 1st pin location */ head.last [cbit] = pin; /* last pin location */ head.value[cbit] = pat; /* pen color */ k = pin; } /* We now have the pins loaded, next determine the three dithered bytes to use for this print head. */ rtot = v_ratio; /* vert no to duplicate */ extra += v_fract; /* spill-over */ if (extra >= 10) { ++rtot; extra -= 10; } /* combine the col_to_do pins into 3 bytes to be printed */ for ( k = 0; k < rtot; k++) { if (++tsum <= tcheck) { PinSet ( &pat1, &pat2, &pat3, k, col_to_do ); if ( Graphics ( pat1, pat2, pat3 ) ) goto GET_OUT; } } /* end for k loop on PinSet */ } /* end for-loop on rows */ for ( ; tsum <= tcheck; ++tsum ) { Graphics ( zero, zero, zero ); } /* do a cr/lf on the printer at the end of line of graphics */ if ( Print (2, crlf) ) goto GET_OUT; } /* end for-loop on cols */ Print ( 3, eop ); /* reset the printer and do a form feed */ GET_OUT: *vds = 0; return; } /*----------------------------------------------------------------------*/ char Read_Pixel ( int row, int col ) { long offset = (long)(col>>3) + (long) row * Columns; int plane; char color = 0x00, mask, temp; union REGS regs; if ((row > Max_Rows) || (col > Max_Cols)) return 0; if (Video_Mode < 8) { /* for non-ega/vga modes do */ /* a ROM BIOS call to get color */ regs.word.ax = 0x0d00; regs.word.bx = 0; regs.word.cx = col; regs.word.dx = row; int86 ( 16, ®s, ®s ); color = regs.byte.al; } else { /* use ega/vga registers to get the color */ mask = 0x80 >> (col % 8); /* the bit mask for addressed byte */ outp (0x3ce,4); /* select the Map Mask register */ for (plane = 3; plane >= 0; --plane) { outp (0x3cf,plane); /* address the bit plane */ temp = *(Regen + offset) & mask; /* mask off the color bit */ temp = temp ? 1 : 0 ; /* set bit if color match */ color = (color << 1) | temp; /* save plane results */ } outp (0x3c4,2); /* restore adaptor to Write Mode 0 */ outp (0x3c5,15); /* with all planes enabled */ } return color; } /*----------------------------------------------------------------------*/ void PinSet ( pat1, pat2, pat3, sect, maxc ) char *pat1, *pat2, *pat3; /* the three bytes to be sent to the printer */ int sect; /* which relative print head column we are on */ int maxc; /* the number of entries in the head structure */ { char pat; char pats[DITHER][DITHER]; /* the dithering matrix */ char R, G, B, I; int bit, k, ndx, b1, b2, wd, i, j, top, kmod; union COVER { /* equivalence is needed for the 24 pins */ long lword; char bytes[4]; } cover; top = v_ratio; if (v_fract) ++top; top = top < DITHER ? top : DITHER; *pat1 = *pat2 = *pat3 = 0x00; for (ndx = 0; ndx < maxc; ++ndx) { /* retrieve the color for this pin section */ pat = head.value[ndx]; b1 = head.first[ndx]; b2 = head.last [ndx]; if (!pat) /* skip remainder if this is a zero byte */ continue; /* get planes that are on in the pattern */ switch (top) { case 1: case 2: R = pat; kmod = 1; break; case 3: R = (pat & 0x03); /* B or R */ G = (pat & 0x0c); /* G or I */ kmod = 2; break; case 4: B = pat & 0x09; /* B or I */ R = pat & 0x0a; /* R or I */ G = pat & 0x0c; /* G or I */ I = pat & 0x08; /* I */ kmod = 3; break; default: B = pat & 0x01; R = pat & 0x02; G = pat & 0x04; I = pat & 0x08; kmod = 4; } for (i = 0, k = 0; i < top; ++i) { for (j = 0; j < top; ++j, ++k) { switch ( k % kmod ) { case 0: pats[i][j] = R; break; case 1: pats[i][j] = G; break; case 2: pats[i][j] = B; break; case 3: pats[i][j] = I; } /* end switch block */ } /* end for j loop */ } /* end for i loop */ /* now create bytes for printing with these patterns */ cover.lword = 0L; for (bit = b1; bit < b2; ++bit) { k = bit - b1; /* col index to pats array */ if (pats[k][sect]) { /* if we are to dither this */ j = bit; wd = j / 8; /* word index */ i = 7 - ( j % 8 ); /* bit index */ cover.bytes[wd] |= (0x01 << i); /* and the bit mask */ } } *pat1 |= cover.bytes[0]; *pat2 |= cover.bytes[1]; *pat3 |= cover.bytes[2]; } return; } /*--------------------------------------------------------------*/ int Graphics ( char byte1, char byte2, char byte3 ) { char array[3]; array[0] = byte1; array[1] = byte2; array[2] = byte3; return ( Print (3, array) ); } /*--------------------------------------------------------------*/ int Print ( int items, char * strng ) { int i; int result; union REGS regs; for (i= 0; i < items; ++i) { regs.byte.ah = 0; /* function number */ regs.byte.al = strng[i]; /* character to print */ regs.word.dx = 0; /* printer Lpt0 */ int86 ( 23, ®s, ®s ); result = (int) regs.byte.ah; /* printer return code */ if (result & 0x0029) { /* printer error */ sound ( 750, 27 ); return ( result ); } } return 0; }