PAGE ,132
        TITLE   CANJETDL - Print Screen Utility

;***    CANJETDL - Print Screen Utility
;
;       CANJETDL is a print screen utility. It intercepts INT 5 from
;       the BIOS (generated when <Print Screen> is struck), and prints
;       the contents of the screen onto the PRN device.
;
;       To execute:
;
;       CANJETDL
;
;       To activate:
;
;       Press <Print Screen>
;
;       OR, if using Mouse Systems' PC PAINT, execute CANJETDL before PC PAINT
;       then, use the normal program procedures for printing a picture.
;
;       Once CANJETDL has been executed, it remains permanently in RAM and
;       does not need to be executed again.
;
;-      Modified Aug 86 by SRN  - Text dump to graphics.
;	Modified again by Wayne D. Markel for IBM EGA
;-      Canon PJ-1080A Inkjet graphics dump.
;-      Code has been taken from various sources and been modified to suit.
;	
;       I wrote numerous versions of this program.
;	This version was written specifically for use with IBM Drawing 
;	Assistant.  It can only be invoked by using the PRINT SCREEN key,
;	and therefore reads only the portion of the screen that contains the
;	picture, not the border and icons.
;
;	This version also rotates the picture 90 degrees and doubles up on
;	the pixels in order to get a larger picture.

;       NOTE: This is my first ever attempt at assembler programming so
;       any comments for improvement would be appreciated.
;       Wayne D. Markel
;       655 Carnathan Ct.
;       Ft. Walton Beach, Florida   32548
;       904-862-5417
;       Compuserve ID 71330,552 
      	

FALSE   =       0
TRUE    =       NOT FALSE

;       The next 2 switches should be set to TRUE and TRUE for:
COLUMNS =       80              ; Characters/line

        page



CODE    SEGMENT BYTE PUBLIC 'CODE'
        ASSUME  CS:CODE,DS:CODE,ES:CODE,SS:CODE

        ORG     100H

;*      Entry point
;

BEGIN:
        JMP     NEAR PTR START


;*      INT 5 handler
;

INT_5:
        PUSH    DS                      ; Save his data segment
        PUSH    AX

        MOV     CS:INT_SP,SP
        MOV     CS:INT_SS,SS            ; Save his stack

        MOV     AX,CS
        MOV     SS,AX                   ; Set local stack
        MOV     SP,OFFSET INT_STACK

        STI                             ; Now allow interrupts to come in

        PUSH    ES
        PUSH    BX
        PUSH    CX
        PUSH    DX
        PUSH    SI
        PUSH    DI

        MOV     DS,AX
        MOV     ES,AX                   ; Set up my segments

        CALL    CANJET


        POP     DI
        POP     SI
        POP     DX
        POP     CX
        POP     BX
        POP     ES

        CLI                             ; INTs off while messing around
        MOV     AX,CS:INT_SP
        MOV     SP,AX
        MOV     AX,CS:INT_SS            ; Restore his stack
        MOV     SS,AX

        POP     AX
        POP     DS
        IRET                            ; Back to BIOS
INT_SS  DW      0                       ; Saved stack values
INT_SP  DW      0

INT_CX  DW      0                       ; Current X location
INT_CY  DW      0                       ; Current Y location
MYCHR   DW      0                       ; Character at position
MYLINE  DB      82 DUP (?)              ; Line buffer
LINES   DW      0                       ; Number of lines valid on screen
BLUE_BUFFER	DB	80 DUP(?)
GREEN_BUFFER	DB	80 DUP(?)
RED_BUFFER	DB	80 DUP(?)
DosVersMsg	db	"ATTR: Needs DOS 2.0 +$"
LOAD_BUFFER	DB	?
ROW		DW	?
COLUMN		DW	?
NO_OF_BYTES	EQU	50H
	        DW      128 DUP (?)
INT_STACK LABEL NEAR                    ; Internal stack


CANJET		PROC	NEAR
;------------------------------------------------------------------------------
;   PROCEDURE TO READ AN EGA MODE 16 SCREEN, ROTATE IT 90 DEGREES CLOCKWISE, 
;   DOUBLE THE DOT OUTPUT FROM 640X350 TO 1280X700 AND PRINT IT ON A CANON 
;   PJ1080A
;------------------------------------------------------------------------------

;This code for checking DOS version came from PC Magazine

	Mov	AH, 30h			; Check for DOS Version
	Int	21h			;   through DOS call
	Cmp	AL, 2			; See if it's 2.0 or above
	Jae	DosVersOK		; If so, continue

	Mov	DX, Offset DosVersMsg	; Error message
ErrorExit:
	Mov	AH, 9			; Print String function call
	Int	21h			; Do it
	Int	20h			; And exit prematurely

DosVersOK:
		
;-------------------------------------------------------------------------------
;     READ A WINDOW, ONE DOT AT A TIME, RETURNING THE VALUE IN AL
;-------------------------------------------------------------------------------

	MOV	COLUMN,92D		;INITIALIZE COLUMN COUNTER

NEWCOLUMN:

	MOV	LOAD_BUFFER,80H		;INITIALIZE THIS VARIABLE WHICH IS USED 
	MOV	ROW,337D		;SET ROW POINTER TO BOTTOM OF WINDOW	
	
;------------------------------------------------------------------------------
;  ZERO OUT BUFFERS AT BEGINNING OF EACH ROW
;------------------------------------------------------------------------------
	MOV	CX,240D
	
	MOV	BX,00			;SET OFFSET POINTER TO ZERO
ZERO:	MOV	[BLUE_BUFFER+BX],00	;PUT ZERO IN BYTE OF RED_BUFFER
	INC	BX
	LOOP	ZERO
;------------------------------------------------------------------------------
;       READ A DOT AT COLUMN=CX ROW=DX
;       RETURN VALUE OF PIXEL IN AL
;------------------------------------------------------------------------------
	MOV	BX,0			;INITIALIZE POINTER FOR BUFFERS
LINE:	MOV 	CX,COLUMN		;SET CX TO CURRENT COLUMN
	MOV 	DX,ROW			;SET DX TO CURRENT ROW
	MOV 	AH,0DH			;READ DOT FUNCTION
	INT 	10H

	MOV	DH,LOAD_BUFFER		;SETUP DH TO TURN ON CORRECT BIT WHEN
					; ORed WITH A BYTE IN ONE OF THE BUFFERS
;------------------------------------------------------------------------------
;     In order to get a picture 8.25X15.0 inches on the CANON, it is necessary
;     to write each pixel FOUR times.  The EGA operates in 640X350 pixel
;     mode. So the program will load the value of the pixel into a buffer
;     TWICE and print each buffer TWICE.  This will
;     produce a picture on paper 1280 by 700 pixels in size.
;------------------------------------------------------------------------------
			
	CALL	LOAD_BUFFERS	

	CALL	LOAD_BUFFERS		

;------------------------------------------------------------------------------
;     Ok, that doubled up on the pixels, now it's time to DEC the ROW
;     counter to read the next pixel
;------------------------------------------------------------------------------


	DEC	WORD PTR [ROW]		;DECREMENT THE ROW COUNTER

;------------------------------------------------------------------------------
;       CHECK TO SEE IF AT TOP OF THE WINDOW
;------------------------------------------------------------------------------

	CMP 	WORD PTR [ROW],18D	;TEST IF ABOVE TOP OF WINDOW
	JGE  	LINE			;NO...READ ANOTHER DOT			


	CALL	OUTPUT_BUFFERS		;YES, OUTPUT ONE LINE TO CANONJET	

	CALL	OUTPUT_BUFFERS		;OUTPUT SECOND LINE


	INC	WORD PTR [COLUMN]	;INCREMENT COLUMN NUMBER

	CMP 	WORD PTR [COLUMN],548D	;AT RIGHT EDGE OF WINDOW?
	JL  	NEWCOLUMN		;NO, READ ANOTHER COLUMN OF DOTS	

	RET				;YES..HAVE READ ALL OF WINDOW, SO EXIT
;-------------------------------------------------------------------------------
;   SUBROUTINE TO LOAD BUFFERS
;-------------------------------------------------------------------------------

LOAD_BUFFERS	PROC	NEAR

	MOV	AH,AL			;PUT THE VALUE FROM THE READ_DOT BIOS
					; CALL INTO AH FOR FURTHER MANIPULATION
	SHR	AH,1			;PUSH THE LSB INTO THE BIT BUCKET
;------------------------------------------------------------------------------
;                   IF IT'S A "1", THEN TURN ON THE
;                   CORRESPONDING BIT IN THE CURRENT
;                   BYTE OF THE BLUE BUFFER 
;------------------------------------------------------------------------------

	JNC	GREEN			;IF IT'S A 0 CHECK THE GREEN BIT
LOAD_BLUE_BUFFER:
	OR	BYTE PTR [BLUE_BUFFER+BX],DH	;TURN ON A BIT IN BUFFER
        	 
GREEN:	SHR	AH,1			;SHIFT RIGHT ONE MORE TIME
					; TO SEE IF THE 2 BIT IS ON
					;IF YES, PUT A BIT IN THE GREEN BUFFER
	JNC	RED			;IF NO, CHECK THE RED BIT
LOAD_GREEN_BUFFER:
	OR	BYTE PTR [GREEN_BUFFER+BX],DH

RED:	SHR	AH,1			;SHIFT ONE MORE TIME TO CHECK THE 4 BIT
										
	JNC	END_LOAD_BUFFER		;IF NOT SET JUMP TO END_LOAD_BUFFER
LOAD_RED_BUFFER:
	OR	BYTE PTR[RED_BUFFER+BX],DH	;SINCE THE 4 BIT IS SET, LOAD...
					        ; TO THE BUFFER

END_LOAD_BUFFER:
	SHR	DX,1
	MOV	LOAD_BUFFER,DH		;SHR THE VARIABLE, "LOAD_BUFFER"	
	CMP	DH,00			;HAVE WE READ 8 DOTS YET?
	JNZ	SAME_BYTE		;NO, READ NEXT DOT
	MOV	LOAD_BUFFER,80H		;RESET MSB OF LOAD_BUFFER
	MOV	DH,LOAD_BUFFER		;SAME FOR DH
;-------------------------------------------------------------------------------
;  AFTER STUFFING 8 DOTS INTO THE BUFFER, INCREMENT THE BUFFER OFFSET POINTER
;-------------------------------------------------------------------------------
	INC	BX			;BUMP POINTER FOR BUFFERS

SAME_BYTE:

	RET


LOAD_BUFFERS		ENDP
;------------------------------------------------------------------------------

OUTPUT_BUFFERS  PROC   	NEAR

;-------------------------------------------------------------------------------
;  SET CANONJET TO GRAPHICS MODE...
; ...THEN OUTPUT ONE ROW OF DOTS TO THE CANONJET.
; NOTE: TWO ROWS OF DOTS MUST BE SENT BEFORE ANY PRINTER ACTION OCCURS
;
;-------------------------------------------------------------------------------



		MOV	AH,5			;SET DOS FUNCTION TO 5 FOR PRINT 
						;TER OUTPUT
		MOV	DL,01BH			;SEND		
		INT	21H			;ESCAPE CHARACTER
		MOV	DL,058H			;THEN "X" CHARACTER
		INT	21H
		MOV	DL,NO_OF_BYTES			;GET READY FOR 10 BYTES OF DATA
		INT	21H

;------------------------------------------------------------------------------
;     OUTPUT (NO_OF_BYTES) FROM THE RED_BUFFER                                 
;------------------------------------------------------------------------------

		MOV	BX,0			;SET OFFSET IN BUFFER TO ZERO	
RED_OUT:	MOV	DL,[RED_BUFFER+BX]	;PUT BYTE IN DL FOR OUTPUT TO 
						;PRINTER
		INT	21H			;DO IT.
		INC	BX			;MOVE OVER TO NEXT BYTE IN
						; BUFFER
		CMP	BX,NO_OF_BYTES
		JL	RED_OUT			;READ ANOTHER BYTE UNTIL 80
						; HAVE BEEN READ.
		
;------------------------------------------------------------------------------
;  OUTPUT (N0_OF_BYTES) FROM THE GREEN_BUFFER
;------------------------------------------------------------------------------
		MOV	BX,0	
GREEN_OUT:	MOV	DL,[GREEN_BUFFER+BX]
		INT	21H
		INC	BX
		CMP 	BX,NO_OF_BYTES		
		JL	GREEN_OUT			
;------------------------------------------------------------------------------
;  OUTPUT  (NO_OF_BYTES) FROM THE BLUE_BUFFER
;------------------------------------------------------------------------------
		MOV	BX,0
BLUE_OUT:	MOV	DL,[BLUE_BUFFER+BX]
		INT	21H
		INC	BX
		CMP	BX,NO_OF_BYTES
		JL	BLUE_OUT
;------------------------------------------------------------------------------
;  ONE LINE OF DOTS HAVE BEEN OUTPUT TO THE CANONJET PRINT BUFFER
;------------------------------------------------------------------------------
		RET	
OUTPUT_BUFFERS		ENDP
;-------------------------------------------------------------------------------
		

	RET				;NEAR RETURN TO DOS
CANJET	ENDP


INT_END LABEL   NEAR

;*      Main entry point
;

START:
        MOV     SP,OFFSET INT_STACK             ; Good place for it
        PUSH    DS

        XOR     AX,AX
        MOV     DS,AX                           ; Clear DS

        MOV     SI,5*4                          ; SI points to interrupt
        CLI

        MOV     WORD PTR [SI],OFFSET INT_5
        MOV     WORD PTR [SI+2],CS              ; Set my interrupt vector

        STI
        POP     DS

        MOV     DX,OFFSET INT_END               ; LWA of resident portion
		
;	MOV	AH,31H				;FUNCTION FOR STAY RESIDENT
;	MOV	AL,1				;RETURN CODE FOR COMMAND
;	MOV	DX,5D				;RESERVE 1.5K MEMORY
;       INT     21H
	INT	27H
CODE    ENDS
        END     BEGIN
