static char copyr[] = "Copyright 1990 by Dr. R. Brooks Van Horn, Jr."; /* This version of the Print Screen routine is for the HP Laser series printers and a VGA or EGA video adaptor with the higher resolution video modes, including super VGA. */ #include #include #include #include #include #include #include #define dither 6 #define esc 27 #define LENMAX 770 /* functions needed in program */ void interrupt (far * int05) (void); void interrupt PrtScrn (void); int Print ( int, char * ); void PinSet ( int, int, int, int ); char Read_Pixel (int, int); /* data needed */ static int dpi = 300; static long Columns; static int Max_Rows; static int Max_Cols; static char Video_Mode; int far * dkb = 0x0000041a; /* DOS Keyboard Area */ char far * dds = 0x00000000; /* DOS Data Segment */ char far * vds = 0x00000500; /* Video Data Segment */ char far * Regen = 0xa0000000; /* Video Screen Address */ char buffer[LENMAX], pline[256]; int h_ratio, h_fract, v_ratio, v_fract; static int number; /*----------------------------------------------------------------------*/ 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 ("Laser.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 ("Laser Graphics Print Screen TSR"); puts ( copyr ); puts ("has now been installed."); keep (0, pgm_size); } /*----------------------------------------------------------------------*/ void interrupt PrtScrn (void) { int kb_head = *dkb, kb_tail= *(dkb+1); int row, col, cbit, error; int total, pin, i, j, k, rtot, extra, tcheck, begin, lenth; char pat, pat1, pat2, pat3, zero = 0x00; char crlf[] = { 0x0d, 0x0a }; /* do cr/lf cmd */ char init_prn[] = { esc, 'E', /* Reset */ esc, '&', 'l', '0', 'O', /* Portrait */ esc, '*', 't', '3', '0', '0', 'R', /* dpi resolution */ esc, '&', 'a', '6', '5', '0', 'H', /* move cursor from left */ esc, '&', 'a', '2', '0', '0', 'V', /* and from the top */ esc, '*', 'r', '1', 'A' /* strt grphs @ cursor pos */ }; /* Transmit xxx bytes of data following command */ char graph[] = { esc, '*', 'b', 'x', 'x', 'x', 'W', 0, 0 }; char width[] = " "; char eop[] = { esc, '*', 'r', 'B', /* end graphics */ 12, /* form feed */ esc, 'E' /* and reset printer */ }; union REGS regs; if (++number > 2) *vds = 0; if (*vds != 0) { /* if printing is active then exit */ sound ( 950, 18 ); return; } Video_Mode = *(dds + 0x0449); if (Video_Mode <= 3) {/* if we are not in a graphics mode */ int05(); 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 */ Max_Rows = (int) *(dds + 0x0484) + 1; Max_Cols = ((int) *(dds + 0x044a)) + (((int) *(dds + 0x0000044b)) << 8); Max_Rows *= (int) *(dds + 0x0485); /* 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); /* 6.5" * dots per inch */ /* 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; } /* now get the actual bytes to be sent to the printer per pass */ tcheck = ((((10 * v_ratio + v_fract) * Max_Cols) / 10) + 7) >> 3; /* initialize the printer */ regs.byte.ah = 1; regs.word.dx = 0; int86 ( 0x17, ®s, ®s ); /* initialize port LPT0 */ if (Print ( 33, init_prn )) { /* reset the printer */ *vds = 0; return; } /* We now process the video screen from the left to the right on the columns. The given pixel values will be dithered to provide a shading like effect for the black and white laser printer. */ total = 0; for ( col = 0; col < Max_Cols; ++col) { if ((col % 100) == 0) sound ( 1500, 1 ); /* check to see if a key has been pressed */ if ((*dkb != kb_head) || (*(dkb+1) != kb_tail)) { *dkb = kb_head; *(dkb+1) = kb_tail; Print ( 7, eop ); goto GET_OUT; } /* read a row of pixels for this column */ for (i = 0, row = Max_Rows-1; row >= 0; --row, ++i ) buffer[i] = Read_Pixel ( row, col ); /* clear out the printer line for packing */ memset ( pline, 0, 256 ); /* now build the 'tcheck' bytes to send to the printer remembering that we will be multiline processing too. */ pin = h_ratio; /* add fraction in to the sum */ total += h_fract; if (total >= 10) { /* adjust for fractionals */ total -= 10; ++pin; } /* This column will be processed 'pin' times in dither length */ for (k = 0; k < pin; ++k) { extra = 0; rtot = 0; begin = 0; lenth = 1; for (i = 0; i < Max_Rows; ++i) { rtot += v_ratio; extra += v_fract; if (extra >= 10) { extra -= 10; ++rtot; } if (buffer[i]) lenth = rtot; PinSet ( i, k, begin, rtot ); begin = rtot; } /* declare number of items to send to printer */ lenth = (lenth + 7) >> 3; itoa ( lenth, width, 10); if (lenth >= LENMAX) { puts (width); lenth = LENMAX; sound (1100,36); } strcpy ( &graph[3], width ); /* copy # bytes to txmt */ strcat (graph, "W"); for (j = 0; graph[j]; ++j) ; /* get length of string */ if ( Print ( j, graph ) ) goto GET_OUT; if ( Print ( lenth, pline ) ) goto GET_OUT; } /* end for-loop on duplicate rows */ } /* end for-loop on cols */ Print ( 7, eop ); GET_OUT: sound ( 1500, 9 ); *vds = 0; number = 0; return; } /*----------------------------------------------------------------------*/ char Read_Pixel ( int row, int col ) { long offset = (long) row * Columns + (long)(col>>3); int plane, k; char color = 0x00, mask, temp; union REGS regs; if (row >= Max_Rows || col >= Max_Cols) return 0; if (Video_Mode < 8) { /* if CGA let BIOS do it */ regs.word.ax = 0x0d00; regs.word.bx = 0; regs.word.dx = row; regs.word.cx = col; int86 ( 16, ®s, ®s ); color = regs.byte.al; } else { mask = 0x80 >> (col % 8); /* 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; /* get bit value */ temp = temp ? 1 : 0 ; /* set bit if color match */ color = (color << 1) | temp; /* save plane results */ } outp (0x3c4,2); /* restore to Write Mode 0 */ outp (0x3c5,15); /* with all planes enabled */ } return color; } /*----------------------------------------------------------------------*/ void PinSet ( ndx, sect, b1, b2 ) int ndx; /* index to the color pattern to be smoothed */ int sect; /* the row duplication index */ int b1; /* the beginning bit to set */ int b2; /* the last bit to set */ { char pats[dither][dither]; int bit, j, k, wd, i, kmod; char I, R, G, B, pat = buffer[ndx]; if (pat == 0) /* if nothing to set then return */ return; k = v_ratio >= dither ? dither : (v_ratio + 1); switch ( k ) { case 1: case 2: case 3: I = R = G = B = pat; kmod = 1; break; case 4: case 5: 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; } bit = 0; for (i = 0; i < k; ++i) { for (j = 0; j < k; ++j, ++bit) { switch ( bit % 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; } } } /* now create bytes for printing with these patterns */ for (bit = b1; bit < b2; ++bit) { k = bit - b1; /* row index to pats array */ if (pats[k][sect]) { /* if dithering has something here */ wd = bit / 8; /* word index */ i = 7 - ( bit % 8 ); /* bit index */ pline[wd] |= (0x01 << i); /* and the bit mask */ } } return; } /*--------------------------------------------------------------*/ 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 ( 0x17, ®s, ®s ); result = (int) regs.byte.ah; /* printer return code */ if (result & 0x0029) { /* printer error */ return ( result ); } } return 0; }