Unit grafdump;

Interface

   Uses
      dos, graph;

   Procedure hardcopy(inverse: boolean;
                      gmode, gdevice: integer);

   { MGA, CGA, Herc, EGA, VGA Graphics screen dump routine
     for EPSON  compatible printers. Turbo Pascal, v4 or better

     Any non black screen pixel (in first page) is printed. }


Implementation

   Procedure hardcopy(inverse: boolean;
                      gmode, gdevice: integer);

    { Inverse true produces an inverse image.
      Gmode and gdevice are the arguments returned from Turbo's
           InitGraph procedure.

      Dot spacing (mode) and multiples of each byte across the page
          are manipulated to give the 'best' aspect ratio on the print.

      Mode: 1 = Double-Density 120 dpi,        2 = High-Speed D-D 120 dpi
            3 = Quad-Density 240 dpi,          4 = 80 dpi
            5 = 72 dpi,                        6 = 90 dpi
            0 = 60 dpi.

      Pre-FX series of EPSON printers should only use Mode 1.

      This routine uses mode 2 for VGAHi (ymaxglbl=479) and CGACn
           (xmaxglb=319), -  mode 6 for all other gmodes.
           CGACn print is 1/2 page and crude, rest are full page

      Nb. Uses ReadMode 1 for EGA & VGA to cmp black with all bit planes.

      Reference : "Programmers guide to PC & PS/2 Video System"
                   R Wilton, MicroSoft Press, 1987
           Graft:  Gordon Findlay, Christchurch School of Medicine
                    (gordon%chmeds.ac.nz@cunyvm.cuny.edu)
                   Mac McLennan, Forest Research Institute
                                 Christchurch, New Zealand
    }

      Const
         esc = 27;
         lptportnum = 1; { Defaults to LPT1. 2 = LPT2 }

      Var
         regs: registers;
         boff: integer;
         mode, pbyte, sb, i, j, n1, n2: byte;
         pwide, grafbase, ymaxglb, xmaxglb: word;


      Function nextpbyte(x, y: word): byte;


         Begin
         Case gdevice Of
            cga:
               If (gmode = cgahi) Then
                  pbyte := mem[grafbase: (y shr 1) * 80 + (y And
                           1) * $2000 + (x shr 3)]
               Else
                  Begin
                  pbyte := 0;
                  i := 0;
                  boff := (y shr 1) * 80 + (y And 1) * $2000 + (x shr 2);
                  Repeat
                     sb := mem[grafbase: boff + i];
                     j := 0;
                     Repeat
                        pbyte := pbyte shl 1;
                        If ((sb And $c0) > 0) Then
                           inc(pbyte);
                        sb := sb shl 2;
                        inc(j);
                     Until (j > 3);
                     inc(i);
                  Until (i > 1);
                  End;

            vga, ega, ega64, egamono:
               pbyte := Not mem[grafbase: (y * 80 + (x shr 3))];

            hercmono:
               pbyte := mem[grafbase: (y And
                        3)shl 13 + 90 * (y shr 2) + (x shr 3)];

            Else
               pbyte := 0 { should never happen }
            End;

         If inverse Then
            nextpbyte := Not pbyte
         Else
            nextpbyte := pbyte;
         End;


      Procedure sendbyte(pb: byte);
       { Send one byte to the printer }

         Begin
         regs.ah := 0;
         regs.al := pb;
         regs.dx := pred(lptportnum);
         intr($17, regs);
         End; { SendByte }


      Procedure dumpgraf;

         Var
            xi, yi: integer; { Pixel coordinates }


         Procedure printaline;

            Begin
            { Select 8-Pin graphics print mode for each line }
            sendbyte(esc);
            sendbyte(ord('*'));
            sendbyte(mode);
            sendbyte(n1);
            sendbyte(n2); { dots on line }

           { Get the next print line off the screen, bottom of screen
             is the lh side of the paper.  Each byte is 8 pixels in the
             X coordinate and 1 in the Y, and is printed twice to improve
             aspect ratio (except where ymaxglb = 199 - printed 3x).      }

            yi := ymaxglb;
            Repeat
               pbyte := nextpbyte(xi, yi); { Each byte is 1 pixel (Y axis)}
               sendbyte(pbyte);
               sendbyte(pbyte);
               If (ymaxglb < 200) Then
                  sendbyte(pbyte);
               dec(yi);
            Until (yi < 0);
            sendbyte(10); { Send LF }
            End;


         Begin
         xi := 0;
         Repeat
            printaline; { Each printed line is 8 pixels deep (X axis) }
            inc(xi, 8);
         Until (xi > xmaxglb);
         sendbyte(13);
         sendbyte(12); { Send CR & FF }
         End; { DumpGraf }


      Function checkprt: boolean;
       { Check Printer connected, online and has paper, If not then BEEP }

         Begin
         regs.ax := $200;
         regs.dx := pred(lptportnum);
         intr($17, regs);
         regs.ah := regs.ah xor $80;
         regs.ah := regs.ah And $A9;
         If (regs.ah <> 0) Then
            Begin
            writeln(#7,#7);
            checkprt := false;
            End
         Else
            checkprt := true;
         End;


      Begin { HardCopy }
      If Not checkprt Then
         exit; { and beep }
      Case gdevice Of
         cga:
            Begin
            grafbase := $B800;
            ymaxglb := 199;
            If (gmode = cgahi) Then
               xmaxglb := 639
            Else
               xmaxglb := 319;
            End;
         ega, ega64, egamono:
            Begin
            grafbase := $A000;
            xmaxglb := 639;
            ymaxglb := 349;
            portw[$3CE] := $805; { Set ReadMode = 1 - all bit planes cmpd.}
            { Defaults assumed:- Color Don't Care register = $0F }
            {                  - Color Compare    register = $00 }
            End;
         vga:
            Begin
            grafbase := $A000;
            xmaxglb := 639;
            portw[$3CE] := $805;
            Case gmode Of
               vgalo:
                  ymaxglb := 199;
               vgamed:
                  ymaxglb := 349;
               vgahi:
                  ymaxglb := 479;
               End;
            End;
         hercmono:
            Begin
            grafbase := $B000;
            xmaxglb := 719;
            ymaxglb := 347
            End;
         Else
            exit
         End;

      sendbyte(esc); { Select 24/216-inch line spacing }
      sendbyte(ord('3'));
      sendbyte(24);

      If ((xmaxglb < 320) Or (ymaxglb = 479)) Then
         mode := 2
      Else
         mode := 6;
      pwide := ymaxglb + 1;
      If (ymaxglb < 200) Then
         pwide := pwide * 3
      Else
         pwide := pwide shl 1;
      n1 := lo(pwide); { Determine 2 byte control code for }
      n2 := hi(pwide); { the number of dots per print line }

      dumpgraf;

      If (gdevice In [vga, ega, ega64, egamono]) Then
         portw[$3CE] := 5;

      sendbyte(esc);
      sendbyte(2); { Reset to 1/6-inch line spacing }
      End; { HardCopy }


End.
