page 60,132 title Graphics Module for Print Screen with EGA and Epson Printer ; Revised 17 Nov 1989 by Joe Doupnik ; Add initial jump label start: and identify it for the DOS loader. ; Relabel "Out" to be "Out1" to avoid assembler keyword. ; ; Revised 6 Dec 1989 by Frank da Cruz ; Change Epson initialization and restore strings: ; Disable perforation skip and paper-out detect during graphics print. ; Restore string is now ESC @ (initialize) rather than ESC 0 (1/8"/line) Epson segment para public 'code' assume cs:Epson,ds:Epson,es:Epson comment # This routine is for public domain for those of you who bought an EGA and enhanced monitor and determined that you could no longer do a Shf_Prt_Scn in mode 10h (16). If you have an IBM compatible and an Epson FX series printer then this routine will replace the GRAPHICS.COM routine. I also have routines for Radio Shack DMP printers with 8 pins (but only 7 usable for graphics) and for HP LaserJet printers when used with an EGA. Enjoy... Dr. R. Brooks Van Horn, Jr. 701 Fall Place Herndon, VA. 22070 # org 100h start: jmp Setup Mlen db 'EGA Graphics Ver 1.0' Cmp_Str dw $-mlen ; normal int 5 entry point Begin: pushf ; enable further interrupts push ax push bx push bp push di push si mov ah,15 ; setup a function call to dos to int 10h ; get the video mode and ax,007fh ; mask off unwanted data mov cs:[Mode],ax ; and save it for future use cmp al,7 ; is this a mono card? jz Out1 ; yes, exit - when in text mode cmp al,3 ; see if we are in the graphics mode? jg cont ; yes, go around using dos Out1: pop si ; restore the registers saved pop di pop bp pop bx pop ax popf ;----- jump far to Dos db 0EAh ; jump far segment to Print dos dw 0 ; offset of jump dos2 dw 0 ; segment of jump Cont: push cx ; and save all the registers push dx push ds push es push cs ; now put code seg register into pop es ; the extra segment register xor ax,ax mov ds,ax inc al ; see if we are already being done mov al,Byte Ptr ds:[500h] ; get the current mode and also set it or al,al jnz Getout ; if 550h was not zero then exit push cs pop ds xchg al,Byte Ptr cs:switch or al,al jnz GetOut sti mov cs:[sp_save],sp jmp Process Return: mov si,Offset Restore mov cl,cs:[si] ; get number of bytes to print xor ch,ch inc si call Tabptr ; restore printer to original state Exit: mov sp,cs:[sp_save] xor ax,ax mov Byte Ptr cs:switch,al ; set value to zero Getout: pop es ; restore registers and exit pop ds pop dx pop cx pop si pop di pop bp pop bx pop ax popf sti iret ; bye............... ;-------------------------------------------------------------------- ; Epson FX Printer with IBM-PC ;-------------------------------------------------------------------- Line_Sp db 7,27,51,24,27,79,27,56 ; Control Codes for 24/216" line spacing ; Also disable perforation skip (ESC O) and ; disable paper-out detect (ESC 8) (fdc) Set_Graf db 4,27,76 ; Cntrl Code for each graphics line printed Col_2_Do dw 0 ; last column number to be printed Restore db 2,27,64,12 ; change count to 3 if you want a form feed ; changed from ESC 0 to ESC @ (fdc) Line_Buf db 960 dup (?) ; line buffer Eight dw 8 Four dw 4 Switch db 0 Sp_Save dw 0 Mode dw 0 ; Current Video Mode Rows dw 0 ; Number of rows for this mode Cols dw 0 ; Number of columns for this mode ; Modes = 4 5 6 7 8 9 A B C D E F 10 Col_Mode dw 320,320,640, 0, 0,320,640, 0,720,320,640,640,640 Row_Mode dw 200,200,200, 0, 0,200,200, 0,348,200,200,350,350 ;-------------------------------------------------------------------- ; Print a Table of Control Values ; =============================== ; Tabptr: mov al,cs:[si] call Printer inc si loop Tabptr nop ret ; ; Send an alarm bell sound ; ======================== ; Bell: mov al,7 mov ah,14 int 10h ret ; Send the character in AL to the printer ; ======================================= ; Printer: push dx sub dx,dx xor ah,ah int 17h pop dx test ah,25h jnz Error ret ; ; Error returns on printer commands ; ================================= ; Error: call Bell call Bell jmp Exit ; ; Send a form feed to the Printer ; =============================== ; Cr_Lf: push dx sub dx,dx mov ax,0dh int 17h mov ax,0ah int 17h pop dx test ah,25h jnz Error ret ;--------------------------------------------------------------------- ; l ; Graphics Processing Section l ; l ;--------------------------------------------------------------------- Process: mov bp,cs:[Mode] sub bp,4 sal bp,1 mov ax,cs:Row_Mode[bp] ; save rows-1 and cols-1 dec ax mov cs:Rows,ax mov ax,cs:Col_Mode[bp] dec ax mov cs:Cols,ax mov ah,1 ; initialize the printer xor dx,dx int 17h mov si,Offset cs:Line_Sp ; setup for correct interline spacing mov cl,cs:[si] ; get length xor ch,ch inc si call TabPtr mov ax,cs:[Cols] ; decide to do graphics by row or column mode cmp ax,320 jg By_Rows jmp By_Cols ;-------------------------------------------------------------------- ; for By_Rows calls we have usually 640 x 200 type, so do 200 ; across and 640 down the page. This means that we can only ; single dot to get lines to connect on the printer paper. ;-------------------------------------------------------------------- By_Rows: mov cx,0 ; start the column index at zero Br_Strt: push cx ; save the current column index mov dx,cs:[Rows] ; initialize the row count to max mov bh,Byte Ptr cs:[Eight] xor si,si ; max characters to print mov cs:[Col_2_Do],si mov di,Offset cs:Line_Buf xor bl,bl ; do for a count of 'Eight' Br_Cont: call Read ; read the next dot at (row,col) and al,07fh ; check if any thing is there jz Br_Fill ; and skip if nothing there mov al,1 ; else fill the byte Br_Fill: shl bl,1 ; move reg left one bit or bl,al ; and or in the next value inc cx ; increment the column count dec bh ; and the loop index jnz Br_Cont ; continue loop for 8 times ; undo add si,2 ; add two to the column counter mov Byte Ptr cs:[di],bl ; save filled byte mov Byte Ptr cs:[di+1],bl ; twice for filling cmp cs:[Rows],199 ; check for less than 200 rows jg Br_Two mov Byte Ptr cs:[di+2],bl ; and 3 times for low resolution inc di inc si Br_Two: add di,2 ; up the buffer ptr or bl,bl ; do we have anything to print? jz Br_Skp ; no, skip mov cs:[Col_2_Do],si ; save index Br_Skp: mov bh,Byte Ptr cs:[Eight] ; set loop for 8 more cols per row dec dx ; delete one from the row index pop cx ; restore the column count push cx ; and save it again for this row cmp dx,0 ; and test to see if we are finished jge Br_Cont ; loop mov cx,cs:[Col_2_Do] ; get the number of bytes to print or cx,cx jz Br_NoP ; skip if didn't get anything push cx ; save number to do mov si,Offset cs:Set_Graf ; setup for graphics mov cl,cs:[si] ; get length xor ch,ch inc si ; point past length field call TabPtr ; perform the setup pop cx ; now get the real characters to do mov si,Offset cs:Line_Buf ; get print line pointer call TabPtr ; and print the line Br_NoP: call Cr_Lf ; do carriage return and line feed at end pop cx add cx,cs:[Eight] ; add 8 to column count cmp cx,cs:[Cols] ; compare to max to do jg Br_Ret jmp Br_Strt ; continue until fini Br_Ret: jmp Return ; restore printer and exit ;-------------------------------------------------------------------- ; for By_Cols calls we have usually 320 x 200 type, so do 320 ; across and 200 down the page. This means that we must double ; dot to get lines to connect on the printer paper. ;-------------------------------------------------------------------- By_Cols: mov dx,0 ; start the row index at zero ; for each row do all the columns Bc_Strt: push dx ; save the current row index mov cx,0 ; initialize the col count to start mov bh,Byte Ptr cs:[Four] xor si,si ; max characters to print mov cs:[Col_2_Do],si mov di,Offset cs:Line_Buf ; for each column in the row, do Bc_Cont: call Read ; read the next dot at (row,col) and al,07fh ; check if any thing is there jz Bc_Fill ; and skip if nothing there mov al,3 ; else fill the byte from the bottom Bc_Fill: shl bl,1 ; move reg left one bit shl bl,1 ; and repeat or bl,al ; and 'or' in the next value inc dx ; increment the row count dec bh ; and the loop index jnz Bc_Cont ; continue loop for 4 times add si,3 ; add three to the column counter mov Byte Ptr cs:[di],bl ; save filled byte mov Byte Ptr cs:[di+1],bl ; twice for filling mov Byte Ptr cs:[di+2],bl ; and three times for a lady add di,3 ; up the buffer ptr or bl,bl ; see if anything is there jz Bc_Skp ; skip if we have nothing to plot mov cs:[Col_2_Do],si ; save index Bc_Skp: mov bh,Byte Ptr cs:[Four] ; set loop for 8 more cols per row inc cx ; add one to the col index pop dx ; restore the row count push dx ; and save it again for this row cmp cx,cs:[Cols] ; and test to see if we are finished jle Bc_Cont ; loop mov cx,cs:[Col_2_Do] ; get the number of bytes to print or cx,cx jz Bc_NoP ; skip if didn't get anything push cx ; save number to do mov si,Offset cs:Set_Graf ; setup for graphics mov cl,cs:[si] ; get length xor ch,ch inc si ; point past length field call TabPtr ; perform the setup pop cx ; now get the real characters to do mov si,Offset cs:Line_Buf ; get print line pointer call TabPtr ; print the line Bc_NoP: call Cr_Lf pop dx add dx,cs:[Four] ; add to column count cmp dx,cs:[Rows] ; compare to max to do jg Bc_Ret ; if fini then exit jmp Bc_Strt ; else go do next row Bc_Ret: jmp Return ; restore printer and exit ;-------------------------------------------------------------------- ; ; Read Dot Routine Using DOS/BIOS or VDI interface for int 10h ; ;------------------------------------------------------------------- Read: xor al,al cmp dx,0 ; see if all is ok jl Read_Ret cmp cx,cs:[Cols] ; also check on overdoing it jg Read_Ret cmp cs:[Mode],10h je Read_Dot ; if mode = 10 then do special I/O mov ah,13 push bx push cx push dx int 10h pop dx pop cx pop bx xor ah,ah ; clear the high byte for testing Read_Ret: ret ;--------------------------------------------------------------- ; ; Read a Pixel (Dot) from the EGA using Read Mode 0 ; ;---------------------------------------------------------------- Read_Dot: push bx push cx push dx mov ax,dx ; save column value mov bx,cx ; and row value mov dx,0a000h ; Video ram address mov ds,dx ; into segment register mov dx,80 mul dx ; column * 80 shr bx,1 shr bx,1 shr bx,1 ; row / 8 add bx,ax ; actual data byte address and cl,7 ; row mod 8 xor cl,7 ; bit mask 7 - (row mod 8) mov ch,1 shl ch,cl ; 2^mask mov ah,3 ; initialize bit plane number Plane_Loop: mov dx,03CEh ; EGA Controller mov al,4 ; map select register out dx,al mov dx,03CFh ; data register mov al,ah ; select bit planes 3,2,1,0 out dx,al mov al,ds:[bx] ; read bit plane shl cl,1 and al,ch jz Not_On or cl,1 Not_On: dec ah jge Plane_Loop and cl,0fh mov al,cl pop dx pop cx pop bx ret dw -1 ; fense ;-------------------------------------------------------------------- ; ; Initialization Routine for EPSON.COM ; ;-------------------------------------------------------------------- Setup: xor ax,ax mov es,ax ; setup to address segment zero mov cx,es:[0016h] ; get current segment mov bx,es:[0014h] ; and offset mov ds,cx ; make that the data segment mov cx,cs:[Cmp_Str] ; setup to check bytes for same mov si,Offset cs:mlen ; data field "Graphic..." mov bx,si Check: mov ax,cs:[si] ; get a byte in accum cmp ax,ds:[bx] ; is it the same jne Ok ; no, then we are ok inc si ; otherwise, increment pointers inc bx ; to both fields loop Check ; and loop for 7 checks mov ax,cs mov ds,ax mov ah,09h mov dx,Offset Message1 int 21h int 20h ; if same then dont overlay but exit Ok: mov bx,es:[0014h] ; get the current offset in int vector mov ax,cs ; now setup to display a message mov ds,ax mov Word Ptr dos,bx ; and save it locally mov bx,es:[0016h] ; get the segment location of item too mov Word Ptr dos2,bx ; and save it also mov ax,cs ; save our entry at int vector mov es:[0016h],ax ; segment mov bx,Offset cs:Begin ; define entry point to routine mov es:[0014h],bx ; offset mov di,Offset Field1 call Convert ; convert starting address mov di,Offset Field2 mov bx,Offset Setup add bx,15 ; convert to next paragraph addr mov cl,4 shr bx,cl add ax,bx call Convert ; and the new ending address mov ah,09h ; now do our message mov dx,Offset Message2 int 21h mov dx,Offset cs:Setup int 27h ; terminate but stay resident Convert proc near ; ; ax = number to be converted ; di = address of field in which to put the hex characters ; push ax push bx push cx push dx lea bx,Ascii mov cl,4 mov dx,ax mov al,ah shr al,cl xlat Ascii mov Byte Ptr cs:[di],al mov al,dh and al,0fh xlat Ascii mov Byte Ptr cs:[di+1],al mov al,dl shr al,cl xlat Ascii mov Byte Ptr cs:[di+2],al mov al,dl and al,0fh xlat Ascii mov Byte Ptr cs:[di+3],al pop dx pop cx pop bx pop ax ret Convert endp Message1 db 'EGA Graphics routine is already resident',13,10,'$' Message2 db 'EGA Graphics routine is now resident (' Field1 db '0000-' Field2 db '0000)',13,10,'$' Ascii db '0123456789abcdef' Epson ends end start