home *** CD-ROM | disk | FTP | other *** search
- {$S-,R-,I-,V-,B-}
-
- {XDUMP - V1.03 translating screen dump program}
- {Copyright (c) 1988 Michael Day - all rights reserved}
- {first release 1 June 1988}
- {second release 24 July 1988} {first public release}
- {third release as of 28 July 1988} {fixed printer and GetP}
- {this release as of 17 August 1988} {fixed range check problem}
-
-
- {This is a shareware program. Refer to the license agreement for further}
- {information. If you do not have the license documentation you may}
- {obtain it by writting to me at: }
-
- { Michael Day }
- { C/O Day Research }
- { P.O. Box 22902 }
- { Milwaukie, OR 97222 }
- { }
- { CIS [73577,2225] }
- { Mike Day UUCP:...!tektronix!reed!qiclab!bakwatr!mikeday }
-
- {If you include $10.00 I will also send you a current copy of the full}
- {shareware package.}
-
- {Note: If you agree to the terms of the shareware license you may}
- {use this program free of royalties, and you may use this program}
- {in conjunction with any program you may develop, that XDUMP is a}
- {part of, in private or commercial applications free of royalty payments.}
- {The catch is that you must provide a copy of any enhancments to XDUMP}
- {to be distributed among the other XDUMP developers.}
- {See the license agreement for further details.}
-
-
- {XDUMP is a screen dump program that can scale up or down from the screen}
- {to the printer. Currently it assumes an Epson or compatible printer is}
- {attached. Minimal definition required is landscape or upright, mono or}
- {color, screen area to read, and printer area to use (seperate for}
- {landscape or upright), printer LPT number, and print mode: Normal,}
- {quick, or VGA (VGA works for landscape mode only). And Screen type.}
- {Note that there currently are no limit checks done, if you give the}
- {wrong values, no telling what will happen.}
-
- Unit xdump;
-
- Interface
-
- uses crt,graph;
-
- const MaxCrt = 999; {maximum crt/prn buffer size}
-
- type
- string8 = string[8];
-
- rect = record
- Xmin, Ymin, Xmax, Ymax : word;
- end;
-
- PDbufType = array [0..7] of array [0..maxcrt] of byte;
-
- PSptr = ^PSrec;
-
- PSrec = record { 11577 bytes }
-
- {these vars are set by the calling program to specify}
- {what the print out is supposed to look like. Initprn}
- {then uses this information to set things up}
- {25 bytes}
- LandScape : boolean; {landscape=true, upright=false}
- Mono : boolean; {Monochrome=true, Color=false}
- ScrnType : word; {screen type in use}
- PStype : word; {print mode}
- LPTnum : word; {printer port to use}
- GPage : byte; {graphics page to use}
- PrnArea : rect; {printer definition area}
- ScrnArea : rect; {screen area to use for dump}
-
- {these arrays are stuffed by initprn for use by prnscrn}
- {2521 bytes}
- px : array [0..maxcrt] of word; {prn x translation}
- py : array [0..maxcrt] of word; {prn y translation}
- CPriority : array [0..255] of byte; {color priority}
- PCSelect : array [0..255] of byte; {screen to printer colors}
- PGmode : string8; {graphics mode entry string}
-
- {this is the virtual screen buffer created by prnscrn}
- {8000 bytes}
- PDbuf : PDbufType; {raw screen -> print data buffer}
-
- {these vars are used by various procedures inside}
- {prnscrn and cannot be used by external programs}
- {1031 bytes}
- PCmax : byte; {max print color}
- pXmod : real; {screen to print translation factor}
- pYmod : real;
- Pbuf : array [0..maxcrt] of byte; {print dot buffer}
- X1,X2,Y1,Y2: word; {current work area definition}
- PBcnt : integer; {print buf byte count}
- gy : word; {screen row being read}
- id : byte; {print head pin reference}
- pc : byte; {print color being used}
- end;
-
-
- {--------------------------------------}
- {how to get access from the outside world}
- procedure PScreen(var PSR:PSrec);
- procedure initprn(var PSR:PSrec);
- {--------------------------------------}
-
- Implementation
-
- const STDmode : string = #$1b#$4C; {misc strings for communicating}
- const QICmode : string = #$1b#$4B; {with the Epson printer}
- const VLSmode : string = #$1b#$2A#5;
- const hercmode : string = #$1b#$4C; {herc is really just standard}
-
- const TAGmode : string = #$1b#$4A#24; {this all needs to be}
- const PGenter : string = #13; {cleaned up sometime}
- const PGline : string = #13;
- const PGexit : string = #13#10#12;
-
- type string4 = string[4];
-
- {how to select a ribbon color}
- const pcolor : array [1..4] of string4 =
- (#$1b#$72#0,#$1b#$72#1,#$1b#$72#2,#$1b#$72#4);
- {pc=1=black, pc=2=red, pc=3=blue, pc=4=yellow }
- { $01 $02 $04 $08 }
-
- {----------------------------------------------}
- {your basic kludge initialization mechanism. Hopefully to be cleaned up}
- {as more knowledge is gained about how to make this mess work}
- procedure initprn(var PSR:PSrec);
- var i,iL : integer;
- begin
- if @PSR = nil then Exit; {don't do anything if never allocated}
- with PSR do
- begin
- PCmax := 4; {the Epson printer has four ribbon colors}
- for i := 0 to 255 do {for now color priority is linear}
- CPriority[i] := i;
-
- case ScrnType of
- 5,6,7,10 : mono := true; {mono only type displays}
- end;
-
- if mono then {in mono any color is black on the printer}
- begin
- FillChar(PCSelect,sizeof(PCSelect),$0f);
- PCSelect[0] := 0; {except black on the screen}
- end
- else
- begin
- case ScrnType of
- EGA, EGA64, VGA :
- begin
- {screen} {printer}
- PCSelect[0] := $00; {crude and rude this way, but it gets}
- PCSelect[1] := $04; {the color translation identified}
- PCSelect[2] := $0c;
- PCSelect[3] := $04; {the color translation uses a bit map}
- PCSelect[4] := $02; {- $01 is black}
- PCSelect[5] := $06; {- $02 is red}
- PCSelect[6] := $08; {- $04 is blue}
- PCSelect[7] := $01; {- $06 is violet (blue+red)}
- PCselect[8] := $00; {- $08 is yellow}
- PCSelect[9] := $04; {- $0A is orange (red+yellow)}
- PCSelect[10] := $0c; {- $0C is green (blue+yellow)}
- PCSelect[11] := $04;
- PCSelect[12] := $02;
- PCSelect[13] := $06;
- PCSelect[14] := $08;
- PCSelect[15] := $01;
- end;
- CGA, MCGA, ATT400 :
- begin
- {screen} {printer}
- PCSelect[0] := $00; {crude and rude this way, but it gets}
- PCSelect[1] := $0c; {the color translation identified}
- PCSelect[2] := $02;
- PCSelect[3] := $08; {the color translation uses a bit map}
- end;
- end;
- end;
-
- {this selects the graphics entry string to use}
- case PStype of
- 1 : PGmode := STDmode; {normal landscape / upright}
- 2 : PGmode := QICmode; {quick landscape / upright}
- 3 : PGmode := VLSmode; {vga landscape - requires late model Epson}
- 4 : PGmode := Hercmode {hercules landscape mode}
- else
- PGmode := STDmode; {if not one of the three, then assume STDmode}
- end;
-
- {-----------------------------------------------------------------}
- {now convert the screen and printer definitions into pixel access}
- {array values. In landscape mode the screen X axis is given to the}
- {printer Y axis, and the screen Y axis to the printer X axis}
-
- FillChar(px,sizeof(px),0); {clear the translation arrays}
- FillChar(py,sizeof(py),0);
-
- if LandScape then
- begin
- pXmod := succ(PrnArea.Xmax-PrnArea.Xmin) / {determine the}
- succ(ScrnArea.Ymax-ScrnArea.Ymin); {scaling factor}
- pYmod := succ(PrnArea.Ymax-PrnArea.Ymin) / {returning the}
- succ(ScrnArea.Xmax-ScrnArea.Xmin); {result as real}
-
- {this fills the px array with the screen pixel reference locations}
- {in landscape mode the printer's X axis is inverted}
- iL := succ(PrnArea.Xmin);
- for i := pred(PrnArea.Xmax) downto succ(PrnArea.Xmin) do
- begin
- px[i] := ScrnArea.Ymin+trunc((iL-PrnArea.Xmin) / pXmod);
- inc(iL);
- end;
- px[PrnArea.Xmin] := ScrnArea.Ymax; {force printer's first and}
- px[PrnArea.Xmax] := ScrnArea.Ymin; {last to be same as screen}
- {one pixel past max must be the same as the last pixel}
- px[succ(PrnArea.Xmax)] := ScrnArea.Ymin;
-
- {this fills the py array with the screen pixel reference locations}
- for i := succ(PrnArea.Ymin) to pred(PrnArea.Ymax) do
- begin
- py[i] := ScrnArea.Xmin+trunc((i-PrnArea.Ymin) / pYmod);
- end;
- py[PrnArea.Ymin] := ScrnArea.Xmin; {force printer's first and}
- py[PrnArea.Ymax] := ScrnArea.Xmax; {last to be same as screen}
- {one pixel past max must be the same as the last pixel}
- py[succ(PrnArea.Ymax)] := ScrnArea.Xmax;
- end
-
- {in upright mode both arrays contain incrementing values,}
- {and the screen X axis matches the printer X axis}
- else
- begin
- pXmod := (succ(PrnArea.Xmax-PrnArea.Xmin)) / {determine the}
- (succ(ScrnArea.Xmax-ScrnArea.Xmin)); {scaling factor}
- pYmod := (succ(PrnArea.Ymax-PrnArea.Ymin)) / {returning the}
- (succ(ScrnArea.Ymax-ScrnArea.Ymin)); {result as real}
-
- {this fills the px array with the screen pixel reference locations}
- for i := succ(PrnArea.Xmin) to pred(PrnArea.Xmax) do
- begin
- px[i] := ScrnArea.Xmin+trunc((i-PrnArea.Xmin) / pXmod);
- end;
- px[PrnArea.Xmin] := ScrnArea.Xmin; {force printer's first and}
- px[PrnArea.Xmax] := ScrnArea.Xmax; {last to be same as screen}
- {one pixel past max must be the same as the last pixel}
- px[succ(PrnArea.Xmax)] := ScrnArea.Xmax;
-
- {this fills the py array with the screen pixel reference locations}
- for i := succ(PrnArea.Ymin) to pred(PrnArea.Ymax) do
- begin
- py[i] := ScrnArea.Ymin+trunc((i-PrnArea.Ymin) / pYmod);
- end;
- py[PrnArea.Ymin] := ScrnArea.Ymin; {force printer's first and}
- py[PrnArea.Ymax] := ScrnArea.Ymax; {last to be same as screen}
- {one pixel past max must be the same as the last pixel}
- py[succ(PrnArea.Ymax)] := ScrnArea.Ymax;
- end;
- end;
- end;
-
- {-----------------------------------------------}
- {this reads gets the pixel data from the screen}
- {X= column, Y=row, P=page}
-
- function GetP(X,Y,P:word):byte;
- begin
- SetVisualPage(P);
- GetP := GetPixel(X,Y);
- end;
-
- (*
- {to use the BIOS instead for none TP supported displays, or to allow}
- {use of this unit in a TSR replace the TP graph function call above}
- {with this inline function code. Warning: Your BIOS must support }
- {the ReadDot function (int 10, ah 13) for this to work. Hercules }
- {boards seem to have problems with this.}
- function GetP(X,Y,P:word):byte;
- Inline($5B { pop bx}
- /$5A { pop dx}
- /$59 { pop cx}
- /$88/$DF { mov bh,bl}
- /$B4/$0D { mov ah,13}
- /$CD/$10); { int $10}
- *)
-
- {-----------------------------------------------}
- {a pair of inline macros to return the min or max}
- {of two word values. Note: these are WORDs not integers}
- function MinWord(A,B:word):word;
- Inline($58 { pop ax}
- /$5B { pop bx}
- /$39/$D8 { cmp ax,bx}
- /$72/$02 { jb minok}
- /$89/$D8); { mov ax,bx}
- {minok:}
-
- function MaxWord(A,B:word):word;
- inline($58 { pop ax}
- /$5B { pop bx}
- /$39/$D8 { cmp ax,bx}
- /$73/$02 { jnb maxok}
- /$89/$D8); { mov ax,bx}
- {maxok:}
-
-
- {-----------------------------------------------}
- {a simple and crude printer interface}
- {to be replaced with something better later}
- function prnstat(LPTnum:word):byte;
- inline($5A/ {pop dx}
- $B4/$02/ {mov ah,2}
- $CD/$17/ {int 17h}
- $86/$E0); {xchg al,ah}
-
- function prndata(LPTnum:word; ch:char):byte;
- inline($58/ {pop ax}
- $5A/ {pop dx}
- $B4/$00/ {mov ah,0}
- $CD/$17/ {int 17h}
- $86/$E0); {xchg al,ah}
-
-
- {----------------------------------------------}
- procedure OutPrn(LPTnum:word; PStr: string);
- var r : boolean;
- i : integer;
- begin
- for i := 1 to length(PStr) do
- begin
- if (prndata(LPTnum,PStr[i]) and 1) = 1 then halt(1);
- end;
- end;
-
- {++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++}
- {this reads in a row of pixels from the screen into the printer buffer}
- procedure GetYrow(var PSR:PSrec);
- var ix, gx, gd, ox : word;
- begin
- with PSR do
- begin
- gx := px[X1]; {get the first pixel of the screen row}
- if LandScape then {note the different getpixel in landscape mode}
- PDbuf[id][X1] := maxword(CPriority[GetP(gy,gx,GPage)],CPriority[PDbuf[id][X1]])
- else
- PDbuf[id][X1] := maxword(CPriority[GetP(gx,gy,GPage)],CPriority[PDbuf[id][X1]]);
-
- for ix := succ(X1) to X2 do {now go get the rest of the pixels}
- begin
- ox := px[pred(ix)]; {get the previous pixel for reference}
- gx := px[ix]; {get the pixel to read}
- if gx = ox then {if we already have the pixel, don't}
- PDbuf[id][ix] := PDbuf[id][pred(ix)] {waste time by reading it again}
- else {if not the same pixel go read it}
- begin
- gd := PDbuf[id][ix]; {read in a copy of background color}
- while gx <> ox do {then read in all intervening pixels}
- begin {prioritizing them based on color}
- if LandScape then {the color with the highest priority wins}
- begin
- gd := maxword(CPriority[GetP(gy,gx,GPage)],CPriority[gd]);
- inc(gx)
- end
- else {do backwards read for upright mode}
- begin
- gd := maxword(CPriority[GetP(gx,gy,GPage)],CPriority[gd]);
- dec(gx);
- end;
- end;
- PDbuf[id][ix] := gd; {save the resulting highest priority color}
- end;
- end;
- end;
- end;
-
- {---------------------------------------------------------------------}
- {this copies the pixel data from the screen to the printer buffer.}
- {In the process it translates colors and scales the pixels to the}
- {requested size. The end result is a virtual screen of the size needed}
- {for the printer. One psuedo screen pixel for each printer dot.}
- {The routine reads in all the pixels needed in each printer row (from}
- {one to eight printer rows). The printer rows being created are specified}
- {by the Y1, and Y2 variables. The dots used in each row are specified by the }
- {X1 and X2 variables. The entire printer data virtual screen is cleared at}
- {the beginning of the procedure, so any unread pixels will be set to zero.}
- {Note: py[] always indexes in a positive direction. px[] indexes positive }
- {in upright mode, and negative in landscape mode. If pYmod and pXmod are }
- {equal or greater than one, all the screen pixels will be presented on the }
- {printer. If pYmod and/or pXmod is less than one, missing pixels will be }
- {prioritized from the CPriority array to select the highest pixel to print.}
- {A final note, (Y1 and 7) must always be less than (Y2 and 7) so that the.}
- {proper print wires will be used for printing.}
-
- procedure PYfill(var PSR:PSrec);
- var iy, oy : word;
- begin
- with PSR do
- begin
- {fill the printer data buffer with the}
- {background color (lowest priority color)}
- FillChar(PDbuf,sizeof(PDbuf),CPriority[0]);
-
- for iy := Y1 to Y2 do {always in a range of 1 to 8}
- begin {Y1 > Y2 are the printer rows to get}
- gy := py[iy]; {get current screen row number}
- oy := py[succ(iy)]; {get next row number for comparison}
- id := byte(iy and 7); {convert current row number to pin number}
-
- if gy = oy then
- begin
- GetYrow(PSR); {if duplicate row, read only this row}
- end
-
- else
- begin
- while gy < oy do {The printer data starts out as 0}
- begin {GetYrow will prioritize the pixels}
- GetYrow(PSR); {such that any screen pixel read that}
- inc(gy); {has a higher priority will replace}
- end; {the current pixel value in the print}
- end; {data buffer}
- end;
-
- end;
- end;
-
- {--------------------------------------}
- {fills graphic print buffer with dots to print (if any)}
- {returns true if there are dots to print, false if none}
-
- function PBfill(var PSR:PSrec):boolean;
- var ix, iy : word;
- bm, cm : byte;
- begin
- PBfill := false; {assume no data found}
- with PSR do {use printer record variables}
- begin
- if mono then
- cm := $0f {for monochrome, use any color}
- else
- cm := 1 shl pred(pc); {convert color to mask for later use}
- FillChar(Pbuf,sizeof(Pbuf),0); {clear the print buffer first}
- for iy := Y1 to Y2 do {printer rows to read (diff = 1 to 8)}
- begin
- id := byte(iy and 7); {convert data buffer index to print wire num}
- bm := $80 shr id; {convert wire num to bit mask}
- for ix := X1 to X2 do {individual column test for color}
- begin
- if (PCSelect[PDbuf[id][ix]] and cm) <> 0 then
- begin {if there is a color match}
- Pbuf[ix] := Pbuf[ix] or bm; {then add it to the buffer}
- PBfill := true; {and mark that there is data to print}
- end;
- end;
- end;
- PBcnt := succ(X2); {return total bytes in PBcnt}
- end;
- end;
-
- {---------------------------------------------}
- {print a graphics print line}
- procedure GLPrint(var PSR:PSrec);
- var i : integer;
- begin
- if PBfill(PSR) then {Tie it all together and send it to the printer}
- begin
- with PSR do
- begin
- if not(mono) then OutPrn(LPTnum,Pcolor[pc]);
- OutPrn(LPTnum,PGmode+char(lo(PBcnt))+char(hi(PBcnt)));
- for i := 0 to pred(PBcnt) do
- begin
- OutPrn(LPTnum,char(Pbuf[i]));
- end;
- OutPrn(LPTnum,PGline);
- end;
- end;
- end;
-
- {---------------------------------------------}
- procedure PScreen(var PSR:PSrec);
- var i,fc : integer;
- Yend : word;
- begin
- if @PSR = nil then Exit; {don't do anything if never allocated}
- with PSR do
- begin
- OutPrn(LPTnum,PGenter); {make sure the printer is in proper mode for graphics}
- for i := 0 to ((PrnArea.Ymin div 8) and $FFF8) do
- OutPrn(LPTnum,TAGmode); {no point in sending data on blank lines}
-
- X1 := PrnArea.Xmin; {define the printer area to start with}
- X2 := PrnArea.Xmax;
- Y1 := PrnArea.Ymin;
- Y2 := Y1;
- Yend := PrnArea.Ymax;
-
- while Y2 < Yend do
- begin
- Y2 := (Y1 and $7ff8) + 7; {Y2 must be one less than boundry}
- if Y2 > Yend then Y2 := Yend; {unless it is the last row}
-
- PYfill(PSR); {go read the virtual screen into the data buffer}
-
- pc := 1; {print mono in black ink}
- if mono then
- GLPrint(PSR) {and we only need one pass}
- else
- for fc := 1 to PCmax do {check for all colors to print}
- begin
- pc := fc;
- GLPrint(PSR);
- end;
- OutPrn(LPTnum,TAGmode); {finally move the paper up for the next line}
- Y1 := succ(Y2); {Y1 starts at old Y2 plus one}
-
- if keypressed then Y2 := succ(Yend); {if a key was pressed, then abort}
-
- end;
- OutPrn(LPTnum,PGexit); {if needed clear the printer mode to non-graphics}
- end;
- end;
-
- {---------------------------------------------------------------------}
- begin
- end.