(*---------------------------------------------------------------------------
    :Program.    PrintIt.mod
    :Author.     Fridtjof Siebert
    :Address.    Nobileweg 67, D-7-Stgt-40
    :Phone.      0711/822509
    :Shortcut.   [fbs]
    :Version.    1.0
    :Date.       14-Jul-88
    :Copyright.  PD
    :Language.   Modula-II
    :Translator. M2Amiga
    :Imports.    IFFLoad  [fbs] (Amok#2 or Amok#3).
    :UpDate.     none.
    :Contents.   Utility to create high-quality Hardcopies Epson-Printers.
    :Remark.     Welche Drucker (außer Citizen 120D) können 144 dots/inch ??
---------------------------------------------------------------------------*)

(*-------------------------------------------------------------------------*)
(*                                                                         *)
(*                     =   =   =   PrintIt !   =   =   =                   *)
(*                                                                         *)
(*  A Graphics-Print Utilities for Epson FX-compatible Printers that       *)
(*  use the ESC/P Standard codes. They should be able to print in          *)
(*  quadruple density.                                                     *)
(*                                                                         *)
(*  This Programm allows you to make really black Hardcopies. It uses      *)
(*  the highest possible horizontal & vertical density, i.e. 240 dpi       *)
(*  and 216 dpi. Your Hardcopys will be stretched a bit (11% higher than   *)
(*  they should be) but this normally isn't too important.                 *)
(*                                                                         *)
(*  PrintIt uses PAR: to print. So don't plug your Printer into SER: (I    *)
(*  don't know, if that is possible, but don't do it!).                    *)
(*                                                                         *)
(*  PrintIt has been developed on a Citizen 120D, which is a very cheap,   *)
(*  but good Printer. If you use other Epson compatible Printers, there    *)
(*  should be no problems. Tell me if there are any !!!                    *)
(*                                                                         *)
(*  © 1988 by Fridtjof Siebert                                             *)
(*            Nobileweg 67                                                 *)
(*            D-7000-Stuttgart-40                                          *)
(*            Phone: (0)711/822509                                         *)
(*                                                                         *)
(*  Contributions wellcome.                                                *)
(*                                                                         *)
(*-------------------------------------------------------------------------*)

MODULE PrintIt;

(*--------------------------  IMPORTs:  -----------------------------------*)

(*------  SYSTEM:  ------*)
FROM SYSTEM         IMPORT ADR, SHIFT, BITSET, INLINE;
FROM Arts           IMPORT TermProcedure, Assert;
FROM Arguments      IMPORT GetArg, NumArgs;

(*------  Libraries:  ------*)
FROM Dos            IMPORT Open, Close, FileHandlePtr, Write, Read, oldFile,
                           newFile, Delay;
FROM Exec           IMPORT AllocMem, FreeMem, MemReqs, MemReqSet, UByte,
                           WaitPort, GetMsg, ReplyMsg;
FROM Intuition      IMPORT ScreenPtr, WindowPtr, CloseScreen, CloseWindow,
                           IntuiMessagePtr, GadgetPtr, IDCMPFlags,
                           ScreenToFront, WBenchToFront, SetPointer,
                           ClearPointer;

(*------  Own stuff:  ------*)
FROM IFFLoad        IMPORT ReadILBM, ReadILBMFlags, ReadILBMFlagSet, IFFInfo;
(* IFFLoad from AMOK#2 or #3 *)
FROM PrintItDisplay IMPORT OpenPrintIt, Window, Gadgets, RP, TextType,
                           GetName, InitPrintIt, StretchX, StretchY,
                           DoublePrint, xRes, yRes, Positive, PixName,
                           Screen, Convert, StrInfo, Buffers;

(*-----------------------  Variables:  ------------------------------------*)

TYPE
  BufferType = ARRAY[0..8249] OF UByte; (* I/O Buffer for PAR: *)

VAR
  MyFile: FileHandlePtr;                (* FileHandlePtr for PAR: *)
  Buffer: POINTER TO BufferType;        (* It's Buffer            *)
  DummyWindow: WindowPtr;               (* not too important      *)
  ok: BOOLEAN;
  i: CARDINAL;
  j: INTEGER;
  len: LONGINT;
  ActLine, CountLines, CountBits, CountBytes: CARDINAL; (* Count anything *)
  RepHorCnt,RepVerCnt: LONGINT;         (* Count Repeats          *)
  ActByte: UByte;                       (* the calcylated Byte    *)
  ActAdr: POINTER TO BITSET;            (* Position in BitMap     *)
  SmallOrBig: CARDINAL;                 (* Counts Printed lines   *)
  Msg: IntuiMessagePtr;
  Gadget: GadgetPtr;
  WaitPointer,DataPtr: POINTER TO ARRAY[0..17] OF LONGCARD;

(*-------------------------------------------------------------------------*)
(*                                                                         *)
(*                        The Main Print-Procedure                         *)
(*                                                                         *)
(*-------------------------------------------------------------------------*)

PROCEDURE PrintIt();

BEGIN

  RepVerCnt := 0;
  REPEAT

(*------  Set LF:  ------*)

    Buffer^[0] := 1BH;
    CASE yRes OF
    DpiV72ID:
      Buffer^[1] := 33H; Buffer^[2] := 23;
      len := Write(MyFile,Buffer,3); |
    DpiV144ID:
      Buffer^[1] := 7EH; Buffer^[2] := 30H; Buffer^[3] := 1;
      len := Write(MyFile,Buffer,4); |
    DpiV216ID:
      Buffer^[1] := 33H; Buffer^[2] := 1;
      len := Write(MyFile,Buffer,3);
    END;

(*------  Main Printing-Loop:  ------*)

    CountLines := 0;  (* Line 0                 *)
    SmallOrBig := 0;  (* Counts small or big LF *)

    WITH Screen^.bitMap DO

(*------  LOOP for Lines:  ------*)

      WHILE (CountLines DIV StretchY) < rows DO

        CountBytes := 0; (* Num of Bytes printed per Line *)
        CountBits := 0;  (* x-Position in BitMap          *)

(*------  LOOP to print a Line:  ------*)

        WHILE SHIFT(CountBits,-3) < bytesPerRow DO

          ActByte := 0;
          i := 0;

(*------  LOOP to get 8 Bits:  ------*)

          LOOP

            CASE yRes OF
              DpiV72ID : ActLine := CountLines + i; |
              DpiV144ID: ActLine := CountLines + i+i; |
              DpiV216ID: ActLine := CountLines + i+i+i; |
            END;
            ActLine := ActLine DIV StretchY;
            IF ActLine >= rows THEN EXIT END;

            ActByte := SHIFT(ActByte,1);
            ActAdr := planes[0];
            INC(ActAdr,ActLine * bytesPerRow + SHIFT(SHIFT(CountBits,-4),1));

            IF 15 - (CountBits-SHIFT(SHIFT(CountBits,-4),4)) IN ActAdr^ THEN
              INC(ActByte,1); (* Bit Set *)
            END;

            INC(i);
            IF i=8 THEN EXIT END;

          END;

          IF NOT(Positive) THEN
            CASE i OF
              8: ActByte := 255-ActByte; |
              7: ActByte := 127-ActByte; |
              6: ActByte :=  63-ActByte; |
              5: ActByte :=  31-ActByte; |
              4: ActByte :=  15-ActByte; |
              3: ActByte :=   7-ActByte; |
              2: ActByte :=   3-ActByte; |
              1: ActByte :=   1-ActByte; |
            END;
          END;
          ActByte := SHIFT(ActByte,8-i);

          i := 0;
          REPEAT
            Buffer^[CountBytes+5] := ActByte; (* Byte to Printer's Buffer *)
            INC(CountBytes); (* Next Byte to Printer *)
            INC(i);
          UNTIL i=StretchX; (* Byte StretchX times into Buffer *)
          INC(CountBits);  (* 1 Pixel to the right *)

        END;

(*------  Print one Line:  ------*)

        Buffer^[0] := 1BH; Buffer^[1] := 2AH;
        CASE xRes OF
          DpiH60ID:  Buffer^[2] := 0; |
          DpiH72ID:  Buffer^[2] := 5; |
          DpiH80ID:  Buffer^[2] := 4; |
          DpiH90ID:  Buffer^[2] := 6; |
          DpiH120ID: Buffer^[2] := 1; |
          DpiH144ID: Buffer^[2] := 7; |
          DpiH240ID: Buffer^[2] := 3; |
        END;
        Buffer^[3] := UByte(CountBytes - SHIFT(SHIFT(CountBytes,-8),8));
        Buffer^[4] := UByte(SHIFT(CountBytes,-8));
        Buffer^[CountBytes+5] := 0DH; (* CR *)
        Buffer^[CountBytes+6] := 0AH; (* LF *)
        IF DoublePrint THEN
          RepHorCnt := 0;
          REPEAT
            len := Write(MyFile,Buffer,CountBytes+5);      (* Print Line *)
            INC(RepHorCnt);
          UNTIL RepHorCnt >= StrInfo[RepHorID].longInt;
          len := Write(MyFile,ADR(Buffer^[CountBytes+5]),1); (* CR *)
        END;
        RepHorCnt := 0;
        REPEAT
          len := Write(MyFile,Buffer,CountBytes+5);        (* Print Line *)
          INC(RepHorCnt);
        UNTIL RepHorCnt >= StrInfo[RepHorID].longInt;
        len := Write(MyFile,ADR(Buffer^[CountBytes+5]),2); (* CR + LF *)

(*------  Increase CountLines and set next LF-Size:  ------*)

        INC(SmallOrBig);
        CASE yRes OF
        DpiV72ID:
          INC(CountLines,8); |
        DpiV144ID:
          Buffer^[0] := 1BH; Buffer^[1] := 7EH;
          Buffer^[2] := 30H;
          CASE SmallOrBig OF
          2: SmallOrBig := 0;
             INC(CountLines,15);
             Buffer^[3] := 1;  |
          1: INC(CountLines);
             Buffer^[3] := 15; |
          END;
          len := Write(MyFile,Buffer,4); |
        DpiV216ID:
          Buffer^[0] := 1BH; Buffer^[1] := 33H;
          CASE SmallOrBig OF
          3: SmallOrBig := 0;
             Buffer^[2] := 1H;     (* small LF: 1/216''             *)
             INC(CountLines,22); | (* 3 Lines done: get a bit down. *)
          2: Buffer^[2] := 16H;    (* next is a big LF (22/216'')   *)
             INC(CountLines); |    (* next Line                     *)
          1: Buffer^[2] := 1H;     (* 1/216''                       *)
             INC(CountLines); |    (* next Line                     *)
          END;
          len := Write(MyFile,Buffer,3); (* set LF-Size *)
        END;

      END;   (* WHILE (CountLines DIV StretchY) < rows DO *)

    END;   (* WITH Screen^.bitMap DO *)

    INC(RepVerCnt);

  UNTIL RepVerCnt >= StrInfo[RepVerID].longInt;

END PrintIt;

(*-----------------------  CleanUp:  --------------------------------------*)

PROCEDURE CleanUp();

BEGIN
  IF Window#NIL THEN CloseWindow(Window) END;
  IF Screen#NIL THEN CloseScreen(Screen) END;
  IF MyFile#NIL THEN Close(MyFile); END;
  IF Buffer#NIL THEN FreeMem(Buffer,SIZE(Buffer^)) END;
  IF WaitPointer#NIL THEN FreeMem(WaitPointer,SIZE(WaitPointer^)) END;
END CleanUp;

(*------  Some Data:  ------*)

PROCEDURE PointerData(); (* $E- Contains SpriteData: *)

BEGIN
  INLINE(0,0,
         0003FH,00000H,0007FH,00021H,0007FH,00000H,000FEH,00042H,
         000FEH,00000H,001FCH,00084H,001FCH,00000H,003F8H,00108H,
         00FFFH,00C07H,017F1H,01A1FH,027F3H,038CFH,04005H,07FFFH,
         0FFF9H,0FFFFH,0800AH,0FFFEH,0800CH,0FFFCH,0FFF8H,0FFF8H,0,0);
END PointerData;

(*---------------------------  MAIN:  -------------------------------------*)

BEGIN

(*------  Itialization:  ------*)

  Screen := NIL;
  MyFile := NIL;
  Buffer := NIL;
  Window := NIL;
  WaitPointer := NIL;
  TermProcedure(CleanUp);

(*------  Get Memory for Pointer:  ------*)

  WaitPointer := AllocMem(SIZE(WaitPointer^),MemReqSet{chip});
  Assert(WaitPointer#NIL,ADR("Not enough Chip Memory !!!"));
  DataPtr := ADR(PointerData);
  WaitPointer^ := DataPtr^;

(*------  Get Argument:  ------*)

  IF NumArgs()=0 THEN
    GetName();
  ELSE
    GetArg(1,PixName,j);
  END;

(*------  Load Pic:  ------*)

  WHILE NOT(ReadILBM(PixName,ReadILBMFlagSet{front,visible},Screen,
        DummyWindow)) DO
    ok := WBenchToFront();
    GetName();
  END;
  ok := WBenchToFront();
  IF Screen^.bitMap.depth > 1 THEN
    Convert();
  END;

(*------  Open Window:  ------*)

  OpenPrintIt();
  InitPrintIt();

(*------  Open PAR:  ------*)

  MyFile := Open(ADR("PAR:"),newFile);
  Assert(MyFile#NIL,ADR("Couldn't open PAR: !!!"));
  Buffer := AllocMem(SIZE(BufferType),MemReqSet{chip});
  Assert(Buffer#NIL,ADR("Not enough Chip Memory !!!"));

(*------  Get Messages:  ------*)

  LOOP
    WaitPort(Window^.userPort);
    Msg := GetMsg(Window^.userPort);
    IF closeWindow IN Msg^.class THEN
      ReplyMsg(Msg);
      EXIT;
    END;
    Gadget := Msg^.iAddress;
    ReplyMsg(Msg);

    CASE Gadgets(Gadget^.gadgetID) OF

    hori1ID..hori8ID:
      StretchX := Gadget^.gadgetID + 1; |

    vert1ID..vert8ID:
      StretchY := Gadget^.gadgetID - 7; |

    PrintNormalID:
      DoublePrint := FALSE; |

    PrintDoubleID:
      DoublePrint := TRUE; |

    PrintItID:
      ScreenToFront(Screen);
      SetPointer(Window,WaitPointer,16,16,-8,-8);
      PrintIt();
      ClearPointer(Window);
      ok := WBenchToFront(); |

    DpiH60ID..DpiH240ID:
      xRes := Gadgets(Gadget^.gadgetID); |

    DpiV72ID..DpiV216ID:
      yRes := Gadgets(Gadget^.gadgetID); |

    PositiveID:
      Positive := NOT(Positive); |

    RepHorID..RepVerID:
      WITH StrInfo[Gadgets(Gadget^.gadgetID)] DO
        IF longInt<1 THEN
          longInt := 1;
        END;
      END; |

    LoadPicID:
      CloseScreen(Screen);
      Screen := NIL;
      REPEAT
        ClearPointer(Window);
        GetName();
        SetPointer(Window,WaitPointer,16,16,-8,-8);
      UNTIL ReadILBM(PixName,ReadILBMFlagSet{front,visible},Screen,
            DummyWindow);
      ClearPointer(Window);
      ok := WBenchToFront();
      IF Screen^.bitMap.depth > 1 THEN
        Convert();
      END; |

    ResetID:
      StretchX := 1; StretchY := 1;
      DoublePrint := FALSE;
      xRes := DpiH240ID;
      yRes := DpiV216ID;
      Positive := TRUE;
      StrInfo[RepHorID].longInt := 1;
      Buffers[RepHorID] := "1";
      StrInfo[RepVerID].longInt := 1;
      Buffers[RepVerID] := "1"; |
    END;

    InitPrintIt();

  END; (* LOOP *)

END PrintIt. That's it.
